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