x86/microcode/intel: Rip out mixed stepping support for Intel CPUs
authorAshok Raj <ashok.raj@intel.com>
Tue, 17 Oct 2023 21:23:33 +0000 (23:23 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Thu, 19 Oct 2023 10:29:39 +0000 (12:29 +0200)
Mixed steppings aren't supported on Intel CPUs. Only one microcode patch
is required for the entire system. The caching of microcode blobs which
match the family and model is therefore pointless and in fact is
dysfunctional as CPU hotplug updates use only a single microcode blob,
i.e. the one where *intel_ucode_patch points to.

Remove the microcode cache and make it an AMD local feature.

  [ tglx:
     - save only at the end. Otherwise random microcode ends up in the
     pointer for early loading
     - free the ucode patch pointer in save_microcode_patch() only
    after kmemdup() has succeeded, as reported by Andrew Cooper ]

Originally-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20231017211722.404362809@linutronix.de
arch/x86/kernel/cpu/microcode/amd.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/cpu/microcode/internal.h

index adb2cc9e959d8c244d71b9ff13f14f89c5bd175c..b827390a0abaf401c171bcbbb2ef9ee6ab56468a 100644 (file)
 
 #include "internal.h"
 
+struct ucode_patch {
+       struct list_head plist;
+       void *data;
+       unsigned int size;
+       u32 patch_id;
+       u16 equiv_cpu;
+};
+
+static LIST_HEAD(microcode_cache);
+
 #define UCODE_MAGIC                    0x00414d44
 #define UCODE_EQUIV_CPU_TABLE_TYPE     0x00000000
 #define UCODE_UCODE_TYPE               0x00000001
index f669e62cabb90e48190872d5836131ce763b5f93..a46df14475e9d9ce6fcf242e43f31a2be1807889 100644 (file)
@@ -46,8 +46,6 @@ static bool dis_ucode_ldr = true;
 
 bool initrd_gone;
 
-LIST_HEAD(microcode_cache);
-
 /*
  * Synchronization.
  *
index 24a5c8b594c6fbc12a536e52af16a785cf002e34..03a55bfa88c57c21ad37fa41bd86b462e6b20086 100644 (file)
 static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
 
 /* Current microcode patch used in early patching on the APs. */
-static struct microcode_intel *intel_ucode_patch;
+static struct microcode_intel *intel_ucode_patch __read_mostly;
 
 /* last level cache size per core */
-static int llc_size_per_core;
+static int llc_size_per_core __ro_after_init;
 
 /* microcode format is extended from prescott processors */
 struct extended_signature {
@@ -253,74 +253,17 @@ static int has_newer_microcode(void *mc, unsigned int csig, int cpf, int new_rev
        return intel_find_matching_signature(mc, csig, cpf);
 }
 
-static struct ucode_patch *memdup_patch(void *data, unsigned int size)
+static void save_microcode_patch(void *data, unsigned int size)
 {
-       struct ucode_patch *p;
-
-       p = kzalloc(sizeof(struct ucode_patch), GFP_KERNEL);
-       if (!p)
-               return NULL;
-
-       p->data = kmemdup(data, size, GFP_KERNEL);
-       if (!p->data) {
-               kfree(p);
-               return NULL;
-       }
-
-       return p;
-}
-
-static void save_microcode_patch(struct ucode_cpu_info *uci, void *data, unsigned int size)
-{
-       struct microcode_header_intel *mc_hdr, *mc_saved_hdr;
-       struct ucode_patch *iter, *tmp, *p = NULL;
-       bool prev_found = false;
-       unsigned int sig, pf;
-
-       mc_hdr = (struct microcode_header_intel *)data;
-
-       list_for_each_entry_safe(iter, tmp, &microcode_cache, plist) {
-               mc_saved_hdr = (struct microcode_header_intel *)iter->data;
-               sig          = mc_saved_hdr->sig;
-               pf           = mc_saved_hdr->pf;
-
-               if (intel_find_matching_signature(data, sig, pf)) {
-                       prev_found = true;
-
-                       if (mc_hdr->rev <= mc_saved_hdr->rev)
-                               continue;
-
-                       p = memdup_patch(data, size);
-                       if (!p)
-                               pr_err("Error allocating buffer %p\n", data);
-                       else {
-                               list_replace(&iter->plist, &p->plist);
-                               kfree(iter->data);
-                               kfree(iter);
-                       }
-               }
-       }
-
-       /*
-        * There weren't any previous patches found in the list cache; save the
-        * newly found.
-        */
-       if (!prev_found) {
-               p = memdup_patch(data, size);
-               if (!p)
-                       pr_err("Error allocating buffer for %p\n", data);
-               else
-                       list_add_tail(&p->plist, &microcode_cache);
-       }
+       struct microcode_header_intel *p;
 
+       p = kmemdup(data, size, GFP_KERNEL);
        if (!p)
                return;
 
-       if (!intel_find_matching_signature(p->data, uci->cpu_sig.sig, uci->cpu_sig.pf))
-               return;
-
+       kfree(intel_ucode_patch);
        /* Save for early loading */
-       intel_ucode_patch = p->data;
+       intel_ucode_patch = (struct microcode_intel *)p;
 }
 
 /*
@@ -332,6 +275,7 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
 {
        struct microcode_header_intel *mc_header;
        struct microcode_intel *patch = NULL;
+       u32 cur_rev = uci->cpu_sig.rev;
        unsigned int mc_size;
 
        while (size) {
@@ -341,8 +285,7 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
                mc_header = (struct microcode_header_intel *)data;
 
                mc_size = get_totalsize(mc_header);
-               if (!mc_size ||
-                   mc_size > size ||
+               if (!mc_size || mc_size > size ||
                    intel_microcode_sanity_check(data, false, MC_HEADER_TYPE_MICROCODE) < 0)
                        break;
 
@@ -354,31 +297,16 @@ scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, bool save)
                        continue;
                }
 
-               if (save) {
-                       save_microcode_patch(uci, data, mc_size);
+               /* BSP scan: Check whether there is newer microcode */
+               if (!save && cur_rev >= mc_header->rev)
                        goto next;
-               }
-
-
-               if (!patch) {
-                       if (!has_newer_microcode(data,
-                                                uci->cpu_sig.sig,
-                                                uci->cpu_sig.pf,
-                                                uci->cpu_sig.rev))
-                               goto next;
 
-               } else {
-                       struct microcode_header_intel *phdr = &patch->hdr;
-
-                       if (!has_newer_microcode(data,
-                                                phdr->sig,
-                                                phdr->pf,
-                                                phdr->rev))
-                               goto next;
-               }
+               /* Save scan: Check whether there is newer or matching microcode */
+               if (save && cur_rev != mc_header->rev)
+                       goto next;
 
-               /* We have a newer patch, save it. */
                patch = data;
+               cur_rev = mc_header->rev;
 
 next:
                data += mc_size;
@@ -387,6 +315,9 @@ next:
        if (size)
                return NULL;
 
+       if (save && patch)
+               save_microcode_patch(patch, mc_size);
+
        return patch;
 }
 
@@ -528,26 +459,10 @@ void load_ucode_intel_ap(void)
        apply_microcode_early(&uci);
 }
 
-static struct microcode_intel *find_patch(struct ucode_cpu_info *uci)
+/* Accessor for microcode pointer */
+static struct microcode_intel *ucode_get_patch(void)
 {
-       struct microcode_header_intel *phdr;
-       struct ucode_patch *iter, *tmp;
-
-       list_for_each_entry_safe(iter, tmp, &microcode_cache, plist) {
-
-               phdr = (struct microcode_header_intel *)iter->data;
-
-               if (phdr->rev <= uci->cpu_sig.rev)
-                       continue;
-
-               if (!intel_find_matching_signature(phdr,
-                                                  uci->cpu_sig.sig,
-                                                  uci->cpu_sig.pf))
-                       continue;
-
-               return iter->data;
-       }
-       return NULL;
+       return intel_ucode_patch;
 }
 
 void reload_ucode_intel(void)
@@ -557,7 +472,7 @@ void reload_ucode_intel(void)
 
        intel_cpu_collect_info(&uci);
 
-       p = find_patch(&uci);
+       p = ucode_get_patch();
        if (!p)
                return;
 
@@ -601,7 +516,7 @@ static enum ucode_state apply_microcode_intel(int cpu)
                return UCODE_ERROR;
 
        /* Look for a newer patch in our cache: */
-       mc = find_patch(uci);
+       mc = ucode_get_patch();
        if (!mc) {
                mc = uci->mc;
                if (!mc)
@@ -730,7 +645,7 @@ static enum ucode_state generic_load_microcode(int cpu, struct iov_iter *iter)
        uci->mc = (struct microcode_intel *)new_mc;
 
        /* Save for CPU hotplug */
-       save_microcode_patch(uci, new_mc, new_mc_size);
+       save_microcode_patch(new_mc, new_mc_size);
 
        pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
                 cpu, new_rev, uci->cpu_sig.rev);
index 8843c32480effce84152469ef88f7b8f7e15f7cb..6001da4c946a934045f8a6552dd8bf12c57b0d12 100644 (file)
@@ -8,16 +8,6 @@
 #include <asm/cpu.h>
 #include <asm/microcode.h>
 
-struct ucode_patch {
-       struct list_head plist;
-       void *data;             /* Intel uses only this one */
-       unsigned int size;
-       u32 patch_id;
-       u16 equiv_cpu;
-};
-
-extern struct list_head microcode_cache;
-
 struct device;
 
 enum ucode_state {