qemu/target/i386/hvf/x86_cpuid.c
<<
>>
Prefs
   1/*
   2 *  i386 CPUID helper functions
   3 *
   4 *  Copyright (c) 2003 Fabrice Bellard
   5 *  Copyright (c) 2017 Google Inc.
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2 of the License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  19 *
  20 * cpuid
  21 */
  22
  23#include "qemu/osdep.h"
  24#include "qemu-common.h"
  25#include "cpu.h"
  26#include "x86.h"
  27#include "vmx.h"
  28#include "sysemu/hvf.h"
  29
  30static uint64_t xgetbv(uint32_t xcr)
  31{
  32    uint32_t eax, edx;
  33
  34    __asm__ volatile ("xgetbv"
  35                      : "=a" (eax), "=d" (edx)
  36                      : "c" (xcr));
  37
  38    return (((uint64_t)edx) << 32) | eax;
  39}
  40
  41static bool vmx_mpx_supported()
  42{
  43    uint64_t cap_exit, cap_entry;
  44
  45    hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &cap_entry);
  46    hv_vmx_read_capability(HV_VMX_CAP_EXIT, &cap_exit);
  47
  48    return ((cap_exit & (1 << 23)) && (cap_entry & (1 << 16)));
  49}
  50
  51uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
  52                                 int reg)
  53{
  54    uint64_t cap;
  55    uint32_t eax, ebx, ecx, edx;
  56
  57    host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
  58
  59    switch (func) {
  60    case 0:
  61        eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd;
  62        break;
  63    case 1:
  64        edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
  65             CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
  66             CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
  67             CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
  68             CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS;
  69        ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
  70             CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
  71             CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
  72             CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE |
  73             CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
  74        ecx |= CPUID_EXT_HYPERVISOR;
  75        break;
  76    case 6:
  77        eax = CPUID_6_EAX_ARAT;
  78        ebx = 0;
  79        ecx = 0;
  80        edx = 0;
  81        break;
  82    case 7:
  83        if (idx == 0) {
  84            ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
  85                    CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 |
  86                    CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 |
  87                    CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM |
  88                    CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
  89                    CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA |
  90                    CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF |
  91                    CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD |
  92                    CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
  93                    CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI |
  94                    CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL |
  95                    CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_MPX;
  96
  97            if (!vmx_mpx_supported()) {
  98                ebx &= ~CPUID_7_0_EBX_MPX;
  99            }
 100            hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
 101            if (!(cap & CPU_BASED2_INVPCID)) {
 102                ebx &= ~CPUID_7_0_EBX_INVPCID;
 103            }
 104
 105            ecx &= CPUID_7_0_ECX_AVX512BMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ;
 106            edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
 107        } else {
 108            ebx = 0;
 109            ecx = 0;
 110            edx = 0;
 111        }
 112        eax = 0;
 113        break;
 114    case 0xD:
 115        if (idx == 0) {
 116            uint64_t host_xcr0 = xgetbv(0);
 117            uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK | XSTATE_SSE_MASK |
 118                                  XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK |
 119                                  XSTATE_BNDCSR_MASK | XSTATE_OPMASK_MASK |
 120                                  XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK);
 121            eax &= supp_xcr0;
 122            if (!vmx_mpx_supported()) {
 123                eax &= ~(XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK);
 124            }
 125        } else if (idx == 1) {
 126            hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
 127            eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
 128            if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) {
 129                eax &= ~CPUID_XSAVE_XSAVES;
 130            }
 131        }
 132        break;
 133    case 0x80000001:
 134        /* LM only if HVF in 64-bit mode */
 135        edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
 136                CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
 137                CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
 138                CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX |
 139                CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT |
 140                CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX;
 141        hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap);
 142        if (!(cap & CPU_BASED_TSC_OFFSET)) {
 143            edx &= ~CPUID_EXT2_RDTSCP;
 144        }
 145        ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG |
 146                CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE |
 147                CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP |
 148                CPUID_EXT3_FMA4 | CPUID_EXT3_TBM;
 149        break;
 150    default:
 151        return 0;
 152    }
 153
 154    switch (reg) {
 155    case R_EAX:
 156        return eax;
 157    case R_EBX:
 158        return ebx;
 159    case R_ECX:
 160        return ecx;
 161    case R_EDX:
 162        return edx;
 163    default:
 164        return 0;
 165    }
 166}
 167