x86/microcode/amd: Do not overwrite final patch levels
A certain number of patch levels of applied microcode should not be overwritten by the microcode loader, otherwise bad things will happen. Check those and abort update if the current core has one of those final patch levels applied by the BIOS. 32-bit needs special handling, of course. See https://bugzilla.suse.com/show_bug.cgi?id=913996 for more info. Tested-by: Peter Kirchgeßner <pkirchgessner@t-online.de> Signed-off-by: Borislav Petkov <bp@suse.de> Cc: Borislav Petkov <bp@alien8.de> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Link: http://lkml.kernel.org/r/1444641762-9437-7-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:

committed by
Ingo Molnar

parent
2eff73c0a1
commit
0399f73299
@@ -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? */
|
||||
|
Reference in New Issue
Block a user