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