summaryrefslogtreecommitdiff
path: root/src/cpu/amd/microcode
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/amd/microcode')
-rw-r--r--src/cpu/amd/microcode/microcode.c166
1 files changed, 132 insertions, 34 deletions
diff --git a/src/cpu/amd/microcode/microcode.c b/src/cpu/amd/microcode/microcode.c
index 45e4bf0a52..badd3b797b 100644
--- a/src/cpu/amd/microcode/microcode.c
+++ b/src/cpu/amd/microcode/microcode.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015 Raptor Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -22,37 +23,96 @@
#include <cpu/x86/msr.h>
#include <cpu/amd/microcode.h>
#include <cbfs.h>
+#include <arch/io.h>
#define UCODE_DEBUG(fmt, args...) \
do { printk(BIOS_DEBUG, "[microcode] "fmt, ##args); } while(0)
+#define UCODE_MAGIC 0x00414d44
+#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
+#define UCODE_SECTION_START_ID 0x00000001
+#define UCODE_MAGIC 0x00414d44
+
+#define F1XH_MPB_MAX_SIZE 2048
+#define F15H_MPB_MAX_SIZE 4096
+#define CONT_HDR 12
+#define SECT_HDR 8
+
+/*
+ * STRUCTURE OF A MICROCODE (UCODE) FILE
+ * Container Header
+ * Section Header
+ * Microcode Header
+ * Microcode "Blob"
+ * Section Header
+ * Microcode Header
+ * Microcode "Blob"
+ * ...
+ * ...
+ * (end of file)
+ *
+ *
+ * CONTAINER HEADER (offset 0 bytes from start of file)
+ * Total size = fixed size (12 bytes) + variable size
+ * [0:3] 32-bit unique ID
+ * [4:7] don't-care
+ * [8-11] Size (n) in bytes of variable portion of container header
+ * [12-n] don't-care
+ *
+ * SECTION HEADER (offset += 12+n)
+ * Total size = 8 bytes
+ * [0:3] Unique identifier signaling start of section (0x00000001)
+ * [4:7] Total size (m) of following microcode section, including microcode header
+ *
+ * MICROCODE HEADER (offset += 8)
+ * Total size = 64 bytes
+ * [0:3] Data code (32 bits)
+ * [4:7] Patch ID (32 bits)
+ * [8:9] Microcode patch data ID (16 bits)
+ * [10] c patch data length (8 bits)
+ * [11] init flag (8 bits)
+ * [12:15] ucode patch data cksum (32 bits)
+ * [16:19] nb dev ID (32 bits)
+ * [20:23] sb dev ID (32 bits)
+ * [24:25] Processor rev ID (16 bits)
+ * [26] nb revision ID (8 bits)
+ * [27] sb revision ID (8 bits)
+ * [28] BIOS API revision (8 bits)
+ * [29-31] Reserved 1 (array of three 8-bit values)
+ * [32-63] Match reg (array of eight 32-bit values)
+ *
+ * MICROCODE BLOB (offset += 64)
+ * Total size = m bytes
+ *
+ */
+
struct microcode {
- u32 date_code;
- u32 patch_id;
+ uint32_t data_code;
+ uint32_t patch_id;
- u16 m_patch_data_id;
- u8 m_patch_data_len;
- u8 init_flag;
+ uint16_t mc_patch_data_id;
+ uint8_t mc_patch_data_len;
+ uint8_t init_flag;
- u32 m_patch_data_cksum;
+ uint32_t mc_patch_data_checksum;
- u32 nb_dev_id;
- u32 ht_io_hub_dev_id;
+ uint32_t nb_dev_id;
+ uint32_t sb_dev_id;
- u16 processor_rev_id;
- u8 ht_io_hub_rev_id;
- u8 nb_rev_id;
+ uint16_t processor_rev_id;
+ uint8_t nb_rev_id;
+ uint8_t sb_rev_id;
- u8 bios_api_rev;
- u8 resv1[3];
+ uint8_t bios_api_rev;
+ uint8_t reserved1[3];
- u32 match_reg[8];
+ uint32_t match_reg[8];
- u8 m_patch_data[896];
- u8 resv2[896];
+ uint8_t m_patch_data[896];
+ uint8_t resv2[896];
- u8 x86_code_present;
- u8 x86_code_entry[191];
+ uint8_t x86_code_present;
+ uint8_t x86_code_entry[191];
};
static void apply_microcode_patch(const struct microcode *m)
@@ -82,35 +142,73 @@ static void amd_update_microcode(const void *ucode, size_t ucode_len,
const struct microcode *m;
const uint8_t *c = ucode;
const uint8_t *ucode_end = (uint8_t*)ucode + ucode_len;
+ const uint8_t *cur_section_hdr;
+
+ uint32_t container_hdr_id;
+ uint32_t container_hdr_size;
+ uint32_t blob_size;
+ uint32_t sec_hdr_id;
+
+ /* Container Header */
+ container_hdr_id = read32(c);
+ if (container_hdr_id != UCODE_MAGIC) {
+ UCODE_DEBUG("Invalid container header ID\n");
+ return;
+ }
+
+ container_hdr_size = read32(c + 8);
+ cur_section_hdr = c + CONT_HDR + container_hdr_size;
+
+ /* Read in first section header ID */
+ sec_hdr_id = read32(cur_section_hdr);
+ c = cur_section_hdr + 4;
+
+ /* Loop through sections */
+ while (sec_hdr_id == UCODE_SECTION_START_ID &&
+ c <= (ucode_end - F15H_MPB_MAX_SIZE)) {
+
+ blob_size = read32(c);
+
+ m = (struct microcode *)(c + 4);
- while (c <= (ucode_end - 2048)) {
- m = (struct microcode *)c;
if (m->processor_rev_id == equivalent_processor_rev_id) {
apply_microcode_patch(m);
break;
}
- c += 2048;
+
+ cur_section_hdr = c + 4 + blob_size;
+ sec_hdr_id = read32(cur_section_hdr);
+ c = cur_section_hdr + 4;
}
}
-#define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin"
+static const char *microcode_cbfs_file[] = {
+ "microcode_amd.bin",
+ "microcode_amd_fam15h.bin",
+};
-void amd_update_microcode_from_cbfs(u32 equivalent_processor_rev_id)
+void amd_update_microcode_from_cbfs(uint32_t equivalent_processor_rev_id)
{
const void *ucode;
size_t ucode_len;
- if (equivalent_processor_rev_id == 0) {
- UCODE_DEBUG("rev id not found. Skipping microcode patch!\n");
- return;
- }
+ uint32_t i;
- ucode = cbfs_boot_map_with_leak(MICROCODE_CBFS_FILE,
- CBFS_TYPE_MICROCODE, &ucode_len);
- if (!ucode) {
- UCODE_DEBUG("microcode file not found. Skipping updates.\n");
- return;
- }
+ for (i = 0; i < ARRAY_SIZE(microcode_cbfs_file); i++)
+ {
+ if (equivalent_processor_rev_id == 0) {
+ UCODE_DEBUG("rev id not found. Skipping microcode patch!\n");
+ return;
+ }
+
+ ucode = cbfs_boot_map_with_leak(microcode_cbfs_file[i],
+ CBFS_TYPE_MICROCODE, &ucode_len);
+ if (!ucode) {
+ UCODE_DEBUG("microcode file not found. Skipping updates.\n");
- amd_update_microcode(ucode, ucode_len, equivalent_processor_rev_id);
+ return;
+ }
+
+ amd_update_microcode(ucode, ucode_len, equivalent_processor_rev_id);
+ }
}