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