xref: /kernel/linux/linux-6.6/arch/x86/include/asm/cpuid.h (revision 62306a36)
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
11struct cpuid_regs {
12	u32 eax, ebx, ecx, edx;
13};
14
15enum cpuid_regs_idx {
16	CPUID_EAX = 0,
17	CPUID_EBX,
18	CPUID_ECX,
19	CPUID_EDX,
20};
21
22#ifdef CONFIG_X86_32
23extern int have_cpuid_p(void);
24#else
25static inline int have_cpuid_p(void)
26{
27	return 1;
28}
29#endif
30static 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)					\
44static 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 */
56native_cpuid_reg(eax)
57native_cpuid_reg(ebx)
58native_cpuid_reg(ecx)
59native_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 */
72static 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 */
82static 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 */
94static 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
103static 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
112static 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
121static 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
130static __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
156static 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(base, &eax, &signature[0], &signature[1], &signature[2]);
162
163		if (!memcmp(sig, signature, 12) &&
164		    (leaves == 0 || ((eax - base) >= leaves)))
165			return base;
166	}
167
168	return 0;
169}
170
171#endif /* _ASM_X86_CPUID_H */
172