[PATCH v4 12/34] x86/cpuid: Parse CPUID(0x80000000)

"Ahmed S. Darwish" <[email protected]>
Newsgroups dev.linux.lists.x86-cpuid,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add CPUID parser logic for CPUID(0x80000000).

Similar to kernel/head_32.S and kernel/cpu/common.c, verify the
CPUID(0x80000000) query output beforehand.  This is due to x86-32
machines without an extended CPUID range, where a CPUID(0x80000000) query
will just repeat the max-valid standard CPUID leaf output.

References: 8a50e5135af0 ("x86-32: Use symbolic constants, safer CPUID when enabling EFER.NX")
References: 67ad24e6d39c ("- pre5:    - Rasmus Andersen: add proper...")  # Historical git
Suggested-by: Andrew Cooper <[email protected]>
Suggested-by: Thomas Gleixner <[email protected]>
Signed-off-by: Ahmed S. Darwish <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
 arch/x86/include/asm/cpuid/types.h |  7 ++++++-
 arch/x86/kernel/cpu/cpuid_parser.c | 27 ++++++++++++++++++++++++++-
 arch/x86/kernel/cpu/cpuid_parser.h |  1 +
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h
index 320f152675af..d0f0e6a8a457 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:
@@ -211,6 +215,7 @@ struct cpuid_leaves {
 	/*         leaf		subleaf		count */
 	CPUID_LEAF(0x0,		0,		1);
 	CPUID_LEAF(0x1,		0,		1);
+	CPUID_LEAF(0x80000000,	0,		1);
 };
 
 /*
diff --git a/arch/x86/kernel/cpu/cpuid_parser.c b/arch/x86/kernel/cpu/cpuid_parser.c
index 80476e578fb8..be9c8571f886 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.c
+++ b/arch/x86/kernel/cpu/cpuid_parser.c
@@ -27,6 +27,29 @@ 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 *l = (struct leaf_0x80000000_0 *)output->regs;
+
+	cpuid_read_subleaf(e->leaf, e->subleaf, l);
+
+	/*
+	 * Protect against 32-bit CPUs lacking an extended CPUID range: Ensure that the
+	 * returned max extended CPUID leaf is in the 0x80000001-0x8000ffff range.
+	 *
+	 * Do not depend on leaving 'info->nr_entries' set as zero, but zero-out the
+	 * whole leaf output area as well.  This is due to the CPUID parser internals
+	 * using the __cpuid_leaves_subleaf_0() API to get the cached max extended leaf,
+	 * which does not do any sanity checks,
+	 */
+	if ((l->max_ext_leaf & 0xffff0000) != 0x80000000) {
+		*l = (struct leaf_0x80000000_0){ };
+		return;
+	}
+
+	output->info->nr_entries = 1;
+}
+
 /*
  * CPUID parser tables:
  *
@@ -46,6 +69,7 @@ static unsigned int cpuid_range_max_leaf(const struct cpuid_table *t, unsigned i
 {
 	switch (range) {
 	case CPUID_BASE_START:	return __cpuid_leaves_subleaf_0(&t->leaves, 0x0).max_std_leaf;
+	case CPUID_EXT_START:   return __cpuid_leaves_subleaf_0(&t->leaves, 0x80000000).max_ext_leaf;
 	default:		return 0;
 	}
 }
@@ -61,7 +85,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 48e962106d4a..c2b78badd67e 100644
--- a/arch/x86/kernel/cpu/cpuid_parser.h
+++ b/arch/x86/kernel/cpu/cpuid_parser.h
@@ -100,5 +100,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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.