qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

x86_cpuid.c (6112B)


      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 
     29 static bool xgetbv(uint32_t cpuid_ecx, uint32_t idx, uint64_t *xcr)
     30 {
     31     uint32_t xcrl, xcrh;
     32 
     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));
     39 
     40         *xcr = (((uint64_t)xcrh) << 32) | xcrl;
     41         return true;
     42     }
     43 
     44     return false;
     45 }
     46 
     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 |
     91                     CPUID_7_0_EBX_INVPCID;
     92 
     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 
     98             ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ |
     99                    CPUID_7_0_ECX_RDPID;
    100             edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
    101         } else {
    102             ebx = 0;
    103             ecx = 0;
    104             edx = 0;
    105         }
    106         eax = 0;
    107         break;
    108     case 0xD:
    109         if (idx == 0) {
    110             uint64_t host_xcr0;
    111             if (xgetbv(ecx, 0, &host_xcr0)) {
    112                 uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK |
    113                                   XSTATE_SSE_MASK | XSTATE_YMM_MASK |
    114                                   XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK |
    115                                   XSTATE_OPMASK_MASK | XSTATE_ZMM_Hi256_MASK |
    116                                   XSTATE_Hi16_ZMM_MASK);
    117                 eax &= supp_xcr0;
    118             }
    119         } else if (idx == 1) {
    120             hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
    121             eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1;
    122             if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) {
    123                 eax &= ~CPUID_XSAVE_XSAVES;
    124             }
    125         }
    126         break;
    127     case 0x80000001:
    128         /* LM only if HVF in 64-bit mode */
    129         edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC |
    130                 CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC |
    131                 CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV |
    132                 CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX |
    133                 CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT |
    134                 CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX;
    135         hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap);
    136         if (!(cap2ctrl(cap, CPU_BASED2_RDTSCP) & CPU_BASED2_RDTSCP)) {
    137             edx &= ~CPUID_EXT2_RDTSCP;
    138         }
    139         hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap);
    140         if (!(cap2ctrl(cap, CPU_BASED_TSC_OFFSET) & CPU_BASED_TSC_OFFSET)) {
    141             edx &= ~CPUID_EXT2_RDTSCP;
    142         }
    143         ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG |
    144                 CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE |
    145                 CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP |
    146                 CPUID_EXT3_FMA4 | CPUID_EXT3_TBM;
    147         break;
    148     default:
    149         return 0;
    150     }
    151 
    152     switch (reg) {
    153     case R_EAX:
    154         return eax;
    155     case R_EBX:
    156         return ebx;
    157     case R_ECX:
    158         return ecx;
    159     case R_EDX:
    160         return edx;
    161     default:
    162         return 0;
    163     }
    164 }