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