]> git.proxmox.com Git - mirror_qemu.git/blob - target/i386/hvf/x86_cpuid.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[mirror_qemu.git] / target / i386 / hvf / x86_cpuid.c
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 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-common.h"
25 #include "cpu.h"
26 #include "x86.h"
27 #include "vmx.h"
28 #include "sysemu/hvf.h"
29
30 static 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
41 uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
42 int reg)
43 {
44 uint64_t cap;
45 uint32_t eax, ebx, ecx, edx;
46
47 host_cpuid(func, idx, &eax, &ebx, &ecx, &edx);
48
49 switch (func) {
50 case 0:
51 eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd;
52 break;
53 case 1:
54 edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
55 CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
56 CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
57 CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX |
58 CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS;
59 ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 |
60 CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID |
61 CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE |
62 CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE |
63 CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND;
64 ecx |= CPUID_EXT_HYPERVISOR;
65 break;
66 case 6:
67 eax = CPUID_6_EAX_ARAT;
68 ebx = 0;
69 ecx = 0;
70 edx = 0;
71 break;
72 case 7:
73 if (idx == 0) {
74 ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
75 CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 |
76 CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 |
77 CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM |
78 CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
79 CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA |
80 CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF |
81 CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD |
82 CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB |
83 CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI |
84 CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL |
85 CPUID_7_0_EBX_INVPCID;
86
87 hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
88 if (!(cap & CPU_BASED2_INVPCID)) {
89 ebx &= ~CPUID_7_0_EBX_INVPCID;
90 }
91
92 ecx &= CPUID_7_0_ECX_AVX512BMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ;
93 edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
94 } else {
95 ebx = 0;
96 ecx = 0;
97 edx = 0;
98 }
99 eax = 0;
100 break;
101 case 0xD:
102 if (idx == 0) {
103 uint64_t host_xcr0 = xgetbv(0);
104 uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK | XSTATE_SSE_MASK |
105 XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK |
106 XSTATE_BNDCSR_MASK | XSTATE_OPMASK_MASK |
107 XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK);
108 eax &= supp_xcr0;
109 } else if (idx == 1) {
110 hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
111 eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
112 if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) {
113 eax &= ~CPUID_XSAVE_XSAVES;
114 }
115 }
116 break;
117 case 0x80000001:
118 /* LM only if HVF in 64-bit mode */
119 edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
120 CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
121 CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
122 CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX |
123 CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT |
124 CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX;
125 hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap);
126 if (!(cap & CPU_BASED_TSC_OFFSET)) {
127 edx &= ~CPUID_EXT2_RDTSCP;
128 }
129 ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG |
130 CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE |
131 CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP |
132 CPUID_EXT3_FMA4 | CPUID_EXT3_TBM;
133 break;
134 default:
135 return 0;
136 }
137
138 switch (reg) {
139 case R_EAX:
140 return eax;
141 case R_EBX:
142 return ebx;
143 case R_ECX:
144 return ecx;
145 case R_EDX:
146 return edx;
147 default:
148 return 0;
149 }
150 }