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 11struct cpuid_regs { 12 u32 eax, ebx, ecx, edx; 13}; 14 15enum cpuid_regs_idx { 16 CPUID_EAX = 0, 17 CPUID_EBX, 18 CPUID_ECX, 19 CPUID_EDX, 20}; 21 22#ifdef CONFIG_X86_32 23extern int have_cpuid_p(void); 24#else 25static inline int have_cpuid_p(void) 26{ 27 return 1; 28} 29#endif 30static 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 : "0" (*eax), "2" (*ecx) 40 : "memory"); 41} 42 43#define native_cpuid_reg(reg) \ 44static 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 */ 56native_cpuid_reg(eax) 57native_cpuid_reg(ebx) 58native_cpuid_reg(ecx) 59native_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 */ 72static 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 */ 82static 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 */ 94static 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 103static 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 112static 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 121static 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 130static 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 147static 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 166static __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 192static 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