x86, microcode: Reload microcode on resume
authorBorislav Petkov <bp@suse.de>
Wed, 3 Dec 2014 16:21:41 +0000 (17:21 +0100)
committerBorislav Petkov <bp@suse.de>
Sat, 6 Dec 2014 12:03:03 +0000 (13:03 +0100)
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>
arch/x86/include/asm/microcode.h
arch/x86/include/asm/microcode_amd.h
arch/x86/include/asm/microcode_intel.h
arch/x86/kernel/cpu/microcode/amd_early.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/microcode/core_early.c
arch/x86/kernel/cpu/microcode/intel_early.c

index 64dc362506b789ca3ea9986669e111da2d9ccea8..201b520521ed74b6e35b63cda531ae58f75ec674 100644 (file)
@@ -78,6 +78,7 @@ static inline void __exit exit_amd_microcode(void) {}
 extern void __init load_ucode_bsp(void);
 extern void load_ucode_ap(void);
 extern int __init save_microcode_in_initrd(void);
+void reload_early_microcode(void);
 #else
 static inline void __init load_ucode_bsp(void) {}
 static inline void load_ucode_ap(void) {}
@@ -85,6 +86,7 @@ static inline int __init save_microcode_in_initrd(void)
 {
        return 0;
 }
+static inline void reload_early_microcode(void) {}
 #endif
 
 #endif /* _ASM_X86_MICROCODE_H */
index 48a48024ebe45ff2db7d393b539b80c4eac7d828..af935397e053e4a504daed8c14cfc06686a08794 100644 (file)
@@ -68,10 +68,12 @@ extern u8 amd_ucode_patch[PATCH_MAX_SIZE];
 extern void __init load_ucode_amd_bsp(void);
 extern void load_ucode_amd_ap(void);
 extern int __init save_microcode_in_initrd_amd(void);
+void reload_ucode_amd(void);
 #else
 static inline void __init load_ucode_amd_bsp(void) {}
 static inline void load_ucode_amd_ap(void) {}
 static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; }
+void reload_ucode_amd(void) {}
 #endif
 
 #endif /* _ASM_X86_MICROCODE_AMD_H */
index bbe296e0bce1995ca8f9324b801ef09714e6399c..dd4c20043ce75be7545e963dd98ba38ce662396e 100644 (file)
@@ -68,11 +68,13 @@ extern void __init load_ucode_intel_bsp(void);
 extern void load_ucode_intel_ap(void);
 extern void show_ucode_info_early(void);
 extern int __init save_microcode_in_initrd_intel(void);
+void reload_ucode_intel(void);
 #else
 static inline __init void load_ucode_intel_bsp(void) {}
 static inline void load_ucode_intel_ap(void) {}
 static inline void show_ucode_info_early(void) {}
 static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; }
+static inline void reload_ucode_intel(void) {}
 #endif
 
 #if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
index 3d988a30a21d13d02ceb1e709fe9ea7862c8a072..737737edbd1ef5bbc478cf2b6f898f25c231ea81 100644 (file)
@@ -402,3 +402,21 @@ int __init save_microcode_in_initrd_amd(void)
 
        return retval;
 }
+
+void reload_ucode_amd(void)
+{
+       struct microcode_amd *mc;
+       u32 rev, eax;
+
+       rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
+
+       mc = (struct microcode_amd *)amd_ucode_patch;
+
+       if (mc && rev < mc->hdr.patch_id) {
+               if (!__apply_microcode_amd(mc)) {
+                       ucode_new_rev = mc->hdr.patch_id;
+                       pr_info("microcode: reload patch_level=0x%08x\n",
+                               ucode_new_rev);
+               }
+       }
+}
index ebd232d7de4db26e5b84f9f57a887586fd166ba0..15c29096136ba5e071c213d1412004740aa1f459 100644 (file)
@@ -466,13 +466,7 @@ static void mc_bp_resume(void)
        if (uci->valid && uci->mc)
                microcode_ops->apply_microcode(cpu);
        else if (!uci->mc)
-               /*
-                * We might resume and not have applied late microcode but still
-                * have a newer patch stashed from the early loader. We don't
-                * have it in uci->mc so we have to load it the same way we're
-                * applying patches early on the APs.
-                */
-               load_ucode_ap();
+               reload_early_microcode();
 }
 
 static struct syscore_ops mc_syscore_ops = {
index 2c017f242a78144ba18499f52aa5ca0c069aa880..d45df4bd16abec23e9725132ab2f9e649237f564 100644 (file)
@@ -176,3 +176,24 @@ int __init save_microcode_in_initrd(void)
 
        return 0;
 }
+
+void reload_early_microcode(void)
+{
+       int vendor, x86;
+
+       vendor = x86_vendor();
+       x86 = x86_family();
+
+       switch (vendor) {
+       case X86_VENDOR_INTEL:
+               if (x86 >= 6)
+                       reload_ucode_intel();
+               break;
+       case X86_VENDOR_AMD:
+               if (x86 >= 0x10)
+                       reload_ucode_amd();
+               break;
+       default:
+               break;
+       }
+}
index 31e7576a123cfa4e14f43a48c70ac0c2d4c03583..f04d0d6638cad1120e00124992260f7b36377f19 100644 (file)
@@ -34,6 +34,8 @@ static struct mc_saved_data {
        struct microcode_intel **mc_saved;
 } mc_saved_data;
 
+static struct microcode_intel bsp_patch;
+
 static enum ucode_state
 generic_load_microcode_early(struct microcode_intel **mc_saved_p,
                             unsigned int mc_saved_count,
@@ -650,7 +652,7 @@ static inline void print_ucode(struct ucode_cpu_info *uci)
 }
 #endif
 
-static int apply_microcode_early(struct ucode_cpu_info *uci)
+static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
 {
        struct microcode_intel *mc_intel;
        unsigned int val[2];
@@ -679,7 +681,10 @@ static int apply_microcode_early(struct ucode_cpu_info *uci)
 #endif
        uci->cpu_sig.rev = val[1];
 
-       print_ucode(uci);
+       if (early)
+               print_ucode(uci);
+       else
+               print_ucode_info(uci, mc_intel->hdr.date);
 
        return 0;
 }
@@ -712,14 +717,22 @@ _load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data,
                      unsigned long *mc_saved_in_initrd,
                      unsigned long initrd_start_early,
                      unsigned long initrd_end_early,
-                     struct ucode_cpu_info *uci)
+                     struct ucode_cpu_info *uci,
+                     struct microcode_intel *bsp)
 {
+       enum ucode_state ret;
+
        collect_cpu_info_early(uci);
        scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data,
                       mc_saved_in_initrd, uci);
-       load_microcode(mc_saved_data, mc_saved_in_initrd,
-                      initrd_start_early, uci);
-       apply_microcode_early(uci);
+
+       ret = load_microcode(mc_saved_data, mc_saved_in_initrd,
+                            initrd_start_early, uci);
+
+       if (ret == UCODE_OK) {
+               apply_microcode_early(uci, true);
+               memcpy(bsp, uci->mc, sizeof(*bsp));
+       }
 }
 
 void __init
@@ -728,10 +741,12 @@ load_ucode_intel_bsp(void)
        u64 ramdisk_image, ramdisk_size;
        unsigned long initrd_start_early, initrd_end_early;
        struct ucode_cpu_info uci;
+       struct microcode_intel *bsp_p;
 #ifdef CONFIG_X86_32
        struct boot_params *boot_params_p;
 
        boot_params_p = (struct boot_params *)__pa_nodebug(&boot_params);
+       bsp_p         = (struct microcode_intel *)__pa_nodebug(&bsp_patch);
        ramdisk_image = boot_params_p->hdr.ramdisk_image;
        ramdisk_size  = boot_params_p->hdr.ramdisk_size;
        initrd_start_early = ramdisk_image;
@@ -740,15 +755,17 @@ load_ucode_intel_bsp(void)
        _load_ucode_intel_bsp(
                (struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
                (unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
-               initrd_start_early, initrd_end_early, &uci);
+               initrd_start_early, initrd_end_early, &uci, bsp_p);
 #else
+       bsp_p         = &bsp_patch;
        ramdisk_image = boot_params.hdr.ramdisk_image;
        ramdisk_size  = boot_params.hdr.ramdisk_size;
        initrd_start_early = ramdisk_image + PAGE_OFFSET;
        initrd_end_early = initrd_start_early + ramdisk_size;
 
        _load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd,
-                             initrd_start_early, initrd_end_early, &uci);
+                             initrd_start_early, initrd_end_early,
+                             &uci, bsp_p);
 #endif
 }
 
@@ -782,5 +799,17 @@ void load_ucode_intel_ap(void)
        collect_cpu_info_early(&uci);
        load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
                       initrd_start_addr, &uci);
-       apply_microcode_early(&uci);
+       apply_microcode_early(&uci, true);
+}
+
+void reload_ucode_intel(void)
+{
+       struct ucode_cpu_info uci;
+
+       if (!bsp_patch.hdr.rev)
+               return;
+
+       uci.mc = &bsp_patch;
+
+       apply_microcode_early(&uci, false);
 }