xref: /linux/arch/x86/include/asm/cpuid.h (revision d800169041c0e035160c8b81f30d4b7e8f8ef777)
1b66370dbSMichael Roth /* SPDX-License-Identifier: GPL-2.0 */
2b66370dbSMichael Roth /*
3b66370dbSMichael Roth  * CPUID-related helpers/definitions
4b66370dbSMichael Roth  */
5b66370dbSMichael Roth 
6b66370dbSMichael Roth #ifndef _ASM_X86_CPUID_H
7b66370dbSMichael Roth #define _ASM_X86_CPUID_H
8b66370dbSMichael Roth 
9*d8001690SBorislav Petkov #include <asm/string.h>
10*d8001690SBorislav Petkov 
11*d8001690SBorislav Petkov struct cpuid_regs {
12*d8001690SBorislav Petkov 	u32 eax, ebx, ecx, edx;
13*d8001690SBorislav Petkov };
14*d8001690SBorislav Petkov 
15*d8001690SBorislav Petkov enum cpuid_regs_idx {
16*d8001690SBorislav Petkov 	CPUID_EAX = 0,
17*d8001690SBorislav Petkov 	CPUID_EBX,
18*d8001690SBorislav Petkov 	CPUID_ECX,
19*d8001690SBorislav Petkov 	CPUID_EDX,
20*d8001690SBorislav Petkov };
21*d8001690SBorislav Petkov 
22*d8001690SBorislav Petkov #ifdef CONFIG_X86_32
23*d8001690SBorislav Petkov extern int have_cpuid_p(void);
24*d8001690SBorislav Petkov #else
25*d8001690SBorislav Petkov static inline int have_cpuid_p(void)
26*d8001690SBorislav Petkov {
27*d8001690SBorislav Petkov 	return 1;
28*d8001690SBorislav Petkov }
29*d8001690SBorislav Petkov #endif
30*d8001690SBorislav Petkov static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
31*d8001690SBorislav Petkov 				unsigned int *ecx, unsigned int *edx)
32*d8001690SBorislav Petkov {
33*d8001690SBorislav Petkov 	/* ecx is often an input as well as an output. */
34*d8001690SBorislav Petkov 	asm volatile("cpuid"
35*d8001690SBorislav Petkov 	    : "=a" (*eax),
36*d8001690SBorislav Petkov 	      "=b" (*ebx),
37*d8001690SBorislav Petkov 	      "=c" (*ecx),
38*d8001690SBorislav Petkov 	      "=d" (*edx)
39*d8001690SBorislav Petkov 	    : "0" (*eax), "2" (*ecx)
40*d8001690SBorislav Petkov 	    : "memory");
41*d8001690SBorislav Petkov }
42*d8001690SBorislav Petkov 
43*d8001690SBorislav Petkov #define native_cpuid_reg(reg)					\
44*d8001690SBorislav Petkov static inline unsigned int native_cpuid_##reg(unsigned int op)	\
45*d8001690SBorislav Petkov {								\
46*d8001690SBorislav Petkov 	unsigned int eax = op, ebx, ecx = 0, edx;		\
47*d8001690SBorislav Petkov 								\
48*d8001690SBorislav Petkov 	native_cpuid(&eax, &ebx, &ecx, &edx);			\
49*d8001690SBorislav Petkov 								\
50*d8001690SBorislav Petkov 	return reg;						\
51*d8001690SBorislav Petkov }
52*d8001690SBorislav Petkov 
53*d8001690SBorislav Petkov /*
54*d8001690SBorislav Petkov  * Native CPUID functions returning a single datum.
55*d8001690SBorislav Petkov  */
56*d8001690SBorislav Petkov native_cpuid_reg(eax)
57*d8001690SBorislav Petkov native_cpuid_reg(ebx)
58*d8001690SBorislav Petkov native_cpuid_reg(ecx)
59*d8001690SBorislav Petkov native_cpuid_reg(edx)
60*d8001690SBorislav Petkov 
61*d8001690SBorislav Petkov #ifdef CONFIG_PARAVIRT_XXL
62*d8001690SBorislav Petkov #include <asm/paravirt.h>
63*d8001690SBorislav Petkov #else
64*d8001690SBorislav Petkov #define __cpuid			native_cpuid
65*d8001690SBorislav Petkov #endif
66*d8001690SBorislav Petkov 
67*d8001690SBorislav Petkov /*
68*d8001690SBorislav Petkov  * Generic CPUID function
69*d8001690SBorislav Petkov  * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
70*d8001690SBorislav Petkov  * resulting in stale register contents being returned.
71*d8001690SBorislav Petkov  */
72*d8001690SBorislav Petkov static inline void cpuid(unsigned int op,
73*d8001690SBorislav Petkov 			 unsigned int *eax, unsigned int *ebx,
74*d8001690SBorislav Petkov 			 unsigned int *ecx, unsigned int *edx)
75*d8001690SBorislav Petkov {
76*d8001690SBorislav Petkov 	*eax = op;
77*d8001690SBorislav Petkov 	*ecx = 0;
78*d8001690SBorislav Petkov 	__cpuid(eax, ebx, ecx, edx);
79*d8001690SBorislav Petkov }
80*d8001690SBorislav Petkov 
81*d8001690SBorislav Petkov /* Some CPUID calls want 'count' to be placed in ecx */
82*d8001690SBorislav Petkov static inline void cpuid_count(unsigned int op, int count,
83*d8001690SBorislav Petkov 			       unsigned int *eax, unsigned int *ebx,
84*d8001690SBorislav Petkov 			       unsigned int *ecx, unsigned int *edx)
85*d8001690SBorislav Petkov {
86*d8001690SBorislav Petkov 	*eax = op;
87*d8001690SBorislav Petkov 	*ecx = count;
88*d8001690SBorislav Petkov 	__cpuid(eax, ebx, ecx, edx);
89*d8001690SBorislav Petkov }
90*d8001690SBorislav Petkov 
91*d8001690SBorislav Petkov /*
92*d8001690SBorislav Petkov  * CPUID functions returning a single datum
93*d8001690SBorislav Petkov  */
94*d8001690SBorislav Petkov static inline unsigned int cpuid_eax(unsigned int op)
95*d8001690SBorislav Petkov {
96*d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
97*d8001690SBorislav Petkov 
98*d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
99*d8001690SBorislav Petkov 
100*d8001690SBorislav Petkov 	return eax;
101*d8001690SBorislav Petkov }
102*d8001690SBorislav Petkov 
103*d8001690SBorislav Petkov static inline unsigned int cpuid_ebx(unsigned int op)
104*d8001690SBorislav Petkov {
105*d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
106*d8001690SBorislav Petkov 
107*d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
108*d8001690SBorislav Petkov 
109*d8001690SBorislav Petkov 	return ebx;
110*d8001690SBorislav Petkov }
111*d8001690SBorislav Petkov 
112*d8001690SBorislav Petkov static inline unsigned int cpuid_ecx(unsigned int op)
113*d8001690SBorislav Petkov {
114*d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
115*d8001690SBorislav Petkov 
116*d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
117*d8001690SBorislav Petkov 
118*d8001690SBorislav Petkov 	return ecx;
119*d8001690SBorislav Petkov }
120*d8001690SBorislav Petkov 
121*d8001690SBorislav Petkov static inline unsigned int cpuid_edx(unsigned int op)
122*d8001690SBorislav Petkov {
123*d8001690SBorislav Petkov 	unsigned int eax, ebx, ecx, edx;
124*d8001690SBorislav Petkov 
125*d8001690SBorislav Petkov 	cpuid(op, &eax, &ebx, &ecx, &edx);
126*d8001690SBorislav Petkov 
127*d8001690SBorislav Petkov 	return edx;
128*d8001690SBorislav Petkov }
129*d8001690SBorislav Petkov 
130b66370dbSMichael Roth static __always_inline bool cpuid_function_is_indexed(u32 function)
131b66370dbSMichael Roth {
132b66370dbSMichael Roth 	switch (function) {
133b66370dbSMichael Roth 	case 4:
134b66370dbSMichael Roth 	case 7:
135b66370dbSMichael Roth 	case 0xb:
136b66370dbSMichael Roth 	case 0xd:
137b66370dbSMichael Roth 	case 0xf:
138b66370dbSMichael Roth 	case 0x10:
139b66370dbSMichael Roth 	case 0x12:
140b66370dbSMichael Roth 	case 0x14:
141b66370dbSMichael Roth 	case 0x17:
142b66370dbSMichael Roth 	case 0x18:
143b66370dbSMichael Roth 	case 0x1d:
144b66370dbSMichael Roth 	case 0x1e:
145b66370dbSMichael Roth 	case 0x1f:
146b66370dbSMichael Roth 	case 0x8000001d:
147b66370dbSMichael Roth 		return true;
148b66370dbSMichael Roth 	}
149b66370dbSMichael Roth 
150b66370dbSMichael Roth 	return false;
151b66370dbSMichael Roth }
152b66370dbSMichael Roth 
153*d8001690SBorislav Petkov #define for_each_possible_hypervisor_cpuid_base(function) \
154*d8001690SBorislav Petkov 	for (function = 0x40000000; function < 0x40010000; function += 0x100)
155*d8001690SBorislav Petkov 
156*d8001690SBorislav Petkov static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
157*d8001690SBorislav Petkov {
158*d8001690SBorislav Petkov 	uint32_t base, eax, signature[3];
159*d8001690SBorislav Petkov 
160*d8001690SBorislav Petkov 	for_each_possible_hypervisor_cpuid_base(base) {
161*d8001690SBorislav Petkov 		cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
162*d8001690SBorislav Petkov 
163*d8001690SBorislav Petkov 		if (!memcmp(sig, signature, 12) &&
164*d8001690SBorislav Petkov 		    (leaves == 0 || ((eax - base) >= leaves)))
165*d8001690SBorislav Petkov 			return base;
166*d8001690SBorislav Petkov 	}
167*d8001690SBorislav Petkov 
168*d8001690SBorislav Petkov 	return 0;
169*d8001690SBorislav Petkov }
170*d8001690SBorislav Petkov 
171b66370dbSMichael Roth #endif /* _ASM_X86_CPUID_H */
172