]>
Commit | Line | Data |
---|---|---|
db5cb9a0 SAGDR |
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 | |
8af82b8e | 10 | * version 2.1 of the License, or (at your option) any later version. |
db5cb9a0 SAGDR |
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" | |
ff2de166 | 24 | #include "cpu.h" |
db5cb9a0 SAGDR |
25 | #include "x86.h" |
26 | #include "vmx.h" | |
27 | #include "sysemu/hvf.h" | |
28 | ||
118f2aad | 29 | static bool xgetbv(uint32_t cpuid_ecx, uint32_t idx, uint64_t *xcr) |
db5cb9a0 | 30 | { |
118f2aad | 31 | uint32_t xcrl, xcrh; |
db5cb9a0 | 32 | |
118f2aad HM |
33 | if (cpuid_ecx & CPUID_EXT_OSXSAVE) { |
34 | /* | |
35 | * The xgetbv instruction is not available to older versions of | |
36 | * the assembler, so we encode the instruction manually. | |
37 | */ | |
38 | asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcrl), "=d" (xcrh) : "c" (idx)); | |
db5cb9a0 | 39 | |
118f2aad HM |
40 | *xcr = (((uint64_t)xcrh) << 32) | xcrl; |
41 | return true; | |
42 | } | |
43 | ||
44 | return false; | |
db5cb9a0 SAGDR |
45 | } |
46 | ||
db5cb9a0 SAGDR |
47 | uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, |
48 | int reg) | |
49 | { | |
50 | uint64_t cap; | |
51 | uint32_t eax, ebx, ecx, edx; | |
52 | ||
53 | host_cpuid(func, idx, &eax, &ebx, &ecx, &edx); | |
54 | ||
55 | switch (func) { | |
56 | case 0: | |
57 | eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd; | |
58 | break; | |
59 | case 1: | |
60 | edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | | |
61 | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | | |
62 | CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | | |
63 | CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | | |
64 | CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS; | |
65 | ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | | |
66 | CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | | |
67 | CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE | | |
68 | CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE | | |
69 | CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND; | |
70 | ecx |= CPUID_EXT_HYPERVISOR; | |
71 | break; | |
72 | case 6: | |
73 | eax = CPUID_6_EAX_ARAT; | |
74 | ebx = 0; | |
75 | ecx = 0; | |
76 | edx = 0; | |
77 | break; | |
78 | case 7: | |
79 | if (idx == 0) { | |
80 | ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | | |
81 | CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | | |
82 | CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | | |
83 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM | | |
84 | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | | |
85 | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA | | |
86 | CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF | | |
87 | CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD | | |
88 | CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | | |
89 | CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI | | |
90 | CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL | | |
c29b48db | 91 | CPUID_7_0_EBX_INVPCID; |
db5cb9a0 | 92 | |
db5cb9a0 SAGDR |
93 | hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap); |
94 | if (!(cap & CPU_BASED2_INVPCID)) { | |
95 | ebx &= ~CPUID_7_0_EBX_INVPCID; | |
96 | } | |
97 | ||
e7694a5e | 98 | ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ; |
db5cb9a0 SAGDR |
99 | edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS; |
100 | } else { | |
101 | ebx = 0; | |
102 | ecx = 0; | |
103 | edx = 0; | |
104 | } | |
105 | eax = 0; | |
106 | break; | |
107 | case 0xD: | |
108 | if (idx == 0) { | |
118f2aad HM |
109 | uint64_t host_xcr0; |
110 | if (xgetbv(ecx, 0, &host_xcr0)) { | |
111 | uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK | | |
112 | XSTATE_SSE_MASK | XSTATE_YMM_MASK | | |
113 | XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK | | |
114 | XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK | | |
115 | XSTATE_Hi16_ZMM_MASK); | |
116 | eax &= supp_xcr0; | |
117 | } | |
db5cb9a0 SAGDR |
118 | } else if (idx == 1) { |
119 | hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap); | |
120 | eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1; | |
121 | if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) { | |
122 | eax &= ~CPUID_XSAVE_XSAVES; | |
123 | } | |
124 | } | |
125 | break; | |
126 | case 0x80000001: | |
127 | /* LM only if HVF in 64-bit mode */ | |
128 | edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | | |
129 | CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | | |
130 | CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | | |
131 | CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX | | |
132 | CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT | | |
133 | CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX; | |
65baabca JC |
134 | hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap); |
135 | if (!(cap & CPU_BASED2_RDTSCP)) { | |
136 | edx &= ~CPUID_EXT2_RDTSCP; | |
137 | } | |
db5cb9a0 SAGDR |
138 | hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap); |
139 | if (!(cap & CPU_BASED_TSC_OFFSET)) { | |
140 | edx &= ~CPUID_EXT2_RDTSCP; | |
141 | } | |
142 | ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG | | |
143 | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE | | |
144 | CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP | | |
145 | CPUID_EXT3_FMA4 | CPUID_EXT3_TBM; | |
146 | break; | |
147 | default: | |
148 | return 0; | |
149 | } | |
150 | ||
151 | switch (reg) { | |
152 | case R_EAX: | |
153 | return eax; | |
154 | case R_EBX: | |
155 | return ebx; | |
156 | case R_ECX: | |
157 | return ecx; | |
158 | case R_EDX: | |
159 | return edx; | |
160 | default: | |
161 | return 0; | |
162 | } | |
163 | } |