* [PATCH 0/2] tip-queue 2015-07-16 @ 2015-07-16 8:05 Borislav Petkov 2015-07-16 8:05 ` [PATCH 1/2] x86/microcode/amd: Extract current patch level read to a function Borislav Petkov 2015-07-16 8:05 ` [PATCH 2/2] x86/microcode/amd: Do not overwrite final patch levels Borislav Petkov 0 siblings, 2 replies; 5+ messages in thread From: Borislav Petkov @ 2015-07-16 8:05 UTC (permalink / raw) To: Ingo Molnar; +Cc: LKML From: Borislav Petkov <bp@suse.de> Hi, here are two microcode loader changes for making certain patch levels applied by the firmware, final. Please apply, thanks. Borislav Petkov (2): x86/microcode/amd: Extract current patch level read to a function x86/microcode/amd: Do not overwrite final patch levels arch/x86/include/asm/microcode_amd.h | 1 + arch/x86/kernel/cpu/microcode/amd.c | 52 +++++++++++++++++++++++++++++-- arch/x86/kernel/cpu/microcode/amd_early.c | 24 ++++++++------ 3 files changed, 65 insertions(+), 12 deletions(-) -- 2.5.0.rc2.28.g6003e7f ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] x86/microcode/amd: Extract current patch level read to a function 2015-07-16 8:05 [PATCH 0/2] tip-queue 2015-07-16 Borislav Petkov @ 2015-07-16 8:05 ` Borislav Petkov 2015-07-21 9:40 ` [tip:x86/microcode] " tip-bot for Borislav Petkov 2015-07-16 8:05 ` [PATCH 2/2] x86/microcode/amd: Do not overwrite final patch levels Borislav Petkov 1 sibling, 1 reply; 5+ messages in thread From: Borislav Petkov @ 2015-07-16 8:05 UTC (permalink / raw) To: Ingo Molnar; +Cc: LKML From: Borislav Petkov <bp@suse.de> Pave the way for checking the current patch level of the microcode in a core. We want to be able to do stuff depending on the patch level - in this case decide whether to update or not. But that will be added in a later patch; here we do not introduce any functionality change. Drop unused local var uci assignment, while at it. Signed-off-by: Borislav Petkov <bp@suse.de> --- arch/x86/include/asm/microcode_amd.h | 1 + arch/x86/kernel/cpu/microcode/amd.c | 24 ++++++++++++++++++++++-- arch/x86/kernel/cpu/microcode/amd_early.c | 17 +++++++---------- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index ac6d328977a6..9b214e10d499 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -76,4 +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); #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 12829c3ced3c..59a36125bf7f 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -177,6 +177,25 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, return patch_size; } +/* + * 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 + * error. + * + * Returns: + * - true: if update should stop + * - false: otherwise + */ +bool check_current_patch_level(u32 *rev) +{ + u32 dummy; + + rdmsr(MSR_AMD64_PATCH_LEVEL, *rev, dummy); + + return false; +} + int __apply_microcode_amd(struct microcode_amd *mc_amd) { u32 rev, dummy; @@ -197,7 +216,7 @@ int apply_microcode_amd(int cpu) struct microcode_amd *mc_amd; struct ucode_cpu_info *uci; struct ucode_patch *p; - u32 rev, dummy; + u32 rev; BUG_ON(raw_smp_processor_id() != cpu); @@ -210,7 +229,8 @@ int apply_microcode_amd(int cpu) mc_amd = p->data; uci->mc = p->data; - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + if (check_current_patch_level(&rev)) + return -1; /* need to apply patch? */ if (rev >= mc_amd->hdr.patch_id) { diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index e8a215a9a345..abb90097582f 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c @@ -196,9 +196,8 @@ static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch) return; } - /* find ucode and update if needed */ - - native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); + if (check_current_patch_level(&rev)) + return; while (left > 0) { struct microcode_amd *mc; @@ -319,7 +318,6 @@ static void __init get_bsp_sig(void) void load_ucode_amd_ap(void) { unsigned int cpu = smp_processor_id(); - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct equiv_cpu_entry *eq; struct microcode_amd *mc; u32 rev, eax; @@ -332,10 +330,8 @@ void load_ucode_amd_ap(void) if (!container) return; - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); - - uci->cpu_sig.rev = rev; - uci->cpu_sig.sig = eax; + if (check_current_patch_level(&rev)) + return; eax = cpuid_eax(0x00000001); eq = (struct equiv_cpu_entry *)(container + CONTAINER_HDR_SZ); @@ -424,9 +420,10 @@ int __init save_microcode_in_initrd_amd(void) void reload_ucode_amd(void) { struct microcode_amd *mc; - u32 rev, eax; + u32 rev; - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); + if (check_current_patch_level(&rev)) + return; mc = (struct microcode_amd *)amd_ucode_patch; -- 2.5.0.rc2.28.g6003e7f ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [tip:x86/microcode] x86/microcode/amd: Extract current patch level read to a function 2015-07-16 8:05 ` [PATCH 1/2] x86/microcode/amd: Extract current patch level read to a function Borislav Petkov @ 2015-07-21 9:40 ` tip-bot for Borislav Petkov 0 siblings, 0 replies; 5+ messages in thread From: tip-bot for Borislav Petkov @ 2015-07-21 9:40 UTC (permalink / raw) To: linux-tip-commits; +Cc: linux-kernel, hpa, bp, tglx, torvalds, peterz, mingo Commit-ID: 7708698e783e304da0fac10052dddce1193f47a8 Gitweb: http://git.kernel.org/tip/7708698e783e304da0fac10052dddce1193f47a8 Author: Borislav Petkov <bp@suse.de> AuthorDate: Thu, 16 Jul 2015 10:05:46 +0200 Committer: Ingo Molnar <mingo@kernel.org> CommitDate: Tue, 21 Jul 2015 09:45:40 +0200 x86/microcode/amd: Extract current patch level read to a function Pave the way for checking the current patch level of the microcode in a core. We want to be able to do stuff depending on the patch level - in this case decide whether to update or not. But that will be added in a later patch; here we do not introduce any functionality change. Drop unused local var uci assignment, while at it. Signed-off-by: Borislav Petkov <bp@suse.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1437033947-30234-2-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar <mingo@kernel.org> --- arch/x86/include/asm/microcode_amd.h | 1 + arch/x86/kernel/cpu/microcode/amd.c | 24 ++++++++++++++++++++++-- arch/x86/kernel/cpu/microcode/amd_early.c | 17 +++++++---------- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h index ac6d328..9b214e1 100644 --- a/arch/x86/include/asm/microcode_amd.h +++ b/arch/x86/include/asm/microcode_amd.h @@ -76,4 +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); #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 12829c3..59a3612 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -177,6 +177,25 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, return patch_size; } +/* + * 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 + * error. + * + * Returns: + * - true: if update should stop + * - false: otherwise + */ +bool check_current_patch_level(u32 *rev) +{ + u32 dummy; + + rdmsr(MSR_AMD64_PATCH_LEVEL, *rev, dummy); + + return false; +} + int __apply_microcode_amd(struct microcode_amd *mc_amd) { u32 rev, dummy; @@ -197,7 +216,7 @@ int apply_microcode_amd(int cpu) struct microcode_amd *mc_amd; struct ucode_cpu_info *uci; struct ucode_patch *p; - u32 rev, dummy; + u32 rev; BUG_ON(raw_smp_processor_id() != cpu); @@ -210,7 +229,8 @@ int apply_microcode_amd(int cpu) mc_amd = p->data; uci->mc = p->data; - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); + if (check_current_patch_level(&rev)) + return -1; /* need to apply patch? */ if (rev >= mc_amd->hdr.patch_id) { diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c index e8a215a..abb9009 100644 --- a/arch/x86/kernel/cpu/microcode/amd_early.c +++ b/arch/x86/kernel/cpu/microcode/amd_early.c @@ -196,9 +196,8 @@ static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch) return; } - /* find ucode and update if needed */ - - native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); + if (check_current_patch_level(&rev)) + return; while (left > 0) { struct microcode_amd *mc; @@ -319,7 +318,6 @@ static void __init get_bsp_sig(void) void load_ucode_amd_ap(void) { unsigned int cpu = smp_processor_id(); - struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct equiv_cpu_entry *eq; struct microcode_amd *mc; u32 rev, eax; @@ -332,10 +330,8 @@ void load_ucode_amd_ap(void) if (!container) return; - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); - - uci->cpu_sig.rev = rev; - uci->cpu_sig.sig = eax; + if (check_current_patch_level(&rev)) + return; eax = cpuid_eax(0x00000001); eq = (struct equiv_cpu_entry *)(container + CONTAINER_HDR_SZ); @@ -424,9 +420,10 @@ int __init save_microcode_in_initrd_amd(void) void reload_ucode_amd(void) { struct microcode_amd *mc; - u32 rev, eax; + u32 rev; - rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax); + if (check_current_patch_level(&rev)) + return; mc = (struct microcode_amd *)amd_ucode_patch; ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] x86/microcode/amd: Do not overwrite final patch levels 2015-07-16 8:05 [PATCH 0/2] tip-queue 2015-07-16 Borislav Petkov 2015-07-16 8:05 ` [PATCH 1/2] x86/microcode/amd: Extract current patch level read to a function Borislav Petkov @ 2015-07-16 8:05 ` Borislav Petkov 2015-07-21 9:40 ` [tip:x86/microcode] " tip-bot for Borislav Petkov 1 sibling, 1 reply; 5+ messages in thread From: Borislav Petkov @ 2015-07-16 8:05 UTC (permalink / raw) To: Ingo Molnar; +Cc: LKML 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. Signed-off-by: Borislav Petkov <bp@suse.de> Tested-by: Peter Kirchgeßner <pkirchgessner@t-online.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 59a36125bf7f..c7d2415b8a24 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; + + 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 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.5.0.rc2.28.g6003e7f ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [tip:x86/microcode] x86/microcode/amd: Do not overwrite final patch levels 2015-07-16 8:05 ` [PATCH 2/2] x86/microcode/amd: Do not overwrite final patch levels Borislav Petkov @ 2015-07-21 9:40 ` tip-bot for Borislav Petkov 0 siblings, 0 replies; 5+ messages in thread From: tip-bot for Borislav Petkov @ 2015-07-21 9:40 UTC (permalink / raw) To: linux-tip-commits Cc: mingo, torvalds, linux-kernel, hpa, peterz, bp, tglx, pkirchgessner Commit-ID: d48a9c164b45c5cc40f00c12231564f9aac8ab1d Gitweb: http://git.kernel.org/tip/d48a9c164b45c5cc40f00c12231564f9aac8ab1d Author: Borislav Petkov <bp@suse.de> AuthorDate: Thu, 16 Jul 2015 10:05:47 +0200 Committer: Ingo Molnar <mingo@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 <pkirchgessner@t-online.de> Signed-off-by: Borislav Petkov <bp@suse.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1437033947-30234-3-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar <mingo@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[] = { + 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; + + 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(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; ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-07-21 9:41 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-07-16 8:05 [PATCH 0/2] tip-queue 2015-07-16 Borislav Petkov 2015-07-16 8:05 ` [PATCH 1/2] x86/microcode/amd: Extract current patch level read to a function Borislav Petkov 2015-07-21 9:40 ` [tip:x86/microcode] " tip-bot for Borislav Petkov 2015-07-16 8:05 ` [PATCH 2/2] x86/microcode/amd: Do not overwrite final patch levels Borislav Petkov 2015-07-21 9:40 ` [tip:x86/microcode] " tip-bot for Borislav Petkov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox