xref: /qemu/target/i386/hvf/x86_cpuid.c (revision 044431cf)
169e0a03cSPaolo Bonzini /*
269e0a03cSPaolo Bonzini  *  i386 CPUID helper functions
369e0a03cSPaolo Bonzini  *
469e0a03cSPaolo Bonzini  *  Copyright (c) 2003 Fabrice Bellard
569e0a03cSPaolo Bonzini  *  Copyright (c) 2017 Google Inc.
669e0a03cSPaolo Bonzini  *
769e0a03cSPaolo Bonzini  * This program is free software; you can redistribute it and/or
869e0a03cSPaolo Bonzini  * modify it under the terms of the GNU Lesser General Public
969e0a03cSPaolo Bonzini  * License as published by the Free Software Foundation; either
108af82b8eSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
1169e0a03cSPaolo Bonzini  *
1269e0a03cSPaolo Bonzini  * This program is distributed in the hope that it will be useful,
1369e0a03cSPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1469e0a03cSPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1569e0a03cSPaolo Bonzini  * Lesser General Public License for more details.
1669e0a03cSPaolo Bonzini  *
1769e0a03cSPaolo Bonzini  * You should have received a copy of the GNU Lesser General Public
1869e0a03cSPaolo Bonzini  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
1969e0a03cSPaolo Bonzini  *
2069e0a03cSPaolo Bonzini  * cpuid
2169e0a03cSPaolo Bonzini  */
2269e0a03cSPaolo Bonzini 
2369e0a03cSPaolo Bonzini #include "qemu/osdep.h"
24ff2de166SPaolo Bonzini #include "cpu.h"
2569e0a03cSPaolo Bonzini #include "x86.h"
2669e0a03cSPaolo Bonzini #include "vmx.h"
2769e0a03cSPaolo Bonzini #include "sysemu/hvf.h"
28044431cfSPhilippe Mathieu-Daudé #include "hvf-i386.h"
2969e0a03cSPaolo Bonzini 
xgetbv(uint32_t cpuid_ecx,uint32_t idx,uint64_t * xcr)30118f2aadSHill Ma static bool xgetbv(uint32_t cpuid_ecx, uint32_t idx, uint64_t *xcr)
3169e0a03cSPaolo Bonzini {
32118f2aadSHill Ma     uint32_t xcrl, xcrh;
3369e0a03cSPaolo Bonzini 
34118f2aadSHill Ma     if (cpuid_ecx & CPUID_EXT_OSXSAVE) {
35118f2aadSHill Ma         /*
36118f2aadSHill Ma          * The xgetbv instruction is not available to older versions of
37118f2aadSHill Ma          * the assembler, so we encode the instruction manually.
38118f2aadSHill Ma          */
39118f2aadSHill Ma         asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcrl), "=d" (xcrh) : "c" (idx));
4069e0a03cSPaolo Bonzini 
41118f2aadSHill Ma         *xcr = (((uint64_t)xcrh) << 32) | xcrl;
42118f2aadSHill Ma         return true;
43118f2aadSHill Ma     }
44118f2aadSHill Ma 
45118f2aadSHill Ma     return false;
4669e0a03cSPaolo Bonzini }
4769e0a03cSPaolo Bonzini 
hvf_get_supported_cpuid(uint32_t func,uint32_t idx,int reg)4869e0a03cSPaolo Bonzini uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
4969e0a03cSPaolo Bonzini                                  int reg)
5069e0a03cSPaolo Bonzini {
5169e0a03cSPaolo Bonzini     uint64_t cap;
5269e0a03cSPaolo Bonzini     uint32_t eax, ebx, ecx, edx;
5369e0a03cSPaolo Bonzini 
5469e0a03cSPaolo Bonzini     host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
5569e0a03cSPaolo Bonzini 
5669e0a03cSPaolo Bonzini     switch (func) {
5769e0a03cSPaolo Bonzini     case 0:
5869e0a03cSPaolo Bonzini         eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd;
5969e0a03cSPaolo Bonzini         break;
6069e0a03cSPaolo Bonzini     case 1:
6169e0a03cSPaolo Bonzini         edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
6269e0a03cSPaolo Bonzini              CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
6369e0a03cSPaolo Bonzini              CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
6469e0a03cSPaolo Bonzini              CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
6569e0a03cSPaolo Bonzini              CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS;
6669e0a03cSPaolo Bonzini         ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
6769e0a03cSPaolo Bonzini              CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
6869e0a03cSPaolo Bonzini              CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
6969e0a03cSPaolo Bonzini              CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE |
7069e0a03cSPaolo Bonzini              CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
7169e0a03cSPaolo Bonzini         ecx |= CPUID_EXT_HYPERVISOR;
7269e0a03cSPaolo Bonzini         break;
7369e0a03cSPaolo Bonzini     case 6:
7469e0a03cSPaolo Bonzini         eax = CPUID_6_EAX_ARAT;
7569e0a03cSPaolo Bonzini         ebx = 0;
7669e0a03cSPaolo Bonzini         ecx = 0;
7769e0a03cSPaolo Bonzini         edx = 0;
7869e0a03cSPaolo Bonzini         break;
7969e0a03cSPaolo Bonzini     case 7:
8069e0a03cSPaolo Bonzini         if (idx == 0) {
8169e0a03cSPaolo Bonzini             ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
8269e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 |
8369e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 |
8469e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM |
8569e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
8669e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA |
8769e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF |
8869e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD |
8969e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
9069e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI |
9169e0a03cSPaolo Bonzini                     CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL |
92c29b48dbSPaolo Bonzini                     CPUID_7_0_EBX_INVPCID;
9369e0a03cSPaolo Bonzini 
9469e0a03cSPaolo Bonzini             hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
9569e0a03cSPaolo Bonzini             if (!(cap & CPU_BASED2_INVPCID)) {
9669e0a03cSPaolo Bonzini                 ebx &= ~CPUID_7_0_EBX_INVPCID;
9769e0a03cSPaolo Bonzini             }
9869e0a03cSPaolo Bonzini 
99d8cf2c29SCameron Esfahani             ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ |
100d8cf2c29SCameron Esfahani                    CPUID_7_0_ECX_RDPID;
10169e0a03cSPaolo Bonzini             edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
10269e0a03cSPaolo Bonzini         } else {
10369e0a03cSPaolo Bonzini             ebx = 0;
10469e0a03cSPaolo Bonzini             ecx = 0;
10569e0a03cSPaolo Bonzini             edx = 0;
10669e0a03cSPaolo Bonzini         }
10769e0a03cSPaolo Bonzini         eax = 0;
10869e0a03cSPaolo Bonzini         break;
10969e0a03cSPaolo Bonzini     case 0xD:
11069e0a03cSPaolo Bonzini         if (idx == 0) {
111118f2aadSHill Ma             uint64_t host_xcr0;
112118f2aadSHill Ma             if (xgetbv(ecx, 0, &host_xcr0)) {
113118f2aadSHill Ma                 uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
114118f2aadSHill Ma                                   XSTATE_SSE_MASK | XSTATE_YMM_MASK |
115118f2aadSHill Ma                                   XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
116118f2aadSHill Ma                                   XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
117118f2aadSHill Ma                                   XSTATE_Hi16_ZMM_MASK);
11869e0a03cSPaolo Bonzini                 eax &= supp_xcr0;
119118f2aadSHill Ma             }
12069e0a03cSPaolo Bonzini         } else if (idx == 1) {
12169e0a03cSPaolo Bonzini             hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
12269e0a03cSPaolo Bonzini             eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
12369e0a03cSPaolo Bonzini             if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) {
12469e0a03cSPaolo Bonzini                 eax &= ~CPUID_XSAVE_XSAVES;
12569e0a03cSPaolo Bonzini             }
12669e0a03cSPaolo Bonzini         }
12769e0a03cSPaolo Bonzini         break;
12869e0a03cSPaolo Bonzini     case 0x80000001:
12969e0a03cSPaolo Bonzini         /* LM only if HVF in 64-bit mode */
13069e0a03cSPaolo Bonzini         edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
13169e0a03cSPaolo Bonzini                 CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
13269e0a03cSPaolo Bonzini                 CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
13369e0a03cSPaolo Bonzini                 CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX |
13469e0a03cSPaolo Bonzini                 CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT |
13569e0a03cSPaolo Bonzini                 CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX;
13665baabcaSJessica Clarke         hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
137d8cf2c29SCameron Esfahani         if (!(cap2ctrl(cap, CPU_BASED2_RDTSCP) & CPU_BASED2_RDTSCP)) {
13865baabcaSJessica Clarke             edx &= ~CPUID_EXT2_RDTSCP;
13965baabcaSJessica Clarke         }
14069e0a03cSPaolo Bonzini         hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap);
141d8cf2c29SCameron Esfahani         if (!(cap2ctrl(cap, CPU_BASED_TSC_OFFSET) & CPU_BASED_TSC_OFFSET)) {
14269e0a03cSPaolo Bonzini             edx &= ~CPUID_EXT2_RDTSCP;
14369e0a03cSPaolo Bonzini         }
14469e0a03cSPaolo Bonzini         ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG |
14569e0a03cSPaolo Bonzini                 CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE |
14669e0a03cSPaolo Bonzini                 CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP |
14769e0a03cSPaolo Bonzini                 CPUID_EXT3_FMA4 | CPUID_EXT3_TBM;
14869e0a03cSPaolo Bonzini         break;
14969e0a03cSPaolo Bonzini     default:
15069e0a03cSPaolo Bonzini         return 0;
15169e0a03cSPaolo Bonzini     }
15269e0a03cSPaolo Bonzini 
15369e0a03cSPaolo Bonzini     switch (reg) {
15469e0a03cSPaolo Bonzini     case R_EAX:
15569e0a03cSPaolo Bonzini         return eax;
15669e0a03cSPaolo Bonzini     case R_EBX:
15769e0a03cSPaolo Bonzini         return ebx;
15869e0a03cSPaolo Bonzini     case R_ECX:
15969e0a03cSPaolo Bonzini         return ecx;
16069e0a03cSPaolo Bonzini     case R_EDX:
16169e0a03cSPaolo Bonzini         return edx;
16269e0a03cSPaolo Bonzini     default:
16369e0a03cSPaolo Bonzini         return 0;
16469e0a03cSPaolo Bonzini     }
16569e0a03cSPaolo Bonzini }
166