[PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)

Ahmed S. Darwish posted 26 patches 7 months, 2 weeks ago
[PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
Posted by Ahmed S. Darwish 7 months, 2 weeks ago
Add CPUID(0x2) support to the CPUID scanner.

Keep the leaf marked as invalid at the CPUID table if the whole leaf, or
all of its output registers, were malformed.

Note, the cpuid_get_leaf_0x2_regs() logic at <cpuid/leaf_0x2_api.h> will
be removed once all CPUID(0x2) call sites are transformed to the new
scanned API.

References: fe78079ec07f ("x86/cpu: Introduce and use CPUID leaf 0x2 parsing helpers")
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
---
 arch/x86/include/asm/cpuid/types.h  |  1 +
 arch/x86/kernel/cpu/cpuid_scanner.c | 35 +++++++++++++++++++++++++++++
 arch/x86/kernel/cpu/cpuid_scanner.h |  1 +
 3 files changed, 37 insertions(+)

diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 51b7e1b59ea5..b8e525725def 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -180,6 +180,7 @@ struct cpuid_leaves {
 	/*         leaf		subleaf		count */
 	CPUID_LEAF(0x0,		0,		1);
 	CPUID_LEAF(0x1,		0,		1);
+	CPUID_LEAF(0x2,		0,		1);
 	CPUID_LEAF(0x80000000,	0,		1);
 };
 
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.c b/arch/x86/kernel/cpu/cpuid_scanner.c
index 7200dd66939f..aaee1ede0472 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.c
+++ b/arch/x86/kernel/cpu/cpuid_scanner.c
@@ -20,6 +20,41 @@ static void cpuid_read_generic(const struct cpuid_scan_entry *e, struct cpuid_re
 		cpuid_subleaf(e->leaf, e->subleaf + i, output->leaf);
 }
 
+static void cpuid_read_0x2(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
+{
+	union leaf_0x2_regs *regs = (union leaf_0x2_regs *)output->leaf;
+	struct leaf_0x2_0 *l2 = (struct leaf_0x2_0 *)output->leaf;
+	int invalid_regs = 0;
+
+	/*
+	 * All Intel CPUs must report an iteration count of 1.	In case of
+	 * bogus hardware, keep the leaf marked as invalid at the CPUID table.
+	 */
+	cpuid_subleaf(e->leaf, e->subleaf, l2);
+	if (l2->iteration_count != 0x01)
+		return;
+
+	/*
+	 * The most significant bit (MSB) of each register must be clear.
+	 * If a register is malformed, replace its descriptors with NULL.
+	 */
+	for (int i = 0; i < 4; i++) {
+		if (regs->reg[i].invalid) {
+			regs->regv[i] = 0;
+			invalid_regs++;
+		}
+	}
+
+	/*
+	 * If all the output registers were malformed, keep the leaf marked
+	 * as invalid at the CPUID table.
+	 */
+	if (invalid_regs == 4)
+		return;
+
+	output->info->nr_entries = 1;
+}
+
 static void cpuid_read_0x80000000(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
 {
 	struct leaf_0x80000000_0 *el0 = (struct leaf_0x80000000_0 *)output->leaf;
diff --git a/arch/x86/kernel/cpu/cpuid_scanner.h b/arch/x86/kernel/cpu/cpuid_scanner.h
index 02bb223b406a..dc1d518c9768 100644
--- a/arch/x86/kernel/cpu/cpuid_scanner.h
+++ b/arch/x86/kernel/cpu/cpuid_scanner.h
@@ -92,6 +92,7 @@ struct cpuid_scan_entry {
 	/*	   leaf		subleaf		reader */			\
 	SCAN_ENTRY(0x0,		0,		generic),			\
 	SCAN_ENTRY(0x1,		0,		generic),			\
+	SCAN_ENTRY(0x2,		0,		0x2),				\
 	SCAN_ENTRY(0x80000000,  0,              0x80000000),
 
 /**
-- 
2.49.0
Re: [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
Posted by Ingo Molnar 7 months, 2 weeks ago
* Ahmed S. Darwish <darwi@linutronix.de> wrote:

> +static void cpuid_read_0x2(const struct cpuid_scan_entry *e, struct cpuid_read_output *output)
> +{
> +	union leaf_0x2_regs *regs = (union leaf_0x2_regs *)output->leaf;
> +	struct leaf_0x2_0 *l2 = (struct leaf_0x2_0 *)output->leaf;
> +	int invalid_regs = 0;
> +
> +	/*
> +	 * All Intel CPUs must report an iteration count of 1.	In case of
> +	 * bogus hardware, keep the leaf marked as invalid at the CPUID table.
> +	 */
> +	cpuid_subleaf(e->leaf, e->subleaf, l2);
> +	if (l2->iteration_count != 0x01)
> +		return;
> +
> +	/*
> +	 * The most significant bit (MSB) of each register must be clear.
> +	 * If a register is malformed, replace its descriptors with NULL.
> +	 */
> +	for (int i = 0; i < 4; i++) {
> +		if (regs->reg[i].invalid) {
> +			regs->regv[i] = 0;
> +			invalid_regs++;
> +		}

Could we please emit a one-time syslog warning & diagnostic when we run 
across invalid or otherwise weird looking CPUID data, instead of just 
silently skipping and sanitizing it?

Thanks,

	Ingo
Re: [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
Posted by Ahmed S. Darwish 7 months, 2 weeks ago
On Tue, 06 May 2025, Ingo Molnar wrote:
>
> Could we please emit a one-time syslog warning & diagnostic when we run
> across invalid or otherwise weird looking CPUID data, instead of just
> silently skipping and sanitizing it?
>

Sure; will do.

Thanks,
Ahmed
Re: [PATCH v1 13/26] x86/cpuid: Scan CPUID(0x2)
Posted by Ingo Molnar 7 months, 2 weeks ago
* Ahmed S. Darwish <darwi@linutronix.de> wrote:

> On Tue, 06 May 2025, Ingo Molnar wrote:
> >
> > Could we please emit a one-time syslog warning & diagnostic when we run
> > across invalid or otherwise weird looking CPUID data, instead of just
> > silently skipping and sanitizing it?
> >
> 
> Sure; will do.

Thanks! We haven't been doing this for any of the current code, right? 
So depending on how frequent these messages are in practice, we might 
have to tone it down a bit - but shining a bit of light on that dark 
corner would be informative I think.

Thanks,

	Ingo