aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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