aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2014-12-03 11:21:41 -0500
committerBorislav Petkov <bp@suse.de>2014-12-06 07:03:03 -0500
commitfbae4ba8c4a387e306adc9c710e5c225cece7678 (patch)
tree661e543af2cab13c77b21519d49534e51e319fbd /arch
parenta18a0f6850d4b286a5ebf02cd5b22fe496b86349 (diff)
x86, microcode: Reload microcode on resume
Normally, we do reapply microcode on resume. However, in the cases where that microcode comes from the early loader and the late loader hasn't been utilized yet, there's no easy way for us to go and apply the patch applied during boot by the early loader. Thus, reuse the patch stashed by the early loader for the BSP. Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/microcode.h2
-rw-r--r--arch/x86/include/asm/microcode_amd.h2
-rw-r--r--arch/x86/include/asm/microcode_intel.h2
-rw-r--r--arch/x86/kernel/cpu/microcode/amd_early.c18
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c8
-rw-r--r--arch/x86/kernel/cpu/microcode/core_early.c21
-rw-r--r--arch/x86/kernel/cpu/microcode/intel_early.c47
7 files changed, 84 insertions, 16 deletions
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 64dc362506b7..201b520521ed 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -78,6 +78,7 @@ static inline void __exit exit_amd_microcode(void) {}
78extern void __init load_ucode_bsp(void); 78extern void __init load_ucode_bsp(void);
79extern void load_ucode_ap(void); 79extern void load_ucode_ap(void);
80extern int __init save_microcode_in_initrd(void); 80extern int __init save_microcode_in_initrd(void);
81void reload_early_microcode(void);
81#else 82#else
82static inline void __init load_ucode_bsp(void) {} 83static inline void __init load_ucode_bsp(void) {}
83static inline void load_ucode_ap(void) {} 84static inline void load_ucode_ap(void) {}
@@ -85,6 +86,7 @@ static inline int __init save_microcode_in_initrd(void)
85{ 86{
86 return 0; 87 return 0;
87} 88}
89static inline void reload_early_microcode(void) {}
88#endif 90#endif
89 91
90#endif /* _ASM_X86_MICROCODE_H */ 92#endif /* _ASM_X86_MICROCODE_H */
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
index 48a48024ebe4..af935397e053 100644
--- a/arch/x86/include/asm/microcode_amd.h
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -68,10 +68,12 @@ extern u8 amd_ucode_patch[PATCH_MAX_SIZE];
68extern void __init load_ucode_amd_bsp(void); 68extern void __init load_ucode_amd_bsp(void);
69extern void load_ucode_amd_ap(void); 69extern void load_ucode_amd_ap(void);
70extern int __init save_microcode_in_initrd_amd(void); 70extern int __init save_microcode_in_initrd_amd(void);
71void reload_ucode_amd(void);
71#else 72#else
72static inline void __init load_ucode_amd_bsp(void) {} 73static inline void __init load_ucode_amd_bsp(void) {}
73static inline void load_ucode_amd_ap(void) {} 74static inline void load_ucode_amd_ap(void) {}
74static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; } 75static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; }
76void reload_ucode_amd(void) {}
75#endif 77#endif
76 78
77#endif /* _ASM_X86_MICROCODE_AMD_H */ 79#endif /* _ASM_X86_MICROCODE_AMD_H */
diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h
index bbe296e0bce1..dd4c20043ce7 100644
--- a/arch/x86/include/asm/microcode_intel.h
+++ b/arch/x86/include/asm/microcode_intel.h
@@ -68,11 +68,13 @@ extern void __init load_ucode_intel_bsp(void);
68extern void load_ucode_intel_ap(void); 68extern void load_ucode_intel_ap(void);
69extern void show_ucode_info_early(void); 69extern void show_ucode_info_early(void);
70extern int __init save_microcode_in_initrd_intel(void); 70extern int __init save_microcode_in_initrd_intel(void);
71void reload_ucode_intel(void);
71#else 72#else
72static inline __init void load_ucode_intel_bsp(void) {} 73static inline __init void load_ucode_intel_bsp(void) {}
73static inline void load_ucode_intel_ap(void) {} 74static inline void load_ucode_intel_ap(void) {}
74static inline void show_ucode_info_early(void) {} 75static inline void show_ucode_info_early(void) {}
75static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; } 76static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; }
77static inline void reload_ucode_intel(void) {}
76#endif 78#endif
77 79
78#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU) 80#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c
index 3d988a30a21d..737737edbd1e 100644
--- a/arch/x86/kernel/cpu/microcode/amd_early.c
+++ b/arch/x86/kernel/cpu/microcode/amd_early.c
@@ -402,3 +402,21 @@ int __init save_microcode_in_initrd_amd(void)
402 402
403 return retval; 403 return retval;
404} 404}
405
406void reload_ucode_amd(void)
407{
408 struct microcode_amd *mc;
409 u32 rev, eax;
410
411 rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
412
413 mc = (struct microcode_amd *)amd_ucode_patch;
414
415 if (mc && rev < mc->hdr.patch_id) {
416 if (!__apply_microcode_amd(mc)) {
417 ucode_new_rev = mc->hdr.patch_id;
418 pr_info("microcode: reload patch_level=0x%08x\n",
419 ucode_new_rev);
420 }
421 }
422}
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index ebd232d7de4d..15c29096136b 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -466,13 +466,7 @@ static void mc_bp_resume(void)
466 if (uci->valid && uci->mc) 466 if (uci->valid && uci->mc)
467 microcode_ops->apply_microcode(cpu); 467 microcode_ops->apply_microcode(cpu);
468 else if (!uci->mc) 468 else if (!uci->mc)
469 /* 469 reload_early_microcode();
470 * We might resume and not have applied late microcode but still
471 * have a newer patch stashed from the early loader. We don't
472 * have it in uci->mc so we have to load it the same way we're
473 * applying patches early on the APs.
474 */
475 load_ucode_ap();
476} 470}
477 471
478static struct syscore_ops mc_syscore_ops = { 472static struct syscore_ops mc_syscore_ops = {
diff --git a/arch/x86/kernel/cpu/microcode/core_early.c b/arch/x86/kernel/cpu/microcode/core_early.c
index 2c017f242a78..d45df4bd16ab 100644
--- a/arch/x86/kernel/cpu/microcode/core_early.c
+++ b/arch/x86/kernel/cpu/microcode/core_early.c
@@ -176,3 +176,24 @@ int __init save_microcode_in_initrd(void)
176 176
177 return 0; 177 return 0;
178} 178}
179
180void reload_early_microcode(void)
181{
182 int vendor, x86;
183
184 vendor = x86_vendor();
185 x86 = x86_family();
186
187 switch (vendor) {
188 case X86_VENDOR_INTEL:
189 if (x86 >= 6)
190 reload_ucode_intel();
191 break;
192 case X86_VENDOR_AMD:
193 if (x86 >= 0x10)
194 reload_ucode_amd();
195 break;
196 default:
197 break;
198 }
199}
diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c
index 31e7576a123c..f04d0d6638ca 100644
--- a/arch/x86/kernel/cpu/microcode/intel_early.c
+++ b/arch/x86/kernel/cpu/microcode/intel_early.c
@@ -34,6 +34,8 @@ static struct mc_saved_data {
34 struct microcode_intel **mc_saved; 34 struct microcode_intel **mc_saved;
35} mc_saved_data; 35} mc_saved_data;
36 36
37static struct microcode_intel bsp_patch;
38
37static enum ucode_state 39static enum ucode_state
38generic_load_microcode_early(struct microcode_intel **mc_saved_p, 40generic_load_microcode_early(struct microcode_intel **mc_saved_p,
39 unsigned int mc_saved_count, 41 unsigned int mc_saved_count,
@@ -650,7 +652,7 @@ static inline void print_ucode(struct ucode_cpu_info *uci)
650} 652}
651#endif 653#endif
652 654
653static int apply_microcode_early(struct ucode_cpu_info *uci) 655static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
654{ 656{
655 struct microcode_intel *mc_intel; 657 struct microcode_intel *mc_intel;
656 unsigned int val[2]; 658 unsigned int val[2];
@@ -679,7 +681,10 @@ static int apply_microcode_early(struct ucode_cpu_info *uci)
679#endif 681#endif
680 uci->cpu_sig.rev = val[1]; 682 uci->cpu_sig.rev = val[1];
681 683
682 print_ucode(uci); 684 if (early)
685 print_ucode(uci);
686 else
687 print_ucode_info(uci, mc_intel->hdr.date);
683 688
684 return 0; 689 return 0;
685} 690}
@@ -712,14 +717,22 @@ _load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data,
712 unsigned long *mc_saved_in_initrd, 717 unsigned long *mc_saved_in_initrd,
713 unsigned long initrd_start_early, 718 unsigned long initrd_start_early,
714 unsigned long initrd_end_early, 719 unsigned long initrd_end_early,
715 struct ucode_cpu_info *uci) 720 struct ucode_cpu_info *uci,
721 struct microcode_intel *bsp)
716{ 722{
723 enum ucode_state ret;
724
717 collect_cpu_info_early(uci); 725 collect_cpu_info_early(uci);
718 scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data, 726 scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data,
719 mc_saved_in_initrd, uci); 727 mc_saved_in_initrd, uci);
720 load_microcode(mc_saved_data, mc_saved_in_initrd, 728
721 initrd_start_early, uci); 729 ret = load_microcode(mc_saved_data, mc_saved_in_initrd,
722 apply_microcode_early(uci); 730 initrd_start_early, uci);
731
732 if (ret == UCODE_OK) {
733 apply_microcode_early(uci, true);
734 memcpy(bsp, uci->mc, sizeof(*bsp));
735 }
723} 736}
724 737
725void __init 738void __init
@@ -728,10 +741,12 @@ load_ucode_intel_bsp(void)
728 u64 ramdisk_image, ramdisk_size; 741 u64 ramdisk_image, ramdisk_size;
729 unsigned long initrd_start_early, initrd_end_early; 742 unsigned long initrd_start_early, initrd_end_early;
730 struct ucode_cpu_info uci; 743 struct ucode_cpu_info uci;
744 struct microcode_intel *bsp_p;
731#ifdef CONFIG_X86_32 745#ifdef CONFIG_X86_32
732 struct boot_params *boot_params_p; 746 struct boot_params *boot_params_p;
733 747
734 boot_params_p = (struct boot_params *)__pa_nodebug(&boot_params); 748 boot_params_p = (struct boot_params *)__pa_nodebug(&boot_params);
749 bsp_p = (struct microcode_intel *)__pa_nodebug(&bsp_patch);
735 ramdisk_image = boot_params_p->hdr.ramdisk_image; 750 ramdisk_image = boot_params_p->hdr.ramdisk_image;
736 ramdisk_size = boot_params_p->hdr.ramdisk_size; 751 ramdisk_size = boot_params_p->hdr.ramdisk_size;
737 initrd_start_early = ramdisk_image; 752 initrd_start_early = ramdisk_image;
@@ -740,15 +755,17 @@ load_ucode_intel_bsp(void)
740 _load_ucode_intel_bsp( 755 _load_ucode_intel_bsp(
741 (struct mc_saved_data *)__pa_nodebug(&mc_saved_data), 756 (struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
742 (unsigned long *)__pa_nodebug(&mc_saved_in_initrd), 757 (unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
743 initrd_start_early, initrd_end_early, &uci); 758 initrd_start_early, initrd_end_early, &uci, bsp_p);
744#else 759#else
760 bsp_p = &bsp_patch;
745 ramdisk_image = boot_params.hdr.ramdisk_image; 761 ramdisk_image = boot_params.hdr.ramdisk_image;
746 ramdisk_size = boot_params.hdr.ramdisk_size; 762 ramdisk_size = boot_params.hdr.ramdisk_size;
747 initrd_start_early = ramdisk_image + PAGE_OFFSET; 763 initrd_start_early = ramdisk_image + PAGE_OFFSET;
748 initrd_end_early = initrd_start_early + ramdisk_size; 764 initrd_end_early = initrd_start_early + ramdisk_size;
749 765
750 _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd, 766 _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd,
751 initrd_start_early, initrd_end_early, &uci); 767 initrd_start_early, initrd_end_early,
768 &uci, bsp_p);
752#endif 769#endif
753} 770}
754 771
@@ -782,5 +799,17 @@ void load_ucode_intel_ap(void)
782 collect_cpu_info_early(&uci); 799 collect_cpu_info_early(&uci);
783 load_microcode(mc_saved_data_p, mc_saved_in_initrd_p, 800 load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
784 initrd_start_addr, &uci); 801 initrd_start_addr, &uci);
785 apply_microcode_early(&uci); 802 apply_microcode_early(&uci, true);
803}
804
805void reload_ucode_intel(void)
806{
807 struct ucode_cpu_info uci;
808
809 if (!bsp_patch.hdr.rev)
810 return;
811
812 uci.mc = &bsp_patch;
813
814 apply_microcode_early(&uci, false);
786} 815}