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