xref: /linux/arch/x86/include/asm/cpuid.h (revision 3efc57369a0ce8f76bf0804f7e673982384e4ac9)
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 
11 struct cpuid_regs {
12 	u32 eax, ebx, ecx, edx;
13 };
14 
15 enum cpuid_regs_idx {
16 	CPUID_EAX = 0,
17 	CPUID_EBX,
18 	CPUID_ECX,
19 	CPUID_EDX,
20 };
21 
22 #ifdef CONFIG_X86_32
23 extern int have_cpuid_p(void);
24 #else
have_cpuid_p(void)25 static inline int have_cpuid_p(void)
26 {
27 	return 1;
28 }
29 #endif
native_cpuid(unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)30 static 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)					\
44 static 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  */
56 native_cpuid_reg(eax)
native_cpuid_reg(ebx)57 native_cpuid_reg(ebx)
58 native_cpuid_reg(ecx)
59 native_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  */
72 static 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 */
cpuid_count(unsigned int op,int count,unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)82 static 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  */
cpuid_eax(unsigned int op)94 static 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 
cpuid_ebx(unsigned int op)103 static 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 
cpuid_ecx(unsigned int op)112 static 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 
cpuid_edx(unsigned int op)121 static 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 
__cpuid_read(unsigned int leaf,unsigned int subleaf,u32 * regs)130 static inline void __cpuid_read(unsigned int leaf, unsigned int subleaf, u32 *regs)
131 {
132 	regs[CPUID_EAX] = leaf;
133 	regs[CPUID_ECX] = subleaf;
134 	__cpuid(regs + CPUID_EAX, regs + CPUID_EBX, regs + CPUID_ECX, regs + CPUID_EDX);
135 }
136 
137 #define cpuid_subleaf(leaf, subleaf, regs) {		\
138 	static_assert(sizeof(*(regs)) == 16);		\
139 	__cpuid_read(leaf, subleaf, (u32 *)(regs));	\
140 }
141 
142 #define cpuid_leaf(leaf, regs) {			\
143 	static_assert(sizeof(*(regs)) == 16);		\
144 	__cpuid_read(leaf, 0, (u32 *)(regs));		\
145 }
146 
__cpuid_read_reg(unsigned int leaf,unsigned int subleaf,enum cpuid_regs_idx regidx,u32 * reg)147 static inline void __cpuid_read_reg(unsigned int leaf, unsigned int subleaf,
148 				    enum cpuid_regs_idx regidx, u32 *reg)
149 {
150 	u32 regs[4];
151 
152 	__cpuid_read(leaf, subleaf, regs);
153 	*reg = regs[regidx];
154 }
155 
156 #define cpuid_subleaf_reg(leaf, subleaf, regidx, reg) {		\
157 	static_assert(sizeof(*(reg)) == 4);			\
158 	__cpuid_read_reg(leaf, subleaf, regidx, (u32 *)(reg));	\
159 }
160 
161 #define cpuid_leaf_reg(leaf, regidx, reg) {			\
162 	static_assert(sizeof(*(reg)) == 4);			\
163 	__cpuid_read_reg(leaf, 0, regidx, (u32 *)(reg));	\
164 }
165 
cpuid_function_is_indexed(u32 function)166 static __always_inline bool cpuid_function_is_indexed(u32 function)
167 {
168 	switch (function) {
169 	case 4:
170 	case 7:
171 	case 0xb:
172 	case 0xd:
173 	case 0xf:
174 	case 0x10:
175 	case 0x12:
176 	case 0x14:
177 	case 0x17:
178 	case 0x18:
179 	case 0x1d:
180 	case 0x1e:
181 	case 0x1f:
182 	case 0x24:
183 	case 0x8000001d:
184 		return true;
185 	}
186 
187 	return false;
188 }
189 
190 #define for_each_possible_hypervisor_cpuid_base(function) \
191 	for (function = 0x40000000; function < 0x40010000; function += 0x100)
192 
hypervisor_cpuid_base(const char * sig,uint32_t leaves)193 static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
194 {
195 	uint32_t base, eax, signature[3];
196 
197 	for_each_possible_hypervisor_cpuid_base(base) {
198 		cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
199 
200 		/*
201 		 * This must not compile to "call memcmp" because it's called
202 		 * from PVH early boot code before instrumentation is set up
203 		 * and memcmp() itself may be instrumented.
204 		 */
205 		if (!__builtin_memcmp(sig, signature, 12) &&
206 		    (leaves == 0 || ((eax - base) >= leaves)))
207 			return base;
208 	}
209 
210 	return 0;
211 }
212 
213 #endif /* _ASM_X86_CPUID_H */
214