diff options
| author | Ahmed S. Darwish <darwi@linutronix.de> | 2025-03-17 23:18:20 +0100 | 
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2025-03-19 11:19:22 +0100 | 
| commit | adc574269bca8dbde9f8f22841e40d3380241921 (patch) | |
| tree | ee581eeceaf7acb0d6b457e81fdc83c11b6de16e | |
| parent | 82070bc0425db949b406ede1c7f066346f5b3eb9 (diff) | |
x86/cpuid: Refactor <asm/cpuid.h>
In preparation for future commits where CPUID headers will be expanded,
refactor the CPUID header <asm/cpuid.h> into:
    asm/cpuid/
    ├── api.h
    └── types.h
Move the CPUID data structures into <asm/cpuid/types.h> and the access
APIs into <asm/cpuid/api.h>.  Let <asm/cpuid.h> be just an include of
<asm/cpuid/api.h> so that existing call sites do not break.
Suggested-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: "Ahmed S. Darwish" <darwi@linutronix.de>
Cc: x86-cpuid@lists.linux.dev
Link: https://lore.kernel.org/r/20250317221824.3738853-2-mingo@kernel.org
| -rw-r--r-- | arch/x86/include/asm/cpuid.h | 217 | ||||
| -rw-r--r-- | arch/x86/include/asm/cpuid/api.h | 208 | ||||
| -rw-r--r-- | arch/x86/include/asm/cpuid/types.h | 29 | 
3 files changed, 238 insertions, 216 deletions
diff --git a/arch/x86/include/asm/cpuid.h b/arch/x86/include/asm/cpuid.h index a92e4b08820a..d5749b25fa10 100644 --- a/arch/x86/include/asm/cpuid.h +++ b/arch/x86/include/asm/cpuid.h @@ -1,223 +1,8 @@  /* SPDX-License-Identifier: GPL-2.0 */ -/* - * CPUID-related helpers/definitions - */  #ifndef _ASM_X86_CPUID_H  #define _ASM_X86_CPUID_H -#include <linux/build_bug.h> -#include <linux/types.h> - -#include <asm/string.h> - -struct cpuid_regs { -	u32 eax, ebx, ecx, edx; -}; - -enum cpuid_regs_idx { -	CPUID_EAX = 0, -	CPUID_EBX, -	CPUID_ECX, -	CPUID_EDX, -}; - -#define CPUID_LEAF_MWAIT	0x5 -#define CPUID_LEAF_DCA		0x9 -#define CPUID_LEAF_XSTATE	0x0d -#define CPUID_LEAF_TSC		0x15 -#define CPUID_LEAF_FREQ		0x16 -#define CPUID_LEAF_TILE		0x1d - -#ifdef CONFIG_X86_32 -bool have_cpuid_p(void); -#else -static inline bool have_cpuid_p(void) -{ -	return true; -} -#endif -static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, -				unsigned int *ecx, unsigned int *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 unsigned int native_cpuid_##reg(unsigned int op)	\ -{								\ -	unsigned int 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 <asm/paravirt.h> -#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(unsigned int op, -			 unsigned int *eax, unsigned int *ebx, -			 unsigned int *ecx, unsigned int *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(unsigned int op, int count, -			       unsigned int *eax, unsigned int *ebx, -			       unsigned int *ecx, unsigned int *edx) -{ -	*eax = op; -	*ecx = count; -	__cpuid(eax, ebx, ecx, edx); -} - -/* - * CPUID functions returning a single datum - */ -static inline unsigned int cpuid_eax(unsigned int op) -{ -	unsigned int eax, ebx, ecx, edx; - -	cpuid(op, &eax, &ebx, &ecx, &edx); - -	return eax; -} - -static inline unsigned int cpuid_ebx(unsigned int op) -{ -	unsigned int eax, ebx, ecx, edx; - -	cpuid(op, &eax, &ebx, &ecx, &edx); - -	return ebx; -} - -static inline unsigned int cpuid_ecx(unsigned int op) -{ -	unsigned int eax, ebx, ecx, edx; - -	cpuid(op, &eax, &ebx, &ecx, &edx); - -	return ecx; -} - -static inline unsigned int cpuid_edx(unsigned int op) -{ -	unsigned int eax, ebx, ecx, edx; - -	cpuid(op, &eax, &ebx, &ecx, &edx); - -	return edx; -} - -static inline void __cpuid_read(unsigned int leaf, unsigned int 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(unsigned int leaf, unsigned int 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));	\ -} - -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_hypervisor_cpuid_base(function) \ -	for (function = 0x40000000; function < 0x40010000; function += 0x100) - -static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) -{ -	uint32_t base, eax, signature[3]; - -	for_each_possible_hypervisor_cpuid_base(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; -} +#include <asm/cpuid/api.h>  #endif /* _ASM_X86_CPUID_H */ diff --git a/arch/x86/include/asm/cpuid/api.h b/arch/x86/include/asm/cpuid/api.h new file mode 100644 index 000000000000..4d1da9cc8b6f --- /dev/null +++ b/arch/x86/include/asm/cpuid/api.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_X86_CPUID_API_H +#define _ASM_X86_CPUID_API_H + +#include <linux/build_bug.h> +#include <linux/types.h> + +#include <asm/cpuid/types.h> +#include <asm/string.h> + +/* + * Raw CPUID accessors + */ + +#ifdef CONFIG_X86_32 +bool have_cpuid_p(void); +#else +static inline bool have_cpuid_p(void) +{ +	return true; +} +#endif +static inline void native_cpuid(unsigned int *eax, unsigned int *ebx, +				unsigned int *ecx, unsigned int *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 unsigned int native_cpuid_##reg(unsigned int op)	\ +{								\ +	unsigned int 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 <asm/paravirt.h> +#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(unsigned int op, +			 unsigned int *eax, unsigned int *ebx, +			 unsigned int *ecx, unsigned int *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(unsigned int op, int count, +			       unsigned int *eax, unsigned int *ebx, +			       unsigned int *ecx, unsigned int *edx) +{ +	*eax = op; +	*ecx = count; +	__cpuid(eax, ebx, ecx, edx); +} + +/* + * CPUID functions returning a single datum + */ + +static inline unsigned int cpuid_eax(unsigned int op) +{ +	unsigned int eax, ebx, ecx, edx; + +	cpuid(op, &eax, &ebx, &ecx, &edx); + +	return eax; +} + +static inline unsigned int cpuid_ebx(unsigned int op) +{ +	unsigned int eax, ebx, ecx, edx; + +	cpuid(op, &eax, &ebx, &ecx, &edx); + +	return ebx; +} + +static inline unsigned int cpuid_ecx(unsigned int op) +{ +	unsigned int eax, ebx, ecx, edx; + +	cpuid(op, &eax, &ebx, &ecx, &edx); + +	return ecx; +} + +static inline unsigned int cpuid_edx(unsigned int op) +{ +	unsigned int eax, ebx, ecx, edx; + +	cpuid(op, &eax, &ebx, &ecx, &edx); + +	return edx; +} + +static inline void __cpuid_read(unsigned int leaf, unsigned int 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(unsigned int leaf, unsigned int 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));	\ +} + +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_hypervisor_cpuid_base(function) \ +	for (function = 0x40000000; function < 0x40010000; function += 0x100) + +static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) +{ +	uint32_t base, eax, signature[3]; + +	for_each_possible_hypervisor_cpuid_base(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; +} + +#endif /* _ASM_X86_CPUID_API_H */ diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h new file mode 100644 index 000000000000..724002aaff4d --- /dev/null +++ b/arch/x86/include/asm/cpuid/types.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_CPUID_TYPES_H +#define _ASM_X86_CPUID_TYPES_H + +#include <linux/types.h> + +/* + * Types for raw CPUID access + */ + +struct cpuid_regs { +	u32 eax, ebx, ecx, edx; +}; + +enum cpuid_regs_idx { +	CPUID_EAX = 0, +	CPUID_EBX, +	CPUID_ECX, +	CPUID_EDX, +}; + +#define CPUID_LEAF_MWAIT	0x5 +#define CPUID_LEAF_DCA		0x9 +#define CPUID_LEAF_XSTATE	0x0d +#define CPUID_LEAF_TSC		0x15 +#define CPUID_LEAF_FREQ		0x16 +#define CPUID_LEAF_TILE		0x1d + +#endif /* _ASM_X86_CPUID_TYPES_H */  | 
