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