Skip to contentSkip to conversation

x86/cpu: Refactor identify_cpu()

PATCH Applied Ihor Solodrai 3 participants 15 messages Sep 16 – Sep 17

Subsystems (3)
lore
Share & tools
lore

Ihor Solodrai

author reviewer
#0 lore raw

v3 cover x86/cpu: Refactor identify_cpu()

Refactor identify_cpu() machinery on x86 and then implement 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] and patch #5 ("x86/cpu: Don't transiently clear the boot CPU's capabilities").

[1] https://lore.kernel.org/bpf/[email protected]/

---

v2->v3:
* Commit message edits on patches #1, #2, #5

v2: https://lore.kernel.org/bpf/[email protected]/

v1->v2:
* Rewrite commit messages to fit more conventional structure (Boris)
* Drop identify_cpu_32() helper, it's unnecessary (Boris)
* New patch (#2): now early_identify_cpu() resets boot_cpu_data through init_cpu_info() as well
* The boot CPU reset is now skipped on 32-bit too (sashiko)

v1: https://lore.kernel.org/bpf/[email protected]/

---

Ihor Solodrai (5):
x86/cpu: Factor init_cpu_info() out of identify_cpu() x86/cpu: Initialize boot CPU cpuinfo defaults early x86/cpu: Inline generic_identify() into identify_cpu() x86/cpu: Move 32-bit SEP setup into identify_cpu() x86/cpu: Don't transiently clear the boot CPU's capabilities

 arch/x86/kernel/cpu/common.c | 92 +++++++++++++++++-------------------
 1 file changed, 44 insertions(+), 48 deletions(-)

base-commit: fd73f4a6659897191fa0d40695fe370925dd3780

Signature · 1 line
2.55.0
author reviewer
#1 lore raw

PATCH v3 1/5 x86/cpu: Factor init_cpu_info() out of identify_cpu()

identify_cpu() unconditionally resets the struct cpuinfo_x86 fields to their default values and clears the capability arrays with memset() before rescanning the CPU to fill it in again.

However the boot CPU capabilities have already been scanned by early_identify_cpu(), with interrupts disabled.

Introduce init_cpu_info() helper in preparation for letting the callers decide whether the reset is needed.

No functional changes.

---
 arch/x86/kernel/cpu/common.c | 51 ++++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 23 deletions(-)
arch/x86/kernel/cpu/common.c +28 -23
index c7352827f491..c3dce89ba590 100644
@@ -1782,6 +1782,32 @@ static void __init cpu_parse_early_param(void)
 	}
 }
 
+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;
+}
+
 /*
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
@@ -1966,8 +1992,6 @@ void check_null_seg_clears_base(struct cpuinfo_x86 *c)
 
 static void generic_identify(struct cpuinfo_x86 *c)
 {
-	c->extended_cpuid_level = 0;
-
 	if (!cpuid_feature())
 		identify_cpu_without_cpuid(c);
 
@@ -2011,27 +2035,8 @@ static void identify_cpu(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... */
-	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
+
+	init_cpu_info(c);
 
 	generic_identify(c);
 
Signature · 1 line
2.55.0
merge bot Applied
#2 lore raw

[tip: x86/cpu] x86/cpu: Factor init_cpu_info() out of identify_cpu()

The following commit has been merged into the x86/cpu branch of tip:

The following commit has been merged into the x86/cpu branch of tip:

Commit-ID:     54a2882ab9f75ab8a77a4f113145d4d709d2387c
Gitweb:        https://git.kernel.org/tip/54a2882ab9f75ab8a77a4f113145d4d709d2387c
Author:        Ihor Solodrai <[email protected]>
AuthorDate:    Wed, 16 Sep 2026 12:51:59 -07:00
Committer:     Borislav Petkov (AMD) <[email protected]>
CommitterDate: Thu, 17 Sep 2026 01:54:28 +02:00

x86/cpu: Factor init_cpu_info() out of identify_cpu()

identify_cpu() unconditionally resets the struct cpuinfo_x86 fields to their default values and clears the capability arrays with memset() before rescanning the CPU to fill it in again.

However the boot CPU capabilities have already been scanned by early_identify_cpu(), with interrupts disabled.

Introduce init_cpu_info() helper in preparation for letting the callers decide whether the reset is needed.

No functional changes.

---
 arch/x86/kernel/cpu/common.c | 51 +++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 23 deletions(-)
arch/x86/kernel/cpu/common.c +28 -23
index 3716a6a..173748a 100644
@@ -1784,6 +1784,32 @@ static void __init cpu_parse_early_param(void)
 	}
 }
 
+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;
+}
+
 /*
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
@@ -1968,8 +1994,6 @@ void check_null_seg_clears_base(struct cpuinfo_x86 *c)
 
 static void generic_identify(struct cpuinfo_x86 *c)
 {
-	c->extended_cpuid_level = 0;
-
 	if (!cpuid_feature())
 		identify_cpu_without_cpuid(c);
 
@@ -2013,27 +2037,8 @@ static void identify_cpu(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... */
-	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
+
+	init_cpu_info(c);
 
 	generic_identify(c);
 
#3 lore raw

Re: [PATCH v3 1/5] x86/cpu: Factor init_cpu_info() out of identify_cpu()

In reply to Ihor Solodrai
This isn't a bug, but would it be worth adding a line noting that c->extended_cpuid_level = 0 also moves here from generic_identify(), which identify_cpu() is the only caller of? That is the one…
Quoted 6 lines

x86/cpu: Factor init_cpu_info() out of identify_cpu()

identify_cpu() unconditionally resets the struct cpuinfo_x86 fields to their default values and clears the capability arrays with memset() before rescanning the CPU to fill it in again.

Quoted 7 lines

However the boot CPU capabilities have already been scanned by early_identify_cpu(), with interrupts disabled.

Introduce init_cpu_info() helper in preparation for letting the callers decide whether the reset is needed.

No functional changes.

This isn't a bug, but would it be worth adding a line noting that c->extended_cpuid_level = 0 also moves here from generic_identify(), which identify_cpu() is the only caller of? That is the one part of the move that isn't local to identify_cpu(), so it would make the "No functional changes" claim easier to confirm.

---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35285131592

author reviewer
#4 lore raw

PATCH v3 2/5 x86/cpu: Initialize boot CPU cpuinfo defaults early

In reply to Ihor Solodrai

early_identify_cpu() clears the capability array, the CPUID table and extended_cpuid_level, but the architectural defaults for the rest of struct cpuinfo_x86 are set only later, in identify_cpu().

Use the same defaults from the start, so that the boot CPU does not depend on a later reset to end up with the right ones.

---

This change comes before the last patch because that one removes the
reset: without the defaults established here the boot CPU would be left at 32 instead of 64 on an x86_64 CPU which does not enumerate CLFLUSH.

---
 arch/x86/kernel/cpu/common.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
arch/x86/kernel/cpu/common.c +3 -4
index c3dce89ba590..66695addbdf3 100644
@@ -1812,16 +1812,15 @@ static void init_cpu_info(struct cpuinfo_x86 *c)
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
  * cache alignment.
- * The others are not touched to avoid unwanted side effects.
+ * The others are reset to their defaults here and only filled in later,
+ * by identify_cpu().
  *
  * WARNING: this function is only called on the boot CPU.  Don't add code
  * here that is supposed to run on all CPUs.
  */
 static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
-	memset(&c->x86_capability, 0, sizeof(c->x86_capability));
-	memset(&c->cpuid, 0, sizeof(c->cpuid));
-	c->extended_cpuid_level = 0;
+	init_cpu_info(c);
 
 	if (!cpuid_feature())
 		identify_cpu_without_cpuid(c);
Signature · 1 line
2.55.0
merge bot Applied
#5 lore raw

[tip: x86/cpu] x86/cpu: Initialize boot CPU cpuinfo defaults early

The following commit has been merged into the x86/cpu branch of tip:

The following commit has been merged into the x86/cpu branch of tip:

Commit-ID:     7a762b51a149b7bfe431a7571bc7df4beea52e5c
Gitweb:        https://git.kernel.org/tip/7a762b51a149b7bfe431a7571bc7df4beea52e5c
Author:        Ihor Solodrai <[email protected]>
AuthorDate:    Wed, 16 Sep 2026 12:52:00 -07:00
Committer:     Borislav Petkov (AMD) <[email protected]>
CommitterDate: Thu, 17 Sep 2026 01:57:26 +02:00

x86/cpu: Initialize boot CPU cpuinfo defaults early

early_identify_cpu() clears the capability array, the CPUID table and extended_cpuid_level, but the architectural defaults for the rest of struct cpuinfo_x86 are set only later, in identify_cpu().

Use the same defaults from the start, so that the boot CPU does not depend on a later reset to end up with the right ones.

---
 arch/x86/kernel/cpu/common.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
arch/x86/kernel/cpu/common.c +3 -4
index 173748a..d1a949a 100644
@@ -1814,16 +1814,15 @@ static void init_cpu_info(struct cpuinfo_x86 *c)
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
  * cache alignment.
- * The others are not touched to avoid unwanted side effects.
+ * The others are reset to their defaults here and only filled in later,
+ * by identify_cpu().
  *
  * WARNING: this function is only called on the boot CPU.  Don't add code
  * here that is supposed to run on all CPUs.
  */
 static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
-	memset(&c->x86_capability, 0, sizeof(c->x86_capability));
-	memset(&c->cpuid, 0, sizeof(c->cpuid));
-	c->extended_cpuid_level = 0;
+	init_cpu_info(c);
 
 	if (!cpuid_feature())
 		identify_cpu_without_cpuid(c);
#6 lore raw

Re: [PATCH v3 2/5] x86/cpu: Initialize boot CPU cpuinfo defaults early

In reply to Ihor Solodrai
Does this comment match what the code does? The comment says fields outside the "really needed" list are only reset here and filled in later by identify_cpu(), but early_identify_cpu() itself fills…

arch/x86/kernel/cpu/common.c static void init_cpu_info(struct cpuinfo_x86 *c) · line 1816

Quoted 11 lines
arch/x86/kernel/cpu/common.c +2 -1
index c3dce89ba5904..66695addbdf33 100644
@@ -1812,16 +1812,15 @@ static void init_cpu_info(struct cpuinfo_x86 *c)
  * Do minimum CPU detection early.
  * Fields really needed: vendor, cpuid_level, family, model, mask,
  * cache alignment.
- * The others are not touched to avoid unwanted side effects.
+ * The others are reset to their defaults here and only filled in later,
+ * by identify_cpu().
                         ^^

Does this comment match what the code does? The comment says fields outside the "really needed" list are only reset here and filled in later by identify_cpu(), but early_identify_cpu() itself fills in most of those fields before it returns.

After init_cpu_info() resets the fields, early_identify_cpu() continues to call:

  cpuid_scan_cpu(c);         /* re-populates c->cpuid */
  cpu_detect(c);             /* x86_clflush_size, x86_cache_alignment */
  get_cpu_cap(c);            /* x86_capability[], extended_cpuid_level */
  get_cpu_address_sizes(c);  /* x86_phys_bits, x86_virt_bits,
                                x86_cache_alignment */

Of the twelve fields init_cpu_info() resets, only three (x86_cache_size, x86_model_id and, under CONFIG_X86_VMX_FEATURE_NAMES, vmx_capability) are left for identify_cpu(); the capability array, the CPUID table, extended_cpuid_level and the address sizes are all re-established in this function.

The sentence also contradicts the line immediately above it, which already lists "cache alignment" among the fields early detection does produce.

This matters more than a normal comment nit because the very next paragraph is a WARNING about what may and may not be added to this function: a reader who believes the non-essential fields are untouched until identify_cpu() would draw the wrong conclusion about what state is valid at this point in boot.

Could the comment say that the architectural defaults for the remaining fields are established here, and that only the cache size, model string (and VMX capabilities) are filled in later by identify_cpu()?

arch/x86/kernel/cpu/common.c static void init_cpu_info(struct cpuinfo_x86 *c) · line 1826

Quoted 13 lines
arch/x86/kernel/cpu/common.c +1 -3
  *
  * WARNING: this function is only called on the boot CPU.  Don't add code
  * here that is supposed to run on all CPUs.
  */
 static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 {
-	memset(&c->x86_capability, 0, sizeof(c->x86_capability));
-	memset(&c->cpuid, 0, sizeof(c->cpuid));
-	c->extended_cpuid_level = 0;
+	init_cpu_info(c);
 
 	if (!cpuid_feature())
 		identify_cpu_without_cpuid(c);

---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35285131592

author reviewer
#7 lore raw

PATCH v3 3/5 x86/cpu: Inline generic_identify() into identify_cpu()

In reply to Ihor Solodrai

generic_identify() has exactly one call site: at the top of identify_cpu(). Fold it into identify_cpu() so that a single function does the job for both the boot CPU and the secondary CPUs.

While at it, fix up both copies of the Cyrix comment.

No functional changes.

---
 arch/x86/kernel/cpu/common.c | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)
arch/x86/kernel/cpu/common.c +14 -18
index 66695addbdf3..2b2a4c40ef76 100644
@@ -1825,7 +1825,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *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()) {
 		cpuid_scan_cpu(c);
 		cpu_detect(c);
@@ -1989,14 +1989,23 @@ 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)
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+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);
@@ -2024,21 +2033,8 @@ static void generic_identify(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_32
 	set_cpu_bug(c, X86_BUG_ESPFIX);
 #endif
-}
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-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)
Signature · 1 line
2.55.0
merge bot Applied
#8 lore raw

[tip: x86/cpu] x86/cpu: Inline generic_identify() into identify_cpu()

The following commit has been merged into the x86/cpu branch of tip:

The following commit has been merged into the x86/cpu branch of tip:

Commit-ID:     ad86fe2134ccdc97a967693d2723a731c99fb7bc
Gitweb:        https://git.kernel.org/tip/ad86fe2134ccdc97a967693d2723a731c99fb7bc
Author:        Ihor Solodrai <[email protected]>
AuthorDate:    Wed, 16 Sep 2026 12:52:01 -07:00
Committer:     Borislav Petkov (AMD) <[email protected]>
CommitterDate: Thu, 17 Sep 2026 02:00:25 +02:00

x86/cpu: Inline generic_identify() into identify_cpu()

generic_identify() has exactly one call site: at the top of identify_cpu(). Fold it into identify_cpu() so that a single function does the job for both the boot CPU and the secondary CPUs.

While at it, fix up both copies of the Cyrix comment.

No functional changes.

---
 arch/x86/kernel/cpu/common.c | 32 ++++++++++++++------------------
 1 file changed, 14 insertions(+), 18 deletions(-)
arch/x86/kernel/cpu/common.c +14 -18
index d1a949a..79a1260 100644
@@ -1827,7 +1827,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *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()) {
 		cpuid_scan_cpu(c);
 		cpu_detect(c);
@@ -1991,14 +1991,23 @@ 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)
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+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);
@@ -2026,21 +2035,8 @@ static void generic_identify(struct cpuinfo_x86 *c)
 #ifdef CONFIG_X86_32
 	set_cpu_bug(c, X86_BUG_ESPFIX);
 #endif
-}
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-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)
#9 lore raw

Re: [PATCH v3 3/5] x86/cpu: Inline generic_identify() into identify_cpu()

In reply to Ihor Solodrai
This isn't a bug, but since identify_cpu() already covered both the boot and secondary CPUs before this patch, could the changelog instead say what the fold enables for the following patches (e.g.…
Quoted 7 lines

generic_identify() has exactly one call site: at the top of identify_cpu(). Fold it into identify_cpu() so that a single function does the job for both the boot CPU and the secondary CPUs.

While at it, fix up both copies of the Cyrix comment.

No functional changes.

This isn't a bug, but since identify_cpu() already covered both the boot and secondary CPUs before this patch, could the changelog instead say what the fold enables for the following patches (e.g. making the init_cpu_info() placement explicit)?

---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35285131592

author reviewer
#10 lore raw

PATCH v3 4/5 x86/cpu: Move 32-bit SEP setup into identify_cpu()

In reply to Ihor Solodrai

identify_boot_cpu() and identify_secondary_cpu() both call enable_sep_cpu() under CONFIG_X86_32 immediately after identify_cpu().

Do it once and drop the ifdefs while at it.

No functional changes.

---
 arch/x86/kernel/cpu/common.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/common.c +3 -6
index 2b2a4c40ef76..83d613d07997 100644
@@ -2126,6 +2126,9 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 	mcheck_cpu_init(c);
 
 	numa_add_cpu(smp_processor_id());
+
+	if (IS_ENABLED(CONFIG_X86_32))
+		enable_sep_cpu();
 }
 
 /*
@@ -2163,9 +2166,6 @@ 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
 	cpu_detect_tlb(&boot_cpu_data);
 	setup_cr_pinning();
 
@@ -2185,9 +2185,6 @@ void identify_secondary_cpu(unsigned int cpu)
 	c->cpu_index = cpu;
 
 	identify_cpu(c);
-#ifdef CONFIG_X86_32
-	enable_sep_cpu();
-#endif
 	x86_spec_ctrl_setup_ap();
 	update_srbds_msr();
 	if (boot_cpu_has_bug(X86_BUG_GDS))
Signature · 1 line
2.55.0
merge bot Applied
#11 lore raw

[tip: x86/cpu] x86/cpu: Move 32-bit SEP setup into identify_cpu()

The following commit has been merged into the x86/cpu branch of tip:

The following commit has been merged into the x86/cpu branch of tip:

Commit-ID:     db349783ca7aa99345f3809523bff2db8f8714de
Gitweb:        https://git.kernel.org/tip/db349783ca7aa99345f3809523bff2db8f8714de
Author:        Ihor Solodrai <[email protected]>
AuthorDate:    Wed, 16 Sep 2026 12:52:02 -07:00
Committer:     Borislav Petkov (AMD) <[email protected]>
CommitterDate: Thu, 17 Sep 2026 02:02:18 +02:00

x86/cpu: Move 32-bit SEP setup into identify_cpu()

identify_boot_cpu() and identify_secondary_cpu() both call enable_sep_cpu() under CONFIG_X86_32 immediately after identify_cpu().

Do it once and drop the ifdefs while at it.

No functional changes.

---
 arch/x86/kernel/cpu/common.c |  9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
arch/x86/kernel/cpu/common.c +3 -6
index 79a1260..156a7b8 100644
@@ -2128,6 +2128,9 @@ no_cpuid:
 	mcheck_cpu_init(c);
 
 	numa_add_cpu(smp_processor_id());
+
+	if (IS_ENABLED(CONFIG_X86_32))
+		enable_sep_cpu();
 }
 
 /*
@@ -2165,9 +2168,6 @@ 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
 	cpu_detect_tlb(&boot_cpu_data);
 	setup_cr_pinning();
 
@@ -2187,9 +2187,6 @@ void identify_secondary_cpu(unsigned int cpu)
 	c->cpu_index = cpu;
 
 	identify_cpu(c);
-#ifdef CONFIG_X86_32
-	enable_sep_cpu();
-#endif
 	x86_spec_ctrl_setup_ap();
 	update_srbds_msr();
 	if (boot_cpu_has_bug(X86_BUG_GDS))
#12 lore raw

Re: [PATCH v3 4/5] x86/cpu: Move 32-bit SEP setup into identify_cpu()

In reply to Ihor Solodrai
Does using IS_ENABLED() here comply with the kernel coding style?

arch/x86/kernel/cpu/common.c static void identify_cpu(struct cpuinfo_x86 *c) · line 2132

Quoted 12 lines
arch/x86/kernel/cpu/common.c +3 -0
index 2b2a4c40ef76c..83d613d07997e 100644
@@ -2126,6 +2126,9 @@ static void identify_cpu(struct cpuinfo_x86 *c)
 	mcheck_cpu_init(c);
 
 	numa_add_cpu(smp_processor_id());
+
+	if (IS_ENABLED(CONFIG_X86_32))
+		enable_sep_cpu();
 }

Does using IS_ENABLED() here comply with the kernel coding style?

Looking at enable_sep_cpu(), it's declared in arch/x86/include/asm/processor.h as extern void enable_sep_cpu(void); but the definition only exists inside #ifdef CONFIG_X86_32 in this file (arch/x86/kernel/cpu/common.c:2138-2160), with no #else stub for 64-bit builds.

Documentation/process/coding-style.rst explains when IS_ENABLED() can and cannot be used:

The compiler will constant-fold the conditional away ... However, this approach still allows the C compiler to see the code inside the block, and check it for correctness (syntax, types, symbol references, etc). Thus, you still have to use an #ifdef if the code inside the block references symbols that will not exist if the condition is not met.

The symbol enable_sep_cpu() won't exist in 64-bit builds, so this seems to be exactly the case the documentation warns against.

In practice this links correctly because the kernel is always built at -O2 or -Os, and both GCC and Clang will drop the untaken arm of a constant if. But it depends on the optimizer eliminating the dead code before the linker sees it.

A survey of other if (IS_ENABLED(CONFIG_X86_32)) sites in arch/x86 shows that they all reference symbols that exist in both builds, making this the first site to rely on dead-code elimination for link correctness.

Would it be more correct to either keep the #ifdef CONFIG_X86_32 around this call, or add a static inline stub for the 64-bit case in processor.h?

---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35285131592

author reviewer
#13 lore raw

PATCH v3 5/5 x86/cpu: Don't transiently clear the boot CPU's capabilities

In reply to Ihor Solodrai

On the boot CPU identify_cpu() runs from arch_cpu_finalize_init(), with interrupts enabled and before alternatives are patched. So cpu_feature_enabled() still evaluates against boot_cpu_data.

identify_cpu() rebuilds c->x86_capability from scratch: the reset zeroes the array and the CPUID rescan fills it in again. An interrupt delivered in that window finds X86_FEATURE_LA57 clear in boot_cpu_data, so pgtable_l5_enabled() is false and KASAN checks a 5-level address against the 4-level addressability limit. The result is a bogus "wild-memory-access" report, and under kasan_multi_shot a report storm that wedges the boot.

The boot CPU has already been scanned by early_identify_cpu(), with interrupts disabled, and its capabilities cannot have changed since. Reset only the CPUs which have not been scanned yet.

The window is as old as identify_cpu() rebuilding the capabilities. Commit 39b9552281ab ("x86/mm: Optimize boot-time paging mode switching cost") merely let KASAN notice it by making pgtable_l5_enabled() read the feature bit. So no Fixes: tag.

---
 arch/x86/kernel/cpu/common.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
arch/x86/kernel/cpu/common.c +1 -2
index 83d613d07997..496ffe429496 100644
@@ -1998,8 +1998,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);
 
@@ -2184,6 +2182,7 @@ void identify_secondary_cpu(unsigned int cpu)
 		*c = boot_cpu_data;
 	c->cpu_index = cpu;
 
+	init_cpu_info(c);
 	identify_cpu(c);
 	x86_spec_ctrl_setup_ap();
 	update_srbds_msr();
Signature · 1 line
2.55.0
merge bot Applied
#14 lore raw

[tip: x86/cpu] x86/cpu: Don't transiently clear the boot CPU's capabilities

The following commit has been merged into the x86/cpu branch of tip:

The following commit has been merged into the x86/cpu branch of tip:

Commit-ID:     2711d67bc3a776abcfc651ad87be5d29ada19166
Gitweb:        https://git.kernel.org/tip/2711d67bc3a776abcfc651ad87be5d29ada19166
Author:        Ihor Solodrai <[email protected]>
AuthorDate:    Wed, 16 Sep 2026 12:52:03 -07:00
Committer:     Borislav Petkov (AMD) <[email protected]>
CommitterDate: Thu, 17 Sep 2026 02:05:39 +02:00

x86/cpu: Don't transiently clear the boot CPU's capabilities

On the boot CPU, identify_cpu() runs from arch_cpu_finalize_init(), with interrupts enabled and before alternatives are patched. So cpu_feature_enabled() still evaluates against boot_cpu_data.

identify_cpu() rebuilds c->x86_capability from scratch: the reset zeroes the array and the CPUID rescan fills it in again. An interrupt delivered in that window finds X86_FEATURE_LA57 clear in boot_cpu_data, so pgtable_l5_enabled() is false and KASAN checks a 5-level address against the 4-level addressability limit. The result is a bogus "wild-memory-access" report, and under kasan_multi_shot a report storm that wedges the boot.

The boot CPU has already been scanned by early_identify_cpu(), with interrupts disabled, and its capabilities cannot have changed since. Reset only the CPUs which have not been scanned yet.

The window is as old as identify_cpu() rebuilding the capabilities. Commit

39b9552281ab ("x86/mm: Optimize boot-time paging mode switching cost")

merely let KASAN notice it by making pgtable_l5_enabled() read the feature bit. So no Fixes: tag.

---
 arch/x86/kernel/cpu/common.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
arch/x86/kernel/cpu/common.c +1 -2
index 156a7b8..7d4ff29 100644
@@ -2000,8 +2000,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);
 
@@ -2186,6 +2184,7 @@ void identify_secondary_cpu(unsigned int cpu)
 		*c = boot_cpu_data;
 	c->cpu_index = cpu;
 
+	init_cpu_info(c);
 	identify_cpu(c);
 	x86_spec_ctrl_setup_ap();
 	update_srbds_msr();