* [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