[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250905121515.192792-13-darwi@linutronix.de>
Date: Fri, 5 Sep 2025 14:14:52 +0200
From: "Ahmed S. Darwish" <darwi@...utronix.de>
To: Borislav Petkov <bp@...en8.de>,
Ingo Molnar <mingo@...hat.com>,
Dave Hansen <dave.hansen@...ux.intel.com>
Cc: Thomas Gleixner <tglx@...utronix.de>,
Andrew Cooper <andrew.cooper3@...rix.com>,
Sean Christopherson <seanjc@...gle.com>,
David Woodhouse <dwmw2@...radead.org>,
"H. Peter Anvin" <hpa@...or.com>,
Peter Zijlstra <peterz@...radead.org>,
Sohil Mehta <sohil.mehta@...el.com>,
John Ogness <john.ogness@...utronix.de>,
x86@...nel.org,
x86-cpuid@...ts.linux.dev,
LKML <linux-kernel@...r.kernel.org>,
"Ahmed S. Darwish" <darwi@...utronix.de>
Subject: [PATCH v5 12/35] x86/cpuid: Parse CPUID(0x80000000)
Add CPUID parser logic for CPUID(0x80000000).
Verify the query output beforehand, since legacy 32-bit Intel machines
without an extended range will just repeat the output of the highest
standard CPUID leaf available. This is similar to what is done at
arch/x86/kernel/head_32.S and arch/x86/kernel/cpu/common.c.
References: 8a50e5135af0 ("x86-32: Use symbolic constants, safer CPUID when enabling EFER.NX")
References: 67ad24e6d39c ("- pre5: - Rasmus Andersen: add proper...") # Historical git
Signed-off-by: Ahmed S. Darwish <darwi@...utronix.de>
Cc: "H. Peter Anvin" <hpa@...or.com>
Link: https://lore.kernel.org/r/d4fcfd91-cc92-4b3c-9dd2-56ecd754cecc@citrix.com
---
arch/x86/include/asm/cpuid/types.h | 7 ++++++-
arch/x86/kernel/cpu/cpuid_parser.c | 22 +++++++++++++++++++++-
arch/x86/kernel/cpu/cpuid_parser.h | 1 +
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 9b8bd6b22ff3..e57245ca6419 100644
--- a/arch/x86/include/asm/cpuid/types.h
+++ b/arch/x86/include/asm/cpuid/types.h
@@ -33,7 +33,11 @@ enum cpuid_regs_idx {
#define CPUID_LEAF_TILE 0x1d
#define CPUID_BASE_START 0x0
-#define CPUID_BASE_END (CPUID_BASE_START + 0xffff)
+#define CPUID_EXT_START 0x80000000
+
+#define __CPUID_RANGE_END(idx) ((idx) + 0xffff)
+#define CPUID_BASE_END __CPUID_RANGE_END(CPUID_BASE_START)
+#define CPUID_EXT_END __CPUID_RANGE_END(CPUID_EXT_START)
/*
* Types for CPUID(0x2) parsing:
@@ -232,6 +236,7 @@ struct cpuid_leaves {
/* Leaf Subleaf number (or max number of dynamic subleaves) */
CPUID_LEAF ( 0x0, 0 );
CPUID_LEAF ( 0x1, 0 );
+ CPUID_LEAF ( 0x80000000, 0 );
};
/*
diff --git a/arch/x86/kernel/cpu/cpuid_parser.c b/arch/x86/kernel/cpu/cpuid_parser.c
index 15264696eaad..9c40c180e3d4 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.c
+++ b/arch/x86/kernel/cpu/cpuid_parser.c
@@ -27,6 +27,23 @@ static void cpuid_read_generic(const struct cpuid_parse_entry *e, struct cpuid_r
cpuid_read_subleaf(e->leaf, e->subleaf + i, output->regs);
}
+static void cpuid_read_0x80000000(const struct cpuid_parse_entry *e, struct cpuid_read_output *output)
+{
+ struct leaf_0x80000000_0 *el0 = (struct leaf_0x80000000_0 *)output->regs;
+
+ cpuid_read_subleaf(e->leaf, e->subleaf, el0);
+
+ /*
+ * Protect against Intel 32-bit CPUs lacking an extended CPUID range. A
+ * CPUID(0x80000000) query on such machines will just repeat the output
+ * of the highest standard CPUID leaf.
+ */
+ if ((el0->max_ext_leaf & 0xffff0000) != 0x80000000)
+ return;
+
+ output->info->nr_entries = 1;
+}
+
/*
* CPUID parser tables:
*
@@ -45,9 +62,11 @@ static const struct cpuid_parse_entry cpuid_parse_entries[] = {
static unsigned int cpuid_range_max_leaf(const struct cpuid_table *t, unsigned int range)
{
const struct leaf_0x0_0 *l0 = __cpuid_table_subleaf(t, 0x0, 0);
+ const struct leaf_0x80000000_0 *el0 = __cpuid_table_subleaf(t, 0x80000000, 0);
switch (range) {
case CPUID_BASE_START: return l0 ? l0->max_std_leaf : 0;
+ case CPUID_EXT_START: return el0 ? el0->max_ext_leaf : 0;
default: return 0;
}
}
@@ -63,7 +82,8 @@ cpuid_range_valid(const struct cpuid_table *t, unsigned int leaf, unsigned int s
static bool cpuid_leaf_in_range(const struct cpuid_table *t, unsigned int leaf)
{
- return cpuid_range_valid(t, leaf, CPUID_BASE_START, CPUID_BASE_END);
+ return cpuid_range_valid(t, leaf, CPUID_BASE_START, CPUID_BASE_END) ||
+ cpuid_range_valid(t, leaf, CPUID_EXT_START, CPUID_EXT_END);
}
static void
diff --git a/arch/x86/kernel/cpu/cpuid_parser.h b/arch/x86/kernel/cpu/cpuid_parser.h
index acddcbc9bd06..39a361eed7ce 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.h
+++ b/arch/x86/kernel/cpu/cpuid_parser.h
@@ -111,5 +111,6 @@ struct cpuid_parse_entry {
/* Leaf Subleaf Reader function */ \
CPUID_PARSE_ENTRY ( 0x0, 0, generic ), \
CPUID_PARSE_ENTRY ( 0x1, 0, generic ), \
+ CPUID_PARSE_ENTRY ( 0x80000000, 0, 0x80000000 ), \
#endif /* _ARCH_X86_CPUID_PARSER_H */
--
2.50.1
Powered by blists - more mailing lists