]> git.hungrycats.org Git - linux/commitdiff
x86/microcode/amd: Do not overwrite final patch levels
authorBorislav Petkov <bp@suse.de>
Mon, 12 Oct 2015 09:22:42 +0000 (11:22 +0200)
committerBen Hutchings <ben@decadent.org.uk>
Wed, 15 Jun 2016 20:28:10 +0000 (21:28 +0100)
commit 0399f73299f1b7e04de329050f7111b362b7eeb5 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: 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>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Cc: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
arch/x86/include/asm/microcode.h
arch/x86/kernel/microcode_amd.c

index 472459c2f627259c0c4b8d862c5fb50c9f4d8231..3a7f5f5a405d4129125dac7f177dcc72ebb5f09f 100644 (file)
@@ -61,5 +61,5 @@ static inline struct microcode_ops * __init init_amd_microcode(void)
 }
 #endif
 
-extern bool check_current_patch_level(u32 *rev);
+extern bool check_current_patch_level(u32 *rev, bool early);
 #endif /* _ASM_X86_MICROCODE_H */
index be7c43bb8807aff2a23d0af73b5a8eea5d450e90..be2fa4d0e81427ea142b0a2e750d54f828ccad3a 100644 (file)
@@ -123,6 +123,16 @@ static int get_matching_microcode(int cpu, struct microcode_header_amd *mc_hdr,
        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.
  *
@@ -133,13 +143,33 @@ static int get_matching_microcode(int cpu, struct microcode_header_amd *mc_hdr,
  *  - 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;
+
+       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)
@@ -156,7 +186,7 @@ static int apply_microcode_amd(int cpu)
        if (mc_amd == NULL)
                return 0;
 
-       if (check_current_patch_level(&rev))
+       if (check_current_patch_level(&rev, false))
                return -1;
 
        wrmsrl(MSR_AMD64_PATCH_LOADER, (u64)(long)&mc_amd->hdr.data_code);