// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD CPU Microcode Update Driver for Linux
*
* This driver allows to upgrade microcode on F10h AMD
* CPUs and later.
*
* Copyright (C) 2008-2011 Advanced Micro Devices Inc.
* 2013-2018 Borislav Petkov <bp@alien8.de>
*
* Author: Peter Oruba <peter.oruba@amd.com>
*
* Based on work by:
* Tigran Aivazian <aivazian.tigran@gmail.com>
*
* early loader:
* Copyright (C) 2013 Advanced Micro Devices, Inc.
*
* Author: Jacob Shin <jacob.shin@amd.com>
* Fixes: Borislav Petkov <bp@suse.de>
*/
#define pr_fmt(fmt) "microcode: " fmt
#include <linux/earlycpio.h>
#include <linux/firmware.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/initrd.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <asm/microcode_amd.h>
#include <asm/microcode.h>
#include <asm/processor.h>
#include <asm/setup.h>
#include <asm/cpu.h>
#include <asm/msr.h>
static struct equiv_cpu_table {
unsigned int num_entries;
struct equiv_cpu_entry *entry;
} equiv_table;
/*
* This points to the current valid container of microcode patches which we will
* save from the initrd/builtin before jettisoning its contents. @mc is the
* microcode patch we found to match.
*/
struct cont_desc {
struct microcode_amd *mc;
u32 cpuid_1_eax;
u32 psize;
u8 *data;
size_t size;
};
static u32 ucode_new_rev;
static u8 amd_ucode_patch[PATCH_MAX_SIZE];
/*
* Microcode patch container file is prepended to the initrd in cpio
* format. See Documentation/x86/microcode.rst
*/
static const char
ucode_path[] __maybe_unused = "kernel/x86/microcode/AuthenticAMD.bin";
static u16 find_equiv_id(struct equiv_cpu_table *et, u32 sig)
{
unsigned int i;
if (!et || !et->num_entries)
return 0;
for (i = 0; i < et->num_entries; i++) {
struct equiv_cpu_entry *e = &et->entry[i];
if (sig == e->installed_cpu)
return e->equiv_cpu;
e++;
}
return 0;
}
/*
* Check whether there is a valid microcode container file at the beginning
* of @buf of size @buf_size. Set @early to use this function in the early path.
*/
static bool verify_container(const u8 *buf, size_t buf_size, bool early)
{
u32 cont_magic;
if (buf_size <= CONTAINER_HDR_SZ) {
if (!early)
pr_debug("Truncated microcode container header.\n");
return false;
}
cont_magic = *(const u32 *)buf;
if (cont_magic != UCODE_MAGIC) {
if (!early)
pr_debug("Invalid magic value (0x%08x).\n", cont_magic);
return false;
}
return true;
}
/*
* Check whether there is a valid, non-truncated CPU equivalence table at the
* beginning of @buf of size @buf_size. Set @early to use this function in the
* early path.
*/
static bool verify_equivalence_table(const u8 *buf, size_t buf_size, bool early)
{
const u32 *hdr = (const u32 *)buf;
u32 cont_type, equiv_tbl_len;
if (!verify_container(buf, buf_size, early))
return false;
cont_type = hdr[1];
if (cont_type != UCODE_EQUIV_CPU_TABLE_TYPE) {
if (!early)
pr_debug("Wrong microcode container equivalence table type: %u.\n",
cont_type);
return false;
}
buf_size -= CONTAINER_HDR_SZ;
equiv_tbl_len = hdr[2];
if (equiv_tbl_len < sizeof(struct equiv_cpu_entry) ||
buf_size < equiv_tbl_len) {
if (!early)
pr_debug("Truncated equivalence table.\n");
return false;
}
return true;
}
/*
* Check whether there is a valid, non-truncated microcode patch section at the
* beginning of @buf of size @buf_size. Set @early to use this function in the
* early path.
*
* On success, @sh_psize returns the patch size according to the section header,
* to the caller.
*/
static bool
__verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize, bool early)
{
u32 p_type, p_size;
const u32 *hdr;
if (buf_size < SECTION_HDR_SIZE) {
if (!early)
pr_debug("Truncated patch section.\n");
return false;
}
hdr = (const u32 *)buf;
p_type = hdr[0];
p_size = hdr[1];
if (p_type != UCODE_UCODE_TYPE) {
if (!early)
pr_debug("Invalid type field (0x%x) in container file section header.\n",
p_type);
return false;
}
if (p_size < sizeof(struct microcode_header_amd)) {
if (!early)
pr_debug("Patch of size %u too short.\n", p_size);
return false;
}
*sh_psize = p_size;
return true;
}
/*
* Check whether the passed remaining file @buf_size is large enough to contain
* a patch of the indicated @sh_psize (and also whether this size does not
* exceed the per-family maximum). @sh_psize is the size read from the section
* header.
*/
static unsigned int __verify_patch_size(u8 family, u32 sh_psize, size_t buf_size)
{
u32 max_size;
if (family >= <