[PATCH 07/16] x86/cpu: Call the vendor early_init() hook in early_cpu_init()

Andrew Cooper posted 16 patches 1 week, 4 days ago
[PATCH 07/16] x86/cpu: Call the vendor early_init() hook in early_cpu_init()
Posted by Andrew Cooper 1 week, 4 days ago
... which is in practice much earlier on boot.

Currently, beyond basic vendor family and model information, the Intel hook
needs the SELF_SNOOP CPUID bit which is collected by early_cpu_init() already.
The AMD hook needs CPUID_USER_DIS, so the collection of leaf e21a needs to
move too.  (identify_cpu() has a second collection of this leaf, which
remains.)

In order to facilitate this, have early_cpu_init() calculate
c->extended_cpuid_level in the usual way.

No practical change.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Julian Vetter <julian.vetter@vates.tech>
CC: Teddy Astie <teddy.astie@vates.tech>
---
 xen/arch/x86/cpu/common.c | 35 +++++++++++++++++++----------------
 1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
index 39e64f3a5f88..d70f9cf87dc8 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -413,8 +413,12 @@ void __init early_cpu_init(bool verbose)
 	}
 
 	eax = cpuid_eax(0x80000000);
-	if ((eax >> 16) == 0x8000 && eax >= 0x80000008) {
-		ebx = eax >= 0x8000001f ? cpuid_ebx(0x8000001f) : 0;
+	if ((eax >> 16) == 0x8000)
+		c->extended_cpuid_level = eax;
+
+	if (c->extended_cpuid_level >= 0x80000008) {
+		ebx = c->extended_cpuid_level >= 0x8000001f
+			? cpuid_ebx(0x8000001f) : 0;
 		eax = cpuid_eax(0x80000008);
 
 		paddr_bits = eax & 0xff;
@@ -433,6 +437,19 @@ void __init early_cpu_init(bool verbose)
 		paddr_bits -= (ebx >> 6) & 0x3f;
 	}
 
+	if (c->extended_cpuid_level >= 0x80000021)
+		c->x86_capability[FEATURESET_e21a] = cpuid_eax(0x80000021);
+
+	/*
+	 * Abuse 'verbose' to signal the first pass thought this function.
+	 *
+	 * Besides basic vendor, family and model information, the hooks need
+	 * certain words of x86_capability[] already scanned, as they may take
+	 * action to cause features to reappear.
+	 */
+	if (verbose && actual_cpu.c_early_init)
+		actual_cpu.c_early_init();
+
 	if (!(c->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON)))
 		park_offline_cpus = opt_mce;
 
@@ -485,10 +502,6 @@ void identify_cpu(struct cpuinfo_x86 *c)
 	c->x86_clflush_size = ((ebx >> 8) & 0xff) * 8;
 	c->phys_proc_id = c->apicid;
 
-	/*
-	 * Early init of Self Snoop support requires 0x1.edx, while there also
-	 * set 0x1.ecx as the value is in context.
-	 */
 	c->x86_capability[FEATURESET_1c] = ecx;
 	c->x86_capability[FEATURESET_1d] = edx;
 
@@ -496,16 +509,6 @@ void identify_cpu(struct cpuinfo_x86 *c)
 	if ((eax >> 16) == 0x8000)
 		c->extended_cpuid_level = eax;
 
-	/*
-	 * These AMD-defined flags are out of place, but we need
-	 * them early for the CPUID faulting probe code
-	 */
-	if (c->extended_cpuid_level >= 0x80000021)
-		c->x86_capability[FEATURESET_e21a] = cpuid_eax(0x80000021);
-
-	if (c == &boot_cpu_data && actual_cpu.c_early_init)
-		alternative_vcall(actual_cpu.c_early_init);
-
 	/* AMD-defined flags: level 0x80000001 */
 	if (c->extended_cpuid_level >= 0x80000001)
 		cpuid(0x80000001, &tmp, &tmp,
-- 
2.39.5


Re: [PATCH 07/16] x86/cpu: Call the vendor early_init() hook in early_cpu_init()
Posted by Jan Beulich 1 week, 3 days ago
On 26.01.2026 18:53, Andrew Cooper wrote:
> @@ -433,6 +437,19 @@ void __init early_cpu_init(bool verbose)
>  		paddr_bits -= (ebx >> 6) & 0x3f;
>  	}
>  
> +	if (c->extended_cpuid_level >= 0x80000021)
> +		c->x86_capability[FEATURESET_e21a] = cpuid_eax(0x80000021);
> +
> +	/*
> +	 * Abuse 'verbose' to signal the first pass thought this function.
> +	 *
> +	 * Besides basic vendor, family and model information, the hooks need
> +	 * certain words of x86_capability[] already scanned, as they may take
> +	 * action to cause features to reappear.
> +	 */
> +	if (verbose && actual_cpu.c_early_init)
> +		actual_cpu.c_early_init();

There's one slight issue with this tying to the "first pass" only: 
early_init_intel() right now calls check_memory_type_self_snoop_errata(),
which in turn uses boot_cpu_has(X86_FEATURE_SS). The comment at the 2nd
pass call site is

        /* Rescan CPUID/MSR features, which may have changed after a load. */

That, in principle, can affect any features, i.e. also SS. While for the
particular feature it may be pretty unlikely that microcode might make it
change, the mere fact that such a feature check is okay to do there may
later lead to more such getting added, not realizing that ucode loads then
may break things.

At the same time I understand that everything else in the *_early_init()
really doesn't want doing twice.

Jan