[PATCH 1/1] x86/microcode/amd: allow multiple family's bin filesappended together

From: Jacob Shin
Date: Fri May 31 2013 - 14:57:02 EST


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

Reported-by: Henrique de Moraes Holschuh <hmh@xxxxxxxxxx>
Signed-off-by: Jacob Shin <jacob.shin@xxxxxxx>
---
arch/x86/kernel/microcode_amd_early.c | 63 +++++++++++++++++++++++++++------
1 file changed, 53 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kernel/microcode_amd_early.c b/arch/x86/kernel/microcode_amd_early.c
index 9618805..2426dab 100644
--- a/arch/x86/kernel/microcode_amd_early.c
+++ b/arch/x86/kernel/microcode_amd_early.c
@@ -16,6 +16,7 @@

static bool ucode_loaded;
static u32 ucode_new_rev;
+static int family_offset;

/*
* Microcode patch container file is prepended to the initrd in cpio format.
@@ -27,6 +28,7 @@ static struct cpio_data __cpuinit find_ucode_in_initrd(void)
{
long offset = 0;
struct cpio_data cd;
+ int *fam_offset = &family_offset;

#ifdef CONFIG_X86_32
/*
@@ -39,12 +41,18 @@ static struct cpio_data __cpuinit find_ucode_in_initrd(void)
cd = find_cpio_data((char *)__pa_nodebug(ucode_path),
(void *)p->hdr.ramdisk_image, p->hdr.ramdisk_size,
&offset);
+ fam_offset = (int *)__pa_nodebug(&family_offset);
} else
#endif
cd = find_cpio_data(ucode_path,
(void *)(boot_params.hdr.ramdisk_image + PAGE_OFFSET),
boot_params.hdr.ramdisk_size, &offset);

+ if (*fam_offset) {
+ cd.data = (u8 *)cd.data + *fam_offset;
+ cd.size -= *fam_offset;
+ }
+
if (*(u32 *)cd.data != UCODE_MAGIC) {
cd.data = NULL;
cd.size = 0;
@@ -68,15 +76,18 @@ static void __cpuinit apply_ucode_in_initrd(void)
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;
+ int *fam_off;

#ifdef CONFIG_X86_32
new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
+ fam_off = (int *)__pa_nodebug(&family_offset);
#else
new_rev = &ucode_new_rev;
+ fam_off = &family_offset;
#endif
cd = find_ucode_in_initrd();
if (!cd.data)
@@ -92,18 +103,44 @@ static void __cpuinit apply_ucode_in_initrd(void)
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, 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;
+ }
+
+ *fam_off = data - (u8 *)cd.data;
+ }

- eq_id = find_equiv_id(eq, cpuid_eax(0x00000001));
if (!eq_id)
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;
@@ -116,8 +153,11 @@ static void __cpuinit apply_ucode_in_initrd(void)
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;
+#ifdef CONFIG_X86_32
+ u8 *mpb = (u8 *)__pa_nodebug(&amd_bsp_mpb);
+ memcpy(mpb, mc, header[1]);
+#endif
+ *new_rev = mc->hdr.patch_id;
break;
}

@@ -182,6 +222,9 @@ void __cpuinit load_ucode_amd_ap(void)

if (cpu && !ucode_loaded) {
struct cpio_data cd = find_ucode_in_initrd();
+ if (!cd.data)
+ return;
+
if (load_microcode_amd(0, cd.data, cd.size) != UCODE_OK)
return;
ucode_loaded = true;
--
1.7.9.5


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