x86/microcode/AMD: Fix mixed steppings support
authorBorislav Petkov (AMD) <bp@alien8.de>
Thu, 26 Jan 2023 15:26:17 +0000 (16:26 +0100)
committerBorislav Petkov (AMD) <bp@alien8.de>
Mon, 6 Feb 2023 12:40:16 +0000 (13:40 +0100)
The AMD side of the loader has always claimed to support mixed
steppings. But somewhere along the way, it broke that by assuming that
the cached patch blob is a single one instead of it being one per
*node*.

So turn it into a per-node one so that each node can stash the blob
relevant for it.

  [ NB: Fixes tag is not really the exactly correct one but it is good
    enough. ]

Fixes: fe055896c040 ("x86/microcode: Merge the early microcode loader")
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: <stable@kernel.org> # 2355370cd941 ("x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter")
Cc: <stable@kernel.org> # a5ad92134bd1 ("x86/microcode/AMD: Add a @cpu parameter to the reloading functions")
Link: https://lore.kernel.org/r/20230130161709.11615-4-bp@alien8.de
arch/x86/kernel/cpu/microcode/amd.c

index 1023be6a695413b9ba0a887b53b9c92c05bfc93b..9eb457b1034133dc03d5560f4c82053bbdc4816c 100644 (file)
@@ -55,7 +55,9 @@ struct cont_desc {
 };
 
 static u32 ucode_new_rev;
-static u8 amd_ucode_patch[PATCH_MAX_SIZE];
+
+/* One blob per node. */
+static u8 amd_ucode_patch[MAX_NUMNODES][PATCH_MAX_SIZE];
 
 /*
  * Microcode patch container file is prepended to the initrd in cpio
@@ -428,7 +430,7 @@ static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, boo
        patch   = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
 #else
        new_rev = &ucode_new_rev;
-       patch   = &amd_ucode_patch;
+       patch   = &amd_ucode_patch[0];
 #endif
 
        desc.cpuid_1_eax = cpuid_1_eax;
@@ -580,10 +582,10 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
 
 void reload_ucode_amd(unsigned int cpu)
 {
-       struct microcode_amd *mc;
        u32 rev, dummy __always_unused;
+       struct microcode_amd *mc;
 
-       mc = (struct microcode_amd *)amd_ucode_patch;
+       mc = (struct microcode_amd *)amd_ucode_patch[cpu_to_node(cpu)];
 
        rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
 
@@ -852,6 +854,8 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
 
 static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
 {
+       struct cpuinfo_x86 *c;
+       unsigned int nid, cpu;
        struct ucode_patch *p;
        enum ucode_state ret;
 
@@ -864,18 +868,22 @@ static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t siz
                return ret;
        }
 
-       p = find_patch(0);
-       if (!p) {
-               return ret;
-       } else {
-               if (boot_cpu_data.microcode >= p->patch_id)
-                       return ret;
+       for_each_node(nid) {
+               cpu = cpumask_first(cpumask_of_node(nid));
+               c = &cpu_data(cpu);
+
+               p = find_patch(cpu);
+               if (!p)
+                       continue;
+
+               if (c->microcode >= p->patch_id)
+                       continue;
 
                ret = UCODE_NEW;
-       }
 
-       memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
-       memcpy(amd_ucode_patch, p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
+               memset(&amd_ucode_patch[nid], 0, PATCH_MAX_SIZE);
+               memcpy(&amd_ucode_patch[nid], p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
+       }
 
        return ret;
 }