/* Current microcode patch used in early patching on the APs. */ staticstruct microcode_intel *ucode_patch_va __read_mostly; staticstruct microcode_intel *ucode_patch_late __read_mostly;
/* last level cache size per core */ staticunsignedint llc_size_per_core __ro_after_init;
/* microcode format is extended from prescott processors */ struct extended_signature { unsignedint sig; unsignedint pf; unsignedint cksum;
};
for (i = 0; i < ext_hdr->count; i++) { if (cpu_signatures_match(sig, ext_sig->sig, ext_sig->pf)) returntrue;
ext_sig++;
} return 0;
}
EXPORT_SYMBOL_GPL(intel_find_matching_signature);
/** * intel_microcode_sanity_check() - Sanity check microcode file. * @mc: Pointer to the microcode file contents. * @print_err: Display failure reason if true, silent if false. * @hdr_type: Type of file, i.e. normal microcode file or In Field Scan file. * Validate if the microcode header type matches with the type * specified here. * * Validate certain header fields and verify if computed checksum matches * with the one specified in the header. * * Return: 0 if the file passes all the checks, -EINVAL if any of the checks * fail.
*/ int intel_microcode_sanity_check(void *mc, bool print_err, int hdr_type)
{ unsignedlong total_size, data_size, ext_table_size; struct microcode_header_intel *mc_header = mc; struct extended_sigtable *ext_header = NULL;
u32 sum, orig_sum, ext_sigcount = 0, i; struct extended_signature *ext_sig;
ext_header = mc + MC_HEADER_SIZE + data_size; if (ext_table_size != exttable_size(ext_header)) { if (print_err)
pr_err("Error: extended signature table size mismatch.\n"); return -EFAULT;
}
ext_sigcount = ext_header->count;
/* * Check extended table checksum: the sum of all dwords that * comprise a valid table must be 0.
*/
ext_tablep = (u32 *)ext_header;
i = ext_table_size / sizeof(u32); while (i--)
ext_table_sum += ext_tablep[i];
if (ext_table_sum) { if (print_err)
pr_warn("Bad extended signature table checksum, aborting.\n"); return -EINVAL;
}
}
/* * Calculate the checksum of update data and header. The checksum of * valid update data and header including the extended signature table * must be 0.
*/
orig_sum = 0;
i = (MC_HEADER_SIZE + data_size) / sizeof(u32); while (i--)
orig_sum += ((u32 *)mc)[i];
if (orig_sum) { if (print_err)
pr_err("Bad microcode data checksum, aborting.\n"); return -EINVAL;
}
if (!ext_table_size) return 0;
/* * Check extended signature checksum: 0 => valid.
*/ for (i = 0; i < ext_sigcount; i++) {
ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
EXT_SIGNATURE_SIZE * i;
if (!intel_find_matching_signature(data, &uci->cpu_sig)) continue;
/* * For saving the early microcode, find the matching revision which * was loaded on the BSP. * * On the BSP during early boot, find a newer revision than * actually loaded in the CPU.
*/ if (save) { if (cur_rev != mc_header->rev) continue;
} elseif (cur_rev >= mc_header->rev) { continue;
}
/* * Save us the MSR write below - which is a particular expensive * operation - when the other hyperthread has updated the microcode * already.
*/
*cur_rev = intel_get_microcode_revision(); if (*cur_rev >= mc->hdr.rev) {
uci->cpu_sig.rev = *cur_rev; return UCODE_OK;
}
/* write microcode via MSR 0x79 */
native_wrmsrq(MSR_IA32_UCODE_WRITE, (unsignedlong)mc->bits);
rev = intel_get_microcode_revision(); if (rev != mc->hdr.rev) return UCODE_ERROR;
/* * Invoked from an early init call to save the microcode blob which was * selected during early boot when mm was not usable. The microcode must be * saved because initrd is going away. It's an early init call so the APs * just can use the pointer and do not have to scan initrd/builtin firmware * again.
*/ staticint __init save_builtin_microcode(void)
{ struct ucode_cpu_info uci;
if (xchg(&ucode_patch_va, NULL) != UCODE_BSP_LOADED) return 0;
if (microcode_loader_disabled() || boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) return 0;
if (WARN_ON_ONCE(smp_processor_id() != cpu)) return UCODE_ERROR;
ret = __apply_microcode(uci, mc, &cur_rev); if (ret != UCODE_UPDATED && ret != UCODE_OK) return ret;
cpu_data(cpu).microcode = uci->cpu_sig.rev; if (!cpu)
boot_cpu_data.microcode = uci->cpu_sig.rev;
return ret;
}
staticbool ucode_validate_minrev(struct microcode_header_intel *mc_header)
{ int cur_rev = boot_cpu_data.microcode;
/* * When late-loading, ensure the header declares a minimum revision * required to perform a late-load. The previously reserved field * is 0 in older microcode blobs.
*/ if (!mc_header->min_req_ver) {
pr_info("Unsafe microcode update: Microcode header does not specify a required min version\n"); returnfalse;
}
/* * Check whether the current revision is either greater or equal to * to the minimum revision specified in the header.
*/ if (cur_rev < mc_header->min_req_ver) {
pr_info("Unsafe microcode update: Current revision 0x%x too old\n", cur_rev);
pr_info("Current should be at 0x%x or higher. Use early loading instead\n", mc_header->min_req_ver); returnfalse;
} returntrue;
}
if (!copy_from_iter_full(&mc_header, sizeof(mc_header), iter)) {
pr_err("error! Truncated or inaccessible header in microcode data file\n"); goto fail;
}
mc_size = get_totalsize(&mc_header); if (mc_size < sizeof(mc_header)) {
pr_err("error! Bad data in microcode data file (totalsize too small)\n"); goto fail;
}
data_size = mc_size - sizeof(mc_header); if (data_size > iov_iter_count(iter)) {
pr_err("error! Bad data in microcode data file (truncated file?)\n"); goto fail;
}
/* For performance reasons, reuse mc area when possible */ if (!mc || mc_size > curr_mc_size) {
kvfree(mc);
mc = kvmalloc(mc_size, GFP_KERNEL); if (!mc) goto fail;
curr_mc_size = mc_size;
}
memcpy(mc, &mc_header, sizeof(mc_header));
data = mc + sizeof(mc_header); if (!copy_from_iter_full(data, data_size, iter) ||
intel_microcode_sanity_check(mc, true, MC_HEADER_TYPE_MICROCODE) < 0) goto fail;
if (cur_rev >= mc_header.rev) continue;
if (!intel_find_matching_signature(mc, &uci->cpu_sig)) continue;
is_safe = ucode_validate_minrev(&mc_header); if (force_minrev && !is_safe) continue;
/* * Late loading on model 79 with microcode revision less than 0x0b000021 * and LLC size per core bigger than 2.5MB may result in a system hang. * This behavior is documented in item BDX90, #334165 (Intel Xeon * Processor E7-8800/4800 v4 Product Family).
*/ if (c->x86_vfm == INTEL_BROADWELL_X &&
c->x86_stepping == 0x01 &&
llc_size_per_core > 2621440 &&
c->microcode < 0x0b000021) {
pr_err_once("Erratum BDX90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode);
pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); returntrue;
}
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.