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