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