Add support for parsing through multiple families' microcode patch
container binary files appended together when early loading. This is
already supported on Intel.

Reported-by: Henrique de Moraes Holschuh <h...@hmh.eng.br>
Signed-off-by: Jacob Shin <jacob.s...@amd.com>
---
 arch/x86/kernel/microcode_amd_early.c |   68 +++++++++++++++++++++++++++------
 1 file changed, 56 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/microcode_amd_early.c 
b/arch/x86/kernel/microcode_amd_early.c
index c783248..1ac6e9a 100644
--- a/arch/x86/kernel/microcode_amd_early.c
+++ b/arch/x86/kernel/microcode_amd_early.c
@@ -87,15 +87,21 @@ static void __cpuinit apply_ucode_in_initrd(void *ucode, 
size_t size)
        struct equiv_cpu_entry *eq;
        u32 *header;
        u8  *data;
-       u16 eq_id;
+       u16 eq_id = 0;
        int offset, left;
-       u32 rev, dummy;
+       u32 rev, eax;
        u32 *new_rev;
+       unsigned long *uoffset;
+       size_t *usize;
 
 #ifdef CONFIG_X86_32
        new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
+       uoffset = (unsigned long *)__pa_nodebug(&ucode_offset);
+       usize   = (size_t *)__pa_nodebug(&ucode_size);
 #else
        new_rev = &ucode_new_rev;
+       uoffset = &ucode_offset;
+       usize   = &ucode_size;
 #endif
 
        data   = ucode;
@@ -108,18 +114,50 @@ static void __cpuinit apply_ucode_in_initrd(void *ucode, 
size_t size)
            header[2] == 0)                            /* size */
                return;
 
-       eq     = (struct equiv_cpu_entry *)(data + CONTAINER_HDR_SZ);
-       offset = header[2] + CONTAINER_HDR_SZ;
-       data  += offset;
-       left  -= offset;
+       eax = cpuid_eax(0x00000001);
+
+       while (left > 0) {
+               eq = (struct equiv_cpu_entry *)(data + CONTAINER_HDR_SZ);
+
+               offset = header[2] + CONTAINER_HDR_SZ;
+               data  += offset;
+               left  -= offset;
 
-       eq_id  = find_equiv_id(eq, cpuid_eax(0x00000001));
-       if (!eq_id)
+               eq_id = find_equiv_id(eq, eax);
+               if (eq_id)
+                       break;
+
+               /*
+                * support multiple container files appended together. if this
+                * one does not have a matching equivalent cpu entry, we fast
+                * forward to the next container file.
+                */
+               while (left > 0) {
+                       header = (u32 *)data;
+                       if (header[0] == UCODE_MAGIC &&
+                           header[1] == UCODE_EQUIV_CPU_TABLE_TYPE)
+                               break;
+
+                       offset = header[1] + SECTION_HDR_SIZE;
+                       data  += offset;
+                       left  -= offset;
+               }
+
+               /* mark where the next microcode container file starts */
+               offset    = data - (u8 *)ucode;
+               *uoffset += offset;
+               *usize   -= offset;
+               ucode     = data;
+       }
+
+       if (!eq_id) {
+               *usize = 0;
                return;
+       }
 
        /* find ucode and update if needed */
 
-       rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
+       rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
 
        while (left > 0) {
                struct microcode_amd *mc;
@@ -132,15 +170,21 @@ static void __cpuinit apply_ucode_in_initrd(void *ucode, 
size_t size)
                mc = (struct microcode_amd *)(data + SECTION_HDR_SIZE);
                if (eq_id == mc->hdr.processor_rev_id && rev < mc->hdr.patch_id)
                        if (__apply_microcode_amd(mc) == 0) {
-                               if (!(*new_rev))
-                                       *new_rev = mc->hdr.patch_id;
-                               break;
+                               rev = mc->hdr.patch_id;
+                               *new_rev = rev;
                        }
 
                offset  = header[1] + SECTION_HDR_SIZE;
                data   += offset;
                left   -= offset;
        }
+
+       /* mark where this microcode container file ends */
+       offset  = *usize - (data - (u8 *)ucode);
+       *usize -= offset;
+
+       if (!(*new_rev))
+               *usize = 0;
 }
 
 void __init load_ucode_amd_bsp(void)
-- 
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to