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 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
147static 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
166static __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
192static 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 */
208