[tip:x86/microcode] x86/microcode/amd: Do not overwrite final patch levels

2015-07-21 Thread tip-bot for Borislav Petkov
Commit-ID:  d48a9c164b45c5cc40f00c12231564f9aac8ab1d
Gitweb: http://git.kernel.org/tip/d48a9c164b45c5cc40f00c12231564f9aac8ab1d
Author: Borislav Petkov 
AuthorDate: Thu, 16 Jul 2015 10:05:47 +0200
Committer:  Ingo Molnar 
CommitDate: Tue, 21 Jul 2015 09:45:40 +0200

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 
Signed-off-by: Borislav Petkov 
Cc: Linus Torvalds 
Cc: Peter Zijlstra 
Cc: Thomas Gleixner 
Link: http://lkml.kernel.org/r/1437033947-30234-3-git-send-email...@alien8.de
Signed-off-by: Ingo Molnar 
---
 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 9b214e1..d3e86cf 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 59a3612..c7d2415 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[] = {
+   0x0198,
+   0x019f,
+   0x01af,
+   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;
+
+   rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy);
+
+   if (IS_ENABLED(CONFIG_X86_32) && early)
+   levels = (u32 *)__pa_nodebug(_levels);
+   else
+   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;
 }
 
 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())
+   if (check_current_patch_level(, 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 abb9009..a54a47b 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())
+   if (check_current_patch_level(, true))
return;
 
while (left > 0) {
@@ -330,7 +330,10 @@ void load_ucode_amd_ap(void)
if (!container)
return;
 
-   if (check_current_patch_level())
+   /*
+* 64-bit runs with paging enabled, thus early==false.
+*/
+   if (check_current_patch_level(, false))
return;
 
eax = cpuid_eax(0x0001);
@@ -422,7 +425,11 @@ void reload_ucode_amd(void)
struct microcode_amd *mc;
u32 rev;
 
-   if (check_current_patch_level())
+   /*
+* early==false because this is a syscore ->resume path and by
+* that time paging is long enabled.
+*/
+   if (check_current_patch_level(, false))
return;
 
mc = (struct microcode_amd *)amd_ucode_patch;
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ 

[tip:x86/microcode] x86/microcode/amd: Do not overwrite final patch levels

2015-07-21 Thread tip-bot for Borislav Petkov
Commit-ID:  d48a9c164b45c5cc40f00c12231564f9aac8ab1d
Gitweb: http://git.kernel.org/tip/d48a9c164b45c5cc40f00c12231564f9aac8ab1d
Author: Borislav Petkov b...@suse.de
AuthorDate: Thu, 16 Jul 2015 10:05:47 +0200
Committer:  Ingo Molnar mi...@kernel.org
CommitDate: Tue, 21 Jul 2015 09:45:40 +0200

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 pkirchgess...@t-online.de
Signed-off-by: Borislav Petkov b...@suse.de
Cc: Linus Torvalds torva...@linux-foundation.org
Cc: Peter Zijlstra pet...@infradead.org
Cc: Thomas Gleixner t...@linutronix.de
Link: http://lkml.kernel.org/r/1437033947-30234-3-git-send-email...@alien8.de
Signed-off-by: Ingo Molnar mi...@kernel.org
---
 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 9b214e1..d3e86cf 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 59a3612..c7d2415 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[] = {
+   0x0198,
+   0x019f,
+   0x01af,
+   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;
+
+   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;
+   }
+   }
 
-   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 abb9009..a54a47b 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(0x0001);
@@ -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;
--
To unsubscribe from this list: send the