The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v1 0/5] x86/cpu: Refactor identify_cpu()
@ 2026-07-04  0:20 Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 1/5] x86/cpu: Factor init_cpu_info() out of identify_cpu() Ihor Solodrai
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Ihor Solodrai @ 2026-07-04  0:20 UTC (permalink / raw)
  To: Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
  Cc: Alexei Starovoitov, Andrii Nakryiko, Andrey Ryabinin,
	Andrew Morton, H . Peter Anvin, Andrey Konovalov, bpf,
	kernel-team, kasan-dev, linux-mm, linux-kernel

This series refactors identify_cpu() machinery on x86 and then
implements a fix for a bug when cpu capabilities are temporarily
cleared within an interruptable window. For more details and
discussion see the relevant bug report [1].

Suggested-by: Borislav Petkov <bp@alien8.de>
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>

[1] https://lore.kernel.org/bpf/20260610175651.647515-1-ihor.solodrai@linux.dev/

Ihor Solodrai (5):
  x86/cpu: Factor init_cpu_info() out of identify_cpu()
  x86/cpu: Inline generic_identify() into identify_cpu()
  x86/cpu: Introduce identify_cpu_32() helper
  x86/cpu: Set X86_BUG_ESPFIX in identify_cpu_32()
  x86/cpu: Don't reset boot CPU cpuinfo in identify_cpu()

 arch/x86/kernel/cpu/common.c | 114 +++++++++++++++++++----------------
 1 file changed, 61 insertions(+), 53 deletions(-)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 1/5] x86/cpu: Factor init_cpu_info() out of identify_cpu()
  2026-07-04  0:20 [PATCH v1 0/5] x86/cpu: Refactor identify_cpu() Ihor Solodrai
@ 2026-07-04  0:20 ` Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 2/5] x86/cpu: Inline generic_identify() into identify_cpu() Ihor Solodrai
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Ihor Solodrai @ 2026-07-04  0:20 UTC (permalink / raw)
  To: Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
  Cc: Alexei Starovoitov, Andrii Nakryiko, Andrey Ryabinin,
	Andrew Morton, H . Peter Anvin, Andrey Konovalov, bpf,
	kernel-team, kasan-dev, linux-mm, linux-kernel

identify_cpu() begins by resetting the struct cpuinfo_x86 fields to
their unknown/default values and clearing the capability arrays with
memset().

Move that reset into a new helper: init_cpu_info(). This is
preparation for letting the callers decide whether the reset is
needed.

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 arch/x86/kernel/cpu/common.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index a3df21d26460..505ce329e821 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1993,14 +1993,8 @@ static void generic_identify(struct cpuinfo_x86 *c)
 #endif
 }
 
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-static void identify_cpu(struct cpuinfo_x86 *c)
+static void init_cpu_info(struct cpuinfo_x86 *c)
 {
-	int i;
-
-	c->loops_per_jiffy = loops_per_jiffy;
 	c->x86_cache_size = 0;
 	c->x86_vendor = X86_VENDOR_UNKNOWN;
 	c->x86_model = c->x86_stepping = 0;	/* So far unknown... */
@@ -2022,6 +2016,15 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_VMX_FEATURE_NAMES
 	memset(&c->vmx_capability, 0, sizeof(c->vmx_capability));
 #endif
+}
+
+static void identify_cpu(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	c->loops_per_jiffy = loops_per_jiffy;
+
+	init_cpu_info(c);
 
 	generic_identify(c);
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 2/5] x86/cpu: Inline generic_identify() into identify_cpu()
  2026-07-04  0:20 [PATCH v1 0/5] x86/cpu: Refactor identify_cpu() Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 1/5] x86/cpu: Factor init_cpu_info() out of identify_cpu() Ihor Solodrai
@ 2026-07-04  0:20 ` Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 3/5] x86/cpu: Introduce identify_cpu_32() helper Ihor Solodrai
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Ihor Solodrai @ 2026-07-04  0:20 UTC (permalink / raw)
  To: Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
  Cc: Alexei Starovoitov, Andrii Nakryiko, Andrey Ryabinin,
	Andrew Morton, H . Peter Anvin, Andrey Konovalov, bpf,
	kernel-team, kasan-dev, linux-mm, linux-kernel

generic_identify() is only ever called from identify_cpu(),
immediately after the cpuinfo reset. Fold it into identify_cpu() so
that a single function does the job for both the boot CPU and the
secondary CPUs.

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 arch/x86/kernel/cpu/common.c | 73 +++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 39 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 505ce329e821..b9a736728a0e 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1954,16 +1954,46 @@ void check_null_seg_clears_base(struct cpuinfo_x86 *c)
 	set_cpu_bug(c, X86_BUG_NULL_SEG);
 }
 
-static void generic_identify(struct cpuinfo_x86 *c)
+static void init_cpu_info(struct cpuinfo_x86 *c)
 {
+	c->x86_cache_size = 0;
+	c->x86_vendor = X86_VENDOR_UNKNOWN;
+	c->x86_model = c->x86_stepping = 0;	/* So far unknown... */
+	c->x86_vendor_id[0] = '\0'; /* Unset */
+	c->x86_model_id[0] = '\0';  /* Unset */
+#ifdef CONFIG_X86_64
+	c->x86_clflush_size = 64;
+	c->x86_phys_bits = 36;
+	c->x86_virt_bits = 48;
+#else
+	c->cpuid_level = -1;	/* CPUID not detected */
+	c->x86_clflush_size = 32;
+	c->x86_phys_bits = 32;
+	c->x86_virt_bits = 32;
+#endif
+	c->x86_cache_alignment = c->x86_clflush_size;
+	memset(&c->x86_capability, 0, sizeof(c->x86_capability));
+	memset(&c->cpuid, 0, sizeof(c->cpuid));
+#ifdef CONFIG_X86_VMX_FEATURE_NAMES
+	memset(&c->vmx_capability, 0, sizeof(c->vmx_capability));
+#endif
 	c->extended_cpuid_level = 0;
+}
+
+static void identify_cpu(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	c->loops_per_jiffy = loops_per_jiffy;
+
+	init_cpu_info(c);
 
 	if (!cpuid_feature())
 		identify_cpu_without_cpuid(c);
 
-	/* cyrix could have cpuid enabled via c_identify()*/
+	/* cyrix could have cpuid enabled via c_identify() */
 	if (!cpuid_feature())
-		return;
+		goto no_cpuid;
 
 	cpuid_scan_cpu(c);
 	cpu_detect(c);
@@ -1991,43 +2021,8 @@ static void generic_identify(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_32
 	set_cpu_bug(c, X86_BUG_ESPFIX);
 #endif
-}
-
-static void init_cpu_info(struct cpuinfo_x86 *c)
-{
-	c->x86_cache_size = 0;
-	c->x86_vendor = X86_VENDOR_UNKNOWN;
-	c->x86_model = c->x86_stepping = 0;	/* So far unknown... */
-	c->x86_vendor_id[0] = '\0'; /* Unset */
-	c->x86_model_id[0] = '\0';  /* Unset */
-#ifdef CONFIG_X86_64
-	c->x86_clflush_size = 64;
-	c->x86_phys_bits = 36;
-	c->x86_virt_bits = 48;
-#else
-	c->cpuid_level = -1;	/* CPUID not detected */
-	c->x86_clflush_size = 32;
-	c->x86_phys_bits = 32;
-	c->x86_virt_bits = 32;
-#endif
-	c->x86_cache_alignment = c->x86_clflush_size;
-	memset(&c->x86_capability, 0, sizeof(c->x86_capability));
-	memset(&c->cpuid, 0, sizeof(c->cpuid));
-#ifdef CONFIG_X86_VMX_FEATURE_NAMES
-	memset(&c->vmx_capability, 0, sizeof(c->vmx_capability));
-#endif
-}
-
-static void identify_cpu(struct cpuinfo_x86 *c)
-{
-	int i;
-
-	c->loops_per_jiffy = loops_per_jiffy;
-
-	init_cpu_info(c);
-
-	generic_identify(c);
 
+no_cpuid:
 	cpu_parse_topology(c);
 
 	if (this_cpu->c_identify)
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 3/5] x86/cpu: Introduce identify_cpu_32() helper
  2026-07-04  0:20 [PATCH v1 0/5] x86/cpu: Refactor identify_cpu() Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 1/5] x86/cpu: Factor init_cpu_info() out of identify_cpu() Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 2/5] x86/cpu: Inline generic_identify() into identify_cpu() Ihor Solodrai
@ 2026-07-04  0:20 ` Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 4/5] x86/cpu: Set X86_BUG_ESPFIX in identify_cpu_32() Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 5/5] x86/cpu: Don't reset boot CPU cpuinfo in identify_cpu() Ihor Solodrai
  4 siblings, 0 replies; 6+ messages in thread
From: Ihor Solodrai @ 2026-07-04  0:20 UTC (permalink / raw)
  To: Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
  Cc: Alexei Starovoitov, Andrii Nakryiko, Andrey Ryabinin,
	Andrew Morton, H . Peter Anvin, Andrey Konovalov, bpf,
	kernel-team, kasan-dev, linux-mm, linux-kernel

Both identify_boot_cpu() and identify_secondary_cpu() call enable_sep_cpu()
under a CONFIG_X86_32 #ifdef. Move that into a new identify_cpu_32() helper
guarded by IS_ENABLED(CONFIG_X86_32).

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 arch/x86/kernel/cpu/common.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index b9a736728a0e..519e495c4a14 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2146,14 +2146,20 @@ void enable_sep_cpu(void)
 }
 #endif
 
+static void identify_cpu_32(struct cpuinfo_x86 *c)
+{
+	if (!IS_ENABLED(CONFIG_X86_32))
+		return;
+
+	enable_sep_cpu();
+}
+
 static __init void identify_boot_cpu(void)
 {
 	identify_cpu(&boot_cpu_data);
 	if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
 		pr_info("CET detected: Indirect Branch Tracking enabled\n");
-#ifdef CONFIG_X86_32
-	enable_sep_cpu();
-#endif
+	identify_cpu_32(&boot_cpu_data);
 	cpu_detect_tlb(&boot_cpu_data);
 	setup_cr_pinning();
 
@@ -2173,9 +2179,7 @@ void identify_secondary_cpu(unsigned int cpu)
 	c->cpu_index = cpu;
 
 	identify_cpu(c);
-#ifdef CONFIG_X86_32
-	enable_sep_cpu();
-#endif
+	identify_cpu_32(c);
 	x86_spec_ctrl_setup_ap();
 	update_srbds_msr();
 	if (boot_cpu_has_bug(X86_BUG_GDS))
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 4/5] x86/cpu: Set X86_BUG_ESPFIX in identify_cpu_32()
  2026-07-04  0:20 [PATCH v1 0/5] x86/cpu: Refactor identify_cpu() Ihor Solodrai
                   ` (2 preceding siblings ...)
  2026-07-04  0:20 ` [PATCH v1 3/5] x86/cpu: Introduce identify_cpu_32() helper Ihor Solodrai
@ 2026-07-04  0:20 ` Ihor Solodrai
  2026-07-04  0:20 ` [PATCH v1 5/5] x86/cpu: Don't reset boot CPU cpuinfo in identify_cpu() Ihor Solodrai
  4 siblings, 0 replies; 6+ messages in thread
From: Ihor Solodrai @ 2026-07-04  0:20 UTC (permalink / raw)
  To: Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
  Cc: Alexei Starovoitov, Andrii Nakryiko, Andrey Ryabinin,
	Andrew Morton, H . Peter Anvin, Andrey Konovalov, bpf,
	kernel-team, kasan-dev, linux-mm, linux-kernel

X86_BUG_ESPFIX is 32-bit-only.  Move setting it into
identify_cpu_32(), next to the other 32-bit-only setup.

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 arch/x86/kernel/cpu/common.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 519e495c4a14..8f093c6c7ccc 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2005,23 +2005,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 
 	get_model_name(c); /* Default name */
 
-	/*
-	 * ESPFIX is a strange bug.  All real CPUs have it.  Paravirt
-	 * systems that run Linux at CPL > 0 may or may not have the
-	 * issue, but, even if they have the issue, there's absolutely
-	 * nothing we can do about it because we can't use the real IRET
-	 * instruction.
-	 *
-	 * NB: For the time being, only 32-bit kernels support
-	 * X86_BUG_ESPFIX as such.  64-bit kernels directly choose
-	 * whether to apply espfix using paravirt hooks.  If any
-	 * non-paravirt system ever shows up that does *not* have the
-	 * ESPFIX issue, we can change this.
-	 */
-#ifdef CONFIG_X86_32
-	set_cpu_bug(c, X86_BUG_ESPFIX);
-#endif
-
 no_cpuid:
 	cpu_parse_topology(c);
 
@@ -2151,6 +2134,23 @@ static void identify_cpu_32(struct cpuinfo_x86 *c)
 	if (!IS_ENABLED(CONFIG_X86_32))
 		return;
 
+	/*
+	 * ESPFIX is a strange bug.  All real CPUs have it.  Paravirt
+	 * systems that run Linux at CPL > 0 may or may not have the
+	 * issue, but, even if they have the issue, there's absolutely
+	 * nothing we can do about it because we can't use the real IRET
+	 * instruction.
+	 *
+	 * NB: For the time being, only 32-bit kernels support
+	 * X86_BUG_ESPFIX as such.  64-bit kernels directly choose
+	 * whether to apply espfix using paravirt hooks.  If any
+	 * non-paravirt system ever shows up that does *not* have the
+	 * ESPFIX issue, we can change this.
+	 */
+#ifdef CONFIG_X86_32
+	set_cpu_bug(c, X86_BUG_ESPFIX);
+#endif
+
 	enable_sep_cpu();
 }
 
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 5/5] x86/cpu: Don't reset boot CPU cpuinfo in identify_cpu()
  2026-07-04  0:20 [PATCH v1 0/5] x86/cpu: Refactor identify_cpu() Ihor Solodrai
                   ` (3 preceding siblings ...)
  2026-07-04  0:20 ` [PATCH v1 4/5] x86/cpu: Set X86_BUG_ESPFIX in identify_cpu_32() Ihor Solodrai
@ 2026-07-04  0:20 ` Ihor Solodrai
  4 siblings, 0 replies; 6+ messages in thread
From: Ihor Solodrai @ 2026-07-04  0:20 UTC (permalink / raw)
  To: Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner
  Cc: Alexei Starovoitov, Andrii Nakryiko, Andrey Ryabinin,
	Andrew Morton, H . Peter Anvin, Andrey Konovalov, bpf,
	kernel-team, kasan-dev, linux-mm, linux-kernel

identify_cpu() used to rebuild c->x86_capability from scratch:
init_cpu_info() memsets the capability array to zero and
identify_cpu() then re-reads CPUID. On the boot CPU identify_cpu()
runs after local_irq_enable() and before alternatives are patched. An
interrupt delivered in the window between the memset() and
get_cpu_cap() therefore will observe cleared x86_capability [1].

However the boot CPU's capabilities have already been scanned, with
interrupts off, by early_identify_cpu(). So move the init_cpu_info()
call out of identify_cpu() into its callers, and skip it for the boot
CPU on 64-bit.

Secondary CPUs call init_cpu_info() then identify_cpu() from
identify_secondary_cpu(), with interrupts off, exactly as
before. 32-bit still resets in identify_boot_cpu(): it relies on the
reset for the no-CPUID cpuid_level default.

[1] https://lore.kernel.org/bpf/20260610175651.647515-1-ihor.solodrai@linux.dev/

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 arch/x86/kernel/cpu/common.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 8f093c6c7ccc..cd3d7c37c174 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1986,8 +1986,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 
 	c->loops_per_jiffy = loops_per_jiffy;
 
-	init_cpu_info(c);
-
 	if (!cpuid_feature())
 		identify_cpu_without_cpuid(c);
 
@@ -2156,6 +2154,13 @@ static void identify_cpu_32(struct cpuinfo_x86 *c)
 
 static __init void identify_boot_cpu(void)
 {
+	/*
+	 * The boot CPU's capabilities were already scanned in early_identify_cpu().
+	 * However 32-bit still needs to init_cpu_info() here for the no-CPUID
+	 * cpuid_level default.
+	 */
+	if (IS_ENABLED(CONFIG_X86_32))
+		init_cpu_info(&boot_cpu_data);
 	identify_cpu(&boot_cpu_data);
 	if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
 		pr_info("CET detected: Indirect Branch Tracking enabled\n");
@@ -2178,6 +2183,7 @@ void identify_secondary_cpu(unsigned int cpu)
 		*c = boot_cpu_data;
 	c->cpu_index = cpu;
 
+	init_cpu_info(c);
 	identify_cpu(c);
 	identify_cpu_32(c);
 	x86_spec_ctrl_setup_ap();
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-07-04  0:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-04  0:20 [PATCH v1 0/5] x86/cpu: Refactor identify_cpu() Ihor Solodrai
2026-07-04  0:20 ` [PATCH v1 1/5] x86/cpu: Factor init_cpu_info() out of identify_cpu() Ihor Solodrai
2026-07-04  0:20 ` [PATCH v1 2/5] x86/cpu: Inline generic_identify() into identify_cpu() Ihor Solodrai
2026-07-04  0:20 ` [PATCH v1 3/5] x86/cpu: Introduce identify_cpu_32() helper Ihor Solodrai
2026-07-04  0:20 ` [PATCH v1 4/5] x86/cpu: Set X86_BUG_ESPFIX in identify_cpu_32() Ihor Solodrai
2026-07-04  0:20 ` [PATCH v1 5/5] x86/cpu: Don't reset boot CPU cpuinfo in identify_cpu() Ihor Solodrai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox