[PATCH v2] x86/microcode/intel: Reject problematic loading on Granite Rapids systems

Chang S. Bae posted 1 patch 2 weeks, 2 days ago
There is a newer version of this series
arch/x86/kernel/cpu/microcode/intel.c | 32 +++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
[PATCH v2] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Chang S. Bae 2 weeks, 2 days ago
Microcode updates can usually jump revisions. However, there is an
erratum on Granite Rapids systems. If they "jump over" to revision
0x1000405 or later, they result in #MC.

Prevent loading 0x1000405 or later unless the running revision is already
at least 0x1000405. Apply this blocking to both early- and late-loading
paths.

Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
Cc: <stable@vger.kernel.org>
---
V1 -> V2:
* Cut the code comments and print messages (Boris)
* Rename the new function and keep the old function as it-is (Boris)
* Rewrote the changelog (Dave)
* Add `revision` in the error messages (Sohil)
---
 arch/x86/kernel/cpu/microcode/intel.c | 32 +++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 1142183c950c..61ad280497e9 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -309,6 +309,32 @@ static void save_microcode_patch(struct microcode_intel *patch)
 		pr_err("Unable to allocate microcode memory size: %u\n", size);
 }
 
+static bool revision_banned(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. This is
+	 * documented item GNR98, #835486 (Intel Xeon 6900/6700/6500-Series
+	 * Processors with P-Cores).
+	 */
+	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: revision 0x1000405 is not loadable.\n");
+		else
+			pr_err_once("Erratum GNR98: revision 0x1000405 is required before 0x%x.\n", rev);
+		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 +356,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
 		if (!intel_find_matching_signature(data, &uci->cpu_sig))
 			continue;
 
+		if (revision_banned(&uci->cpu_sig, mc_header->rev))
+			continue;
+
 		/*
 		 * For saving the early microcode, find the matching revision which
 		 * was loaded on the BSP.
@@ -878,6 +907,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 (revision_banned(&uci->cpu_sig, mc_header.rev))
+			continue;
+
 		is_safe = ucode_validate_minrev(&mc_header);
 		if (force_minrev && !is_safe)
 			continue;
-- 
2.53.0
Re: [PATCH v2] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Dave Hansen 2 weeks, 2 days ago
On 9/8/26 15:32, Chang S. Bae wrote:
> Microcode updates can usually jump revisions. However, there is an
> erratum on Granite Rapids systems. If they "jump over" to revision
> 0x1000405 or later, they result in #MC.
> 
> Prevent loading 0x1000405 or later unless the running revision is already
> at least 0x1000405. Apply this blocking to both early- and late-loading
> paths.

This is a kinda wonky-looking patch but I don't know a nicer way to do
it, so:

Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>

> +static bool revision_banned(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. This is
> +	 * documented item GNR98, #835486 (Intel Xeon 6900/6700/6500-Series
> +	 * Processors with P-Cores).
> +	 */

I honestly still prefer that this comment be more short and sweet. Does
this miss anything?

	/*
	 * Erratum GNR98 can cause #MC's if "jumping over"
	 * revision 0x1000405. Avoid the jumps.
	 */

Also, we don't need to put whole document titles or numbers in here.
They're fine, but if you can Google "erratum GNR98" and get the doc for
the first hit, what does it matter?

Leave the precision and long chit chat for the changelog, I say.

But we can edit this in place when it gets applied.

> +	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: revision 0x1000405 is not loadable.\n");
> +		else
> +			pr_err_once("Erratum GNR98: revision 0x1000405 is required before 0x%x.\n", rev);
> +		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 +356,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
>  		if (!intel_find_matching_signature(data, &uci->cpu_sig))
>  			continue;
>  
> +		if (revision_banned(&uci->cpu_sig, mc_header->rev))
> +			continue;
> +
>  		/*
>  		 * For saving the early microcode, find the matching revision which
>  		 * was loaded on the BSP.
> @@ -878,6 +907,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 (revision_banned(&uci->cpu_sig, mc_header.rev))
> +			continue;
> +
>  		is_safe = ucode_validate_minrev(&mc_header);
>  		if (force_minrev && !is_safe)
>  			continue;
Re: [PATCH v2] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Borislav Petkov 2 weeks, 2 days ago
On Tue, Sep 08, 2026 at 10:32:09PM +0000, Chang S. Bae wrote:
> Microcode updates can usually jump revisions. However, there is an
> erratum on Granite Rapids systems. If they "jump over" to revision
> 0x1000405 or later, they result in #MC.
>
> Prevent loading 0x1000405 or later unless the running revision is already
> at least 0x1000405. Apply this blocking to both early- and late-loading
> paths.

People have got to stop explaining the patch in the commit message. That
should be obvious from the diff. If you have to explain it then there is
something very non-obvious here which I don't see it...

> Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
> Cc: <stable@vger.kernel.org>
> ---
> V1 -> V2:
> * Cut the code comments and print messages (Boris)
> * Rename the new function and keep the old function as it-is (Boris)
> * Rewrote the changelog (Dave)
> * Add `revision` in the error messages (Sohil)
> ---
>  arch/x86/kernel/cpu/microcode/intel.c | 32 +++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
> 
> diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
> index 1142183c950c..61ad280497e9 100644
> --- a/arch/x86/kernel/cpu/microcode/intel.c
> +++ b/arch/x86/kernel/cpu/microcode/intel.c
> @@ -309,6 +309,32 @@ static void save_microcode_patch(struct microcode_intel *patch)
>  		pr_err("Unable to allocate microcode memory size: %u\n", size);
>  }
>  
> +static bool revision_banned(struct cpu_signature *sig, u32 rev)

I like Andy's naming:

https://lore.kernel.org/xen-devel/20260908171525.3196765-1-andrew.cooper3@citrix.com/T/#u

...is_safe is much better than banned.

> +{
> +	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. This is
> +	 * documented item GNR98, #835486 (Intel Xeon 6900/6700/6500-Series
> +	 * Processors with P-Cores).
> +	 */

What dhansen said - keep this short'n'sweet.

> +	if (vfm == INTEL_GRANITERAPIDS_X &&
> +	    x86_stepping(sig->sig) == 1 &&
> +	    sig->pf & 0x95 &&
> +	    sig->rev < 0x1000405 &&
> +	    rev >= 0x1000405) {
> +		if (rev == 0x1000405)

I also like Andy's testing of the patch revs:

+         ((cpu_sig->rev < 0x01000380 && mc->rev >= 0x01000405) ||
+          (cpu_sig->rev < 0x01000405 && mc->rev >  0x01000405)) )

> +			pr_err_once("Erratum GNR98: revision 0x1000405 is not loadable.\n");
> +		else
> +			pr_err_once("Erratum GNR98: revision 0x1000405 is required before 0x%x.\n", rev);

And you don't need those semi-identical strings here.

> +		return true;
> +	}
> +
> +	return false;
> +}

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v2] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Chang S. Bae 2 weeks, 2 days ago
On 9/8/2026 5:13 PM, Borislav Petkov wrote:
> On Tue, Sep 08, 2026 at 10:32:09PM +0000, Chang S. Bae wrote:
>> Microcode updates can usually jump revisions. However, there is an
>> erratum on Granite Rapids systems. If they "jump over" to revision
>> 0x1000405 or later, they result in #MC.
>>
>> Prevent loading 0x1000405 or later unless the running revision is already
>> at least 0x1000405. Apply this blocking to both early- and late-loading
>> paths.
> 
> People have got to stop explaining the patch in the commit message. That
> should be obvious from the diff. If you have to explain it then there is
> something very non-obvious here which I don't see it...

... If they "jump over" to revision 0x1000405 or later, they result in 
#MC. Avoid it.

>>   
>> +static bool revision_banned(struct cpu_signature *sig, u32 rev)
> 
> I like Andy's naming:
> 
> https://lore.kernel.org/xen-devel/20260908171525.3196765-1-andrew.cooper3@citrix.com/T/#u
> 
> ...is_safe is much better than banned.

s/revision_banned/revision_is_safe/ in V3.

> 
>> +{
>> +	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. This is
>> +	 * documented item GNR98, #835486 (Intel Xeon 6900/6700/6500-Series
>> +	 * Processors with P-Cores).
>> +	 */
> 
> What dhansen said - keep this short'n'sweet.

Will replace the above with Dave's.

> 
>> +	if (vfm == INTEL_GRANITERAPIDS_X &&
>> +	    x86_stepping(sig->sig) == 1 &&
>> +	    sig->pf & 0x95 &&
>> +	    sig->rev < 0x1000405 &&
>> +	    rev >= 0x1000405) {
>> +		if (rev == 0x1000405)
> 
> I also like Andy's testing of the patch revs:
> 
> +         ((cpu_sig->rev < 0x01000380 && mc->rev >= 0x01000405) ||
> +          (cpu_sig->rev < 0x01000405 && mc->rev >  0x01000405)) )

Let me double-check this with ucode folks, first. Then will take.

> 
>> +			pr_err_once("Erratum GNR98: revision 0x1000405 is not loadable.\n");
>> +		else
>> +			pr_err_once("Erratum GNR98: revision 0x1000405 is required before 0x%x.\n", rev);
 > > And you don't need those semi-identical strings here.

pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev);

Yeah, overall I can hear "keep it simple & short" messages.

Thanks,
Chang
Re: [PATCH v2] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Andrew Cooper 2 weeks, 2 days ago
On 08/09/2026 11:32 pm, Chang S. Bae wrote:
> diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
> index 1142183c950c..61ad280497e9 100644
> --- a/arch/x86/kernel/cpu/microcode/intel.c
> +++ b/arch/x86/kernel/cpu/microcode/intel.c
> @@ -309,6 +309,32 @@ static void save_microcode_patch(struct microcode_intel *patch)
>  		pr_err("Unable to allocate microcode memory size: %u\n", size);
>  }
>  
> +static bool revision_banned(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. This is
> +	 * documented item GNR98, #835486 (Intel Xeon 6900/6700/6500-Series
> +	 * Processors with P-Cores).
> +	 */
> +	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: revision 0x1000405 is not loadable.\n");
> +		else
> +			pr_err_once("Erratum GNR98: revision 0x1000405 is required before 0x%x.\n", rev);
> +		return true;
> +	}

This logic is going to need editing when the muti-blob finally appears.

This is what I'm doing for Xen:
https://lore.kernel.org/xen-devel/20260908171525.3196765-1-andrew.cooper3@citrix.com/T/#u

Notably, 0x1000405 is safe to load if 0x1000380 is in FIT, and this is a
necessary hoop to jump through in due course.

~Andrew
[PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Chang S. Bae 1 week, 1 day ago
Microcode updates can usually jump revisions. However, there is an
erratum on Granite Rapids systems. If they "jump over" revision
0x1000405, they result in #MC. Avoid it.

Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: <stable@vger.kernel.org>
---
V2 -> V3:
* Shorten the changelog and rename the function (Boris)
* Reduce the code comment (Dave)
* Allow 0x1000405 loading. Thanks to Andrew, this fix got attention.
* Collect Dave review tag. Thanks, Dave!

Note:
* GNR98 currently describes loading 0x1000405 itself is unsafe, but it
  will be updated to say okay with that. I will watch out the GNR98
  changes.
* Jumping from < 0x1000380 to 0x1000405 was identified as an issue, but
  0x1000380 is the first revision as GNR products. So loading 0x1000405
  in production systems should be okay.
---
 arch/x86/kernel/cpu/microcode/intel.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 1142183c950c..30a22388d4b1 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -309,6 +309,26 @@ static void save_microcode_patch(struct microcode_intel *patch)
 		pr_err("Unable to allocate microcode memory size: %u\n", size);
 }
 
+static bool revision_is_safe(struct cpu_signature *sig, u32 rev)
+{
+	u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig));
+
+	/*
+	 * Erratum GNR98 can cause #MC's if "jumping over" revision 0x1000405.
+	 * Avoid the jumps.
+	 */
+	if (vfm == INTEL_GRANITERAPIDS_X &&
+	    x86_stepping(sig->sig) == 1 &&
+	    sig->pf & 0x95 &&
+	    sig->rev < 0x1000405 &&
+	    rev > 0x1000405) {
+		pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev);
+		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,
@@ -330,6 +350,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
 		if (!intel_find_matching_signature(data, &uci->cpu_sig))
 			continue;
 
+		if (!revision_is_safe(&uci->cpu_sig, mc_header->rev))
+			continue;
+
 		/*
 		 * For saving the early microcode, find the matching revision which
 		 * was loaded on the BSP.
@@ -878,6 +901,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 (!revision_is_safe(&uci->cpu_sig, mc_header.rev))
+			continue;
+
 		is_safe = ucode_validate_minrev(&mc_header);
 		if (force_minrev && !is_safe)
 			continue;
-- 
2.53.0
Re: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Ingo Molnar 1 week ago
* Chang S. Bae <chang.seok.bae@intel.com> wrote:

> Microcode updates can usually jump revisions. However, there is an
> erratum on Granite Rapids systems. If they "jump over" revision
> 0x1000405, they result in #MC. Avoid it.
> 
> Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
> Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: <stable@vger.kernel.org>
> ---
> V2 -> V3:
> * Shorten the changelog and rename the function (Boris)
> * Reduce the code comment (Dave)
> * Allow 0x1000405 loading. Thanks to Andrew, this fix got attention.
> * Collect Dave review tag. Thanks, Dave!
> 
> Note:
> * GNR98 currently describes loading 0x1000405 itself is unsafe, but it
>   will be updated to say okay with that. I will watch out the GNR98
>   changes.
> * Jumping from < 0x1000380 to 0x1000405 was identified as an issue, but
>   0x1000380 is the first revision as GNR products. So loading 0x1000405
>   in production systems should be okay.
> ---
>  arch/x86/kernel/cpu/microcode/intel.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
> index 1142183c950c..30a22388d4b1 100644
> --- a/arch/x86/kernel/cpu/microcode/intel.c
> +++ b/arch/x86/kernel/cpu/microcode/intel.c
> @@ -309,6 +309,26 @@ static void save_microcode_patch(struct microcode_intel *patch)
>  		pr_err("Unable to allocate microcode memory size: %u\n", size);
>  }
>  
> +static bool revision_is_safe(struct cpu_signature *sig, u32 rev)
> +{
> +	u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig));
> +
> +	/*
> +	 * Erratum GNR98 can cause #MC's if "jumping over" revision 0x1000405.
> +	 * Avoid the jumps.
> +	 */
> +	if (vfm == INTEL_GRANITERAPIDS_X &&
> +	    x86_stepping(sig->sig) == 1 &&
> +	    sig->pf & 0x95 &&
> +	    sig->rev < 0x1000405 &&
> +	    rev > 0x1000405) {
> +		pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev);

So this was explained in a really confusing way, I had to read the
changelog and comments trice and then the code to figure out what's
going on:

 - There's a microcode bug that makes it unsafe to apply current
   post-0x1000405 revisions on Granite Rapid CPUs if the current
   microcode version is below 0x1000405. The interim 0x1000405
   version *must* be applied first for it to be safe to upgrade
   GNR CPUs. Will this be a problem perpetually? Will it be unsafe
   to have an older GNR CPU and simply apply fresh microcode to it,
   without first loading the interim 0x1000405 version? Will GNR
   microcode upgrades on pre-0x1000405 CPUs will always be a
   two-step process?

 - The new code doesn't declare it, but this patch creates a hidden,
   permanent microcode version upgrade barrier if user-space
   firmware/microcode tools do not provide the 0x1000405
   microcode version reliably and implement the two-step upgrade
   workaround.

 - The message the kernel prints is rather passive-aggressive as well:

		Erratum GNR98: skipping revision 0x%x

   It does not explain *why* the fresh microcode upgrade is skipped,
   and if firmware tooling does not apply 0x1000405 then the kernel
   stays in this state indefinitely.

   It should at minimum say something like:

      Erratum GNR98: new revision %x is unsafe to apply until 0x1000405 is applied first, skipping it. Please upgrade firmware tools.

   Because, presumably, this scenario should not be possible with
   new user-space tooling, right?

   The comment and changelog should be updated accordingly as well.

So this patch is still problematic IMO.

Thanks,

	Ingo
Re: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Borislav Petkov 1 week ago
On Fri, Sep 18, 2026 at 08:54:01AM +0200, Ingo Molnar wrote:
>    It should at minimum say something like:
> 
>       Erratum GNR98: new revision %x is unsafe to apply until 0x1000405 is applied first, skipping it. Please upgrade firmware tools.

Even if you put prose in a warning message, it still doesn't explain the issue
fully. For stuff like that you need some properly written longer explanation
in the documentation.

Which I'm hoping we'll get eventually once the dust has settled down.

That's what the rest of this thread is trying to do but I haven't reviewed
yet.

> So this patch is still problematic IMO.

This patch is a minimal stable fix to stop it from #MCing. The real stuff
comes later. It all has been discussed on this very thread.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Re: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Sohil Mehta 1 week, 1 day ago
>  /* 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 +350,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
>  		if (!intel_find_matching_signature(data, &uci->cpu_sig))
>  			continue;
>  
> +		if (!revision_is_safe(&uci->cpu_sig, mc_header->rev))
> +			continue;
> +
>  		/*
>  		 * For saving the early microcode, find the matching revision which
>  		 * was loaded on the BSP.
> @@ -878,6 +901,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 (!revision_is_safe(&uci->cpu_sig, mc_header.rev))
> +			continue;
> +
>  		is_safe = ucode_validate_minrev(&mc_header);
>  		if (force_minrev && !is_safe)
>  			continue;

TL;dr: Should there be a revision_is_safe() check during
__apply_microcode()?

The patch only adds the revision check during blob selection. Have we
evaluated the corner cases hinted by sashiko when this check might be
bypassed? It talks about suspend/resume and the CPU hotplug cases.

v1:
https://sashiko.dev/#/patchset/20260901231634.714144-1-chang.seok.bae%40intel.com?part=1

v3:
https://sashiko.dev/#/patchset/20260916225939.1144524-1-chang.seok.bae%40intel.com?part=1

The suspend/resume path probably doesn't matter for GNR servers and most
of the CPU hotplug flows also seem to be covered. But, what about ucode
update on cores that are not enabled at boot? If there are brought
online later, would the ucode update skip the above check?

For example, maxcpus=N prevents certain CPUs from showing up in
cpus_booted_once_mask. So the checks in setup_cpus() during late-loading
would not catch them. IIUC, the BIOS version can be < 0x1000405, early
load can bump the booted cpus to 0x1000405, and then late-loading can
load newer versions and only cache the latest ucode revision.

All this while, the non-booted cores would be stuck at a revision less
than 0x1000405. So, when they are brought online later, could they
directly jump to a revision greater than 0x1000405?

Would it be safer to add the revision_is_safe() check in
__apply_microcode() so that all of such cases are covered?

Maybe sashiko just made me paranoid. I only started looking at this
because it complained! :(
Re: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Chang S. Bae 1 week, 1 day ago
On 9/17/2026 10:52 AM, Sohil Mehta wrote:
> 
> TL;dr: Should there be a revision_is_safe() check during
> __apply_microcode()?
> 
> The patch only adds the revision check during blob selection. Have we
> evaluated the corner cases hinted by sashiko when this check might be
> bypassed? It talks about suspend/resume and the CPU hotplug cases.
> 
> v1:
> https://sashiko.dev/#/patchset/20260901231634.714144-1-chang.seok.bae%40intel.com?part=1
> 
> v3:
> https://sashiko.dev/#/patchset/20260916225939.1144524-1-chang.seok.bae%40intel.com?part=1
> 
> The suspend/resume path probably doesn't matter for GNR servers and most
> of the CPU hotplug flows also seem to be covered. But, what about ucode
> update on cores that are not enabled at boot? If there are brought
> online later, would the ucode update skip the above check?
> 
> For example, maxcpus=N prevents certain CPUs from showing up in
> cpus_booted_once_mask. So the checks in setup_cpus() during late-loading
> would not catch them. IIUC, the BIOS version can be < 0x1000405, early
> load can bump the booted cpus to 0x1000405, and then late-loading can
> load newer versions and only cache the latest ucode revision.

Currently, what setup_cpus() does as its comment says is first ensure 
all CPUs that are present and has been booted up have their primary 
threads online. It just allows its secondary thread offline with nosmt. 
I don't think the current logic is broken there.

Then, those sibling threads assuming late-loading while soft-offlined 
will see an updated revision on its bringup because the loading scope is 
per-core by default, meaning the update performed by the primary thread 
also applies to its sibling.

Also, the NMI stop-machine rendezvous includes those soft-offlined CPUs. 
They are brought into the rendezvous and wait there while the update is 
being performed.

Now, I think it could be misleading if we put the revision check toward 
the end right before the application.

For example, suppose a multi-blob image that is bundled with revision 
0x1000405 and later ones and currently running < 0x1000405. With the 
check during blob selection, the parser can identify 0x1000405 as the 
loadable revision and reject later revisions.

If we move the check to just before application, the parser may instead 
select a revision newer than 0x1000405. The application would then be 
rejected, and the same blob would be selected again on the next attempt, 
resulting in the loading process repeatedly aborting without ever making 
progress.

So the revision check needs to remain part of blob selection, where it 
can affect which revision is considered loadable, rather than being only 
an application-time check.

Thanks,
Chang
RE: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Van De Ven, Arjan 1 week, 1 day ago
 
> If we move the check to just before application, the parser may instead
> select a revision newer than 0x1000405. The application would then be
> rejected, and the same blob would be selected again on the next attempt,
> resulting in the loading process repeatedly aborting without ever making
> progress.
> 
> So the revision check needs to remain part of blob selection, where it
> can affect which revision is considered loadable, rather than being only
> an application-time check.


Agreed that we need the early check.
But we could, on the actual application, at least check if the ucode already got upgraded to EXACTLY the target version, and skip the actual application if it has been upgraded. That is a simple check with basically no policy ("identity") but with huge savings

Re: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Chang S. Bae 1 week, 1 day ago
On 9/17/2026 11:43 AM, Van De Ven, Arjan wrote:
> 
> But we could, on the actual application, at least check if the ucode 
 > already got upgraded to EXACTLY the target version, and skip the
 > actual application if it has been upgraded. That is a simple check
 > with basically no policy ("identity") but with huge savings

Yes, I think that' what we do now:

__apply_microcode(..., struct microcode_intel *mc, ...)
{
	u32 rev;

	if (!mc)
		return UCODE_NFOUND;

	*cur_rev = intel_get_microcode_revision();
                    ^ read MSR0x8b (aka MSR_IA32_UCODE_REV)
	if (*cur_rev >= mc->hdr.rev) {
		uci->cpu_sig.rev = *cur_rev;
		return UCODE_OK;
		^ we skip the loading if updated
	}

	/* write microcode via MSR 0x79 */
	native_wrmsrq(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
	...
}

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/microcode/intel.c#n646

Thanks,
Chang
Re: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by David Laight 1 week, 1 day ago
On Wed, 16 Sep 2026 22:59:39 +0000
"Chang S. Bae" <chang.seok.bae@intel.com> wrote:

> Microcode updates can usually jump revisions. However, there is an
> erratum on Granite Rapids systems. If they "jump over" revision
> 0x1000405, they result in #MC. Avoid it.

A probably silly question.
Is it valid to downgrade microcode?

David

> 
> Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
> Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: <stable@vger.kernel.org>
> ---
> V2 -> V3:
> * Shorten the changelog and rename the function (Boris)
> * Reduce the code comment (Dave)
> * Allow 0x1000405 loading. Thanks to Andrew, this fix got attention.
> * Collect Dave review tag. Thanks, Dave!
> 
> Note:
> * GNR98 currently describes loading 0x1000405 itself is unsafe, but it
>   will be updated to say okay with that. I will watch out the GNR98
>   changes.
> * Jumping from < 0x1000380 to 0x1000405 was identified as an issue, but
>   0x1000380 is the first revision as GNR products. So loading 0x1000405
>   in production systems should be okay.
> ---
>  arch/x86/kernel/cpu/microcode/intel.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
> index 1142183c950c..30a22388d4b1 100644
> --- a/arch/x86/kernel/cpu/microcode/intel.c
> +++ b/arch/x86/kernel/cpu/microcode/intel.c
> @@ -309,6 +309,26 @@ static void save_microcode_patch(struct microcode_intel *patch)
>  		pr_err("Unable to allocate microcode memory size: %u\n", size);
>  }
>  
> +static bool revision_is_safe(struct cpu_signature *sig, u32 rev)
> +{
> +	u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig));
> +
> +	/*
> +	 * Erratum GNR98 can cause #MC's if "jumping over" revision 0x1000405.
> +	 * Avoid the jumps.
> +	 */
> +	if (vfm == INTEL_GRANITERAPIDS_X &&
> +	    x86_stepping(sig->sig) == 1 &&
> +	    sig->pf & 0x95 &&
> +	    sig->rev < 0x1000405 &&
> +	    rev > 0x1000405) {
> +		pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev);
> +		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,
> @@ -330,6 +350,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
>  		if (!intel_find_matching_signature(data, &uci->cpu_sig))
>  			continue;
>  
> +		if (!revision_is_safe(&uci->cpu_sig, mc_header->rev))
> +			continue;
> +
>  		/*
>  		 * For saving the early microcode, find the matching revision which
>  		 * was loaded on the BSP.
> @@ -878,6 +901,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 (!revision_is_safe(&uci->cpu_sig, mc_header.rev))
> +			continue;
> +
>  		is_safe = ucode_validate_minrev(&mc_header);
>  		if (force_minrev && !is_safe)
>  			continue;
RE: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Van De Ven, Arjan 1 week, 1 day ago
> > Microcode updates can usually jump revisions. However, there is an
> > erratum on Granite Rapids systems. If they "jump over" revision
> > 0x1000405, they result in #MC. Avoid it.
> 
> A probably silly question.
> Is it valid to downgrade microcode?


Within SVN in theory it can be done

In practice, unless you have very special circumstances (and check with Intel if the exact downgrade you have in mind has been tested for downgrading) I would very strongly recommend against doing so. It may appear to work, but note that 

A -> B -> A 

Is NOT identical to just

A  (staying at A)

as part of the microcode load, some microcode runs as "setup" which may change settings in the CPU (versus runtime behavior changes) -- and that setup step is not undone as you go back to A.... which means you run A with a (partial or whole) setup of B. 
Re: [PATCH v3] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by Andrew Cooper 1 week, 1 day ago
On 17/09/2026 11:14 am, David Laight wrote:
> On Wed, 16 Sep 2026 22:59:39 +0000
> "Chang S. Bae" <chang.seok.bae@intel.com> wrote:
>
>> Microcode updates can usually jump revisions. However, there is an
>> erratum on Granite Rapids systems. If they "jump over" revision
>> 0x1000405, they result in #MC. Avoid it.
> A probably silly question.
> Is it valid to downgrade microcode?

Yes, and it does happen in practice.

Intel microcode contains a field called the Security Version Number. 
The SVN bumps as infrequently as possible, but does bump when necessary.

There is a hard block on the SVN going backwards, but as long as you're
not violating this constraint, you can upgrade or downgrade microcode as
desired.

~Andrew
[tip: x86/urgent] x86/microcode/intel: Reject problematic loading on Granite Rapids systems
Posted by tip-bot2 for Chang S. Bae 1 week ago
The following commit has been merged into the x86/urgent branch of tip:

Commit-ID:     e7d3e2f46dd5a69046e6d95a0f189155a5516b93
Gitweb:        https://git.kernel.org/tip/e7d3e2f46dd5a69046e6d95a0f189155a5516b93
Author:        Chang S. Bae <chang.seok.bae@intel.com>
AuthorDate:    Wed, 16 Sep 2026 22:59:39 
Committer:     Borislav Petkov (AMD) <bp@alien8.de>
CommitterDate: Thu, 17 Sep 2026 16:54:20 -07:00

x86/microcode/intel: Reject problematic loading on Granite Rapids systems

Microcode updates can usually jump revisions. However, there is an erratum on
Granite Rapids systems. If they "jump over" revision 0x1000405, they result in
an #MC. Avoid it.

Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260916225939.1144524-1-chang.seok.bae@intel.com
---
 arch/x86/kernel/cpu/microcode/intel.c | 26 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+)

diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index 1142183..9f09d38 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -309,6 +309,26 @@ static void save_microcode_patch(struct microcode_intel *patch)
 		pr_err("Unable to allocate microcode memory size: %u\n", size);
 }
 
+static bool revision_is_safe(struct cpu_signature *sig, u32 rev)
+{
+	u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig));
+
+	/*
+	 * Erratum GNR98 can cause #MCs if "jumping over" revision 0x1000405.
+	 * Avoid the jumps.
+	 */
+	if (vfm == INTEL_GRANITERAPIDS_X &&
+	    x86_stepping(sig->sig) == 1 &&
+	    sig->pf & 0x95 &&
+	    sig->rev < 0x1000405 &&
+	    rev > 0x1000405) {
+		pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev);
+		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,
@@ -330,6 +350,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
 		if (!intel_find_matching_signature(data, &uci->cpu_sig))
 			continue;
 
+		if (!revision_is_safe(&uci->cpu_sig, mc_header->rev))
+			continue;
+
 		/*
 		 * For saving the early microcode, find the matching revision which
 		 * was loaded on the BSP.
@@ -878,6 +901,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 (!revision_is_safe(&uci->cpu_sig, mc_header.rev))
+			continue;
+
 		is_safe = ucode_validate_minrev(&mc_header);
 		if (force_minrev && !is_safe)
 			continue;