xref: /openbmc/qemu/target/i386/hvf/x86_cpuid.c (revision f7ceab1e)
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/cpuid.h"
25 #include "host/cpuinfo.h"
26 #include "cpu.h"
27 #include "x86.h"
28 #include "vmx.h"
29 #include "sysemu/hvf.h"
30 #include "hvf-i386.h"
31 
32 static bool cached_xcr0;
33 static uint64_t supported_xcr0;
34 
35 static void cache_host_xcr0(void)
36 {
37     if (cached_xcr0) {
38         return;
39     }
40 
41     if (cpuinfo & CPUINFO_OSXSAVE) {
42         uint64_t host_xcr0 = xgetbv_low(0);
43 
44         /* Only show xcr0 bits corresponding to usable features.  */
45         supported_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
46                                       XSTATE_SSE_MASK | XSTATE_YMM_MASK |
47                                       XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
48                                       XSTATE_Hi16_ZMM_MASK);
49         if ((supported_xcr0 & (XSTATE_FP_MASK | XSTATE_SSE_MASK)) !=
50             (XSTATE_FP_MASK | XSTATE_SSE_MASK)) {
51             supported_xcr0 = 0;
52         }
53     }
54 
55     cached_xcr0 = true;
56 }
57 
58 uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
59                                  int reg)
60 {
61     uint64_t cap;
62     uint32_t eax, ebx, ecx, edx;
63 
64     cache_host_xcr0();
65     host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
66 
67     switch (func) {
68     case 0:
69         eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd;
70         break;
71     case 1:
72         edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
73              CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
74              CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
75              CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
76              CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS;
77         ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
78              CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
79              CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
80              CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_X2APIC |
81              (supported_xcr0 ? CPUID_EXT_XSAVE : 0) |
82              CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
83         ecx |= CPUID_EXT_HYPERVISOR;
84         break;
85     case 6:
86         eax = CPUID_6_EAX_ARAT;
87         ebx = 0;
88         ecx = 0;
89         edx = 0;
90         break;
91     case 7:
92         if (idx == 0) {
93             ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
94                     CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 |
95                     CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 |
96                     CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM |
97                     CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
98                     CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA |
99                     CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF |
100                     CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD |
101                     CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
102                     CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI |
103                     CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL |
104                     CPUID_7_0_EBX_INVPCID;
105 
106             hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
107             if (!(cap & CPU_BASED2_INVPCID)) {
108                 ebx &= ~CPUID_7_0_EBX_INVPCID;
109             }
110 
111             ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ |
112                    CPUID_7_0_ECX_RDPID;
113             edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
114         } else {
115             ebx = 0;
116             ecx = 0;
117             edx = 0;
118         }
119         eax = 0;
120         break;
121     case 0xD:
122         if (!supported_xcr0 || idx >= 63 ||
123             (idx > 1 && !(supported_xcr0 & (UINT64_C(1) << idx)))) {
124             eax = ebx = ecx = edx = 0;
125             break;
126         }
127 
128         if (idx == 0) {
129             eax = supported_xcr0;
130         } else if (idx == 1) {
131             hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
132             eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
133             if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) {
134                 eax &= ~CPUID_XSAVE_XSAVES;
135             }
136         }
137         break;
138     case 0x80000001:
139         /* LM only if HVF in 64-bit mode */
140         edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
141                 CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
142                 CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
143                 CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX |
144                 CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT |
145                 CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX;
146         hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
147         if (!(cap2ctrl(cap, CPU_BASED2_RDTSCP) & CPU_BASED2_RDTSCP)) {
148             edx &= ~CPUID_EXT2_RDTSCP;
149         }
150         hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap);
151         if (!(cap2ctrl(cap, CPU_BASED_TSC_OFFSET) & CPU_BASED_TSC_OFFSET)) {
152             edx &= ~CPUID_EXT2_RDTSCP;
153         }
154         ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG |
155                 CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE |
156                 CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP |
157                 CPUID_EXT3_FMA4 | CPUID_EXT3_TBM;
158         break;
159     case 0x80000007:
160         edx &= CPUID_APM_INVTSC;
161         eax = ebx = ecx = 0;
162         break;
163     default:
164         return 0;
165     }
166 
167     switch (reg) {
168     case R_EAX:
169         return eax;
170     case R_EBX:
171         return ebx;
172     case R_ECX:
173         return ecx;
174     case R_EDX:
175         return edx;
176     default:
177         return 0;
178     }
179 }
180