xen/arch/x86/cpu/microcode/intel.c | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
Block loads which are known to hang the system.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <jbeulich@suse.com>
CC: Roger Pau Monné <roger@xenproject.org>
CC: Teddy Astie <teddy.astie@vates.tech>
A more complete solution is in the works, but it's taken 4 months to get this
much published...
v3:
* Double XENLOG_WARNING
v2:
* Correct the sign of the cpu_sig->rev check.
* Expand the comment to explain why we are not following what GNR98 says.
---
xen/arch/x86/cpu/microcode/intel.c | 40 ++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/xen/arch/x86/cpu/microcode/intel.c b/xen/arch/x86/cpu/microcode/intel.c
index c45b00c6b033..86cbfb798160 100644
--- a/xen/arch/x86/cpu/microcode/intel.c
+++ b/xen/arch/x86/cpu/microcode/intel.c
@@ -27,6 +27,7 @@
#include <xen/string.h>
#include <xen/xmalloc.h>
+#include <asm/intel-family.h>
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -273,6 +274,44 @@ static bool microcode_fits_cpu(const struct microcode_patch *mc)
return false;
}
+static bool microcode_safe_to_load(const struct microcode_patch *mc)
+{
+ struct cpu_signature *cpu_sig = &this_cpu(cpu_sig);
+
+ /*
+ * Treat pre-production as always safe - anyone using pre-production
+ * microcode knows what they are doing, and can keep any resulting pieces.
+ */
+ if ( (int)cpu_sig->rev < 0 || mc->rev < 0 )
+ return true;
+
+ /*
+ * GNR98 states that Granite Rapids systems hang when loading new ucode on
+ * sufficiently old firmware. GNR101 retroactively states that one ucode
+ * had an incorrect minimum revision field, in light of discovering GNR98.
+ *
+ * Both are incomplete statements of the problem.
+ *
+ * At the time of writing (August 2026), the believed safe sequence is:
+ * 0x01000370 -> [0x01000380...0x010003f3] -> 0x01000405 -> any later
+ *
+ * Disallow known-unsafe loads while permitting believed-safe loads. For
+ * GNR, this allows multi-hop loading to get up to the latest.
+ */
+ if ( boot_cpu_data.vfm == INTEL_GRANITERAPIDS_X &&
+ boot_cpu_data.stepping == 1 && (cpu_sig->pf & 0x95) &&
+ ((cpu_sig->rev < 0x01000380 && mc->rev >= 0x01000405) ||
+ (cpu_sig->rev < 0x01000405 && mc->rev > 0x01000405)) )
+ {
+ printk_once(XENLOG_WARNING "microcode: Granite Rapids erratum GNR98 detected. Skipping ucode 0x%08x\n"
+ XENLOG_WARNING "microcode: Firmware update recommended\n",
+ mc->rev);
+ return false;
+ }
+
+ return true;
+}
+
static int cf_check intel_compare(
const struct microcode_patch *old, const struct microcode_patch *new)
{
@@ -365,6 +404,7 @@ static struct microcode_patch *cf_check intel_ucode_parse(
* one with higher revision.
*/
if ( microcode_fits_cpu(mc) &&
+ microcode_safe_to_load(mc) &&
(!saved || compare_revisions(saved->rev, mc->rev) == NEW_UCODE) )
saved = mc;
--
2.39.5
On Tue, Sep 08, 2026 at 06:15:25PM +0100, Andrew Cooper wrote:
> Block loads which are known to hang the system.
>
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> ---
> CC: Jan Beulich <jbeulich@suse.com>
> CC: Roger Pau Monné <roger@xenproject.org>
> CC: Teddy Astie <teddy.astie@vates.tech>
>
> A more complete solution is in the works, but it's taken 4 months to get this
> much published...
>
> v3:
> * Double XENLOG_WARNING
>
> v2:
> * Correct the sign of the cpu_sig->rev check.
> * Expand the comment to explain why we are not following what GNR98 says.
> ---
> xen/arch/x86/cpu/microcode/intel.c | 40 ++++++++++++++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/xen/arch/x86/cpu/microcode/intel.c b/xen/arch/x86/cpu/microcode/intel.c
> index c45b00c6b033..86cbfb798160 100644
> --- a/xen/arch/x86/cpu/microcode/intel.c
> +++ b/xen/arch/x86/cpu/microcode/intel.c
> @@ -27,6 +27,7 @@
> #include <xen/string.h>
> #include <xen/xmalloc.h>
>
> +#include <asm/intel-family.h>
> #include <asm/msr.h>
> #include <asm/processor.h>
> #include <asm/system.h>
> @@ -273,6 +274,44 @@ static bool microcode_fits_cpu(const struct microcode_patch *mc)
> return false;
> }
>
> +static bool microcode_safe_to_load(const struct microcode_patch *mc)
> +{
> + struct cpu_signature *cpu_sig = &this_cpu(cpu_sig);
I think this could be const? Or are there further changes expected
that will modify the signature?
> +
> + /*
> + * Treat pre-production as always safe - anyone using pre-production
> + * microcode knows what they are doing, and can keep any resulting pieces.
> + */
> + if ( (int)cpu_sig->rev < 0 || mc->rev < 0 )
> + return true;
> +
> + /*
> + * GNR98 states that Granite Rapids systems hang when loading new ucode on
> + * sufficiently old firmware. GNR101 retroactively states that one ucode
> + * had an incorrect minimum revision field, in light of discovering GNR98.
> + *
> + * Both are incomplete statements of the problem.
> + *
> + * At the time of writing (August 2026), the believed safe sequence is:
> + * 0x01000370 -> [0x01000380...0x010003f3] -> 0x01000405 -> any later
> + *
> + * Disallow known-unsafe loads while permitting believed-safe loads. For
> + * GNR, this allows multi-hop loading to get up to the latest.
> + */
> + if ( boot_cpu_data.vfm == INTEL_GRANITERAPIDS_X &&
> + boot_cpu_data.stepping == 1 && (cpu_sig->pf & 0x95) &&
> + ((cpu_sig->rev < 0x01000380 && mc->rev >= 0x01000405) ||
> + (cpu_sig->rev < 0x01000405 && mc->rev > 0x01000405)) )
Given the logic, I don't think the CPU needs to strictly be in version
0x01000370 to update to the [0x01000380...0x010003f3] range?
Maybe you want to replace 0x01000370 with "any previous" to match the
semantics used in the tail of the sequence with "any later".
In any case:
Reviewed-by: Roger Pau Monné <roger@xenproject.org>
Thanks, Roger.
On 09/09/2026 10:35 am, Roger Pau Monné wrote: > On Tue, Sep 08, 2026 at 06:15:25PM +0100, Andrew Cooper wrote: >> + >> + /* >> + * Treat pre-production as always safe - anyone using pre-production >> + * microcode knows what they are doing, and can keep any resulting pieces. >> + */ >> + if ( (int)cpu_sig->rev < 0 || mc->rev < 0 ) >> + return true; >> + >> + /* >> + * GNR98 states that Granite Rapids systems hang when loading new ucode on >> + * sufficiently old firmware. GNR101 retroactively states that one ucode >> + * had an incorrect minimum revision field, in light of discovering GNR98. >> + * >> + * Both are incomplete statements of the problem. >> + * >> + * At the time of writing (August 2026), the believed safe sequence is: >> + * 0x01000370 -> [0x01000380...0x010003f3] -> 0x01000405 -> any later >> + * >> + * Disallow known-unsafe loads while permitting believed-safe loads. For >> + * GNR, this allows multi-hop loading to get up to the latest. >> + */ >> + if ( boot_cpu_data.vfm == INTEL_GRANITERAPIDS_X && >> + boot_cpu_data.stepping == 1 && (cpu_sig->pf & 0x95) && >> + ((cpu_sig->rev < 0x01000380 && mc->rev >= 0x01000405) || >> + (cpu_sig->rev < 0x01000405 && mc->rev > 0x01000405)) ) > Given the logic, I don't think the CPU needs to strictly be in version > 0x01000370 to update to the [0x01000380...0x010003f3] range? > > Maybe you want to replace 0x01000370 with "any previous" to match the > semantics used in the tail of the sequence with "any later". Hmm. 370 was the first release, so the analysis of the problem stops there. Everything older was development phase. But yes, the eventual planned fix doesn't have 370 as a boundary, so I'll adjust to "previous". > > In any case: > > Reviewed-by: Roger Pau Monné <roger@xenproject.org> Thanks. ~Andrew
Le 08/09/2026 à 19:15, Andrew Cooper a écrit :
> Block loads which are known to hang the system.
>
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> ---
> CC: Jan Beulich <jbeulich@suse.com>
> CC: Roger Pau Monné <roger@xenproject.org>
> CC: Teddy Astie <teddy.astie@vates.tech>
>
> A more complete solution is in the works, but it's taken 4 months to get this
> much published...
>
> v3:
> * Double XENLOG_WARNING
>
> v2:
> * Correct the sign of the cpu_sig->rev check.
> * Expand the comment to explain why we are not following what GNR98 says.
> ---
> xen/arch/x86/cpu/microcode/intel.c | 40 ++++++++++++++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/xen/arch/x86/cpu/microcode/intel.c b/xen/arch/x86/cpu/microcode/intel.c
> index c45b00c6b033..86cbfb798160 100644
> --- a/xen/arch/x86/cpu/microcode/intel.c
> +++ b/xen/arch/x86/cpu/microcode/intel.c
> @@ -27,6 +27,7 @@
> #include <xen/string.h>
> #include <xen/xmalloc.h>
>
> +#include <asm/intel-family.h>
> #include <asm/msr.h>
> #include <asm/processor.h>
> #include <asm/system.h>
> @@ -273,6 +274,44 @@ static bool microcode_fits_cpu(const struct microcode_patch *mc)
> return false;
> }
>
> +static bool microcode_safe_to_load(const struct microcode_patch *mc)
> +{
> + struct cpu_signature *cpu_sig = &this_cpu(cpu_sig);
> +
> + /*
> + * Treat pre-production as always safe - anyone using pre-production
> + * microcode knows what they are doing, and can keep any resulting pieces.
> + */
> + if ( (int)cpu_sig->rev < 0 || mc->rev < 0 )
> + return true;
> +
> + /*
> + * GNR98 states that Granite Rapids systems hang when loading new ucode on
> + * sufficiently old firmware. GNR101 retroactively states that one ucode
> + * had an incorrect minimum revision field, in light of discovering GNR98.
> + *
> + * Both are incomplete statements of the problem.
> + *
> + * At the time of writing (August 2026), the believed safe sequence is:
> + * 0x01000370 -> [0x01000380...0x010003f3] -> 0x01000405 -> any later
> + *
> + * Disallow known-unsafe loads while permitting believed-safe loads. For
> + * GNR, this allows multi-hop loading to get up to the latest.
> + */
> + if ( boot_cpu_data.vfm == INTEL_GRANITERAPIDS_X &&
> + boot_cpu_data.stepping == 1 && (cpu_sig->pf & 0x95) &&
> + ((cpu_sig->rev < 0x01000380 && mc->rev >= 0x01000405) ||
> + (cpu_sig->rev < 0x01000405 && mc->rev > 0x01000405)) )
> + {
> + printk_once(XENLOG_WARNING "microcode: Granite Rapids erratum GNR98 detected. Skipping ucode 0x%08x\n"
> + XENLOG_WARNING "microcode: Firmware update recommended\n",
> + mc->rev);
> + return false;
> + }
> +
> + return true;
> +}
> +
> static int cf_check intel_compare(
> const struct microcode_patch *old, const struct microcode_patch *new)
> {
> @@ -365,6 +404,7 @@ static struct microcode_patch *cf_check intel_ucode_parse(
> * one with higher revision.
> */
> if ( microcode_fits_cpu(mc) &&
> + microcode_safe_to_load(mc) &&
> (!saved || compare_revisions(saved->rev, mc->rev) == NEW_UCODE) )
> saved = mc;
>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
Teddy
© 2016 - 2026 Red Hat, Inc.