[PATCH v7 020/120] x86/cpuid: Parse Transmeta and Centaur extended ranges
"Ahmed S. Darwish" <[email protected]> Thu, 28 May 2026 17:37:42 +0200
| Newsgroups | dev.linux.lists.x86-cpuid,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Parse the Transmeta extended CPUID(0x80860000)->CPUID(0x80860006) range. Reuse the CPUID(0x80000000) read function and its safety guards against CPUs repeating the output of the highest standard CPUID leaf. Transmeta's code at early_init_transmeta() already carries a similar guard. Parse Centaur/Zhaoxin extended CPUID(0xc0000000) and CPUID(0xc0000001). Add x86 vendor tags for the Transmeta and Centaur/Zhaoxin CPUID leaves so that they are not parsed on other vendors. Signed-off-by: Ahmed S. Darwish <[email protected]> --- arch/x86/include/asm/cpuid/types.h | 13 ++++++++ arch/x86/kernel/cpu/cpuid_parser.c | 48 +++++++++++++++++++----------- arch/x86/kernel/cpu/cpuid_parser.h | 18 +++++++++++ 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/arch/x86/include/asm/cpuid/types.h b/arch/x86/include/asm/cpuid/types.h index 2939ad095f6c..8cc9f81e9526 100644 --- a/arch/x86/include/asm/cpuid/types.h +++ b/arch/x86/include/asm/cpuid/types.h @@ -37,9 +37,13 @@ enum cpuid_regs_idx { #define CPUID_BASE_START 0x00000000 #define CPUID_EXT_START 0x80000000 +#define CPUID_TMX_START 0x80860000 +#define CPUID_CTR_START 0xc0000000 #define CPUID_BASE_END CPUID_RANGE_MAX(CPUID_BASE_START) #define CPUID_EXT_END CPUID_RANGE_MAX(CPUID_EXT_START) +#define CPUID_TMX_END CPUID_RANGE_MAX(CPUID_TMX_START) +#define CPUID_CTR_END CPUID_RANGE_MAX(CPUID_CTR_START) /* * Types for CPUID(0x2) parsing: @@ -211,6 +215,15 @@ struct cpuid_leaves { CPUID_LEAF ( 0x80000002, 0 ); CPUID_LEAF ( 0x80000003, 0 ); CPUID_LEAF ( 0x80000004, 0 ); + CPUID_LEAF ( 0x80860000, 0 ); + CPUID_LEAF ( 0x80860001, 0 ); + CPUID_LEAF ( 0x80860002, 0 ); + CPUID_LEAF ( 0x80860003, 0 ); + CPUID_LEAF ( 0x80860004, 0 ); + CPUID_LEAF ( 0x80860005, 0 ); + CPUID_LEAF ( 0x80860006, 0 ); + CPUID_LEAF ( 0xc0000000, 0 ); + CPUID_LEAF ( 0xc0000001, 0 ); }; /* diff --git a/arch/x86/kernel/cpu/cpuid_parser.c b/arch/x86/kernel/cpu/cpuid_parser.c index ab736f03051e..a7e6692f767b 100644 --- a/arch/x86/kernel/cpu/cpuid_parser.c +++ b/arch/x86/kernel/cpu/cpuid_parser.c @@ -42,24 +42,30 @@ cpuid_read_generic(const struct cpuid_parse_entry *e, const struct cpuid_read_ou cpuid_read_subleaf(e->leaf, e->subleaf + i, regs); } -static void -cpuid_read_0x80000000(const struct cpuid_parse_entry *e, const 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 repeat the output of the - * highest standard CPUID leaf instead. - */ - if (CPUID_RANGE(el0->max_ext_leaf) != CPUID_EXT_START) - return; - - output->info->nr_entries = 1; +/* + * Define an extended range CPUID read function + * + * Guard against CPUs lacking the passed range leaf; e.g. Intel 32-bit CPUs lacking + * CPUID(0x80000000). A query on such machines will just repeat the output of the + * highest standard CPUID leaf. + */ +#define define_cpuid_range_read_function(_range, _name) \ +static void \ +cpuid_read_##_range(const struct cpuid_parse_entry *e, const struct cpuid_read_output *output) \ +{ \ + struct leaf_##_range##_0 *l = (struct leaf_##_range##_0 *)output->regs; \ + \ + cpuid_read_subleaf(e->leaf, e->subleaf, l); \ + if (CPUID_RANGE(l->max_##_name##_leaf) != _range) \ + return; \ + \ + output->info->nr_entries = 1; \ } +define_cpuid_range_read_function(0x80000000, ext); +define_cpuid_range_read_function(0x80860000, tra); +define_cpuid_range_read_function(0xc0000000, cntr); + /* * CPUID parser tables: * @@ -115,10 +121,14 @@ static unsigned int cpuid_range_max_leaf(const struct cpuid_table *t, unsigned i { const struct leaf_0x0_0 *l0 = __cpuid_table_subleaf(t, 0x0, 0); const struct leaf_0x80000000_0 *el0 = __cpuid_table_subleaf(t, 0x80000000, 0); + const struct leaf_0x80860000_0 *tl0 = __cpuid_table_subleaf(t, 0x80860000, 0); + const struct leaf_0xc0000000_0 *cl0 = __cpuid_table_subleaf(t, 0xc0000000, 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; + case CPUID_BASE_START: return l0 ? l0->max_std_leaf : 0; + case CPUID_EXT_START: return el0 ? el0->max_ext_leaf : 0; + case CPUID_TMX_START: return tl0 ? tl0->max_tra_leaf : 0; + case CPUID_CTR_START: return cl0 ? cl0->max_cntr_leaf : 0; default: return 0; } } @@ -180,6 +190,8 @@ cpuid_fill_table(struct cpuid_table *t, const struct cpuid_parse_entry entries[] } ranges[] = { { CPUID_BASE_START, CPUID_BASE_END }, { CPUID_EXT_START, CPUID_EXT_END }, + { CPUID_TMX_START, CPUID_TMX_END }, + { CPUID_CTR_START, CPUID_CTR_END }, }; for (unsigned int i = 0; i < ARRAY_SIZE(ranges); i++) diff --git a/arch/x86/kernel/cpu/cpuid_parser.h b/arch/x86/kernel/cpu/cpuid_parser.h index ee1958f3d369..76a87a71b430 100644 --- a/arch/x86/kernel/cpu/cpuid_parser.h +++ b/arch/x86/kernel/cpu/cpuid_parser.h @@ -149,6 +149,15 @@ struct cpuid_parse_entry { CPUID_PARSE_ENTRY ( 0x80000002, 0, generic ), \ CPUID_PARSE_ENTRY ( 0x80000003, 0, generic ), \ CPUID_PARSE_ENTRY ( 0x80000004, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0x80860000, 0, 0x80860000 ), \ + CPUID_PARSE_ENTRY ( 0x80860001, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0x80860002, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0x80860003, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0x80860004, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0x80860005, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0x80860006, 0, generic ), \ + CPUID_PARSE_ENTRY ( 0xc0000000, 0, 0xc0000000 ), \ + CPUID_PARSE_ENTRY ( 0xc0000001, 0, generic ), \ /* * CPUID parser phases: @@ -182,5 +191,14 @@ struct cpuid_vendor_entry { #define CPUID_VENDOR_ENTRIES \ /* Leaf Vendor list */ \ CPUID_VENDOR_ENTRY(0x16, X86_VENDOR_INTEL), \ + CPUID_VENDOR_ENTRY(0x80860000, X86_VENDOR_TRANSMETA), \ + CPUID_VENDOR_ENTRY(0x80860001, X86_VENDOR_TRANSMETA), \ + CPUID_VENDOR_ENTRY(0x80860002, X86_VENDOR_TRANSMETA), \ + CPUID_VENDOR_ENTRY(0x80860003, X86_VENDOR_TRANSMETA), \ + CPUID_VENDOR_ENTRY(0x80860004, X86_VENDOR_TRANSMETA), \ + CPUID_VENDOR_ENTRY(0x80860005, X86_VENDOR_TRANSMETA), \ + CPUID_VENDOR_ENTRY(0x80860006, X86_VENDOR_TRANSMETA), \ + CPUID_VENDOR_ENTRY(0xc0000000, X86_VENDOR_CENTAUR, X86_VENDOR_ZHAOXIN), \ + CPUID_VENDOR_ENTRY(0xc0000001, X86_VENDOR_CENTAUR, X86_VENDOR_ZHAOXIN), \ #endif /* _ARCH_X86_CPUID_PARSER_H */ -- 2.54.0