microcode.c revision 843e19887f64dde75055cf8842fc4db2171eff45
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER START
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
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 *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * or http://www.opensolaris.org/os/licensing.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * See the License for the specific language governing permissions
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and limitations under the License.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
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 *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER END
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Use is subject to license terms.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#pragma ident "%Z%%M% %I% %E% SMI"
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/asm_linkage.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/bootconf.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/cpuvar.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/cmn_err.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/controlregs.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/debug.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/kobj.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/kobj_impl.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/machsystm.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/param.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/machparam.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/promif.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/sysmacros.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/systm.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/types.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/thread.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/ucode.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/x86_archext.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/x_call.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef __xpv
843e19887f64dde75055cf8842fc4db2171eff45johnlev#include <sys/hypervisor.h>
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Microcode specific information per core
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstruct cpu_ucode_info {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t cui_platid; /* platform id */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t cui_rev; /* microcode revision */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym};
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Data structure used for xcall
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstruct ucode_update_struct {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t sig; /* signature */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct cpu_ucode_info info; /* ucode info */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t expected_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t new_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint8_t *ucodep; /* pointer to ucode body */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym};
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * mcpu_ucode_info for the boot CPU. Statically allocated.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic struct cpu_ucode_info cpu_ucode_info0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_file_t ucodefile = { 0 };
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic int ucode_capable(cpu_t *);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void ucode_file_reset(ucode_file_t *, processorid_t);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t ucode_match(int, struct cpu_ucode_info *,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_header_t *, ucode_ext_table_t *);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t ucode_locate(cpu_t *, struct cpu_ucode_info *,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_file_t *);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void ucode_update_intel(uint8_t *, struct cpu_ucode_info *);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void ucode_read_rev(struct cpu_ucode_info *);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic const char ucode_failure_fmt[] =
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym "cpu%d: failed to update microcode code from version 0x%x to 0x%x\n";
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic const char ucode_success_fmt[] =
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym "?cpu%d: microcode code has been updated from version 0x%x to 0x%x\n";
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
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 */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymint ucode_force_update = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Allocate space for mcpu_ucode_info in the machcpu structure
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * for all non-boot CPUs.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymvoid
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_alloc_space(cpu_t *cp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(cp->cpu_id != 0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cp->cpu_m.mcpu_ucode_info =
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymvoid
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_free_space(cpu_t *cp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(cp->cpu_id != 0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kmem_free(cp->cpu_m.mcpu_ucode_info,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym sizeof (*cp->cpu_m.mcpu_ucode_info));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Called when we are done with microcode update on all processors to free up
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * space allocated for the microcode file.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymvoid
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_free()
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_file_reset(&ucodefile, -1);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check whether or not a processor is capable of microcode operations
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns 1 if it is capable, 0 if not.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
843e19887f64dde75055cf8842fc4db2171eff45johnlev/*ARGSUSED*/
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic int
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_capable(cpu_t *cp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
843e19887f64dde75055cf8842fc4db2171eff45johnlev /* i86xpv guest domain can't update microcode */
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifdef __xpv
843e19887f64dde75055cf8842fc4db2171eff45johnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev }
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
843e19887f64dde75055cf8842fc4db2171eff45johnlev
843e19887f64dde75055cf8842fc4db2171eff45johnlev#ifndef __xpv
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * At this point we only support microcode update for Intel
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * processors family 6 and above.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * We also assume that we don't support a mix of Intel and
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * AMD processors in the same box.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (cpuid_getvendor(cp) != X86_VENDOR_Intel ||
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cpuid_getfamily(cp) < 6)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym else
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (1);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#else
843e19887f64dde75055cf8842fc4db2171eff45johnlev /*
843e19887f64dde75055cf8842fc4db2171eff45johnlev * XXPV - remove when microcode loading works in dom0. Don't support
843e19887f64dde75055cf8842fc4db2171eff45johnlev * microcode loading in dom0 right now.
843e19887f64dde75055cf8842fc4db2171eff45johnlev */
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
843e19887f64dde75055cf8842fc4db2171eff45johnlev#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
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.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_file_reset(ucode_file_t *ucodefp, processorid_t id)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int total_size, body_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucodefp == NULL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
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 if (ucodefp->uf_body) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Space for the boot CPU is allocated with BOP_ALLOC()
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and does not require a free.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (id != 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kmem_free(ucodefp->uf_body, body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_body = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucodefp->uf_ext_table) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int size = total_size - body_size - UCODE_HEADER_SIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Space for the boot CPU is allocated with BOP_ALLOC()
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and does not require a free.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (id != 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kmem_free(ucodefp->uf_ext_table, size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_ext_table = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym bzero(&ucodefp->uf_header, UCODE_HEADER_SIZE);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Populate the ucode file structure from microcode file corresponding to
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * this CPU, if exists.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Return EM_OK on success, corresponding error code on failure.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char name[MAXPATHLEN];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym intptr_t fd;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int count;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int header_size = UCODE_HEADER_SIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int cpi_sig = cpuid_getsig(cp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t rc = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If the microcode matches the CPU we are processing, use it.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_OK);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Look for microcode file with the right name.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(name, MAXPATHLEN, "/%s/%s/%08X-%02X",
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), cpi_sig,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_platid);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((fd = kobj_open(name)) == -1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_OPENFILE);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * We found a microcode file for the CPU we are processing,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * reset the microcode data structure and read in the new
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * file.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_file_reset(ucodefp, cp->cpu_id);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym count = kobj_read(fd, (char *)&ucodefp->uf_header, header_size, 0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym switch (count) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case UCODE_HEADER_SIZE: {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_header_t *uhp = &ucodefp->uf_header;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t offset = header_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int total_size, body_size, ext_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t sum = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Make sure that the header contains valid fields.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((rc = ucode_header_validate(uhp)) == EM_OK) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (cp->cpu_id != 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((ucodefp->uf_body = kmem_zalloc(body_size,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym KM_NOSLEEP)) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_NOMEM;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * BOP_ALLOC() failure results in panic so we
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * don't have to check for NULL return.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_body =
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (uint8_t *)BOP_ALLOC(bootops,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym NULL, body_size, MMU_PAGESIZE);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (kobj_read(fd, (char *)ucodefp->uf_body,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym body_size, offset) != body_size)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_FILESIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (rc)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym sum = ucode_checksum(0, header_size,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (uint8_t *)&ucodefp->uf_header);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucode_checksum(sum, body_size, ucodefp->uf_body)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_CHECKSUM;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check to see if there is extended signature table.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym offset = body_size + header_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ext_size = total_size - offset;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ext_size <= 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (cp->cpu_id != 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((ucodefp->uf_ext_table = kmem_zalloc(ext_size,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym KM_NOSLEEP)) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_NOMEM;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * BOP_ALLOC() failure results in panic so we
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * don't have to check for NULL return.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_ext_table =
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (ucode_ext_table_t *)BOP_ALLOC(bootops, NULL,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ext_size, MMU_PAGESIZE);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (kobj_read(fd, (char *)ucodefp->uf_ext_table,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ext_size, offset) != ext_size) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_FILESIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else if (ucode_checksum(0, ext_size,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (uint8_t *)(ucodefp->uf_ext_table))) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_CHECKSUM;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int i;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ext_size -= UCODE_EXT_TABLE_SIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < ucodefp->uf_ext_table->uet_count;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym i++) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucode_checksum(0, UCODE_EXT_SIG_SIZE,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (uint8_t *)(&(ucodefp->uf_ext_table->
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uet_ext_sig[i])))) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_CHECKSUM;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym default:
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_FILESIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kobj_close(fd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (rc != EM_OK)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_ext_table);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns 1 if the microcode is for this processor; 0 otherwise.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_header_t *uhp, ucode_ext_table_t *uetp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(uhp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (UCODE_MATCH(cpi_sig, uhp->uh_signature,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_platid, uhp->uh_proc_flags)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_HIGHERREV);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_OK);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uetp != NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int i;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < uetp->uet_count; i++) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_ext_sig_t *uesp;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uesp = &uetp->uet_ext_sig[i];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (UCODE_MATCH(cpi_sig, uesp->ues_signature,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_platid, uesp->ues_proc_flags)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uinfop->cui_rev >= uhp->uh_rev &&
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym !ucode_force_update)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_HIGHERREV);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_OK);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_NOMATCH);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*ARGSUSED*/
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic int
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_update_struct *uusp = (struct ucode_update_struct *)arg1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct cpu_ucode_info *uinfop = CPU->cpu_m.mcpu_ucode_info;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(uusp->ucodep);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
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 */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (!ucode_force_update) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->new_rev = uinfop->cui_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uinfop->cui_rev >= uusp->expected_rev)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym wrmsr(MSR_INTC_UCODE_WRITE,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (uint64_t)(intptr_t)(uusp->ucodep));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->new_rev = uinfop->cui_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_update_intel(uint8_t *ucode_body, struct cpu_ucode_info *uinfop)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_disable();
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym wrmsr(MSR_INTC_UCODE_WRITE, (uint64_t)(uintptr_t)ucode_body);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_enable();
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_read_rev(struct cpu_ucode_info *uinfop)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct cpuid_regs crs;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
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 */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym wrmsr(MSR_INTC_UCODE_REV, 0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) __cpuid_insn(&crs);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Entry point to microcode update from the ucode_drv driver.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns EM_OK on success, corresponding error code on failure.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_errno_t
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_update(uint8_t *ucodep, int size)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t header_size = UCODE_HEADER_SIZE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int remaining;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int found = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym processorid_t id;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_update_struct cached = { 0 };
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_update_struct *cachedp = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t rc = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t search_rc = EM_NOMATCH; /* search result */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cpuset_t cpuset;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(ucodep);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym CPUSET_ZERO(cpuset);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (!ucode_capable(CPU))
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_NOTSUP);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym mutex_enter(&cpu_lock);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (id = 0; id < max_ncpus; id++) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cpu_t *cpu;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_update_struct uus = { 0 };
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_update_struct *uusp = &uus;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If there is no such CPU or it is not xcall ready, skip it.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((cpu = cpu_get(id)) == NULL ||
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym !(cpu->cpu_flags & CPU_READY))
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->sig = cpuid_getsig(cpu);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym sizeof (uusp->info));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If the current CPU has the same signature and platform
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * id as the previous one we processed, reuse the information.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (cachedp && cachedp->sig == cpuid_getsig(cpu) &&
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cachedp->info.cui_platid == uusp->info.cui_platid) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->ucodep = cachedp->ucodep;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->expected_rev = cachedp->expected_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
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 */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Go through the whole buffer in case there are
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * multiple versions of matching microcode for this
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * processor.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (remaining = size; remaining > 0; ) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int total_size, body_size, ext_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint8_t *curbuf = &ucodep[size - remaining];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_header_t *uhp = (ucode_header_t *)curbuf;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_ext_table_t *uetp = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t tmprc;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym total_size =
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym UCODE_TOTAL_SIZE(uhp->uh_total_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ext_size = total_size -
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (header_size + body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ext_size > 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uetp = (ucode_ext_table_t *)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym &curbuf[header_size + body_size];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym tmprc = ucode_match(uusp->sig, &uusp->info,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uhp, uetp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
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 */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (tmprc == EM_HIGHERREV)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym search_rc = EM_HIGHERREV;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (tmprc == EM_OK &&
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->expected_rev < uhp->uh_rev) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->ucodep = &curbuf[header_size];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->expected_rev = uhp->uh_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym bcopy(uusp, &cached, sizeof (cached));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cachedp = &cached;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym found = 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym remaining -= total_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Nothing to do */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uusp->ucodep == NULL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym CPUSET_ADD(cpuset, id);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_disable();
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym xc_sync((xc_arg_t)uusp, 0, 0, X_CALL_HIPRI, cpuset,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_write);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_enable();
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym CPUSET_DEL(cpuset, id);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uusp->expected_rev == uusp->new_rev) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cmn_err(CE_CONT, ucode_success_fmt,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym id, uusp->info.cui_rev, uusp->expected_rev);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cmn_err(CE_WARN, ucode_failure_fmt,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym id, uusp->info.cui_rev, uusp->expected_rev);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_UPDATE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym mutex_exit(&cpu_lock);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (!found)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = search_rc;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
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 *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * cpuid_info must be initialized before ucode_check can be called.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymvoid
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_check(cpu_t *cp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct cpu_ucode_info *uinfop;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t rc = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(cp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (cp->cpu_id == 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop = cp->cpu_m.mcpu_ucode_info;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (!ucode_capable(cp))
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * (Family 6, model 5 and above) and all processors after.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check to see if we need ucode update
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((rc = ucode_locate(cp, uinfop, &ucodefile)) == EM_OK) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_update_intel(ucodefile.uf_body, uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uinfop->cui_rev != ucodefile.uf_header.uh_rev)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop->cui_rev, ucodefile.uf_header.uh_rev);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
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 *
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 */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (rc != EM_OK || cp->cpu_id == 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_file_reset(&ucodefile, cp->cpu_id);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns microcode revision from the machcpu structure.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_errno_t
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_get_rev(uint32_t *revp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int i;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(revp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (!ucode_capable(CPU))
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_NOTSUP);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym mutex_enter(&cpu_lock);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < max_ncpus; i++) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cpu_t *cpu;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((cpu = cpu_get(i)) == NULL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym mutex_exit(&cpu_lock);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_OK);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}