[PATCH 03/13] x86/microcode/intel: Fix a hang if early loading microcode fails

From: Ashok Raj
Date: Fri Oct 14 2022 - 16:09:45 EST


When early loading of microcode fails for any reason other than the wrong
family-model-stepping, Linux can get into an infinite loop retrying the
same failed load.

A single retry is needed to handle any mixed stepping case.

Assume we have a microcode that fails to load for some reason.
load_ucode_ap() seems to retry if the loading fails. But it searches for
a new rev, but ends up finding the same copy. Hence it appears to repeat
the same load, retry loop for ever.

We can fix it as follows.

1) When the load_ucode_intel_bsp() fails, record the revision that failed.
2) In load_ucode_intel_ap() check if AP is same FMS as BP, and the code
that failed earlier isn't going to apply anyway. So use the saved
information to abort loading on AP's altogether.

load_ucode_intel_ap()
{
..
reget:
if (!*iup) {
patch = __load_ucode_intel(&uci);
^^^^^ Finds the same patch every time.

if (!patch)
return;

*iup = patch;
}

uci.mc = *iup;

if (apply_microcode_early(&uci, true)) {
^^^^^^^^^^^^ apply fails
/* Mixed-silicon system? Try to refetch the proper patch: */
*iup = NULL;

goto reget;
^^^^^ Rince repeat.
}

}

Fixes: 06b8534cb728 ("x86/microcode: Rework microcode loading")
Signed-off-by: Ashok Raj <ashok.raj@xxxxxxxxx>
---
arch/x86/kernel/cpu/microcode/intel.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index cf1e2c30b230..0f7e4ba05c39 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -606,6 +606,7 @@ void __init load_ucode_intel_bsp(void)
{
struct microcode_intel *patch;
struct ucode_cpu_info uci;
+ int rev, ret;

patch = __load_ucode_intel(&uci);
if (!patch)
@@ -613,13 +614,18 @@ void __init load_ucode_intel_bsp(void)

uci.mc = patch;

- apply_microcode_early(&uci, true);
+ ret = apply_microcode_early(&uci, true);
+ if (ret) {
+ rev = patch->hdr.rev;
+ pr_err("Revision 0x%x failed during early loading\n", rev);
+ }
}

void load_ucode_intel_ap(void)
{
struct microcode_intel *patch, **iup;
struct ucode_cpu_info uci;
+ bool retried = false;

if (IS_ENABLED(CONFIG_X86_32))
iup = (struct microcode_intel **) __pa_nodebug(&intel_ucode_patch);
@@ -638,9 +644,13 @@ void load_ucode_intel_ap(void)
uci.mc = *iup;

if (apply_microcode_early(&uci, true)) {
+ if (retried)
+ return;
+
/* Mixed-silicon system? Try to refetch the proper patch: */
*iup = NULL;

+ retried = true;
goto reget;
}
}
--
2.34.1