Re: [PATCH v7 020/120] x86/cpuid: Parse Transmeta and Centaur extended ranges
Borislav Petkov <[email protected]> Wed, 24 Jun 2026 16:31:06 -0700
| Newsgroups | dev.linux.lists.x86-cpuid,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260624233106.GBajxoupFGt0f8Mtxb@fat_crate.local> |
On Thu, May 28, 2026 at 05:37:42PM +0200, Ahmed S. Darwish wrote: > 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 Those are weird abbreviations. What's wrong with CPUID_TRANSMETA_START and CPUID_CENTAUR_START ? > > #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 ); This parser thing has so many macros but here we need to specify each leaf one-by-one explicitly? Not by doing CPUID_LEAFS_RANGE(0x80860000, 0x80860006); for example? > }; > > /* > 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) This function should not even be added in an earlier patch to be removed here but... > -{ > - 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); ... using this from the get-go. > +define_cpuid_range_read_function(0x80860000, tra); > +define_cpuid_range_read_function(0xc0000000, cntr); Please use proper full names - not this abbreviated stuff. > + > /* > * 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 ), \ A range macro here too pls. Thx. -- Regards/Gruss, Boris. https://people.kernel.org/tglx/notes-about-netiquette