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