[PATCH 1/8] x86/microcode/intel: Reject problematic loading on GNR systems
From: Chang S. Bae
Date: Tue Sep 01 2026 - 19:44:23 EST
Revision 0x1000405 contains internal microcode changes that are required
by subsequent revisions to avoid #MC during loading. This dependency
logically fits the minimum revision requirement.
The minimum revision check, however, currently applies only to the late
loading path, since the dependency was primarily intended for OS-visible
changes. The early loading path is therefore still vulnerable to this
issue.
Furthermore, one of the subsequent revisions does not correctly specify
the minimum revision, so unfortunately the late loading cannot rely on
that check either in this case.
Prevent loading 0x1000405 or later when the system has not yet been
updated to 0x1000405 or later. Apply this blocking to both early- and
late-loading paths.
Rename is_blacklisted() to is_late_loading_denied() so the new function
that covers both loading paths is not confused with the late-load only
one.
Signed-off-by: Chang S. Bae <chang.seok.bae@xxxxxxxxx>
Cc: <stable@xxxxxxxxxxxxxxx>
---
The GNR errata page:
https://edc.intel.com/content/www/jp/ja/design/products-and-solutions/processors-and-chipsets/birch-stream/xeon-6900-6700-6500-series-processors-with-p-cores-specification-update/016US/errata-summary-table/
Thanks to Sohil, I noticed the naming guideline in
Documentation/process/coding-style.rst:
For symbol names and documentation, avoid introducing new usage of
'master / slave' (or 'slave' independent of 'master') and 'blacklist /
whitelist'.
---
arch/x86/kernel/cpu/microcode/intel.c | 42 +++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 1142183c950c..c502138fd8e9 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -309,6 +309,38 @@ static void save_microcode_patch(struct microcode_intel *patch)
pr_err("Unable to allocate microcode memory size: %u\n", size);
}
+static bool is_loading_denied(struct cpu_signature *sig, u32 rev)
+{
+ u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig));
+
+ /*
+ * Revision 0x1000405 contains prerequisite changes for subsequent
+ * microcode updates on Granite Rapids systems. Updates directly from
+ * an older revision to this or a newer one can result in #MC (GNR98).
+ *
+ * This dependency can be indicated from the minimum revision field.
+ * However, revision 0x1000423 has an incorrect minimum revision in its
+ * header (GNR101).
+ *
+ * Prevent loading 0x1000405 or later unless the CPU has already been
+ * updated to 0x1000405 or later.
+ */
+ if (vfm == INTEL_GRANITERAPIDS_X &&
+ x86_stepping(sig->sig) == 1 &&
+ sig->pf & 0x95 &&
+ sig->rev < 0x1000405 &&
+ rev >= 0x1000405) {
+ if (rev == 0x1000405)
+ pr_err_once("Erratum GNR98: 0x1000405 is not loadable.\n");
+ else
+ pr_err_once("Erratum GNR98: 0x1000405 is required before 0x%x.\n", rev);
+ pr_err_once("Please update the system BIOS or firmware.\n");
+ return true;
+ }
+
+ return false;
+}
+
/* 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,
@@ -330,6 +362,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
if (!intel_find_matching_signature(data, &uci->cpu_sig))
continue;
+ if (is_loading_denied(&uci->cpu_sig, mc_header->rev))
+ continue;
+
/*
* For saving the early microcode, find the matching revision which
* was loaded on the BSP.
@@ -878,6 +913,9 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
if (!intel_find_matching_signature(mc, &uci->cpu_sig))
continue;
+ if (is_loading_denied(&uci->cpu_sig, mc_header.rev))
+ continue;
+
is_safe = ucode_validate_minrev(&mc_header);
if (force_minrev && !is_safe)
continue;
@@ -905,7 +943,7 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter)
return UCODE_ERROR;
}
-static bool is_blacklisted(unsigned int cpu)
+static bool is_late_loading_denied(unsigned int cpu)
{
struct cpuinfo_x86 *c = &cpu_data(cpu);
@@ -936,7 +974,7 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device)
struct kvec kvec;
char name[30];
- if (is_blacklisted(cpu))
+ if (is_late_loading_denied(cpu))
return UCODE_NFOUND;
sprintf(name, "intel-ucode/%02x-%02x-%02x",
--
2.53.0