Commit | Line | Data |
---|---|---|
b66370db MR |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* | |
3 | * CPUID-related helpers/definitions | |
b66370db MR |
4 | */ |
5 | ||
6 | #ifndef _ASM_X86_CPUID_H | |
7 | #define _ASM_X86_CPUID_H | |
8 | ||
d8001690 BP |
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 | |
25 | static inline int have_cpuid_p(void) | |
26 | { | |
27 | return 1; | |
28 | } | |
29 | #endif | |
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) | |
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 */ | |
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 | */ | |
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 | ||
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 | ||
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 | ||
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 | ||
43d86e3c TG |
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 | ||
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 | ||
b66370db MR |
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 0x8000001d: | |
183 | return true; | |
184 | } | |
185 | ||
186 | return false; | |
187 | } | |
188 | ||
d8001690 BP |
189 | #define for_each_possible_hypervisor_cpuid_base(function) \ |
190 | for (function = 0x40000000; function < 0x40010000; function += 0x100) | |
191 | ||
192 | static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) | |
193 | { | |
194 | uint32_t base, eax, signature[3]; | |
195 | ||
196 | for_each_possible_hypervisor_cpuid_base(base) { | |
197 | cpuid(base, &eax, &signature[0], &signature[1], &signature[2]); | |
198 | ||
199 | if (!memcmp(sig, signature, 12) && | |
200 | (leaves == 0 || ((eax - base) >= leaves))) | |
201 | return base; | |
202 | } | |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
b66370db | 207 | #endif /* _ASM_X86_CPUID_H */ |