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: &eax, ebx: &ebx, ecx: &ecx, edx: &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: &eax, ebx: &ebx, ecx: &ecx, edx: &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: &eax, ebx: &ebx, ecx: &ecx, edx: &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: &eax, ebx: &ebx, ecx: &ecx, edx: &edx); |
126 | |
127 | return edx; |
128 | } |
129 | |
130 | static __always_inline bool cpuid_function_is_indexed(u32 function) |
131 | { |
132 | switch (function) { |
133 | case 4: |
134 | case 7: |
135 | case 0xb: |
136 | case 0xd: |
137 | case 0xf: |
138 | case 0x10: |
139 | case 0x12: |
140 | case 0x14: |
141 | case 0x17: |
142 | case 0x18: |
143 | case 0x1d: |
144 | case 0x1e: |
145 | case 0x1f: |
146 | case 0x8000001d: |
147 | return true; |
148 | } |
149 | |
150 | return false; |
151 | } |
152 | |
153 | #define for_each_possible_hypervisor_cpuid_base(function) \ |
154 | for (function = 0x40000000; function < 0x40010000; function += 0x100) |
155 | |
156 | static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves) |
157 | { |
158 | uint32_t base, eax, signature[3]; |
159 | |
160 | for_each_possible_hypervisor_cpuid_base(base) { |
161 | cpuid(op: base, eax: &eax, ebx: &signature[0], ecx: &signature[1], edx: &signature[2]); |
162 | |
163 | if (!memcmp(p: sig, q: signature, size: 12) && |
164 | (leaves == 0 || ((eax - base) >= leaves))) |
165 | return base; |
166 | } |
167 | |
168 | return 0; |
169 | } |
170 | |
171 | #endif /* _ASM_X86_CPUID_H */ |
172 | |