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