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/*
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Use is subject to license terms.
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov *
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
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>
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld#include <sys/ontrap.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/*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * AMD-specific equivalence table
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_eqtbl_amd_t *ucode_eqtbl_amd;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * mcpu_ucode_info for the boot CPU. Statically allocated.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic struct cpu_ucode_info cpu_ucode_info0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_file_t ucodefile;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void* ucode_zalloc(processorid_t, size_t);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void ucode_free(processorid_t, void *, size_t);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic int ucode_capable_amd(cpu_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic int ucode_capable_intel(cpu_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t ucode_extract_amd(ucode_update_t *, uint8_t *, int);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t ucode_extract_intel(ucode_update_t *, uint8_t *,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void ucode_file_reset_amd(ucode_file_t *, processorid_t);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void ucode_file_reset_intel(ucode_file_t *, processorid_t);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic uint32_t ucode_load_amd(ucode_file_t *, cpu_ucode_info_t *, cpu_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic uint32_t ucode_load_intel(ucode_file_t *, cpu_ucode_info_t *, cpu_t *);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#ifdef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void ucode_load_xpv(ucode_update_t *);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnsonstatic void ucode_chipset_amd(uint8_t *, int);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnsonstatic int ucode_equiv_cpu_amd(cpu_t *, uint16_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t ucode_locate_amd(cpu_t *, cpu_ucode_info_t *,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t ucode_locate_intel(cpu_t *, cpu_ucode_info_t *,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#ifndef __xpv
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnsonstatic ucode_errno_t ucode_match_amd(uint16_t, cpu_ucode_info_t *,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_amd_t *, int);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t ucode_match_intel(int, cpu_ucode_info_t *,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_intel_t *, ucode_ext_table_intel_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void ucode_read_rev_amd(cpu_ucode_info_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void ucode_read_rev_intel(cpu_ucode_info_t *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic const struct ucode_ops ucode_amd = {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson MSR_AMD_PATCHLOADER,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_capable_amd,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_reset_amd,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_read_rev_amd,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_load_amd,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_validate_amd,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_extract_amd,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_locate_amd
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson};
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic const struct ucode_ops ucode_intel = {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson MSR_INTC_UCODE_WRITE,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_capable_intel,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_reset_intel,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_read_rev_intel,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_load_intel,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_validate_intel,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_extract_intel,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_locate_intel
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson};
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonconst struct ucode_ops *ucode;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
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
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);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(cp->cpu_m.mcpu_ucode_info == NULL);
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{
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(cp->cpu_m.mcpu_ucode_info != NULL);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu ASSERT(cp->cpu_m.mcpu_ucode_info != &cpu_ucode_info0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kmem_free(cp->cpu_m.mcpu_ucode_info,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym sizeof (*cp->cpu_m.mcpu_ucode_info));
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu cp->cpu_m.mcpu_ucode_info = NULL;
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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_cleanup()
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
126b0a7149858848c18e1e18979f54c432790aa2Mark Johnson if (ucode == NULL)
126b0a7149858848c18e1e18979f54c432790aa2Mark Johnson return;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->file_reset(&ucodefile, -1);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson/*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * allocated with BOP_ALLOC() and does not require a free.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_zalloc(processorid_t id, size_t size)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (id)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (kmem_zalloc(size, KM_NOSLEEP));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* BOP_ALLOC() failure results in panic */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_free(processorid_t id, void* buf, size_t size)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (id)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson kmem_free(buf, size);
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.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson *
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * At this point we only support microcode update for:
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * - Intel processors family 6 and above, and
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * - AMD processors family 0x10 and above.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson *
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * We also assume that we don't support a mix of Intel and
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * AMD processors in the same box.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson *
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov * An i86xpv guest domain or VM can't update the microcode.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov#define XPVDOMU_OR_HVM \
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov ((hwenv == HW_XEN_PV && !is_controldom()) || (hwenv & HW_VIRTUAL) != 0)
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson/*ARGSUSED*/
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic int
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_capable_amd(cpu_t *cp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
b9bfdccda8a7c490cc133ece2ab92d914e10b8d7Stuart Maybee int hwenv = get_hwenv();
b9bfdccda8a7c490cc133ece2ab92d914e10b8d7Stuart Maybee
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov if (XPVDOMU_OR_HVM)
843e19887f64dde75055cf8842fc4db2171eff45johnlev return (0);
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (cpuid_getfamily(cp) >= 0x10);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic int
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_capable_intel(cpu_t *cp)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
b9bfdccda8a7c490cc133ece2ab92d914e10b8d7Stuart Maybee int hwenv = get_hwenv();
b9bfdccda8a7c490cc133ece2ab92d914e10b8d7Stuart Maybee
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov if (XPVDOMU_OR_HVM)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (0);
79ec9da85c2648e2e165ce68612ad0cb6e185618Yuri Pankov
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (cpuid_getfamily(cp) >= 6);
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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_file_reset_amd(ucode_file_t *ufp, processorid_t id)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_amd_t *ucodefp = ufp->amd;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucodefp == NULL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_free(id, ucodefp, sizeof (ucode_file_amd_t));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ufp->amd = NULL;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_file_reset_intel(ucode_file_t *ufp, processorid_t id)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int total_size, body_size;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucodefp == NULL || ucodefp->uf_header == NULL)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucodefp->uf_body) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_free(id, ucodefp->uf_body, body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_body = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucodefp->uf_ext_table) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int size = total_size - body_size - UCODE_HEADER_SIZE_INTEL;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_free(id, ucodefp->uf_ext_table, size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_ext_table = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_free(id, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucodefp->uf_header = NULL;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson/*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Find the equivalent CPU id in the equivalence table.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic int
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnsonucode_equiv_cpu_amd(cpu_t *cp, uint16_t *eq_sig)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson char name[MAXPATHLEN];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson intptr_t fd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int count;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int offset = 0, cpi_sig = cpuid_getsig(cp);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_eqtbl_amd_t *eqtbl = ucode_eqtbl_amd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/equivalence-table",
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * No kmem_zalloc() etc. available on boot cpu.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (cp->cpu_id == 0) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((fd = kobj_open(name)) == -1)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OPENFILE);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* ucode_zalloc() cannot fail on boot cpu */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson eqtbl = ucode_zalloc(cp->cpu_id, sizeof (*eqtbl));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(eqtbl);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson do {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = kobj_read(fd, (int8_t *)eqtbl,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson sizeof (*eqtbl), offset);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (count != sizeof (*eqtbl)) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) kobj_close(fd);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_HIGHERREV);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson offset += count;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson } while (eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) kobj_close(fd);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * If not already done, load the equivalence table.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Not done on boot CPU.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (eqtbl == NULL) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson struct _buf *eq;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint64_t size;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((eq = kobj_open_file(name)) == (struct _buf *)-1)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OPENFILE);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (kobj_get_filesize(eq, &size) < 0) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson kobj_close_file(eq);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OPENFILE);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_eqtbl_amd = kmem_zalloc(size, KM_NOSLEEP);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_eqtbl_amd == NULL) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson kobj_close_file(eq);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMEM);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = kobj_read_file(eq, (char *)ucode_eqtbl_amd, size, 0);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson kobj_close_file(eq);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (count != size)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_FILESIZE);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* Get the equivalent CPU id. */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (cp->cpu_id)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson for (eqtbl = ucode_eqtbl_amd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson eqtbl++)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson *eq_sig = eqtbl->ue_equiv_cpu;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* No equivalent CPU id found, assume outdated microcode file. */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (*eq_sig == 0)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_HIGHERREV);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OK);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson/*
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * xVM cannot check for the presence of PCI devices. Look for chipset-
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * specific microcode patches in the container file and disable them
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * by setting their CPU revision to an invalid value.
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#ifdef __xpv
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnsonstatic void
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnsonucode_chipset_amd(uint8_t *buf, int size)
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson{
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucode_header_amd_t *uh;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uint32_t *ptr = (uint32_t *)buf;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson int len = 0;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /* skip to first microcode patch */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ptr += 2; len = *ptr++; ptr += len >> 2; size -= len;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson while (size >= sizeof (ucode_header_amd_t) + 8) {
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ptr++; len = *ptr++;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uh = (ucode_header_amd_t *)ptr;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ptr += len >> 2; size -= len;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (uh->uh_nb_id) {
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson cmn_err(CE_WARN, "ignoring northbridge-specific ucode: "
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson "chipset id %x, revision %x",
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uh->uh_nb_id, uh->uh_nb_rev);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uh->uh_cpu_rev = 0xffff;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson }
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (uh->uh_sb_id) {
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson cmn_err(CE_WARN, "ignoring southbridge-specific ucode: "
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson "chipset id %x, revision %x",
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uh->uh_sb_id, uh->uh_sb_rev);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uh->uh_cpu_rev = 0xffff;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson }
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson }
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson}
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#endif
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
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 */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson/*ARGSUSED*/
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_locate_amd(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson char name[MAXPATHLEN];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson intptr_t fd;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson int count, rc;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_amd_t *ucodefp = ufp->amd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#ifndef __xpv
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uint16_t eq_sig = 0;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson int i;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* get equivalent CPU id */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((rc = ucode_equiv_cpu_amd(cp, &eq_sig)) != EM_OK)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (rc);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Allocate a buffer for the microcode patch. If the buffer has been
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * allocated before, check for a matching microcode to avoid loading
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * the file again.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucodefp == NULL)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson else if (ucode_match_amd(eq_sig, uinfop, ucodefp, sizeof (*ucodefp))
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson == EM_OK)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OK);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucodefp == NULL)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMEM);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ufp->amd = ucodefp;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Find the patch for this CPU. The patch files are named XXXX-YY, where
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * XXXX is the equivalent CPU id and YY is the running patch number.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Patches specific to certain chipsets are guaranteed to have lower
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * numbers than less specific patches, so we can just load the first
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * patch that matches.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson for (i = 0; i < 0xff; i++) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/%04X-%02X",
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), eq_sig, i);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((fd = kobj_open(name)) == -1)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = kobj_read(fd, (char *)ucodefp, sizeof (*ucodefp), 0);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) kobj_close(fd);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_match_amd(eq_sig, uinfop, ucodefp, count) == EM_OK)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OK);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#else
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson int size = 0;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson char c;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /*
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * The xVM case is special. To support mixed-revision systems, the
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * hypervisor will choose which patch to load for which CPU, so the
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * whole microcode patch container file will have to be loaded.
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson *
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * Since this code is only run on the boot cpu, we don't have to care
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * about failing ucode_zalloc() or freeing allocated memory.
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (cp->cpu_id != 0)
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (EM_INVALIDARG);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/container",
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp));
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if ((fd = kobj_open(name)) == -1)
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (EM_OPENFILE);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /* get the file size by counting bytes */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson do {
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson count = kobj_read(fd, &c, 1, size);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson size += count;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson } while (count);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp));
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ASSERT(ucodefp);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ufp->amd = ucodefp;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucodefp->usize = size;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucodefp->ucodep = ucode_zalloc(cp->cpu_id, size);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ASSERT(ucodefp->ucodep);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /* load the microcode patch container file */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson count = kobj_read(fd, (char *)ucodefp->ucodep, size, 0);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson (void) kobj_close(fd);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (count != size)
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (EM_FILESIZE);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /* make sure the container file is valid */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson rc = ucode->validate(ucodefp->ucodep, ucodefp->usize);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (rc != EM_OK)
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (rc);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /* disable chipset-specific patches */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucode_chipset_amd(ucodefp->ucodep, ucodefp->usize);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (EM_OK);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_locate_intel(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char name[MAXPATHLEN];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym intptr_t fd;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int count;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int header_size = UCODE_HEADER_SIZE_INTEL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int cpi_sig = cpuid_getsig(cp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t rc = EM_OK;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ucode);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If the microcode matches the CPU we are processing, use it.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_match_intel(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 */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->file_reset(ufp, cp->cpu_id);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucodefp->uf_header = ucode_zalloc(cp->cpu_id, header_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucodefp->uf_header == NULL)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMEM);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = kobj_read(fd, (char *)ucodefp->uf_header, header_size, 0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym switch (count) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson case UCODE_HEADER_SIZE_INTEL: {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_intel_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 */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((rc = ucode_header_validate_intel(uhp)) == EM_OK) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucodefp->uf_body = ucode_zalloc(cp->cpu_id, body_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucodefp->uf_body == NULL) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson rc = EM_NOMEM;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson break;
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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson sum = ucode_checksum_intel(0, header_size,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (uint8_t *)ucodefp->uf_header);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_checksum_intel(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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucodefp->uf_ext_table = ucode_zalloc(cp->cpu_id, ext_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucodefp->uf_ext_table == NULL) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson rc = EM_NOMEM;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (kobj_read(fd, (char *)ucodefp->uf_ext_table,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ext_size, offset) != ext_size) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_FILESIZE;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson } else if (ucode_checksum_intel(0, ext_size,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (uint8_t *)(ucodefp->uf_ext_table))) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_CHECKSUM;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int i;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ext_size -= UCODE_EXT_TABLE_SIZE_INTEL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < ucodefp->uf_ext_table->uet_count;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym i++) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_checksum_intel(0,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson UCODE_EXT_SIG_SIZE_INTEL,
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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson rc = ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucodefp->uf_ext_table);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#ifndef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnsonucode_match_amd(uint16_t eq_sig, cpu_ucode_info_t *uinfop,
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucode_file_amd_t *ucodefp, int size)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_amd_t *uh;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucodefp == NULL || size < sizeof (ucode_header_amd_t))
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld uh = &ucodefp->uf_header;
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Don't even think about loading patches that would require code
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld * execution. Does not apply to patches for family 0x14 and beyond.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld if (uh->uh_cpu_rev < 0x5000 &&
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld size > offsetof(ucode_file_amd_t, uf_code_present) &&
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucodefp->uf_code_present)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (eq_sig != uh->uh_cpu_rev)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (uh->uh_nb_id) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson cmn_err(CE_WARN, "ignoring northbridge-specific ucode: "
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson "chipset id %x, revision %x", uh->uh_nb_id, uh->uh_nb_rev);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (uh->uh_sb_id) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson cmn_err(CE_WARN, "ignoring southbridge-specific ucode: "
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson "chipset id %x, revision %x", uh->uh_sb_id, uh->uh_sb_rev);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld if (uh->uh_patch_id <= uinfop->cui_rev && !ucode_force_update)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_HIGHERREV);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OK);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns 1 if the microcode is for this processor; 0 otherwise.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_match_intel(int cpi_sig, cpu_ucode_info_t *uinfop,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_intel_t *uhp, ucode_ext_table_intel_t *uetp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (uhp == NULL)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_NOMATCH);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (UCODE_MATCH_INTEL(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++) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_ext_sig_intel_t *uesp;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uesp = &uetp->uet_ext_sig[i];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (UCODE_MATCH_INTEL(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{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_update_t *uusp = (ucode_update_t *)arg1;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info;
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld#ifndef __xpv
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld on_trap_data_t otd;
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ucode);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(uusp->ucodep);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#ifndef __xpv
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) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->new_rev = uinfop->cui_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uinfop->cui_rev >= uusp->expected_rev)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld if (!on_trap(&otd, OT_DATA_ACCESS))
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep);
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld no_trap();
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uusp->new_rev = uinfop->cui_rev;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson/*ARGSUSED*/
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic uint32_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_amd_t *ucodefp = ufp->amd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#ifdef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_update_t uus;
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld#else
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld on_trap_data_t otd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ucode);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ucodefp);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#ifndef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson kpreempt_disable();
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld if (on_trap(&otd, OT_DATA_ACCESS)) {
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld no_trap();
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld kpreempt_enable();
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld return (0);
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson wrmsr(ucode->write_msr, (uintptr_t)ucodefp);
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld no_trap();
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->read_rev(uinfop);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson kpreempt_enable();
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (ucodefp->uf_header.uh_patch_id);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#else
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uus.ucodep = ucodefp->ucodep;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uus.usize = ucodefp->usize;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_load_xpv(&uus);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->read_rev(uinfop);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uus.new_rev = uinfop->cui_rev;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (uus.new_rev);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson/*ARGSUSED2*/
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic uint32_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_load_intel(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#ifdef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t ext_offset;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t body_size;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t ext_size;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint8_t *ustart;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t usize;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_update_t uus;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ucode);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#ifdef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * the hypervisor wants the header, data, and extended
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * signature tables. We can only get here from the boot
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * CPU (cpu #0), we don't need to free as ucode_zalloc() will
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * use BOP_ALLOC().
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson usize = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ustart = ucode_zalloc(cp->cpu_id, usize);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ustart);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ext_offset = body_size + UCODE_HEADER_SIZE_INTEL;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ext_size = usize - ext_offset;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ext_size >= 0);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) memcpy(ustart, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) memcpy(&ustart[UCODE_HEADER_SIZE_INTEL], ucodefp->uf_body,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson body_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ext_size > 0) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) memcpy(&ustart[ext_offset],
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucodefp->uf_ext_table, ext_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uus.ucodep = ustart;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uus.usize = usize;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_load_xpv(&uus);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->read_rev(uinfop);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uus.new_rev = uinfop->cui_rev;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#else
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_disable();
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson wrmsr(ucode->write_msr, (uintptr_t)ucodefp->uf_body);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_enable();
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (ucodefp->uf_header->uh_rev);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#ifdef __xpv
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnsonstatic void
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_load_xpv(ucode_update_t *uusp)
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson{
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson xen_platform_op_t op;
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson int e;
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson ASSERT(DOMAIN_IS_INITDOMAIN(xen_info));
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson kpreempt_disable();
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson op.cmd = XENPF_microcode_update;
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson op.interface_version = XENPF_INTERFACE_VERSION;
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson /*LINTED: constant in conditional context*/
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson set_xen_guest_handle(op.u.microcode.data, uusp->ucodep);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson op.u.microcode.length = uusp->usize;
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson e = HYPERVISOR_platform_op(&op);
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson if (e != 0) {
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson cmn_err(CE_WARN, "hypervisor failed to accept uCode update");
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson }
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson kpreempt_enable();
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson}
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#endif /* __xpv */
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic void
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_read_rev_amd(cpu_ucode_info_t *uinfop)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uinfop->cui_rev = rdmsr(MSR_AMD_PATCHLEVEL);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_read_rev_intel(cpu_ucode_info_t *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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_extract_amd(ucode_update_t *uusp, uint8_t *ucodep, int size)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#ifndef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t *ptr = (uint32_t *)ucodep;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_eqtbl_amd_t *eqtbl;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_file_amd_t *ufp;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson int count;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson int higher = 0;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucode_errno_t rc = EM_NOMATCH;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uint16_t eq_sig;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* skip over magic number & equivalence table header */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ptr += 2; size -= 8;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = *ptr++; size -= 4;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson for (eqtbl = (ucode_eqtbl_amd_t *)ptr;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != uusp->sig;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson eqtbl++)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson eq_sig = eqtbl->ue_equiv_cpu;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* No equivalent CPU id found, assume outdated microcode file. */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (eq_sig == 0)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_HIGHERREV);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* Use the first microcode patch that matches. */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson do {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ptr += count >> 2; size -= count;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (!size)
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (higher ? EM_HIGHERREV : EM_NOMATCH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ptr++; size -= 4;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = *ptr++; size -= 4;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ufp = (ucode_file_amd_t *)ptr;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson rc = ucode_match_amd(eq_sig, &uusp->info, ufp, count);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (rc == EM_HIGHERREV)
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson higher = 1;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson } while (rc != EM_OK);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->ucodep = (uint8_t *)ufp;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->usize = count;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->expected_rev = ufp->uf_header.uh_patch_id;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#else
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /*
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * The hypervisor will choose the patch to load, so there is no way to
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * know the "expected revision" in advance. This is especially true on
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * mixed-revision systems where more than one patch will be loaded.
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson */
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uusp->expected_rev = 0;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uusp->ucodep = ucodep;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uusp->usize = size;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson ucode_chipset_amd(ucodep, size);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OK);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_extract_intel(ucode_update_t *uusp, uint8_t *ucodep, int size)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t header_size = UCODE_HEADER_SIZE_INTEL;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int remaining;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int found = 0;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_errno_t search_rc = EM_NOMATCH; /* search result */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Go through the whole buffer in case there are
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * multiple versions of matching microcode for this
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * processor.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson for (remaining = size; remaining > 0; ) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int total_size, body_size, ext_size;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint8_t *curbuf = &ucodep[size - remaining];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_ext_table_intel_t *uetp = NULL;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_errno_t tmprc;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ext_size = total_size - (header_size + body_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ext_size > 0)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uetp = (ucode_ext_table_intel_t *)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson &curbuf[header_size + body_size];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson tmprc = ucode_match_intel(uusp->sig, &uusp->info, uhp, uetp);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /*
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * Since we are searching through a big file
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * containing microcode for pretty much all the
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * processors, we are bound to get EM_NOMATCH
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * at one point. However, if we return
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * EM_NOMATCH to users, it will really confuse
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * them. Therefore, if we ever find a match of
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * a lower rev, we will set return code to
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson * EM_HIGHERREV.
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (tmprc == EM_HIGHERREV)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson search_rc = EM_HIGHERREV;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (tmprc == EM_OK &&
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->expected_rev < uhp->uh_rev) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#ifndef __xpv
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->ucodep = (uint8_t *)&curbuf[header_size];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#else
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->ucodep = (uint8_t *)curbuf;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson#endif
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->usize =
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uusp->expected_rev = uhp->uh_rev;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson found = 1;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson remaining -= total_size;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (!found)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (search_rc);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OK);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
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 int found = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym processorid_t id;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_update_t cached = { 0 };
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_update_t *cachedp = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t rc = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t search_rc = EM_NOMATCH; /* search result */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cpuset_t cpuset;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ucode);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(ucodep);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym CPUSET_ZERO(cpuset);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson 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;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_update_t uus = { 0 };
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_update_t *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 */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson } else if ((search_rc = ucode->extract(uusp, ucodep, size))
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson == EM_OK) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson bcopy(uusp, &cached, sizeof (cached));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson cachedp = &cached;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson found = 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Nothing to do */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uusp->ucodep == NULL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#ifdef __xpv
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson /*
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.
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson */
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson if (id == 0) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_load_xpv(uusp);
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson }
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson#endif
882a7af5ebaf4ff499b73f69bef1ae833f507418Mark Johnson
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym CPUSET_ADD(cpuset, id);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_disable();
f34a71784df3fbc5d1227a7b6201fd318ad1667eJoe Bonasera xc_sync((xc_arg_t)uusp, 0, 0, CPUSET2BV(cpuset), ucode_write);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym kpreempt_enable();
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym CPUSET_DEL(cpuset, id);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld if (uusp->new_rev != 0 && uusp->info.cui_rev == uusp->new_rev &&
5e53ed34920bc03b619b50f459f2475e7bf80b6fHans Rosenfeld !ucode_force_update) {
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson rc = EM_HIGHERREV;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson } else if ((uusp->new_rev == 0) || (uusp->expected_rev != 0 &&
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson uusp->expected_rev != uusp->new_rev)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cmn_err(CE_WARN, ucode_failure_fmt,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym id, uusp->info.cui_rev, uusp->expected_rev);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_UPDATE;
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson } else {
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson cmn_err(CE_CONT, ucode_success_fmt,
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson id, uusp->info.cui_rev, uusp->new_rev);
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{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson cpu_ucode_info_t *uinfop;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t rc = EM_OK;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t new_rev = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(cp);
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu /*
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu * Space statically allocated for BSP, ensure pointer is set
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu */
a31148363f598def767ac48c5d82e1572e44b935Gerry Liu if (cp->cpu_id == 0 && cp->cpu_m.mcpu_ucode_info == NULL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uinfop = cp->cpu_m.mcpu_ucode_info;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* set up function pointers if not already done */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (!ucode)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson switch (cpuid_getvendor(cp)) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson case X86_VENDOR_AMD:
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode = &ucode_amd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson break;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson case X86_VENDOR_Intel:
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode = &ucode_intel;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson break;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson default:
126b0a7149858848c18e1e18979f54c432790aa2Mark Johnson ucode = NULL;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson 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 */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((cpuid_getvendor(cp) == X86_VENDOR_Intel) &&
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ((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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode->read_rev(uinfop);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson#ifdef __xpv
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson /*
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson * for i86xpv, the hypervisor will update all the CPUs. We only need
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson * do do this on one of the CPUs (and there always is a CPU 0).
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson */
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson if (cp->cpu_id != 0) {
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson return;
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson }
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson#endif
c9b5d7d22ea8bfd18ef2f988a885f1cb268f2ec7Mark Johnson
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Check to see if we need ucode update
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((rc = ucode->locate(cp, uinfop, &ucodefile)) == EM_OK) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson new_rev = ucode->load(&ucodefile, uinfop, cp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (uinfop->cui_rev != new_rev)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uinfop->cui_rev, new_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)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson 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
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ASSERT(ucode);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ASSERT(revp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson 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}