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 0x24: 183 case 0x8000001d: 184 return true; 185 } 186 187 return false; 188 } 189 190 #define for_each_possible_hypervisor_cpuid_base(function) \ 191 for (function = 0x40000000; function < 0x40010000; function += 0x100) 192 193 static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) 194 { 195 uint32_t base, eax, signature[3]; 196 197 for_each_possible_hypervisor_cpuid_base(base) { 198 cpuid(base, &eax, &signature[0], &signature[1], &signature[2]); 199 200 /* 201 * This must not compile to "call memcmp" because it's called 202 * from PVH early boot code before instrumentation is set up 203 * and memcmp() itself may be instrumented. 204 */ 205 if (!__builtin_memcmp(sig, signature, 12) && 206 (leaves == 0 || ((eax - base) >= leaves))) 207 return base; 208 } 209 210 return 0; 211 } 212 213 #endif /* _ASM_X86_CPUID_H */ 214
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.