Merge tag 'x86_mtrr_for_v6.9_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / arch / x86 / include / asm / cpuid.h
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
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
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
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
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
207 #endif /* _ASM_X86_CPUID_H */