x86/microcode/intel: Save pointer to ucode patch for early AP loading
authorBorislav Petkov <bp@suse.de>
Wed, 14 Jun 2017 14:06:26 +0000 (16:06 +0200)
committerIngo Molnar <mingo@kernel.org>
Tue, 20 Jun 2017 10:54:25 +0000 (12:54 +0200)
Normally, when the initrd is gone, we can't search it for microcode
blobs to apply anymore. For that we need to stash away the patch in our
own storage.

And save_microcode_in_initrd_intel() looks like the proper place to
do that from. So in order for early loading to work, invalidate the
intel_ucode_patch pointer to the patch *before* scanning the initrd one
last time.

If the scanning code finds a microcode patch, it will assign that
pointer again, this time with our own storage's address.

This way, early microcode application during resume-from-RAM works too,
even after the initrd is long gone.

Tested-by: Dominik Brodowski <linux@dominikbrodowski.net>
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/20170614140626.4462-2-bp@alien8.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/kernel/cpu/microcode/intel.c

index f522415bf9e53690733250b31120d9d62d63a872..d525a0bd7d28ba7c2201b10f29a8a326ac3224f4 100644 (file)
@@ -166,7 +166,7 @@ static struct ucode_patch *__alloc_microcode_buf(void *data, unsigned int size)
 static void save_microcode_patch(void *data, unsigned int size)
 {
        struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
-       struct ucode_patch *iter, *tmp, *p;
+       struct ucode_patch *iter, *tmp, *p = NULL;
        bool prev_found = false;
        unsigned int sig, pf;
 
@@ -202,6 +202,18 @@ static void save_microcode_patch(void *data, unsigned int size)
                else
                        list_add_tail(&p->plist, &microcode_cache);
        }
+
+       /*
+        * Save for early loading. On 32-bit, that needs to be a physical
+        * address as the APs are running from physical addresses, before
+        * paging has been enabled.
+        */
+       if (p) {
+               if (IS_ENABLED(CONFIG_X86_32))
+                       intel_ucode_patch = (struct microcode_intel *)__pa_nodebug(p->data);
+               else
+                       intel_ucode_patch = p->data;
+       }
 }
 
 static int microcode_sanity_check(void *mc, int print_err)
@@ -607,6 +619,14 @@ int __init save_microcode_in_initrd_intel(void)
        struct ucode_cpu_info uci;
        struct cpio_data cp;
 
+       /*
+        * initrd is going away, clear patch ptr. We will scan the microcode one
+        * last time before jettisoning and save a patch, if found. Then we will
+        * update that pointer too, with a stable patch address to use when
+        * resuming the cores.
+        */
+       intel_ucode_patch = NULL;
+
        if (!load_builtin_intel_microcode(&cp))
                cp = find_microcode_in_initrd(ucode_path, false);
 
@@ -619,9 +639,6 @@ int __init save_microcode_in_initrd_intel(void)
 
        show_saved_mc();
 
-       /* initrd is going away, clear patch ptr. */
-       intel_ucode_patch = NULL;
-
        return 0;
 }