Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1244531
| From | Borislav Petkov <bp@alien8.de> |
|---|---|
| Newsgroups | linux.kernel |
| Subject | [PATCH 6/6] x86/microcode/amd: Do not overwrite final patch levels |
| Date | 2015-10-12 11:30 +0200 |
| Message-ID | <qiHAE-38y-51@gated-at.bofh.it> (permalink) |
| References | <qiHAD-38y-13@gated-at.bofh.it> |
| Organization | linux.* mail to news gateway |
From: Borislav Petkov <bp@suse.de>
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>
---
arch/x86/include/asm/microcode_amd.h | 2 +-
arch/x86/kernel/cpu/microcode/amd.c | 38 +++++++++++++++++++++++++++----
arch/x86/kernel/cpu/microcode/amd_early.c | 13 ++++++++---
3 files changed, 44 insertions(+), 9 deletions(-)
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
@@ -178,6 +178,16 @@ static unsigned int verify_patch_size(u8 family, u32 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.
*
* @rev: Use it to return the patch level. It is set to 0 in the case of
@@ -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, lvl, dummy);
+
+ 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;
+ }
+ }
- native_rdmsr(MSR_AMD64_PATCH_LEVEL, *rev, dummy);
+ if (rev)
+ *rev = lvl;
- return false;
+ 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;
--
2.3.5
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Back to linux.kernel | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
[PATCH 0/6] tip-queue 2015-10-12 Borislav Petkov <bp@alien8.de> - 2015-10-12 11:30 +0200
[PATCH 3/6] x86/ras/mce_amd_inj: Trigger deferred and thresholding errors interrupts Borislav Petkov <bp@alien8.de> - 2015-10-12 11:30 +0200
[tip:ras/core] x86/ras/mce_amd_inj: Trigger deferred and thresholding errors interrupts tip-bot for Aravind Gopalakrishnan <tipbot@zytor.com> - 2015-10-12 16:40 +0200
[PATCH 2/6] x86/ras/mce_amd_inj: Return early on invalid input Borislav Petkov <bp@alien8.de> - 2015-10-12 11:30 +0200
[tip:ras/core] x86/ras/mce_amd_inj: Return early on invalid input tip-bot for Aravind Gopalakrishnan <tipbot@zytor.com> - 2015-10-12 16:40 +0200
[PATCH 4/6] x86/ras/mce_amd_inj: Inject bank 4 errors on the NBC Borislav Petkov <bp@alien8.de> - 2015-10-12 11:30 +0200
[tip:ras/core] x86/ras/mce_amd_inj: Inject bank 4 errors on the NBC tip-bot for Aravind Gopalakrishnan <tipbot@zytor.com> - 2015-10-12 16:40 +0200
[PATCH 6/6] x86/microcode/amd: Do not overwrite final patch levels Borislav Petkov <bp@alien8.de> - 2015-10-12 11:30 +0200
[tip:ras/core] x86/microcode/amd: Do not overwrite final patch levels tip-bot for Borislav Petkov <tipbot@zytor.com> - 2015-10-12 16:40 +0200
csiph-web