All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Xen-devel <xen-devel@lists.xenproject.org>
Cc: "Andrew Cooper" <andrew.cooper3@citrix.com>,
	"Jan Beulich" <JBeulich@suse.com>,
	"Roger Pau Monné" <roger.pau@citrix.com>, "Wei Liu" <wl@xen.org>,
	"Sergey Dyasli" <sergey.dyasli@citrix.com>
Subject: [PATCH 5/5] x86/ucode: Drop ucode_mod and ucode_blob
Date: Mon, 27 Mar 2023 20:41:26 +0100	[thread overview]
Message-ID: <20230327194126.3573997-6-andrew.cooper3@citrix.com> (raw)
In-Reply-To: <20230327194126.3573997-1-andrew.cooper3@citrix.com>

These both incorrectly cache bootstrap_map()'d pointers across returns back to
__start_xen().  This is never valid, and such pointers may fault, or point to
something unrelated.

With the refactoring work in the previous patches, they're clearly now just
non-standard function return parameters.

Rename struct ucode_mod_blob to just struct blob for breviy and because
there's nothing really ucode-specific about it.

Introduce find_microcode_blob(), to replace microcode_grab_module(), and
rework microcode_scan_module() so they both return a pointer/size tuple, and
don't cache their return values in global state.

This allows us to remove the microcode_init() initcall, the comments of which
gives the false impression that either of the cached pointers are safe to use.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Wei Liu <wl@xen.org>
CC: Sergey Dyasli <sergey.dyasli@citrix.com>
---
 xen/arch/x86/cpu/microcode/core.c | 154 +++++++++++++-----------------
 1 file changed, 68 insertions(+), 86 deletions(-)

diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c
index 7d32bc13db6f..0ae628ba99d4 100644
--- a/xen/arch/x86/cpu/microcode/core.c
+++ b/xen/arch/x86/cpu/microcode/core.c
@@ -55,7 +55,6 @@
  */
 #define MICROCODE_UPDATE_TIMEOUT_US 1000000
 
-static module_t __initdata ucode_mod;
 static signed int __initdata ucode_mod_idx;
 static bool_t __initdata ucode_mod_forced;
 static unsigned int nr_cores;
@@ -76,18 +75,11 @@ static enum {
     LOADING_EXIT,
 } loading_state;
 
-/*
- * If we scan the initramfs.cpio for the early microcode code
- * and find it, then 'ucode_blob' will contain the pointer
- * and the size of said blob. It is allocated from Xen's heap
- * memory.
- */
-struct ucode_mod_blob {
+struct blob {
     const void *data;
     size_t size;
 };
 
-static struct ucode_mod_blob __initdata ucode_blob;
 /*
  * By default we will NOT parse the multiboot modules to see if there is
  * cpio image with the microcode images.
@@ -148,7 +140,15 @@ static int __init cf_check parse_ucode(const char *s)
 }
 custom_param("ucode", parse_ucode);
 
-void __init microcode_scan_module(
+/*
+ * Scan all unclaimed modules, looking for a decompressed CPIO archive
+ * containing a microcode file according to the Linux early microcode API.
+ *
+ * Always caches the results, positive or negative.
+ *
+ * Returns a ptr/size tupe.  Either NULL/0, or a bootstrap_map()'d region.
+ */
+static struct blob __init microcode_scan_module(
     unsigned long *module_map,
     const multiboot_info_t *mbi)
 {
@@ -159,32 +159,35 @@ void __init microcode_scan_module(
     } scan;
 
     module_t *mod = (module_t *)__va(mbi->mods_addr);
+    struct blob blob = {};
     const char *p = NULL;
     int i;
 
-    ucode_blob.size = 0;
-
     if ( scan.mod_idx ) /* Previous scan was successful. */
     {
         void *map = bootstrap_map(&mod[scan.mod_idx]);
 
         if ( !map )
-            return;
+            return blob;
+
+        blob.size = scan.size;
+        blob.data = map + scan.offset;
 
-        ucode_blob.size = scan.size;
-        ucode_blob.data = map + scan.offset;
-        return;
+        return blob;
     }
 
     if ( !ucode_scan )
-        return;
+        return blob;
+
+    /* Only scan once, whatever the outcome. */
+    ucode_scan = false;
 
     if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
         p = "kernel/x86/microcode/AuthenticAMD.bin";
     else if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
         p = "kernel/x86/microcode/GenuineIntel.bin";
     else
-        return;
+        return blob;
 
     /*
      * Try all modules and see whichever could be the microcode blob.
@@ -214,30 +217,15 @@ void __init microcode_scan_module(
             scan.offset  = cd.data - _blob_start;
             scan.size    = cd.size;
 
-            ucode_blob.size = cd.size;
-            ucode_blob.data = cd.data;
+            blob.size = cd.size;
+            blob.data = cd.data;
             break;
         }
 
         bootstrap_map(NULL);
     }
-}
-
-static void __init microcode_grab_module(
-    unsigned long *module_map,
-    const multiboot_info_t *mbi)
-{
-    module_t *mod = (module_t *)__va(mbi->mods_addr);
 
-    if ( ucode_mod_idx < 0 )
-        ucode_mod_idx += mbi->mods_count;
-    if ( ucode_mod_idx <= 0 || ucode_mod_idx >= mbi->mods_count ||
-         !__test_and_clear_bit(ucode_mod_idx, module_map) )
-        goto scan;
-    ucode_mod = mod[ucode_mod_idx];
-scan:
-    if ( ucode_scan )
-        microcode_scan_module(module_map, mbi);
+    return blob;
 }
 
 static struct microcode_ops __ro_after_init ucode_ops;
@@ -746,28 +734,6 @@ int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
                                      microcode_update_helper, buffer);
 }
 
-static int __init cf_check microcode_init(void)
-{
-    /*
-     * At this point, all CPUs should have updated their microcode
-     * via the early_microcode_* paths so free the microcode blob.
-     */
-    if ( ucode_blob.size )
-    {
-        bootstrap_map(NULL);
-        ucode_blob.size = 0;
-        ucode_blob.data = NULL;
-    }
-    else if ( ucode_mod.mod_end )
-    {
-        bootstrap_map(NULL);
-        ucode_mod.mod_end = 0;
-    }
-
-    return 0;
-}
-__initcall(microcode_init);
-
 /* Load a cached update to current cpu */
 int microcode_update_one(void)
 {
@@ -779,26 +745,53 @@ int microcode_update_one(void)
     return microcode_update_cpu(NULL);
 }
 
+/*
+ * Find microcode within the boot modules provided.
+ *
+ * This is called twice on boot, once very early to find the BSP microcode,
+ * and a second time in order to initalise the cache once we've set up the
+ * heap to use.
+ *
+ * Returns a ptr/size tuple, either NULL/0 or a bootstrap_map()'d region.
+ */
+static struct blob __init find_microcode_blob(
+    unsigned long *module_map, const multiboot_info_t *mbi)
+{
+    struct blob blob = {};
+
+    if ( ucode_mod_idx != 0 )
+    {
+        module_t *mod = __va(mbi->mods_addr);
+
+        /* Adjust to support negative backreferences. */
+        if ( ucode_mod_idx < 0 )
+            ucode_mod_idx += mbi->mods_count;
+
+        if ( ucode_mod_idx > 0 &&
+             ucode_mod_idx < mbi->mods_count &&
+             __test_and_clear_bit(ucode_mod_idx, module_map) )
+        {
+            mod += ucode_mod_idx;
+
+            blob.data = bootstrap_map(mod);
+            blob.size = mod->mod_end;
+
+            return blob;
+        }
+
+        /* Still not valid.  Ignore it next time around. */
+        ucode_mod_idx = 0;
+    }
+
+    return microcode_scan_module(module_map, mbi);
+}
+
 int __init microcode_init_cache(unsigned long *module_map,
                                 const struct multiboot_info *mbi)
 {
     int rc = 0;
     struct microcode_patch *patch;
-    struct ucode_mod_blob blob = {};
-
-    if ( ucode_scan )
-        /* Need to rescan the modules because they might have been relocated */
-        microcode_scan_module(module_map, mbi);
-
-    if ( ucode_mod.mod_end )
-    {
-        blob.data = bootstrap_map(&ucode_mod);
-        blob.size = ucode_mod.mod_end;
-    }
-    else if ( ucode_blob.size )
-    {
-        blob = ucode_blob;
-    }
+    struct blob blob = find_microcode_blob(module_map, mbi);
 
     if ( !blob.data )
         return 0;
@@ -833,7 +826,7 @@ int __init early_microcode_init(unsigned long *module_map,
 {
     const struct cpuinfo_x86 *c = &boot_cpu_data;
     struct microcode_patch *patch;
-    struct ucode_mod_blob blob = {};
+    struct blob blob = {};
     int rc = 0;
 
     switch ( c->x86_vendor )
@@ -855,20 +848,9 @@ int __init early_microcode_init(unsigned long *module_map,
         return -ENODEV;
     }
 
-    microcode_grab_module(module_map, mbi);
-
     ucode_ops.collect_cpu_info();
 
-    if ( ucode_blob.data )
-    {
-        blob = ucode_blob;
-    }
-    else if ( ucode_mod.mod_end )
-    {
-        blob.data = bootstrap_map(&ucode_mod);
-        blob.size = ucode_mod.mod_end;
-    }
-
+    blob = find_microcode_blob(module_map, mbi);
     if ( !blob.data )
         return 0;
 
-- 
2.30.2



  parent reply	other threads:[~2023-03-27 19:42 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-27 19:41 [PATCH 0/5] x86/ucode: Fixes to bootstrap_map() handling Andrew Cooper
2023-03-27 19:41 ` [PATCH 1/5] xen/earlycpio: Drop nextoff parameter Andrew Cooper
2023-03-28 13:38   ` Jan Beulich
2023-03-27 19:41 ` [PATCH 2/5] x86/ucode: Fold early_update_cache() into microcode_init_cache() Andrew Cooper
2023-03-28 13:51   ` Jan Beulich
2023-03-28 15:07     ` Andrew Cooper
2023-03-28 15:57       ` Jan Beulich
2023-03-29  9:13         ` George Dunlap
2023-03-29  9:26           ` Jan Beulich
2023-03-29  7:41       ` Jan Beulich
2023-03-27 19:41 ` [PATCH 3/5] x86/ucode: Fold early_microcode_update_cpu() into early_microcode_init() Andrew Cooper
2023-03-28 14:06   ` Jan Beulich
2023-03-28 15:11     ` Andrew Cooper
2023-03-28 15:59       ` Jan Beulich
2023-03-27 19:41 ` [PATCH 4/5] x86/ucode: Cache results in microcode_scan_module() Andrew Cooper
2023-03-28 14:19   ` Jan Beulich
2023-03-28 15:12     ` Andrew Cooper
2023-03-28 16:01       ` Jan Beulich
2023-03-28 16:07         ` Andrew Cooper
2023-03-29  7:23           ` Jan Beulich
2023-03-27 19:41 ` Andrew Cooper [this message]
2023-03-28 14:28   ` [PATCH 5/5] x86/ucode: Drop ucode_mod and ucode_blob Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230327194126.3573997-6-andrew.cooper3@citrix.com \
    --to=andrew.cooper3@citrix.com \
    --cc=JBeulich@suse.com \
    --cc=roger.pau@citrix.com \
    --cc=sergey.dyasli@citrix.com \
    --cc=wl@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.