Re: [PATCH v7 020/120] x86/cpuid: Parse Transmeta and Centaur extended ranges

From: Borislav Petkov

Date: Wed Jun 24 2026 - 19:31:47 EST


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 <darwi@xxxxxxxxxxxxx>
> ---
> 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