src/cpu/amd/pi/00730F01: Add microcode update infrastructure for fam16h PI

Code is based on microcode update procedure from fam10-15h with necessary
microcode blob structure updates for fam16h.

Currently updating microcode in romstage seem to be impossible. AGESA is
overriding the microcode patch regardles of the current microcode revision
patched on CPU. Use ramstage CPU init procedures to update microcode easily.
Tested with microcode blob 07030106 released 2018-02-09 from
platomav/CPUMicrocodes GitHub repository on apu2 platform.

TEST=boot Linux kernel 4.14.50 on PC Engines apu2 and run dmesg to see
patch_level=0x07030106 on all cores

Change-Id: Ic15cba06f3cd9cfbc538b6764b158fa699f0ecf6
Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/29272
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Michał Żygowski 2018-10-25 15:48:54 +02:00 committed by Patrick Georgi
parent 1a86cda6db
commit 319f0370bf
5 changed files with 236 additions and 0 deletions

View File

@ -16,6 +16,8 @@
config CPU_AMD_PI_00730F01 config CPU_AMD_PI_00730F01
bool bool
select X86_AMD_FIXED_MTRRS select X86_AMD_FIXED_MTRRS
select SUPPORT_CPU_UCODE_IN_CBFS
select MICROCODE_BLOB_UNDISCLOSED
if CPU_AMD_PI_00730F01 if CPU_AMD_PI_00730F01

View File

@ -14,10 +14,14 @@
# #
romstage-y += fixme.c romstage-y += fixme.c
romstage-y += update_microcode.c
romstage-y += microcode_fam16h.c
ramstage-y += fixme.c ramstage-y += fixme.c
ramstage-y += chip_name.c ramstage-y += chip_name.c
ramstage-y += model_16_init.c ramstage-y += model_16_init.c
ramstage-y += update_microcode.c
ramstage-y += microcode_fam16h.c
subdirs-y += ../../mtrr subdirs-y += ../../mtrr
subdirs-y += ../../../x86/tsc subdirs-y += ../../../x86/tsc

View File

@ -0,0 +1,169 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Copyright (C) 2015 Raptor Engineering
* Copyright (C) 2019 PC Engines GmbH
*
* 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
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include <console/console.h>
#include <cpu/x86/msr.h>
#include <cpu/amd/microcode.h>
#include <cbfs.h>
#include <arch/io.h>
#include <smp/spinlock.h>
/*
* Values and header structure from:
* BKDG for AMD Family 16h Models 30h-3Fh Processors
* 52740 Rev 3.06 - March 18, 2016
*/
#define F16H_MPB_MAX_SIZE 3458
#define F16H_MPB_DATA_OFFSET 32
/*
* STRUCTURE OF A MICROCODE (UCODE) FILE FOR FAM16h
* Microcode Patch Block
* Microcode Header
* Microcode "Blob"
* ...
* ...
* (end of file)
*
*
* MICROCODE HEADER (offset 0 bytes from start of file)
* Total size = 32 bytes
* [0:3] Date code (32 bits)
* [4:7] Patch level (32 bits)
* [8:9] Microcode patch data ID (16 bits)
* [10:15] Reserved (48 bits)
* [16:19] Chipset 1 device ID (32 bits)
* [20:23] Chipset 2 device ID (32 bits)
* [24:25] Processor Revisions ID (16 bits)
* [26] Chipset 1 revision ID (8 bits)
* [27] Chipset 2 revision ID (8 bits)
* [28:31] Reserved (32 bits)
*
* MICROCODE BLOB (offset += 32)
* Total size = m bytes
*
*/
struct microcode {
uint32_t date_code;
uint32_t patch_id;
uint16_t mc_patch_data_id;
uint8_t reserved1[6];
uint32_t chipset1_dev_id;
uint32_t chipset2_dev_id;
uint16_t processor_rev_id;
uint8_t chipset1_rev_id;
uint8_t chipset2_rev_id;
uint8_t reserved2[4];
uint8_t m_patch_data[F16H_MPB_MAX_SIZE-F16H_MPB_DATA_OFFSET];
};
static void apply_microcode_patch(const struct microcode *m)
{
uint32_t new_patch_id;
msr_t msr;
/* apply patch */
msr.hi = 0;
msr.lo = (uint32_t)m;
wrmsr(0xc0010020, msr);
printk(BIOS_DEBUG, "microcode: patch id to apply = 0x%08x\n",
m->patch_id);
/* patch authentication */
msr = rdmsr(0x8b);
new_patch_id = msr.lo;
printk(BIOS_DEBUG, "microcode: updated to patch id = 0x%08x %s\n",
new_patch_id,
(new_patch_id == m->patch_id) ? "success" : "fail");
}
static void amd_update_microcode(const void *ucode, size_t ucode_len,
uint32_t equivalent_processor_rev_id)
{
const struct microcode *m;
const uint8_t *c = ucode;
m = (struct microcode *)c;
if (m->processor_rev_id == equivalent_processor_rev_id)
apply_microcode_patch(m);
}
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) {
printk(BIOS_DEBUG, "microcode: rev id not found. "
"Skipping microcode patch!\n");
return;
}
#ifdef __PRE_RAM__
#if CONFIG(HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
spin_lock(romstage_microcode_cbfs_lock());
#endif
#endif
ucode = cbfs_boot_map_with_leak("cpu_microcode_blob.bin",
CBFS_TYPE_MICROCODE,
&ucode_len);
if (!ucode) {
printk(BIOS_DEBUG, "cpu_microcode_blob.bin not found. "
"Skipping updates.\n");
#ifdef __PRE_RAM__
#if CONFIG(HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
spin_unlock(romstage_microcode_cbfs_lock());
#endif
#endif
return;
}
if (ucode_len > F16H_MPB_MAX_SIZE ||
ucode_len < F16H_MPB_DATA_OFFSET) {
printk(BIOS_DEBUG, "microcode file invalid. Skipping "
"updates.\n");
#ifdef __PRE_RAM__
#if CONFIG(HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
spin_unlock(romstage_microcode_cbfs_lock());
#endif
#endif
return;
}
amd_update_microcode(ucode, ucode_len,
equivalent_processor_rev_id);
#ifdef __PRE_RAM__
#if CONFIG(HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
spin_unlock(romstage_microcode_cbfs_lock());
#endif
#endif
}

View File

@ -14,6 +14,7 @@
*/ */
#include <console/console.h> #include <console/console.h>
#include <cpu/amd/microcode.h>
#include <cpu/x86/msr.h> #include <cpu/x86/msr.h>
#include <cpu/amd/msr.h> #include <cpu/amd/msr.h>
#include <cpu/x86/mtrr.h> #include <cpu/x86/mtrr.h>
@ -98,6 +99,8 @@ static void model_16_init(struct device *dev)
msr = rdmsr(HWCR_MSR); msr = rdmsr(HWCR_MSR);
msr.lo |= (1 << 0); msr.lo |= (1 << 0);
wrmsr(HWCR_MSR, msr); wrmsr(HWCR_MSR, msr);
update_microcode(cpuid_eax(1));
} }
static struct device_operations cpu_dev_ops = { static struct device_operations cpu_dev_ops = {

View File

@ -0,0 +1,58 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
* Copyright (C) 2007 Advanced Micro Devices, Inc.
* Copyright (C) 2019 PC Engines GmbH
*
* 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
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdint.h>
#include <cpu/amd/microcode.h>
struct id_mapping {
uint32_t orig_id;
uint16_t new_id;
};
static u16 get_equivalent_processor_rev_id(u32 orig_id)
{
static const struct id_mapping id_mapping_table[] = {
/* Family 16h */
/* TODO This equivalent processor revisions ID needs verification */
{ 0x730f01, 0x7301 },
/* Array terminator */
{ 0xffffff, 0x0000 },
};
u32 new_id;
int i;
new_id = 0;
for (i = 0; id_mapping_table[i].orig_id != 0xffffff; i++) {
if (id_mapping_table[i].orig_id == orig_id) {
new_id = id_mapping_table[i].new_id;
break;
}
}
return new_id;
}
void update_microcode(u32 cpu_deviceid)
{
u32 equivalent_processor_rev_id =
get_equivalent_processor_rev_id(cpu_deviceid);
amd_update_microcode_from_cbfs(equivalent_processor_rev_id);
}