microcode.c revision 882a7af5ebaf4ff499b73f69bef1ae833f507418
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER START
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * The contents of this file are subject to the terms of the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Common Development and Distribution License (the "License").
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * You may not use this file except in compliance with the License.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * See the License for the specific language governing permissions
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and limitations under the License.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * When distributing Covered Code, include this CDDL HEADER in each
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If applicable, add the following below this CDDL HEADER, with the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * fields enclosed by brackets "[]" replaced with your own identifying
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * information: Portions Copyright [yyyy] [name of copyright owner]
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER END
88699bdd7d55fd959cedd294efadffd7589fb9fasherrym * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Use is subject to license terms.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Microcode specific information per core
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Data structure used for xcall
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * mcpu_ucode_info for the boot CPU. Statically allocated.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void ucode_file_reset(ucode_file_t *, processorid_t);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t ucode_match(int, struct cpu_ucode_info *,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t ucode_locate(cpu_t *, struct cpu_ucode_info *,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void ucode_update_intel(uint8_t *, struct cpu_ucode_info *);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnsonstatic void ucode_update_xpv(struct ucode_update_struct *, uint8_t *, uint32_t);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic const char ucode_failure_fmt[] =
88699bdd7d55fd959cedd294efadffd7589fb9fasherrym "cpu%d: failed to update microcode from version 0x%x to 0x%x\n";
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic const char ucode_success_fmt[] =
88699bdd7d55fd959cedd294efadffd7589fb9fasherrym "?cpu%d: microcode has been updated from version 0x%x to 0x%x\n";
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Force flag. If set, the first microcode binary that matches
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * signature and platform id will be used for microcode update,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * regardless of version. Should only be used for debugging.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Allocate space for mcpu_ucode_info in the machcpu structure
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * for all non-boot CPUs.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Called when we are done with microcode update on all processors to free up
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * space allocated for the microcode file.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check whether or not a processor is capable of microcode operations
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns 1 if it is capable, 0 if not.
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* i86xpv guest domain can't update microcode */
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * At this point we only support microcode update for Intel
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * processors family 6 and above.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * We also assume that we don't support a mix of Intel and
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * AMD processors in the same box.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (1);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Called when it is no longer necessary to keep the microcode around,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * or when the cached microcode doesn't match the CPU being processed.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_file_reset(ucode_file_t *ucodefp, processorid_t id)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym total_size = UCODE_TOTAL_SIZE(ucodefp->uf_header.uh_total_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym body_size = UCODE_BODY_SIZE(ucodefp->uf_header.uh_body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Space for the boot CPU is allocated with BOP_ALLOC()
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and does not require a free.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int size = total_size - body_size - UCODE_HEADER_SIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Space for the boot CPU is allocated with BOP_ALLOC()
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and does not require a free.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Populate the ucode file structure from microcode file corresponding to
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * this CPU, if exists.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Return EM_OK on success, corresponding error code on failure.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If the microcode matches the CPU we are processing, use it.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Look for microcode file with the right name.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(name, MAXPATHLEN, "/%s/%s/%08X-%02X",
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), cpi_sig,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * We found a microcode file for the CPU we are processing,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * reset the microcode data structure and read in the new
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym count = kobj_read(fd, (char *)&ucodefp->uf_header, header_size, 0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Make sure that the header contains valid fields.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * BOP_ALLOC() failure results in panic so we
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * don't have to check for NULL return.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucode_checksum(sum, body_size, ucodefp->uf_body)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check to see if there is extended signature table.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * BOP_ALLOC() failure results in panic so we
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * don't have to check for NULL return.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns 1 if the microcode is for this processor; 0 otherwise.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*ARGSUSED*/
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_update_struct *uusp = (struct ucode_update_struct *)arg1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct cpu_ucode_info *uinfop = CPU->cpu_m.mcpu_ucode_info;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check one more time to see if it is really necessary to update
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * microcode just in case this is a hyperthreaded processor where
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * the threads share the same microcode.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_update_intel(uint8_t *ucode_body, struct cpu_ucode_info *uinfop)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym wrmsr(MSR_INTC_UCODE_WRITE, (uint64_t)(uintptr_t)ucode_body);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnsonucode_update_xpv(struct ucode_update_struct *uusp, uint8_t *ucode,
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson op.interface_version = XENPF_INTERFACE_VERSION;
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson /*LINTED: constant in conditional context*/
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson set_xen_guest_handle(op.u.microcode.data, ucode);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson if (e != 0) {
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson cmn_err(CE_WARN, "hypervisor failed to accept uCode update");
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#endif /* __xpv */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * The Intel 64 and IA-32 Architecture Software Developer's Manual
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * recommends that MSR_INTC_UCODE_REV be loaded with 0 first, then
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * execute cpuid to guarantee the correct reading of this register.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Entry point to microcode update from the ucode_drv driver.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns EM_OK on success, corresponding error code on failure.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t search_rc = EM_NOMATCH; /* search result */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If there is no such CPU or it is not xcall ready, skip it.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If the current CPU has the same signature and platform
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * id as the previous one we processed, reuse the information.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cachedp->info.cui_platid == uusp->info.cui_platid) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Intuitively we should check here to see whether the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * running microcode rev is >= the expected rev, and
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * quit if it is. But we choose to proceed with the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * xcall regardless of the running version so that
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * the other threads in an HT processor can update
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * the cpu_ucode_info structure in machcpu.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Go through the whole buffer in case there are
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * multiple versions of matching microcode for this
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * processor.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Since we are searching through a big file
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * containing microcode for pretty much all the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * processors, we are bound to get EM_NOMATCH
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * at one point. However, if we return
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * EM_NOMATCH to users, it will really confuse
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * them. Therefore, if we ever find a match of
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * a lower rev, we will set return code to
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * EM_HIGHERREV.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Nothing to do */
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * for i86xpv, the hypervisor will update all the CPUs.
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * the hypervisor wants the header, data, and extended
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * signature tables. ucode_write will just read in the
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * updated version on all the CPUs after the update has
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * completed.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Initialize mcpu_ucode_info, and perform microcode update if necessary.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * This is the entry point from boot path where pointer to CPU structure
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * is available.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * cpuid_info must be initialized before ucode_check can be called.
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * for i86xpv, the hypervisor will update all the CPUs. We only need
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * do do this on one of the CPUs (and there always is a CPU 0). We do
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * need to update the CPU version though. Do that before returning.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * (Family 6, model 5 and above) and all processors after.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check to see if we need ucode update
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((rc = ucode_locate(cp, uinfop, &ucodefile)) == EM_OK) {
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * the hypervisor wants the header, data, and extended
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * signature tables. We can only get here from the boot
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * CPU (cpu #0), so use BOP_ALLOC. Since we're using BOP_ALLOC,
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson * We don't need to free.
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson usize = UCODE_TOTAL_SIZE(ucodefile.uf_header.uh_total_size);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson ustart = (uint8_t *)BOP_ALLOC(bootops, NULL, usize,
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson body_size = UCODE_BODY_SIZE(ucodefile.uf_header.uh_body_size);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson (void) memcpy(ustart, &ucodefile.uf_header, UCODE_HEADER_SIZE);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson (void) memcpy(&ustart[UCODE_HEADER_SIZE], ucodefile.uf_body,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If we fail to find a match for any reason, free the file structure
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * just in case we have read in a partial file.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Since the scratch memory for holding the microcode for the boot CPU
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * came from BOP_ALLOC, we will reset the data structure as if we
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * never did the allocation so we don't have to keep track of this
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * special chunk of memory. We free the memory used for the rest
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * of the CPUs in start_other_cpus().
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns microcode revision from the machcpu structure.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < max_ncpus; i++) {