From: "Chang S. Bae" <chang.seok.bae@intel.com>
To: linux-kernel@vger.kernel.org
Cc: x86@kernel.org, tglx@kernel.org, mingo@redhat.com, bp@alien8.de,
dave.hansen@linux.intel.com, hpa@zytor.com,
andrew.cooper3@citrix.com, arjan.van.de.ven@intel.com,
chang.seok.bae@intel.com
Subject: [PATCH RFC 5/8] x86/microcode: Decouple minimum revision check from late loading
Date: Tue, 1 Sep 2026 23:16:30 +0000 [thread overview]
Message-ID: <20260901231634.714144-6-chang.seok.bae@intel.com> (raw)
In-Reply-To: <20260901231634.714144-1-chang.seok.bae@intel.com>
The microcode minimum revision check was originally introduced to express
dependencies involving OS-visible changes, thus it has been limited to
the late-load path.
In fact this can serve as a general guard against unsafe microcode
loading. Make the check independent of the loading path in preparation
for applying it to the early path as well.
For now, reject early loading if enforced. Taint the kernel on early
loading because the early path does not perform the check yet.
Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
---
Note for the review:
The AMD loader does not have the minrev checker anywhere (yet). So,
force_minrev is effectively dis_ucode_ldr which may appear excessive.
Without enforcement though, it is going to taint the kernel on every
early loading then. This side-effect should be reviewed.
---
.../admin-guide/kernel-parameters.txt | 4 ++--
arch/x86/Kconfig | 19 +++++++++----------
arch/x86/kernel/cpu/microcode/amd.c | 8 +++++++-
arch/x86/kernel/cpu/microcode/core.c | 13 ++++++++++---
arch/x86/kernel/cpu/microcode/intel.c | 17 ++++++++++++-----
arch/x86/kernel/cpu/microcode/internal.h | 1 +
6 files changed, 41 insertions(+), 21 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index cde092017cd8..b5f7a8142f58 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4073,8 +4073,8 @@ Kernel parameters
force_minrev[=<bool>]:
Enable or disable microcode minimal revision enforcement
- for the runtime microcode loader according to <bool>. If
- <bool> is not given, enable the enforcement.
+ for the microcode loader according to <bool>. If <bool>
+ is not given, enable the enforcement.
mini2440= [ARM,HW,KNL]
Format:[0..2][b][c][t]
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 15fd9ec5ecac..6c503004775e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1338,18 +1338,17 @@ config MICROCODE_LATE_LOADING
minimal revision check. This minimal revision check can be enforced on
the kernel command line with "microcode=force_minrev".
-config MICROCODE_LATE_FORCE_MINREV
- bool "Enforce late microcode loading minimal revision check"
+config MICROCODE_FORCE_MINREV
+ bool "Enforce microcode loading minimal revision check"
default n
- depends on MICROCODE_LATE_LOADING
+ depends on MICROCODE
help
- To prevent that users load microcode late which modifies already
- in use features, newer microcode patches have a minimum revision field
- in the microcode header, which tells the kernel which minimum
- revision must be active in the CPU to safely load that new microcode
- late into the running system. If disabled the check will not
- be enforced but the kernel will be tainted when the minimal
- revision check fails.
+ To prevent that users load microcode which modifies already in use
+ features, newer microcode patches have a minimum revision field in the
+ microcode header, which tells the kernel which minimum revision must
+ be active in the CPU to safely load that new microcode into the system.
+ If disabled the check will not be enforced but the kernel will be
+ tainted when the minimal revision check fails.
This minimal revision check can also be controlled via the
"microcode=force_minrev" parameter on the kernel command line.
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index 6cdc410e7547..0625d5e8eb7e 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -800,6 +800,11 @@ void __init load_ucode_amd_bsp(struct early_load_data *ed, unsigned int cpuid_1_
/* Needed in load_microcode_amd() */
ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax;
+ if (force_minrev) {
+ pr_warn_once("No early load: minimum revision check is not implemented.\n");
+ return;
+ }
+
if (!find_blobs_in_containers(&cp))
return;
@@ -1202,7 +1207,8 @@ static int __init save_microcode_in_initrd(void)
enum ucode_state ret;
struct cpio_data cp;
- if (microcode_loader_disabled() || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10)
+ if (microcode_loader_disabled() || c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10 ||
+ force_minrev)
return 0;
cpuid_1_eax = native_cpuid_eax(1);
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index ed1eb6b753d6..7d6caf191795 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -46,7 +46,7 @@
static struct microcode_ops *microcode_ops;
static bool dis_ucode_ldr;
-bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV);
+bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_FORCE_MINREV);
/*
* Those below should be behind CONFIG_MICROCODE_DBG ifdeffery but in
@@ -603,7 +603,7 @@ static int load_late_stop_cpus(bool is_safe)
if (!is_safe) {
pr_err("Late microcode loading without minimal revision check.\n");
- pr_err("You should switch to early loading, if possible.\n");
+ pr_err("You should update microcode incrementally.\n");
}
/*
@@ -912,9 +912,16 @@ static int __init microcode_init(void)
pr_info_once("Current revision: 0x%08x\n", (early_data.new_rev ?: early_data.old_rev));
- if (early_data.new_rev)
+ if (early_data.new_rev) {
pr_info_once("Updated early from: 0x%08x\n", early_data.old_rev);
+ if (!early_data.is_safe) {
+ pr_err("Early microcode loading without minimal revision check.\n");
+ pr_err("You should update microcode incrementally.\n");
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+ }
+ }
+
microcode_fdev = faux_device_create("microcode", NULL, NULL);
if (!microcode_fdev)
return -ENODEV;
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index c502138fd8e9..3247c619eaa1 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -786,7 +786,15 @@ void __init load_ucode_intel_bsp(struct early_load_data *ed)
uci.mc = get_microcode_blob(&uci, false);
ed->old_rev = uci.cpu_sig.rev;
- if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) {
+ if (!uci.mc)
+ return;
+
+ if (force_minrev) {
+ pr_warn_once("No early load: minimum revision check is not implemented.\n");
+ return;
+ }
+
+ if (apply_microcode_early(&uci) == UCODE_UPDATED) {
ucode_patch_va = UCODE_BSP_LOADED;
ed->new_rev = uci.cpu_sig.rev;
}
@@ -842,9 +850,8 @@ static bool ucode_validate_minrev(struct microcode_header_intel *mc_header)
int cur_rev = boot_cpu_data.microcode;
/*
- * When late-loading, ensure the header declares a minimum revision
- * required to perform a late-load. The previously reserved field
- * is 0 in older microcode blobs.
+ * Ensure the header declares a minimum revision required to perform a
+ * load. The previously reserved field is 0 in older microcode blobs.
*/
if (!mc_header->min_req_ver) {
pr_info("Unsafe microcode update: Microcode header does not specify a required min version\n");
@@ -857,7 +864,7 @@ static bool ucode_validate_minrev(struct microcode_header_intel *mc_header)
*/
if (cur_rev < mc_header->min_req_ver) {
pr_info("Unsafe microcode update: Current revision 0x%x too old\n", cur_rev);
- pr_info("Current should be at 0x%x or higher. Use early loading instead\n", mc_header->min_req_ver);
+ pr_info("Current should be at 0x%x or higher. Update incrementally.\n", mc_header->min_req_ver);
return false;
}
return true;
diff --git a/arch/x86/kernel/cpu/microcode/internal.h b/arch/x86/kernel/cpu/microcode/internal.h
index a10b547eda1e..1b35f9099580 100644
--- a/arch/x86/kernel/cpu/microcode/internal.h
+++ b/arch/x86/kernel/cpu/microcode/internal.h
@@ -42,6 +42,7 @@ struct microcode_ops {
struct early_load_data {
u32 old_rev;
u32 new_rev;
+ bool is_safe;
};
extern struct early_load_data early_data;
--
2.53.0
next prev parent reply other threads:[~2026-09-01 23:43 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 23:16 [PATCH 0/8] x86/microcode: Address GNR errata and follow-up Chang S. Bae
2026-09-01 23:16 ` [PATCH 1/8] x86/microcode/intel: Reject problematic loading on GNR systems Chang S. Bae
2026-09-02 13:11 ` Sohil Mehta
2026-09-02 13:21 ` Van De Ven, Arjan
2026-09-02 14:23 ` Dave Hansen
2026-09-03 1:51 ` Borislav Petkov
2026-09-03 21:04 ` Chang S. Bae
2026-09-01 23:16 ` [PATCH 2/8] x86/microcode: Solidify base_rev= option parsing Chang S. Bae
2026-09-01 23:16 ` [PATCH 3/8] x86/microcode: Accept a boolean for force_minrev parameter Chang S. Bae
2026-09-01 23:16 ` [PATCH 4/8] x86/microcode: Mark early_data __initdata Chang S. Bae
2026-09-01 23:16 ` Chang S. Bae [this message]
2026-09-01 23:16 ` [PATCH RFC 6/8] x86/microcode/intel: Apply minimum revision check to early loading Chang S. Bae
2026-09-01 23:16 ` [PATCH RFC 7/8] x86/microcode: Introduce iterative late loading Chang S. Bae
2026-09-01 23:16 ` [PATCH RFC 8/8] x86/microcode/intel: Select the lowest loadable revision for iterative loading Chang S. Bae
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260901231634.714144-6-chang.seok.bae@intel.com \
--to=chang.seok.bae@intel.com \
--cc=andrew.cooper3@citrix.com \
--cc=arjan.van.de.ven@intel.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®