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