diff options
Diffstat (limited to 'src/cpu/amd')
-rw-r--r-- | src/cpu/amd/microcode/microcode.c | 166 |
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); + } } |