/* * 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 psize;
u8 *data;
size_t size;
};
/* * Microcode patch container file is prepended to the initrd in cpio * format. See Documentation/arch/x86/microcode.rst
*/ staticconstchar
ucode_path[] __maybe_unused = "kernel/x86/microcode/AuthenticAMD.bin";
/* * This is CPUID(1).EAX on the BSP. It is used in two ways: * * 1. To ignore the equivalence table on Zen1 and newer. * * 2. To match which patches to load because the patch revision ID * already contains the f/m/s for which the microcode is destined * for.
*/ static u32 bsp_cpuid_1_eax __ro_after_init;
staticbool need_sha_check(u32 cur_rev)
{ if (!cur_rev) {
cur_rev = cpuid_to_ucode_rev(bsp_cpuid_1_eax);
pr_info_once("No current revision, generating the lowest one: 0x%x\n", cur_rev);
}
switch (cur_rev >> 8) { case 0x80012: return cur_rev <= 0x8001277; break; case 0x80082: return cur_rev <= 0x800820f; break; case 0x83010: return cur_rev <= 0x830107c; break; case 0x86001: return cur_rev <= 0x860010e; break; case 0x86081: return cur_rev <= 0x8608108; break; case 0x87010: return cur_rev <= 0x8701034; break; case 0x8a000: return cur_rev <= 0x8a0000a; break; case 0xa0010: return cur_rev <= 0xa00107a; break; case 0xa0011: return cur_rev <= 0xa0011da; break; case 0xa0012: return cur_rev <= 0xa001243; break; case 0xa0082: return cur_rev <= 0xa00820e; break; case 0xa1011: return cur_rev <= 0xa101153; break; case 0xa1012: return cur_rev <= 0xa10124e; break; case 0xa1081: return cur_rev <= 0xa108109; break; case 0xa2010: return cur_rev <= 0xa20102f; break; case 0xa2012: return cur_rev <= 0xa201212; break; case 0xa4041: return cur_rev <= 0xa404109; break; case 0xa5000: return cur_rev <= 0xa500013; break; case 0xa6012: return cur_rev <= 0xa60120a; break; case 0xa7041: return cur_rev <= 0xa704109; break; case 0xa7052: return cur_rev <= 0xa705208; break; case 0xa7080: return cur_rev <= 0xa708009; break; case 0xa70c0: return cur_rev <= 0xa70C009; break; case 0xaa001: return cur_rev <= 0xaa00116; break; case 0xaa002: return cur_rev <= 0xaa00218; break; case 0xb0021: return cur_rev <= 0xb002146; break; case 0xb0081: return cur_rev <= 0xb008111; break; case 0xb1010: return cur_rev <= 0xb101046; break; case 0xb2040: return cur_rev <= 0xb204031; break; case 0xb4040: return cur_rev <= 0xb404031; break; case 0xb4041: return cur_rev <= 0xb404101; break; case 0xb6000: return cur_rev <= 0xb600031; break; case 0xb6080: return cur_rev <= 0xb608031; break; case 0xb7000: return cur_rev <= 0xb700031; break; default: break;
}
pr_info("You should not be seeing this. Please send the following couple of lines to x86--kernel.org\n");
pr_info("CPUID(1).EAX: 0x%x, current revision: 0x%x\n", bsp_cpuid_1_eax, cur_rev); returntrue;
}
/* Zen and newer do not need an equivalence table. */ if (x86_family(bsp_cpuid_1_eax) >= 0x17) return 0;
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;
} return 0;
}
/* * Check whether there is a valid microcode container file at the beginning * of @buf of size @buf_size.
*/ staticbool verify_container(const u8 *buf, size_t buf_size)
{
u32 cont_magic;
cont_magic = *(const u32 *)buf; if (cont_magic != UCODE_MAGIC) {
pr_debug("Invalid magic value (0x%08x).\n", cont_magic); returnfalse;
}
returntrue;
}
/* * Check whether there is a valid, non-truncated CPU equivalence table at the * beginning of @buf of size @buf_size.
*/ staticbool verify_equivalence_table(const u8 *buf, size_t buf_size)
{ const u32 *hdr = (const u32 *)buf;
u32 cont_type, equiv_tbl_len;
if (!verify_container(buf, buf_size)) returnfalse;
/* Zen and newer do not need an equivalence table. */ if (x86_family(bsp_cpuid_1_eax) >= 0x17) returntrue;
/* * Check whether there is a valid, non-truncated microcode patch section at the * beginning of @buf of size @buf_size. * * On success, @sh_psize returns the patch size according to the section header, * to the caller.
*/ staticbool __verify_patch_section(const u8 *buf, size_t buf_size, u32 *sh_psize)
{
u32 p_type, p_size; const u32 *hdr;
if (buf_size < SECTION_HDR_SIZE) {
pr_debug("Truncated patch section.\n"); returnfalse;
}
if (p_type != UCODE_UCODE_TYPE) {
pr_debug("Invalid type field (0x%x) in container file section header.\n",
p_type); returnfalse;
}
if (p_size < sizeof(struct microcode_header_amd)) {
pr_debug("Patch of size %u too short.\n", p_size); returnfalse;
}
*sh_psize = p_size;
returntrue;
}
/* * 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.
*/ staticbool __verify_patch_size(u32 sh_psize, size_t buf_size)
{
u8 family = x86_family(bsp_cpuid_1_eax);
u32 max_size;
ret: /* Working with the whole buffer so < is ok. */ return sh_psize <= buf_size;
}
/* * Verify the patch in @buf. * * Returns: * negative: on error * positive: patch is not for this family, skip it * 0: success
*/ staticint verify_patch(const u8 *buf, size_t buf_size, u32 *patch_size)
{
u8 family = x86_family(bsp_cpuid_1_eax); struct microcode_header_amd *mc_hdr;
u32 sh_psize;
u16 proc_id;
u8 patch_fam;
if (!__verify_patch_section(buf, buf_size, &sh_psize)) return -1;
/* * The section header length is not included in this indicated size * but is present in the leftover file length so we need to subtract * it before passing this value to the function below.
*/
buf_size -= SECTION_HDR_SIZE;
/* * Check if the remaining buffer is big enough to contain a patch of * size sh_psize, as the section claims.
*/ if (buf_size < sh_psize) {
pr_debug("Patch of size %u truncated.\n", sh_psize); return -1;
}
staticbool mc_patch_matches(struct microcode_amd *mc, u16 eq_id)
{ /* Zen and newer do not need an equivalence table. */ if (x86_family(bsp_cpuid_1_eax) >= 0x17) return ucode_rev_to_cpuid(mc->hdr.patch_id).full == bsp_cpuid_1_eax; else return eq_id == mc->hdr.processor_rev_id;
}
/* * This scans the ucode blob for the proper container as we can have multiple * containers glued together. * * Returns the amount of bytes consumed while scanning. @desc contains all the * data we're going to use in later stages of the application.
*/ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
{ struct equiv_cpu_table table;
size_t orig_size = size;
u32 *hdr = (u32 *)ucode;
u16 eq_id;
u8 *buf;
if (!verify_equivalence_table(ucode, size)) return 0;
/* * Find the equivalence ID of our CPU in this table. Even if this table * doesn't contain a patch for the CPU, scan through the whole container * so that it can be skipped in case there are other containers appended.
*/
eq_id = find_equiv_id(&table, bsp_cpuid_1_eax);
/* * Scan through the rest of the container to find where it ends. We do * some basic sanity-checking too.
*/ while (size > 0) { struct microcode_amd *mc;
u32 patch_size; int ret;
ret = verify_patch(buf, size, &patch_size); if (ret < 0) { /* * Patch verification failed, skip to the next container, if * there is one. Before exit, check whether that container has * found a patch already. If so, use it.
*/ goto out;
} elseif (ret > 0) { goto skip;
}
mc = (struct microcode_amd *)(buf + SECTION_HDR_SIZE); if (mc_patch_matches(mc, eq_id)) {
desc->psize = patch_size;
desc->mc = mc;
}
out: /* * If we have found a patch (desc->mc), it means we're looking at the * container which has a patch for this CPU so return 0 to mean, @ucode * already points to the proper container. Otherwise, we return the size * we scanned so that we can advance to the next container in the * buffer.
*/ if (desc->mc) {
desc->data = ucode;
desc->size = orig_size - size;
return 0;
}
return orig_size - size;
}
/* * Scan the ucode blob for the proper container as we can have multiple * containers glued together.
*/ staticvoid scan_containers(u8 *ucode, size_t size, struct cont_desc *desc)
{ while (size) {
size_t s = parse_container(ucode, size, desc); if (!s) return;
if (!get_builtin_microcode(&cp))
cp = find_microcode_in_initrd(ucode_path);
found = cp.data && cp.size; if (found)
*ret = cp;
return found;
}
/* * Early load occurs before we can vmalloc(). So we look for the microcode * patch container file in initrd, traverse equivalent cpu table, look for a * matching microcode patch, and update, all in initrd memory in place. * When vmalloc() is available for use later -- on 64-bit during first AP load, * and on 32-bit during save_microcode_in_initrd() -- we can call * load_microcode_amd() to save equivalent cpu table and microcode patches in * kernel heap memory.
*/ void __init load_ucode_amd_bsp(struct early_load_data *ed, unsignedint cpuid_1_eax)
{ struct cont_desc desc = { }; struct microcode_amd *mc; struct cpio_data cp = { }; char buf[4];
u32 rev;
if (cmdline_find_option(boot_command_line, "microcode.amd_sha_check", buf, 4)) { if (!strncmp(buf, "off", 3)) {
sha_check = false;
pr_warn_once("It is a very very bad idea to disable the blobs SHA check!\n");
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
}
}
bsp_cpuid_1_eax = cpuid_1_eax;
rev = get_patch_level();
ed->old_rev = rev;
/* Needed in load_microcode_amd() */
ucode_cpu_info[0].cpu_sig.sig = cpuid_1_eax;
if (!find_blobs_in_containers(&cp)) return;
scan_containers(cp.data, cp.size, &desc);
mc = desc.mc; if (!mc) return;
/* * Allow application of the same revision to pick up SMT-specific * changes even if the revision of the other SMT thread is already * up-to-date.
*/ if (ed->old_rev > mc->hdr.patch_id) return;
if (__apply_microcode_amd(mc, &rev, desc.psize))
ed->new_rev = rev;
}
staticinlinebool patch_cpus_equivalent(struct ucode_patch *p, struct ucode_patch *n, bool ignore_stepping)
{ /* Zen and newer hardcode the f/m/s in the patch ID */ if (x86_family(bsp_cpuid_1_eax) >= 0x17) { union cpuid_1_eax p_cid = ucode_rev_to_cpuid(p->patch_id); union cpuid_1_eax n_cid = ucode_rev_to_cpuid(n->patch_id);
if (ignore_stepping) {
p_cid.stepping = 0;
n_cid.stepping = 0;
}
list_for_each_entry(p, µcode_cache, plist) if (patch_cpus_equivalent(p, &n, false)) return p;
return NULL;
}
staticinlineint patch_newer(struct ucode_patch *p, struct ucode_patch *n)
{ /* Zen and newer hardcode the f/m/s in the patch ID */ if (x86_family(bsp_cpuid_1_eax) >= 0x17) { union zen_patch_rev zp, zn;
/* * a patch could have been loaded early, set uci->mc so that * mc_bp_resume() can call apply_microcode()
*/
p = find_patch(cpu); if (p && (p->patch_id == csig->rev))
uci->mc = p->data;
/* * Return a non-negative value even if some of the checks failed so that * we can skip over the next patch. If we return a negative value, we * signal a grave error like a memory allocation has failed and the * driver cannot continue functioning normally. In such cases, we tear * down everything we've used up so far and exit.
*/ staticint verify_and_add_patch(u8 family, u8 *fw, unsignedint leftover, unsignedint *patch_size)
{ struct microcode_header_amd *mc_hdr; struct ucode_patch *patch;
u16 proc_id; int ret;
ret = verify_patch(fw, leftover, patch_size); if (ret) return ret;
/* * AMD microcode firmware naming convention, up to family 15h they are in * the legacy file: * * amd-ucode/microcode_amd.bin * * This legacy file is always smaller than 2K in size. * * Beginning with family 15h, they are in family-specific firmware files: * * amd-ucode/microcode_amd_fam15h.bin * amd-ucode/microcode_amd_fam16h.bin * ... * * These might be larger than 2K.
*/ staticenum ucode_state request_microcode_amd(int cpu, struct device *device)
{ char fw_name[36] = "amd-ucode/microcode_amd.bin"; struct cpuinfo_x86 *c = &cpu_data(cpu); enum ucode_state ret = UCODE_NFOUND; conststruct firmware *fw;
if (force_minrev) return UCODE_NFOUND;
if (c->x86 >= 0x15)
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
if (request_firmware_direct(&fw, (constchar *)fw_name, device)) {
pr_debug("failed to load file %s\n", fw_name); goto out;
}
ret = UCODE_ERROR; if (!verify_container(fw->data, fw->size)) goto fw_release;
ret = load_microcode_amd(c->x86, fw->data, fw->size);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.