From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933488AbcFLVni (ORCPT ); Sun, 12 Jun 2016 17:43:38 -0400 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:36770 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933092AbcFLVf4 (ORCPT ); Sun, 12 Jun 2016 17:35:56 -0400 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 From: Ben Hutchings To: linux-kernel@vger.kernel.org, stable@vger.kernel.org CC: akpm@linux-foundation.org, "Tony Luck" , "Thomas Gleixner" , "Peter Zijlstra" , "Henrique de Moraes Holschuh" , "Peter =?UTF-8?Q?Kirchge=C3=9Fner?=" , "H. Peter Anvin" , "Borislav Petkov" , "Borislav Petkov" , "Ingo Molnar" , "Linus Torvalds" Date: Sun, 12 Jun 2016 22:34:41 +0100 Message-ID: X-Mailer: LinuxStableQueue (scripts by bwh) Subject: [PATCH 3.2 04/46] x86/microcode/amd: Do not overwrite final patch levels In-Reply-To: X-SA-Exim-Connect-IP: 2a02:8011:400e:2:6f00:88c8:c921:d332 X-SA-Exim-Mail-From: ben@decadent.org.uk X-SA-Exim-Scanned: No (on shadbolt.decadent.org.uk); SAEximRunCond expanded to false Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.2.81-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Borislav Petkov 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 Signed-off-by: Borislav Petkov Cc: Borislav Petkov Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tony Luck Link: http://lkml.kernel.org/r/1444641762-9437-7-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar Signed-off-by: Ben Hutchings Cc: Henrique de Moraes Holschuh --- arch/x86/include/asm/microcode.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(-) --- a/arch/x86/include/asm/microcode.h +++ b/arch/x86/include/asm/microcode.h @@ -61,5 +61,5 @@ static inline struct microcode_ops * __i } #endif -extern bool check_current_patch_level(u32 *rev); +extern bool check_current_patch_level(u32 *rev, bool early); #endif /* _ASM_X86_MICROCODE_H */ --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -124,6 +124,16 @@ static int get_matching_microcode(int cp } /* + * 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 @@ -133,13 +143,33 @@ static int get_matching_microcode(int cp * - 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);