aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2017-01-20 15:29:51 -0500
committerThomas Gleixner <tglx@linutronix.de>2017-01-23 04:02:50 -0500
commitf3ad136d6ef966c8ba9090770c2bfe7e85f18471 (patch)
tree0dc1ad8daeeff482ea918ecce926859a4432b182
parent7a93a40be23e5557934d773cc89b7b3627c08097 (diff)
x86/microcode/AMD: Check patch level only on the BSP
Check final patch levels for AMD only on the BSP. This way, we decide early and only once whether to continue loading or to leave the loader disabled on such systems. Simplify a lot. Signed-off-by: Borislav Petkov <bp@suse.de> Link: http://lkml.kernel.org/r/20170120202955.4091-13-bp@alien8.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/include/asm/microcode_amd.h2
-rw-r--r--arch/x86/kernel/cpu/microcode/amd.c78
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c41
3 files changed, 52 insertions, 69 deletions
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
index 3e3e20be829a..3d57009e168b 100644
--- a/arch/x86/include/asm/microcode_amd.h
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -54,6 +54,4 @@ static inline int __init
54save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; } 54save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
55void reload_ucode_amd(void) {} 55void reload_ucode_amd(void) {}
56#endif 56#endif
57
58extern bool check_current_patch_level(u32 *rev, bool early);
59#endif /* _ASM_X86_MICROCODE_AMD_H */ 57#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 7727f278de58..61743476c25b 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -207,7 +207,7 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size,
207 struct cont_desc desc = { 0 }; 207 struct cont_desc desc = { 0 };
208 u8 (*patch)[PATCH_MAX_SIZE]; 208 u8 (*patch)[PATCH_MAX_SIZE];
209 struct microcode_amd *mc; 209 struct microcode_amd *mc;
210 u32 rev, *new_rev; 210 u32 rev, dummy, *new_rev;
211 bool ret = false; 211 bool ret = false;
212 212
213#ifdef CONFIG_X86_32 213#ifdef CONFIG_X86_32
@@ -218,9 +218,6 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size,
218 patch = &amd_ucode_patch; 218 patch = &amd_ucode_patch;
219#endif 219#endif
220 220
221 if (check_current_patch_level(&rev, true))
222 return false;
223
224 desc.cpuid_1_eax = cpuid_1_eax; 221 desc.cpuid_1_eax = cpuid_1_eax;
225 222
226 scan_containers(ucode, size, &desc); 223 scan_containers(ucode, size, &desc);
@@ -231,6 +228,7 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size,
231 if (!mc) 228 if (!mc)
232 return ret; 229 return ret;
233 230
231 native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
234 if (rev >= mc->hdr.patch_id) 232 if (rev >= mc->hdr.patch_id)
235 return ret; 233 return ret;
236 234
@@ -328,13 +326,8 @@ void load_ucode_amd_ap(unsigned int cpuid_1_eax)
328{ 326{
329 struct equiv_cpu_entry *eq; 327 struct equiv_cpu_entry *eq;
330 struct microcode_amd *mc; 328 struct microcode_amd *mc;
331 u32 rev;
332 u16 eq_id; 329 u16 eq_id;
333 330
334 /* 64-bit runs with paging enabled, thus early==false. */
335 if (check_current_patch_level(&rev, false))
336 return;
337
338 /* First AP hasn't cached it yet, go through the blob. */ 331 /* First AP hasn't cached it yet, go through the blob. */
339 if (!cont.data) { 332 if (!cont.data) {
340 struct cpio_data cp; 333 struct cpio_data cp;
@@ -371,6 +364,10 @@ reget:
371 return; 364 return;
372 365
373 if (eq_id == cont.eq_id) { 366 if (eq_id == cont.eq_id) {
367 u32 rev, dummy;
368
369 native_rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
370
374 mc = (struct microcode_amd *)amd_ucode_patch; 371 mc = (struct microcode_amd *)amd_ucode_patch;
375 372
376 if (mc && rev < mc->hdr.patch_id) { 373 if (mc && rev < mc->hdr.patch_id) {
@@ -436,19 +433,14 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
436void reload_ucode_amd(void) 433void reload_ucode_amd(void)
437{ 434{
438 struct microcode_amd *mc; 435 struct microcode_amd *mc;
439 u32 rev; 436 u32 rev, dummy;
440
441 /*
442 * early==false because this is a syscore ->resume path and by
443 * that time paging is long enabled.
444 */
445 if (check_current_patch_level(&rev, false))
446 return;
447 437
448 mc = (struct microcode_amd *)amd_ucode_patch; 438 mc = (struct microcode_amd *)amd_ucode_patch;
449 if (!mc) 439 if (!mc)
450 return; 440 return;
451 441
442 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
443
452 if (rev < mc->hdr.patch_id) { 444 if (rev < mc->hdr.patch_id) {
453 if (!__apply_microcode_amd(mc)) { 445 if (!__apply_microcode_amd(mc)) {
454 ucode_new_rev = mc->hdr.patch_id; 446 ucode_new_rev = mc->hdr.patch_id;
@@ -586,60 +578,13 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size,
586 return patch_size; 578 return patch_size;
587} 579}
588 580
589/*
590 * Those patch levels cannot be updated to newer ones and thus should be final.
591 */
592static u32 final_levels[] = {
593 0x01000098,
594 0x0100009f,
595 0x010000af,
596 0, /* T-101 terminator */
597};
598
599/*
600 * Check the current patch level on this CPU.
601 *
602 * @rev: Use it to return the patch level. It is set to 0 in the case of
603 * error.
604 *
605 * Returns:
606 * - true: if update should stop
607 * - false: otherwise
608 */
609bool check_current_patch_level(u32 *rev, bool early)
610{
611 u32 lvl, dummy, i;
612 bool ret = false;
613 u32 *levels;
614
615 native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy);
616
617 if (IS_ENABLED(CONFIG_X86_32) && early)
618 levels = (u32 *)__pa_nodebug(&final_levels);
619 else
620 levels = final_levels;
621
622 for (i = 0; levels[i]; i++) {
623 if (lvl == levels[i]) {
624 lvl = 0;
625 ret = true;
626 break;
627 }
628 }
629
630 if (rev)
631 *rev = lvl;
632
633 return ret;
634}
635
636static int apply_microcode_amd(int cpu) 581static int apply_microcode_amd(int cpu)
637{ 582{
638 struct cpuinfo_x86 *c = &cpu_data(cpu); 583 struct cpuinfo_x86 *c = &cpu_data(cpu);
639 struct microcode_amd *mc_amd; 584 struct microcode_amd *mc_amd;
640 struct ucode_cpu_info *uci; 585 struct ucode_cpu_info *uci;
641 struct ucode_patch *p; 586 struct ucode_patch *p;
642 u32 rev; 587 u32 rev, dummy;
643 588
644 BUG_ON(raw_smp_processor_id() != cpu); 589 BUG_ON(raw_smp_processor_id() != cpu);
645 590
@@ -652,8 +597,7 @@ static int apply_microcode_amd(int cpu)
652 mc_amd = p->data; 597 mc_amd = p->data;
653 uci->mc = p->data; 598 uci->mc = p->data;
654 599
655 if (check_current_patch_level(&rev, false)) 600 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
656 return -1;
657 601
658 /* need to apply patch? */ 602 /* need to apply patch? */
659 if (rev >= mc_amd->hdr.patch_id) { 603 if (rev >= mc_amd->hdr.patch_id) {
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index dc54518299c4..3b74d2f315d3 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -69,6 +69,42 @@ struct cpu_info_ctx {
69 int err; 69 int err;
70}; 70};
71 71
72/*
73 * Those patch levels cannot be updated to newer ones and thus should be final.
74 */
75static u32 final_levels[] = {
76 0x01000098,
77 0x0100009f,
78 0x010000af,
79 0, /* T-101 terminator */
80};
81
82/*
83 * Check the current patch level on this CPU.
84 *
85 * Returns:
86 * - true: if update should stop
87 * - false: otherwise
88 */
89static bool amd_check_current_patch_level(void)
90{
91 u32 lvl, dummy, i;
92 u32 *levels;
93
94 native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy);
95
96 if (IS_ENABLED(CONFIG_X86_32))
97 levels = (u32 *)__pa_nodebug(&final_levels);
98 else
99 levels = final_levels;
100
101 for (i = 0; levels[i]; i++) {
102 if (lvl == levels[i])
103 return true;
104 }
105 return false;
106}
107
72static bool __init check_loader_disabled_bsp(void) 108static bool __init check_loader_disabled_bsp(void)
73{ 109{
74 static const char *__dis_opt_str = "dis_ucode_ldr"; 110 static const char *__dis_opt_str = "dis_ucode_ldr";
@@ -95,6 +131,11 @@ static bool __init check_loader_disabled_bsp(void)
95 if (native_cpuid_ecx(1) & BIT(31)) 131 if (native_cpuid_ecx(1) & BIT(31))
96 return *res; 132 return *res;
97 133
134 if (x86_cpuid_vendor() == X86_VENDOR_AMD) {
135 if (amd_check_current_patch_level())
136 return *res;
137 }
138
98 if (cmdline_find_option_bool(cmdline, option) <= 0) 139 if (cmdline_find_option_bool(cmdline, option) <= 0)
99 *res = false; 140 *res = false;
100 141