Commit 6d07d5b0 authored by Borislav Petkov's avatar Borislav Petkov Committed by Ben Hutchings

x86/microcode/amd: Do not overwrite final patch levels

commit 0399f732 upstream.

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: default avatarPeter Kirchgeßner <pkirchgessner@t-online.de>
Signed-off-by: default avatarBorislav 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.deSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
Cc: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
parent c908303c
...@@ -61,5 +61,5 @@ static inline struct microcode_ops * __init init_amd_microcode(void) ...@@ -61,5 +61,5 @@ static inline struct microcode_ops * __init init_amd_microcode(void)
} }
#endif #endif
extern bool check_current_patch_level(u32 *rev); extern bool check_current_patch_level(u32 *rev, bool early);
#endif /* _ASM_X86_MICROCODE_H */ #endif /* _ASM_X86_MICROCODE_H */
...@@ -123,6 +123,16 @@ static int get_matching_microcode(int cpu, struct microcode_header_amd *mc_hdr, ...@@ -123,6 +123,16 @@ static int get_matching_microcode(int cpu, struct microcode_header_amd *mc_hdr,
return 1; return 1;
} }
/*
* 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. * Check the current patch level on this CPU.
* *
...@@ -133,13 +143,33 @@ static int get_matching_microcode(int cpu, struct microcode_header_amd *mc_hdr, ...@@ -133,13 +143,33 @@ static int get_matching_microcode(int cpu, struct microcode_header_amd *mc_hdr,
* - true: if update should stop * - true: if update should stop
* - false: otherwise * - 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;
rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy);
#ifdef CONFIG_X86_32
if (early)
levels = (u32 *)__pa_nodebug(&final_levels);
else
#endif
levels = final_levels;
for (i = 0; levels[i]; i++) {
if (lvl == levels[i]) {
lvl = 0;
ret = true;
break;
}
}
rdmsr(MSR_AMD64_PATCH_LEVEL, *rev, dummy); if (rev)
*rev = lvl;
return false; return ret;
} }
static int apply_microcode_amd(int cpu) static int apply_microcode_amd(int cpu)
...@@ -156,7 +186,7 @@ static int apply_microcode_amd(int cpu) ...@@ -156,7 +186,7 @@ static int apply_microcode_amd(int cpu)
if (mc_amd == NULL) if (mc_amd == NULL)
return 0; return 0;
if (check_current_patch_level(&rev)) if (check_current_patch_level(&rev, false))
return -1; return -1;
wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code); wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment