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 __always_inline bool cpuid_function_is_indexed(u32 function) 131{ 132 switch (function) { 133 case 4: 134 case 7: 135 case 0xb: 136 case 0xd: 137 case 0xf: 138 case 0x10: 139 case 0x12: 140 case 0x14: 141 case 0x17: 142 case 0x18: 143 case 0x1d: 144 case 0x1e: 145 case 0x1f: 146 case 0x8000001d: 147 return true; 148 } 149 150 return false; 151} 152 153#define for_each_possible_hypervisor_cpuid_base(function) \ 154 for (function = 0x40000000; function < 0x40010000; function += 0x100) 155 156static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) 157{ 158 uint32_t base, eax, signature[3]; 159 160 for_each_possible_hypervisor_cpuid_base(base) { 161 cpuid(base, &eax, &signature[0], &signature[1], &signature[2]); 162 163 if (!memcmp(sig, signature, 12) && 164 (leaves == 0 || ((eax - base) >= leaves))) 165 return base; 166 } 167 168 return 0; 169} 170 171#endif /* _ASM_X86_CPUID_H */ 172