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