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