/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _ASM_X86_CPUID_API_H #define _ASM_X86_CPUID_API_H #include #include #include #include /* * Raw CPUID accessors: */ #ifdef CONFIG_X86_32 bool cpuid_feature(void); #else static inline bool cpuid_feature(void) { return true; } #endif static inline void native_cpuid(u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) { /* ecx is often an input as well as an output. */ asm volatile("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "0" (*eax), "2" (*ecx) : "memory"); } #define NATIVE_CPUID_REG(reg) \ static inline u32 native_cpuid_##reg(u32 op) \ { \ u32 eax = op, ebx, ecx = 0, edx; \ \ native_cpuid(&eax, &ebx, &ecx, &edx); \ \ return reg; \ } /* * Native CPUID functions returning a single datum: */ NATIVE_CPUID_REG(eax) NATIVE_CPUID_REG(ebx) NATIVE_CPUID_REG(ecx) NATIVE_CPUID_REG(edx) #ifdef CONFIG_PARAVIRT_XXL # include #else # define __cpuid native_cpuid #endif /* * Generic CPUID function * * Clear ECX since some CPUs (Cyrix MII) do not set or clear ECX * resulting in stale register contents being returned. */ static inline void cpuid(u32 op, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) { *eax = op; *ecx = 0; __cpuid(eax, ebx, ecx, edx); } /* Some CPUID calls want 'count' to be placed in ECX */ static inline void cpuid_count(u32 op, int count, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) { *eax = op; *ecx = count; __cpuid(eax, ebx, ecx, edx); } /* * CPUID functions returning a single datum: */ static inline u32 cpuid_eax(u32 op) { u32 eax, ebx, ecx, edx; cpuid(op, &eax, &ebx, &ecx, &edx); return eax; } static inline u32 cpuid_ebx(u32 op) { u32 eax, ebx, ecx, edx; cpuid(op, &eax, &ebx, &ecx, &edx); return ebx; } static inline u32 cpuid_ecx(u32 op) { u32 eax, ebx, ecx, edx; cpuid(op, &eax, &ebx, &ecx, &edx); return ecx; } static inline u32 cpuid_edx(u32 op) { u32 eax, ebx, ecx, edx; cpuid(op, &eax, &ebx, &ecx, &edx); return edx; } static inline void __cpuid_read(u32 leaf, u32 subleaf, u32 *regs) { regs[CPUID_EAX] = leaf; regs[CPUID_ECX] = subleaf; __cpuid(regs + CPUID_EAX, regs + CPUID_EBX, regs + CPUID_ECX, regs + CPUID_EDX); } #define cpuid_subleaf(leaf, subleaf, regs) { \ static_assert(sizeof(*(regs)) == 16); \ __cpuid_read(leaf, subleaf, (u32 *)(regs)); \ } #define cpuid_leaf(leaf, regs) { \ static_assert(sizeof(*(regs)) == 16); \ __cpuid_read(leaf, 0, (u32 *)(regs)); \ } static inline void __cpuid_read_reg(u32 leaf, u32 subleaf, enum cpuid_regs_idx regidx, u32 *reg) { u32 regs[4]; __cpuid_read(leaf, subleaf, regs); *reg = regs[regidx]; } #define cpuid_subleaf_reg(leaf, subleaf, regidx, reg) { \ static_assert(sizeof(*(reg)) == 4); \ __cpuid_read_reg(leaf, subleaf, regidx, (u32 *)(reg)); \ } #define cpuid_leaf_reg(leaf, regidx, reg) { \ static_assert(sizeof(*(reg)) == 4); \ __cpuid_read_reg(leaf, 0, regidx, (u32 *)(reg)); \ } /* * Hypervisor-related APIs: */ static __always_inline bool cpuid_function_is_indexed(u32 function) { switch (function) { case 4: case 7: case 0xb: case 0xd: case 0xf: case 0x10: case 0x12: case 0x14: case 0x17: case 0x18: case 0x1d: case 0x1e: case 0x1f: case 0x24: case 0x8000001d: return true; } return false; } #define for_each_possible_cpuid_base_hypervisor(function) \ for (function = 0x40000000; function < 0x40010000; function += 0x100) static inline u32 cpuid_base_hypervisor(const char *sig, u32 leaves) { u32 base, eax, signature[3]; for_each_possible_cpuid_base_hypervisor(base) { cpuid(base, &eax, &signature[0], &signature[1], &signature[2]); /* * This must not compile to "call memcmp" because it's called * from PVH early boot code before instrumentation is set up * and memcmp() itself may be instrumented. */ if (!__builtin_memcmp(sig, signature, 12) && (leaves == 0 || ((eax - base) >= leaves))) return base; } return 0; } /* * CPUID(0x2) parsing: */ /** * cpuid_leaf_0x2() - Return sanitized CPUID(0x2) register output * @regs: Output parameter * * Query CPUID(0x2) and store its output in @regs. Force set any * invalid 1-byte descriptor returned by the hardware to zero (the NULL * cache/TLB descriptor) before returning it to the caller. * * Use for_each_cpuid_0x2_desc() to iterate over the register output in * parsed form. */ static inline void cpuid_leaf_0x2(union leaf_0x2_regs *regs) { cpuid_leaf(0x2, regs); /* * All Intel CPUs must report an iteration count of 1. In case * of bogus hardware, treat all returned descriptors as NULL. */ if (regs->desc[0] != 0x01) { for (int i = 0; i < 4; i++) regs->regv[i] = 0; return; } /* * The most significant bit (MSB) of each register must be clear. * If a register is invalid, replace its descriptors with NULL. */ for (int i = 0; i < 4; i++) { if (regs->reg[i].invalid) regs->regv[i] = 0; } } /** * for_each_cpuid_0x2_desc() - Iterator for parsed CPUID(0x2) descriptors * @_regs: CPUID(0x2) register output, as returned by cpuid_leaf_0x2() * @_ptr: u8 pointer, for macro internal use only * @_desc: Pointer to the parsed CPUID(0x2) descriptor at each iteration * * Loop over the 1-byte descriptors in the passed CPUID(0x2) output registers * @_regs. Provide the parsed information for each descriptor through @_desc. * * To handle cache-specific descriptors, switch on @_desc->c_type. For TLB * descriptors, switch on @_desc->t_type. * * Example usage for cache descriptors:: * * const struct leaf_0x2_table *desc; * union leaf_0x2_regs regs; * u8 *ptr; * * cpuid_leaf_0x2(®s); * for_each_cpuid_0x2_desc(regs, ptr, desc) { * switch (desc->c_type) { * ... * } * } */ #define for_each_cpuid_0x2_desc(_regs, _ptr, _desc) \ for (_ptr = &(_regs).desc[1]; \ _ptr < &(_regs).desc[16] && (_desc = &cpuid_0x2_table[*_ptr]); \ _ptr++) /* * CPUID(0x80000006) parsing: */ static inline bool cpuid_amd_hygon_has_l3_cache(void) { return cpuid_edx(0x80000006); } #endif /* _ASM_X86_CPUID_API_H */