xref: /linux/arch/x86/kernel/cpu/cpuid_parser.c (revision 805185b7c7a1069e407b6f7b3bc98e44d415f484)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * CPUID parser; for populating the system's CPUID tables.
4  */
5 
6 #include <linux/kernel.h>
7 
8 #include <asm/cpuid/api.h>
9 #include <asm/processor.h>
10 
11 #include "cpuid_parser.h"
12 
13 /* Clear a single CPUID table entry */
14 static void cpuid_clear(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output)
15 {
16 	struct cpuid_regs *regs = output->regs;
17 
18 	for (int i = 0; i < e->maxcnt; i++, regs++)
19 		memset(regs, 0, sizeof(*regs));
20 
21 	memset(output->info, 0, sizeof(*output->info));
22 }
23 
24 /*
25  * Leaf read functions:
26  */
27 
28 /*
29  * Default CPUID read function
30  * Satisfies the requirements stated at 'struct cpuid_parse_entry'->read().
31  */
32 static void
33 cpuid_read_generic(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output)
34 {
35 	struct cpuid_regs *regs = output->regs;
36 
37 	for (int i = 0; i < e->maxcnt; i++, regs++, output->info->nr_entries++)
38 		cpuid_read_subleaf(e->leaf, e->subleaf + i, regs);
39 }
40 
41 /*
42  * CPUID parser table:
43  */
44 
45 static const struct cpuid_parse_entry cpuid_parse_entries[] = {
46 	CPUID_PARSE_ENTRIES
47 };
48 
49 /*
50  * Leaf-independent parser code:
51  */
52 
53 static unsigned int cpuid_range_max_leaf(const struct cpuid_table *t, unsigned int range)
54 {
55 	const struct leaf_0x0_0 *l0 = __cpuid_table_subleaf(t, 0x0, 0);
56 
57 	switch (range) {
58 	case CPUID_BASE_START:	return l0  ?  l0->max_std_leaf : 0;
59 	default:		return 0;
60 	}
61 }
62 
63 static void
64 __cpuid_reset_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[],
65 		    unsigned int nr_entries, unsigned int start, unsigned int end, bool fill)
66 {
67 	const struct cpuid_parse_entry *entry = entries;
68 	unsigned int range = CPUID_RANGE(start);
69 
70 	for (unsigned int i = 0; i < nr_entries; i++, entry++) {
71 		struct cpuid_read_output output = {
72 			.regs = cpuid_table_regs_p(t, entry->regs_offs),
73 			.info = cpuid_table_info_p(t, entry->info_offs),
74 		};
75 
76 		if (entry->leaf < start || entry->leaf > end)
77 			continue;
78 
79 		cpuid_clear(entry, &output);
80 
81 		/*
82 		 * Read the range's anchor leaf unconditionally so that the cached
83 		 * maximum valid leaf value is available for the remaining entries.
84 		 */
85 		if (fill && (entry->leaf == range || entry->leaf <= cpuid_range_max_leaf(t, range)))
86 			entry->read(entry, &output);
87 	}
88 }
89 
90 /*
91  * Zero all cached CPUID entries within [@start-@end] range.  This is needed when
92  * certain operations like MSR writes induce changes to the CPU's CPUID layout.
93  */
94 static void
95 __cpuid_zero_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[],
96 		   unsigned int nr_entries, unsigned int start, unsigned int end)
97 {
98 	__cpuid_reset_table(t, entries, nr_entries, start, end, false);
99 }
100 
101 static void
102 __cpuid_fill_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[],
103 		   unsigned int nr_entries, unsigned int start, unsigned int end)
104 {
105 	__cpuid_reset_table(t, entries, nr_entries, start, end, true);
106 }
107 
108 static void
109 cpuid_fill_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[], unsigned int nr_entries)
110 {
111 	static const struct {
112 		unsigned int start;
113 		unsigned int end;
114 	} ranges[] = {
115 		{ CPUID_BASE_START, CPUID_BASE_END },
116 	};
117 
118 	for (unsigned int i = 0; i < ARRAY_SIZE(ranges); i++)
119 		__cpuid_fill_table(t, entries, nr_entries, ranges[i].start, ranges[i].end);
120 }
121 
122 static void __cpuid_scan_cpu_full(struct cpuinfo_x86 *c)
123 {
124 	unsigned int nr_entries = ARRAY_SIZE(cpuid_parse_entries);
125 	struct cpuid_table *table = &c->cpuid;
126 
127 	cpuid_fill_table(table, cpuid_parse_entries, nr_entries);
128 }
129 
130 static void
131 __cpuid_scan_cpu_partial(struct cpuinfo_x86 *c, unsigned int start_leaf, unsigned int end_leaf)
132 {
133 	unsigned int nr_entries = ARRAY_SIZE(cpuid_parse_entries);
134 	struct cpuid_table *table = &c->cpuid;
135 
136 	__cpuid_zero_table(table, cpuid_parse_entries, nr_entries, start_leaf, end_leaf);
137 	__cpuid_fill_table(table, cpuid_parse_entries, nr_entries, start_leaf, end_leaf);
138 }
139 
140 /*
141  * Call-site APIs:
142  */
143 
144 /**
145  * cpuid_scan_cpu() - Populate current CPU's CPUID table
146  * @c:		CPU capability structure associated with the current CPU
147  *
148  * Populate the CPUID table embedded within @c with parsed CPUID data.  All CPUID
149  * instructions are invoked locally, so this must be called on the CPU associated
150  * with @c.
151  */
152 void cpuid_scan_cpu(struct cpuinfo_x86 *c)
153 {
154 	__cpuid_scan_cpu_full(c);
155 }
156 
157 /**
158  * cpuid_refresh_range() - Rescan a CPUID table's leaf range
159  * @c:		CPU capability structure associated with the current CPU
160  * @start:	Start of leaf range to be re-scanned
161  * @end:	End of leaf range
162  */
163 void cpuid_refresh_range(struct cpuinfo_x86 *c, u32 start, u32 end)
164 {
165 	if (WARN_ON_ONCE(start > end))
166 		return;
167 
168 	if (WARN_ON_ONCE(CPUID_RANGE(start) != CPUID_RANGE(end)))
169 		return;
170 
171 	__cpuid_scan_cpu_partial(c, start, end);
172 }
173 
174 /**
175  * cpuid_refresh_leaf() - Rescan a CPUID table's leaf
176  * @c:		CPU capability structure associated with the current CPU
177  * @leaf:	Leaf to be re-scanned
178  */
179 void cpuid_refresh_leaf(struct cpuinfo_x86 *c, u32 leaf)
180 {
181 	cpuid_refresh_range(c, leaf, leaf);
182 }
183