master
c 158 lines 5.21 KB
Raw
1 /*
2 * i386 CPUID helper functions
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 * Copyright (c) 2017 Google Inc.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "qemu/osdep.h"
11 #include "qemu/cpuid.h"
12 #include "host/cpuinfo.h"
13 #include "cpu.h"
14 #include "emulate/x86.h"
15 #include "whpx-i386.h"
16
17 static bool cached_xcr0;
18 static uint64_t supported_xcr0;
19
20 static void cache_host_xcr0(void)
21 {
22 if (cached_xcr0) {
23 return;
24 }
25
26 if (whpx_has_xsave()) {
27 uint64_t host_xcr0 = xgetbv_low(0);
28
29 /* Only show xcr0 bits corresponding to usable features. */
30 supported_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
31 XSTATE_SSE_MASK | XSTATE_YMM_MASK |
32 XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
33 XSTATE_Hi16_ZMM_MASK);
34 if ((supported_xcr0 & (XSTATE_FP_MASK | XSTATE_SSE_MASK)) !=
35 (XSTATE_FP_MASK | XSTATE_SSE_MASK)) {
36 supported_xcr0 = 0;
37 }
38 }
39
40 cached_xcr0 = true;
41 }
42
43 uint32_t whpx_get_supported_cpuid_legacy(uint32_t func, uint32_t idx,
44 int reg)
45 {
46 uint32_t eax, ebx, ecx, edx;
47
48 cache_host_xcr0();
49 host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
50
51 switch (func) {
52 case 0:
53 eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd;
54 break;
55 case 1:
56 edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
57 CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
58 CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
59 CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
60 CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_HT;
61 ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
62 CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
63 CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
64 CPUID_EXT_POPCNT | CPUID_EXT_AES |
65 (supported_xcr0 ? CPUID_EXT_XSAVE : 0) |
66 CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
67 ecx |= CPUID_EXT_HYPERVISOR;
68 ecx |= CPUID_EXT_X2APIC;
69 edx |= CPUID_HT;
70 break;
71 case 6:
72 eax = CPUID_6_EAX_ARAT;
73 ebx = 0;
74 ecx = 0;
75 edx = 0;
76 break;
77 case 7:
78 if (idx == 0) {
79 ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
80 CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 |
81 CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 |
82 CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM |
83 CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
84 CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA |
85 CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF |
86 CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD |
87 CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
88 CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI |
89 CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL |
90 CPUID_7_0_EBX_INVPCID;
91
92 if (!whpx_has_invpcid()) {
93 ebx &= ~CPUID_7_0_EBX_INVPCID;
94 }
95
96 ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ |
97 CPUID_7_0_ECX_RDPID;
98 edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
99 } else {
100 ebx = 0;
101 ecx = 0;
102 edx = 0;
103 }
104 eax = 0;
105 break;
106 case 0xD:
107 if (!supported_xcr0 || idx >= 63 ||
108 (idx > 1 && !(supported_xcr0 & (UINT64_C(1) << idx)))) {
109 eax = ebx = ecx = edx = 0;
110 break;
111 }
112
113 if (idx == 0) {
114 eax = supported_xcr0;
115 } else if (idx == 1) {
116 eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES;
117 if (!whpx_has_xsaves()) {
118 eax &= ~CPUID_XSAVE_XSAVES;
119 }
120 }
121 break;
122 case 0x80000001:
123 /* LM only if HVF in 64-bit mode */
124 edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
125 CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
126 CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
127 CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX |
128 CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT |
129 CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX;
130 if (!(whpx_has_rdtscp())) {
131 edx &= ~CPUID_EXT2_RDTSCP;
132 }
133 ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG |
134 CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE |
135 CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP |
136 CPUID_EXT3_FMA4 | CPUID_EXT3_TBM;
137 break;
138 case 0x80000007:
139 edx &= CPUID_APM_INVTSC;
140 eax = ebx = ecx = 0;
141 break;
142 default:
143 return 0;
144 }
145
146 switch (reg) {
147 case R_EAX:
148 return eax;
149 case R_EBX:
150 return ebx;
151 case R_ECX:
152 return ecx;
153 case R_EDX:
154 return edx;
155 default:
156 return 0;
157 }
158 }