diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index 9b214e10d499..d3e86cfd08fe 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -76,5 +76,5 @@ static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; } void reload_ucode_amd(void) {} #endif -extern bool check_current_patch_level(u32 *rev); +extern bool check_current_patch_level(u32 *rev, bool early); #endif /* _ASM_X86_MICROCODE_AMD_H */ diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 2d630138bf3e..da922d1e2f71 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -177,6 +177,16 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, return patch_size; } +/* + * Those patch levels cannot be updated to newer ones and thus should be final. + */ +static u32 final_levels[] = { + 0x01000098, + 0x0100009f, + 0x010000af, + 0, /* T-101 terminator */ +}; + /* * Check the current patch level on this CPU. * @@ -187,13 +197,31 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, * - true: if update should stop * - false: otherwise */ -bool check_current_patch_level(u32 *rev) +bool check_current_patch_level(u32 *rev, bool early) { - u32 dummy; + u32 lvl, dummy, i; + bool ret = false; + u32 *levels; - native_rdmsr(MSR_AMD64_PATCH_LEVEL, *rev, dummy); + native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); - return false; + if (IS_ENABLED(CONFIG_X86_32) && early) + levels = (u32 *)__pa_nodebug(&final_levels); + else + levels = final_levels; + + for (i = 0; levels[i]; i++) { + if (lvl == levels[i]) { + lvl = 0; + ret = true; + break; + } + } + + if (rev) + *rev = lvl; + + return ret; } int __apply_microcode_amd(struct microcode_amd *mc_amd) @@ -229,7 +257,7 @@ int apply_microcode_amd(int cpu) mc_amd = p->data; uci->mc = p->data; - if (check_current_patch_level(&rev)) + if (check_current_patch_level(&rev, false)) return -1; /* need to apply patch? */ diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index abb90097582f..a54a47b9d8ea 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c @@ -196,7 +196,7 @@ static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch) return; } - if (check_current_patch_level(&rev)) + if (check_current_patch_level(&rev, true)) return; while (left > 0) { @@ -330,7 +330,10 @@ void load_ucode_amd_ap(void) if (!container) return; - if (check_current_patch_level(&rev)) + /* + * 64-bit runs with paging enabled, thus early==false. + */ + if (check_current_patch_level(&rev, false)) return; eax = cpuid_eax(0x00000001); @@ -422,7 +425,11 @@ void reload_ucode_amd(void) struct microcode_amd *mc; u32 rev; - if (check_current_patch_level(&rev)) + /* + * early==false because this is a syscore ->resume path and by + * that time paging is long enabled. + */ + if (check_current_patch_level(&rev, false)) return; mc = (struct microcode_amd *)amd_ucode_patch;