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.1 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 bool xgetbv(uint32_t cpuid_ecx, uint32_t idx, uint64_t *xcr)
  31{
  32    uint32_t xcrl, xcrh;
  33
  34    if (cpuid_ecx & CPUID_EXT_OSXSAVE) {
  35        /*
  36         * The xgetbv instruction is not available to older versions of
  37         * the assembler, so we encode the instruction manually.
  38         */
  39        asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcrl), "=d" (xcrh) : "c" (idx));
  40
  41        *xcr = (((uint64_t)xcrh) << 32) | xcrl;
  42        return true;
  43    }
  44
  45    return false;
  46}
  47
  48uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
  49                                 int reg)
  50{
  51    uint64_t cap;
  52    uint32_t eax, ebx, ecx, edx;
  53
  54    host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
  55
  56    switch (func) {
  57    case 0:
  58        eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd;
  59        break;
  60    case 1:
  61        edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
  62             CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
  63             CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
  64             CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
  65             CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS;
  66        ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
  67             CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
  68             CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
  69             CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE |
  70             CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
  71        ecx |= CPUID_EXT_HYPERVISOR;
  72        break;
  73    case 6:
  74        eax = CPUID_6_EAX_ARAT;
  75        ebx = 0;
  76        ecx = 0;
  77        edx = 0;
  78        break;
  79    case 7:
  80        if (idx == 0) {
  81            ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
  82                    CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 |
  83                    CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 |
  84                    CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM |
  85                    CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
  86                    CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA |
  87                    CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF |
  88                    CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD |
  89                    CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
  90                    CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI |
  91                    CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL |
  92                    CPUID_7_0_EBX_INVPCID;
  93
  94            hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
  95            if (!(cap & CPU_BASED2_INVPCID)) {
  96                ebx &= ~CPUID_7_0_EBX_INVPCID;
  97            }
  98
  99            ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ;
 100            edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
 101        } else {
 102            ebx = 0;
 103            ecx = 0;
 104            edx = 0;
 105        }
 106        eax = 0;
 107        break;
 108    case 0xD:
 109        if (idx == 0) {
 110            uint64_t host_xcr0;
 111            if (xgetbv(ecx, 0, &host_xcr0)) {
 112                uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
 113                                  XSTATE_SSE_MASK | XSTATE_YMM_MASK |
 114                                  XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
 115                                  XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
 116                                  XSTATE_Hi16_ZMM_MASK);
 117                eax &= supp_xcr0;
 118            }
 119        } else if (idx == 1) {
 120            hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
 121            eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
 122            if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) {
 123                eax &= ~CPUID_XSAVE_XSAVES;
 124            }
 125        }
 126        break;
 127    case 0x80000001:
 128        /* LM only if HVF in 64-bit mode */
 129        edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
 130                CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
 131                CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
 132                CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX |
 133                CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT |
 134                CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX;
 135        hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
 136        if (!(cap & CPU_BASED2_RDTSCP)) {
 137            edx &= ~CPUID_EXT2_RDTSCP;
 138        }
 139        hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap);
 140        if (!(cap & CPU_BASED_TSC_OFFSET)) {
 141            edx &= ~CPUID_EXT2_RDTSCP;
 142        }
 143        ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG |
 144                CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE |
 145                CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP |
 146                CPUID_EXT3_FMA4 | CPUID_EXT3_TBM;
 147        break;
 148    default:
 149        return 0;
 150    }
 151
 152    switch (reg) {
 153    case R_EAX:
 154        return eax;
 155    case R_EBX:
 156        return ebx;
 157    case R_ECX:
 158        return ecx;
 159    case R_EDX:
 160        return edx;
 161    default:
 162        return 0;
 163    }
 164}
 165