1b66370dbSMichael Roth /* SPDX-License-Identifier: GPL-2.0 */ 2b66370dbSMichael Roth /* 3b66370dbSMichael Roth * CPUID-related helpers/definitions 4b66370dbSMichael Roth */ 5b66370dbSMichael Roth 6b66370dbSMichael Roth #ifndef _ASM_X86_CPUID_H 7b66370dbSMichael Roth #define _ASM_X86_CPUID_H 8b66370dbSMichael Roth 9*d8001690SBorislav Petkov #include <asm/string.h> 10*d8001690SBorislav Petkov 11*d8001690SBorislav Petkov struct cpuid_regs { 12*d8001690SBorislav Petkov u32 eax, ebx, ecx, edx; 13*d8001690SBorislav Petkov }; 14*d8001690SBorislav Petkov 15*d8001690SBorislav Petkov enum cpuid_regs_idx { 16*d8001690SBorislav Petkov CPUID_EAX = 0, 17*d8001690SBorislav Petkov CPUID_EBX, 18*d8001690SBorislav Petkov CPUID_ECX, 19*d8001690SBorislav Petkov CPUID_EDX, 20*d8001690SBorislav Petkov }; 21*d8001690SBorislav Petkov 22*d8001690SBorislav Petkov #ifdef CONFIG_X86_32 23*d8001690SBorislav Petkov extern int have_cpuid_p(void); 24*d8001690SBorislav Petkov #else 25*d8001690SBorislav Petkov static inline int have_cpuid_p(void) 26*d8001690SBorislav Petkov { 27*d8001690SBorislav Petkov return 1; 28*d8001690SBorislav Petkov } 29*d8001690SBorislav Petkov #endif 30*d8001690SBorislav Petkov static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, 31*d8001690SBorislav Petkov unsigned int *ecx, unsigned int *edx) 32*d8001690SBorislav Petkov { 33*d8001690SBorislav Petkov /* ecx is often an input as well as an output. */ 34*d8001690SBorislav Petkov asm volatile("cpuid" 35*d8001690SBorislav Petkov : "=a" (*eax), 36*d8001690SBorislav Petkov "=b" (*ebx), 37*d8001690SBorislav Petkov "=c" (*ecx), 38*d8001690SBorislav Petkov "=d" (*edx) 39*d8001690SBorislav Petkov : "0" (*eax), "2" (*ecx) 40*d8001690SBorislav Petkov : "memory"); 41*d8001690SBorislav Petkov } 42*d8001690SBorislav Petkov 43*d8001690SBorislav Petkov #define native_cpuid_reg(reg) \ 44*d8001690SBorislav Petkov static inline unsigned int native_cpuid_##reg(unsigned int op) \ 45*d8001690SBorislav Petkov { \ 46*d8001690SBorislav Petkov unsigned int eax = op, ebx, ecx = 0, edx; \ 47*d8001690SBorislav Petkov \ 48*d8001690SBorislav Petkov native_cpuid(&eax, &ebx, &ecx, &edx); \ 49*d8001690SBorislav Petkov \ 50*d8001690SBorislav Petkov return reg; \ 51*d8001690SBorislav Petkov } 52*d8001690SBorislav Petkov 53*d8001690SBorislav Petkov /* 54*d8001690SBorislav Petkov * Native CPUID functions returning a single datum. 55*d8001690SBorislav Petkov */ 56*d8001690SBorislav Petkov native_cpuid_reg(eax) 57*d8001690SBorislav Petkov native_cpuid_reg(ebx) 58*d8001690SBorislav Petkov native_cpuid_reg(ecx) 59*d8001690SBorislav Petkov native_cpuid_reg(edx) 60*d8001690SBorislav Petkov 61*d8001690SBorislav Petkov #ifdef CONFIG_PARAVIRT_XXL 62*d8001690SBorislav Petkov #include <asm/paravirt.h> 63*d8001690SBorislav Petkov #else 64*d8001690SBorislav Petkov #define __cpuid native_cpuid 65*d8001690SBorislav Petkov #endif 66*d8001690SBorislav Petkov 67*d8001690SBorislav Petkov /* 68*d8001690SBorislav Petkov * Generic CPUID function 69*d8001690SBorislav Petkov * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx 70*d8001690SBorislav Petkov * resulting in stale register contents being returned. 71*d8001690SBorislav Petkov */ 72*d8001690SBorislav Petkov static inline void cpuid(unsigned int op, 73*d8001690SBorislav Petkov unsigned int *eax, unsigned int *ebx, 74*d8001690SBorislav Petkov unsigned int *ecx, unsigned int *edx) 75*d8001690SBorislav Petkov { 76*d8001690SBorislav Petkov *eax = op; 77*d8001690SBorislav Petkov *ecx = 0; 78*d8001690SBorislav Petkov __cpuid(eax, ebx, ecx, edx); 79*d8001690SBorislav Petkov } 80*d8001690SBorislav Petkov 81*d8001690SBorislav Petkov /* Some CPUID calls want 'count' to be placed in ecx */ 82*d8001690SBorislav Petkov static inline void cpuid_count(unsigned int op, int count, 83*d8001690SBorislav Petkov unsigned int *eax, unsigned int *ebx, 84*d8001690SBorislav Petkov unsigned int *ecx, unsigned int *edx) 85*d8001690SBorislav Petkov { 86*d8001690SBorislav Petkov *eax = op; 87*d8001690SBorislav Petkov *ecx = count; 88*d8001690SBorislav Petkov __cpuid(eax, ebx, ecx, edx); 89*d8001690SBorislav Petkov } 90*d8001690SBorislav Petkov 91*d8001690SBorislav Petkov /* 92*d8001690SBorislav Petkov * CPUID functions returning a single datum 93*d8001690SBorislav Petkov */ 94*d8001690SBorislav Petkov static inline unsigned int cpuid_eax(unsigned int op) 95*d8001690SBorislav Petkov { 96*d8001690SBorislav Petkov unsigned int eax, ebx, ecx, edx; 97*d8001690SBorislav Petkov 98*d8001690SBorislav Petkov cpuid(op, &eax, &ebx, &ecx, &edx); 99*d8001690SBorislav Petkov 100*d8001690SBorislav Petkov return eax; 101*d8001690SBorislav Petkov } 102*d8001690SBorislav Petkov 103*d8001690SBorislav Petkov static inline unsigned int cpuid_ebx(unsigned int op) 104*d8001690SBorislav Petkov { 105*d8001690SBorislav Petkov unsigned int eax, ebx, ecx, edx; 106*d8001690SBorislav Petkov 107*d8001690SBorislav Petkov cpuid(op, &eax, &ebx, &ecx, &edx); 108*d8001690SBorislav Petkov 109*d8001690SBorislav Petkov return ebx; 110*d8001690SBorislav Petkov } 111*d8001690SBorislav Petkov 112*d8001690SBorislav Petkov static inline unsigned int cpuid_ecx(unsigned int op) 113*d8001690SBorislav Petkov { 114*d8001690SBorislav Petkov unsigned int eax, ebx, ecx, edx; 115*d8001690SBorislav Petkov 116*d8001690SBorislav Petkov cpuid(op, &eax, &ebx, &ecx, &edx); 117*d8001690SBorislav Petkov 118*d8001690SBorislav Petkov return ecx; 119*d8001690SBorislav Petkov } 120*d8001690SBorislav Petkov 121*d8001690SBorislav Petkov static inline unsigned int cpuid_edx(unsigned int op) 122*d8001690SBorislav Petkov { 123*d8001690SBorislav Petkov unsigned int eax, ebx, ecx, edx; 124*d8001690SBorislav Petkov 125*d8001690SBorislav Petkov cpuid(op, &eax, &ebx, &ecx, &edx); 126*d8001690SBorislav Petkov 127*d8001690SBorislav Petkov return edx; 128*d8001690SBorislav Petkov } 129*d8001690SBorislav Petkov 130b66370dbSMichael Roth static __always_inline bool cpuid_function_is_indexed(u32 function) 131b66370dbSMichael Roth { 132b66370dbSMichael Roth switch (function) { 133b66370dbSMichael Roth case 4: 134b66370dbSMichael Roth case 7: 135b66370dbSMichael Roth case 0xb: 136b66370dbSMichael Roth case 0xd: 137b66370dbSMichael Roth case 0xf: 138b66370dbSMichael Roth case 0x10: 139b66370dbSMichael Roth case 0x12: 140b66370dbSMichael Roth case 0x14: 141b66370dbSMichael Roth case 0x17: 142b66370dbSMichael Roth case 0x18: 143b66370dbSMichael Roth case 0x1d: 144b66370dbSMichael Roth case 0x1e: 145b66370dbSMichael Roth case 0x1f: 146b66370dbSMichael Roth case 0x8000001d: 147b66370dbSMichael Roth return true; 148b66370dbSMichael Roth } 149b66370dbSMichael Roth 150b66370dbSMichael Roth return false; 151b66370dbSMichael Roth } 152b66370dbSMichael Roth 153*d8001690SBorislav Petkov #define for_each_possible_hypervisor_cpuid_base(function) \ 154*d8001690SBorislav Petkov for (function = 0x40000000; function < 0x40010000; function += 0x100) 155*d8001690SBorislav Petkov 156*d8001690SBorislav Petkov static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) 157*d8001690SBorislav Petkov { 158*d8001690SBorislav Petkov uint32_t base, eax, signature[3]; 159*d8001690SBorislav Petkov 160*d8001690SBorislav Petkov for_each_possible_hypervisor_cpuid_base(base) { 161*d8001690SBorislav Petkov cpuid(base, &eax, &signature[0], &signature[1], &signature[2]); 162*d8001690SBorislav Petkov 163*d8001690SBorislav Petkov if (!memcmp(sig, signature, 12) && 164*d8001690SBorislav Petkov (leaves == 0 || ((eax - base) >= leaves))) 165*d8001690SBorislav Petkov return base; 166*d8001690SBorislav Petkov } 167*d8001690SBorislav Petkov 168*d8001690SBorislav Petkov return 0; 169*d8001690SBorislav Petkov } 170*d8001690SBorislav Petkov 171b66370dbSMichael Roth #endif /* _ASM_X86_CPUID_H */ 172