[PATCH RFC 6/8] x86/microcode/intel: Apply minimum revision check to early loading

From: Chang S. Bae

Date: Tue Sep 01 2026 - 19:47:06 EST


The minimum revision check is now generally applicable. Establish the
minimum revision check on early loading. Follow the late loading behavior
when the check fails:

* Load but taint the kernel if not enforced, or
* Reject the loading if enforced.

Adjust the check function so that the early path can pass the current
revision.

With this establishment, do not reject early loading anymore when
enforced.

Suggested-by: Arjan van de Ven <arjan.van.de.ven@xxxxxxxxx>
Signed-off-by: Chang S. Bae <chang.seok.bae@xxxxxxxxx>
---
arch/x86/kernel/cpu/microcode/intel.c | 64 ++++++++++++---------------
1 file changed, 29 insertions(+), 35 deletions(-)

diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 3247c619eaa1..ddd5b72b27a1 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -341,6 +341,29 @@ static bool is_loading_denied(struct cpu_signature *sig, u32 rev)
return false;
}

+static bool ucode_validate_minrev(u32 cur_rev, struct microcode_header_intel *mc_header)
+{
+ /*
+ * 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");
+ return false;
+ }
+
+ /*
+ * Check whether the current revision is either greater or equal to
+ * the minimum revision specified in the 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. Update incrementally.\n", mc_header->min_req_ver);
+ return false;
+ }
+ return true;
+}
+
/* Scan blob for microcode matching the boot CPUs family, model, stepping */
static __init struct microcode_intel *scan_microcode(void *data, size_t size,
struct ucode_cpu_info *uci,
@@ -365,6 +388,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
if (is_loading_denied(&uci->cpu_sig, mc_header->rev))
continue;

+ if (force_minrev && !ucode_validate_minrev(uci->cpu_sig.rev, mc_header))
+ continue;
+
/*
* For saving the early microcode, find the matching revision which
* was loaded on the BSP.
@@ -786,17 +812,10 @@ 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)
- 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) {
+ if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) {
ucode_patch_va = UCODE_BSP_LOADED;
ed->new_rev = uci.cpu_sig.rev;
+ ed->is_safe = ucode_validate_minrev(ed->old_rev, uci.mc);
}
}

@@ -845,31 +864,6 @@ static enum ucode_state apply_microcode_late(int cpu)
return ret;
}

-static bool ucode_validate_minrev(struct microcode_header_intel *mc_header)
-{
- int cur_rev = boot_cpu_data.microcode;
-
- /*
- * 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");
- return false;
- }
-
- /*
- * Check whether the current revision is either greater or equal to
- * to the minimum revision specified in the 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. Update incrementally.\n", mc_header->min_req_ver);
- return false;
- }
- return true;
-}
-
static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -923,7 +917,7 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
if (is_loading_denied(&uci->cpu_sig, mc_header.rev))
continue;

- is_safe = ucode_validate_minrev(&mc_header);
+ is_safe = ucode_validate_minrev(uci->cpu_sig.rev, &mc_header);
if (force_minrev && !is_safe)
continue;

--
2.53.0