xref: /linux/arch/x86/include/asm/cpuid.h (revision 3efc57369a0ce8f76bf0804f7e673982384e4ac9)
1b66370dbSMichael Roth /* SPDX-License-Identifier: GPL-2.0 */
2b66370dbSMichael Roth /*
3b66370dbSMichael Roth  * CPUID-related helpers/definitions
4b66370dbSMichael Roth  */
5b66370dbSMichael Roth 
6b66370dbSMichael Roth #ifndef _ASM_X86_CPUID_H
7b66370dbSMichael Roth #define _ASM_X86_CPUID_H
8b66370dbSMichael Roth 
9d8001690SBorislav Petkov #include <asm/string.h>
10d8001690SBorislav Petkov 
11d8001690SBorislav Petkov struct cpuid_regs {
12d8001690SBorislav Petkov 	u32 eax, ebx, ecx, edx;
13d8001690SBorislav Petkov };
14d8001690SBorislav Petkov 
15d8001690SBorislav Petkov enum cpuid_regs_idx {
16d8001690SBorislav Petkov 	CPUID_EAX = 0,
17d8001690SBorislav Petkov 	CPUID_EBX,
18d8001690SBorislav Petkov 	CPUID_ECX,
19d8001690SBorislav Petkov 	CPUID_EDX,
20d8001690SBorislav Petkov };
21d8001690SBorislav Petkov 
22d8001690SBorislav Petkov #ifdef CONFIG_X86_32
23d8001690SBorislav Petkov extern int have_cpuid_p(void);
24d8001690SBorislav Petkov #else
have_cpuid_p(void)25d8001690SBorislav Petkov static inline int have_cpuid_p(void)
26d8001690SBorislav Petkov {
27d8001690SBorislav Petkov 	return 1;
28d8001690SBorislav Petkov }
29d8001690SBorislav Petkov #endif
native_cpuid(unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)30d8001690SBorislav Petkov static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
31d8001690SBorislav Petkov 				unsigned int *ecx, unsigned int *edx)
32d8001690SBorislav Petkov {
33d8001690SBorislav Petkov 	/* ecx is often an input as well as an output. */
34d8001690SBorislav Petkov 	asm volatile("cpuid"
35d8001690SBorislav Petkov 	    : "=a" (*eax),
36d8001690SBorislav Petkov 	      "=b" (*ebx),
37d8001690SBorislav Petkov 	      "=c" (*ecx),
38d8001690SBorislav Petkov 	      "=d" (*edx)
39d8001690SBorislav Petkov 	    : "0" (*eax), "2" (*ecx)
40d8001690SBorislav Petkov 	    : "memory");
41d8001690SBorislav Petkov }
42d8001690SBorislav Petkov 
43d8001690SBorislav Petkov #define native_cpuid_reg(reg)					\
44d8001690SBorislav Petkov static inline unsigned int native_cpuid_##reg(unsigned int op)	\
45d8001690SBorislav Petkov {								\
46d8001690SBorislav Petkov 	unsigned int eax = op, ebx, ecx = 0, edx;		\
47d8001690SBorislav Petkov 								\
48d8001690SBorislav Petkov 	native_cpuid(&eax, &ebx, &ecx, &edx);			\
49d8001690SBorislav Petkov 								\
50d8001690SBorislav Petkov 	return reg;						\
51d8001690SBorislav Petkov }
52d8001690SBorislav Petkov 
53d8001690SBorislav Petkov /*
54d8001690SBorislav Petkov  * Native CPUID functions returning a single datum.
55d8001690SBorislav Petkov  */
56d8001690SBorislav Petkov native_cpuid_reg(eax)
native_cpuid_reg(ebx)57d8001690SBorislav Petkov native_cpuid_reg(ebx)
58d8001690SBorislav Petkov native_cpuid_reg(ecx)
59d8001690SBorislav Petkov native_cpuid_reg(edx)
60d8001690SBorislav Petkov 
61d8001690SBorislav Petkov #ifdef CONFIG_PARAVIRT_XXL
62d8001690SBorislav Petkov #include <asm/paravirt.h>
63d8001690SBorislav Petkov #else
64d8001690SBorislav Petkov #define __cpuid			native_cpuid
65d8001690SBorislav Petkov #endif
66d8001690SBorislav Petkov 
67d8001690SBorislav Petkov /*
68d8001690SBorislav Petkov  * Generic CPUID function
69d8001690SBorislav Petkov  * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
70d8001690SBorislav Petkov  * resulting in stale register contents being returned.
71d8001690SBorislav Petkov  */
72d8001690SBorislav Petkov static inline void cpuid(unsigned int op,
73d8001690SBorislav Petkov 			 unsigned int *eax, unsigned int *ebx,
74d8001690SBorislav Petkov 			 unsigned int *ecx, unsigned int *edx)
75d8001690SBorislav Petkov {
76d8001690SBorislav Petkov 	*eax = op;
77d8001690SBorislav Petkov 	*ecx = 0;
78d8001690SBorislav Petkov 	__cpuid(eax, ebx, ecx, edx);
79d8001690SBorislav Petkov }
80d8001690SBorislav Petkov 
81d8001690SBorislav Petkov /* Some CPUID calls want 'count' to be placed in ecx */
cpuid_count(unsigned int op,int count,unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)82d8001690SBorislav Petkov static inline void cpuid_count(unsigned int op, int count,
83d8001690SBorislav Petkov 			       unsigned int *eax, unsigned int *ebx,
84d8001690SBorislav Petkov 			       unsigned int *ecx, unsigned int *edx)
85d8001690SBorislav Petkov {
86d8001690SBorislav Petkov 	*eax = op;
87d8001690SBorislav Petkov 	*ecx = count;
88d8001690SBorislav Petkov 	__cpuid(eax, ebx, ecx, edx);
89d8001690SBorislav Petkov }
90d8001690SBorislav Petkov 
91d8001690SBorislav Petkov /*
92d8001690SBorislav Petkov  * CPUID functions returning a single datum
93d8001690SBorislav Petkov  */
cpuid_eax(unsigned int op)94d8001690SBorislav Petkov static inline unsigned int cpuid_eax(unsigned int op)
95d8001690SBorislav Petkov {
96d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
97d8001690SBorislav Petkov 
98d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
99d8001690SBorislav Petkov 
100d8001690SBorislav Petkov 	return eax;
101d8001690SBorislav Petkov }
102d8001690SBorislav Petkov 
cpuid_ebx(unsigned int op)103d8001690SBorislav Petkov static inline unsigned int cpuid_ebx(unsigned int op)
104d8001690SBorislav Petkov {
105d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
106d8001690SBorislav Petkov 
107d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
108d8001690SBorislav Petkov 
109d8001690SBorislav Petkov 	return ebx;
110d8001690SBorislav Petkov }
111d8001690SBorislav Petkov 
cpuid_ecx(unsigned int op)112d8001690SBorislav Petkov static inline unsigned int cpuid_ecx(unsigned int op)
113d8001690SBorislav Petkov {
114d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
115d8001690SBorislav Petkov 
116d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
117d8001690SBorislav Petkov 
118d8001690SBorislav Petkov 	return ecx;
119d8001690SBorislav Petkov }
120d8001690SBorislav Petkov 
cpuid_edx(unsigned int op)121d8001690SBorislav Petkov static inline unsigned int cpuid_edx(unsigned int op)
122d8001690SBorislav Petkov {
123d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
124d8001690SBorislav Petkov 
125d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
126d8001690SBorislav Petkov 
127d8001690SBorislav Petkov 	return edx;
128d8001690SBorislav Petkov }
129d8001690SBorislav Petkov 
__cpuid_read(unsigned int leaf,unsigned int subleaf,u32 * regs)13043d86e3cSThomas Gleixner static inline void __cpuid_read(unsigned int leaf, unsigned int subleaf, u32 *regs)
13143d86e3cSThomas Gleixner {
13243d86e3cSThomas Gleixner 	regs[CPUID_EAX] = leaf;
13343d86e3cSThomas Gleixner 	regs[CPUID_ECX] = subleaf;
13443d86e3cSThomas Gleixner 	__cpuid(regs + CPUID_EAX, regs + CPUID_EBX, regs + CPUID_ECX, regs + CPUID_EDX);
13543d86e3cSThomas Gleixner }
13643d86e3cSThomas Gleixner 
13743d86e3cSThomas Gleixner #define cpuid_subleaf(leaf, subleaf, regs) {		\
13843d86e3cSThomas Gleixner 	static_assert(sizeof(*(regs)) == 16);		\
13943d86e3cSThomas Gleixner 	__cpuid_read(leaf, subleaf, (u32 *)(regs));	\
14043d86e3cSThomas Gleixner }
14143d86e3cSThomas Gleixner 
14243d86e3cSThomas Gleixner #define cpuid_leaf(leaf, regs) {			\
14343d86e3cSThomas Gleixner 	static_assert(sizeof(*(regs)) == 16);		\
14443d86e3cSThomas Gleixner 	__cpuid_read(leaf, 0, (u32 *)(regs));		\
14543d86e3cSThomas Gleixner }
14643d86e3cSThomas Gleixner 
__cpuid_read_reg(unsigned int leaf,unsigned int subleaf,enum cpuid_regs_idx regidx,u32 * reg)14743d86e3cSThomas Gleixner static inline void __cpuid_read_reg(unsigned int leaf, unsigned int subleaf,
14843d86e3cSThomas Gleixner 				    enum cpuid_regs_idx regidx, u32 *reg)
14943d86e3cSThomas Gleixner {
15043d86e3cSThomas Gleixner 	u32 regs[4];
15143d86e3cSThomas Gleixner 
15243d86e3cSThomas Gleixner 	__cpuid_read(leaf, subleaf, regs);
15343d86e3cSThomas Gleixner 	*reg = regs[regidx];
15443d86e3cSThomas Gleixner }
15543d86e3cSThomas Gleixner 
15643d86e3cSThomas Gleixner #define cpuid_subleaf_reg(leaf, subleaf, regidx, reg) {		\
15743d86e3cSThomas Gleixner 	static_assert(sizeof(*(reg)) == 4);			\
15843d86e3cSThomas Gleixner 	__cpuid_read_reg(leaf, subleaf, regidx, (u32 *)(reg));	\
15943d86e3cSThomas Gleixner }
16043d86e3cSThomas Gleixner 
16143d86e3cSThomas Gleixner #define cpuid_leaf_reg(leaf, regidx, reg) {			\
16243d86e3cSThomas Gleixner 	static_assert(sizeof(*(reg)) == 4);			\
16343d86e3cSThomas Gleixner 	__cpuid_read_reg(leaf, 0, regidx, (u32 *)(reg));	\
16443d86e3cSThomas Gleixner }
16543d86e3cSThomas Gleixner 
cpuid_function_is_indexed(u32 function)166b66370dbSMichael Roth static __always_inline bool cpuid_function_is_indexed(u32 function)
167b66370dbSMichael Roth {
168b66370dbSMichael Roth 	switch (function) {
169b66370dbSMichael Roth 	case 4:
170b66370dbSMichael Roth 	case 7:
171b66370dbSMichael Roth 	case 0xb:
172b66370dbSMichael Roth 	case 0xd:
173b66370dbSMichael Roth 	case 0xf:
174b66370dbSMichael Roth 	case 0x10:
175b66370dbSMichael Roth 	case 0x12:
176b66370dbSMichael Roth 	case 0x14:
177b66370dbSMichael Roth 	case 0x17:
178b66370dbSMichael Roth 	case 0x18:
179b66370dbSMichael Roth 	case 0x1d:
180b66370dbSMichael Roth 	case 0x1e:
181b66370dbSMichael Roth 	case 0x1f:
182*1c450ffeSTao Su 	case 0x24:
183b66370dbSMichael Roth 	case 0x8000001d:
184b66370dbSMichael Roth 		return true;
185b66370dbSMichael Roth 	}
186b66370dbSMichael Roth 
187b66370dbSMichael Roth 	return false;
188b66370dbSMichael Roth }
189b66370dbSMichael Roth 
190d8001690SBorislav Petkov #define for_each_possible_hypervisor_cpuid_base(function) \
191d8001690SBorislav Petkov 	for (function = 0x40000000; function < 0x40010000; function += 0x100)
192d8001690SBorislav Petkov 
hypervisor_cpuid_base(const char * sig,uint32_t leaves)193d8001690SBorislav Petkov static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
194d8001690SBorislav Petkov {
195d8001690SBorislav Petkov 	uint32_t base, eax, signature[3];
196d8001690SBorislav Petkov 
197d8001690SBorislav Petkov 	for_each_possible_hypervisor_cpuid_base(base) {
198d8001690SBorislav Petkov 		cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
199d8001690SBorislav Petkov 
200416a33c9SAlexey Dobriyan 		/*
201416a33c9SAlexey Dobriyan 		 * This must not compile to "call memcmp" because it's called
202416a33c9SAlexey Dobriyan 		 * from PVH early boot code before instrumentation is set up
203416a33c9SAlexey Dobriyan 		 * and memcmp() itself may be instrumented.
204416a33c9SAlexey Dobriyan 		 */
205416a33c9SAlexey Dobriyan 		if (!__builtin_memcmp(sig, signature, 12) &&
206d8001690SBorislav Petkov 		    (leaves == 0 || ((eax - base) >= leaves)))
207d8001690SBorislav Petkov 			return base;
208d8001690SBorislav Petkov 	}
209d8001690SBorislav Petkov 
210d8001690SBorislav Petkov 	return 0;
211d8001690SBorislav Petkov }
212d8001690SBorislav Petkov 
213b66370dbSMichael Roth #endif /* _ASM_X86_CPUID_H */
214