12449e17fSsherrym /* 22449e17fSsherrym * CDDL HEADER START 32449e17fSsherrym * 42449e17fSsherrym * The contents of this file are subject to the terms of the 52449e17fSsherrym * Common Development and Distribution License (the "License"). 62449e17fSsherrym * You may not use this file except in compliance with the License. 72449e17fSsherrym * 82449e17fSsherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92449e17fSsherrym * or http://www.opensolaris.org/os/licensing. 102449e17fSsherrym * See the License for the specific language governing permissions 112449e17fSsherrym * and limitations under the License. 122449e17fSsherrym * 132449e17fSsherrym * When distributing Covered Code, include this CDDL HEADER in each 142449e17fSsherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152449e17fSsherrym * If applicable, add the following below this CDDL HEADER, with the 162449e17fSsherrym * fields enclosed by brackets "[]" replaced with your own identifying 172449e17fSsherrym * information: Portions Copyright [yyyy] [name of copyright owner] 182449e17fSsherrym * 192449e17fSsherrym * CDDL HEADER END 202449e17fSsherrym */ 212449e17fSsherrym 222449e17fSsherrym /* 230ba6f73dSMark Johnson * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 242449e17fSsherrym * Use is subject to license terms. 25*79ec9da8SYuri Pankov * 26*79ec9da8SYuri Pankov * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 272449e17fSsherrym */ 282449e17fSsherrym 292449e17fSsherrym #include <sys/asm_linkage.h> 302449e17fSsherrym #include <sys/bootconf.h> 312449e17fSsherrym #include <sys/cpuvar.h> 322449e17fSsherrym #include <sys/cmn_err.h> 332449e17fSsherrym #include <sys/controlregs.h> 342449e17fSsherrym #include <sys/debug.h> 352449e17fSsherrym #include <sys/kobj.h> 362449e17fSsherrym #include <sys/kobj_impl.h> 372449e17fSsherrym #include <sys/machsystm.h> 385e53ed34SHans Rosenfeld #include <sys/ontrap.h> 392449e17fSsherrym #include <sys/param.h> 402449e17fSsherrym #include <sys/machparam.h> 412449e17fSsherrym #include <sys/promif.h> 422449e17fSsherrym #include <sys/sysmacros.h> 432449e17fSsherrym #include <sys/systm.h> 442449e17fSsherrym #include <sys/types.h> 452449e17fSsherrym #include <sys/thread.h> 462449e17fSsherrym #include <sys/ucode.h> 472449e17fSsherrym #include <sys/x86_archext.h> 482449e17fSsherrym #include <sys/x_call.h> 49843e1988Sjohnlev #ifdef __xpv 50843e1988Sjohnlev #include <sys/hypervisor.h> 51843e1988Sjohnlev #endif 522449e17fSsherrym 532449e17fSsherrym /* 54adc586deSMark Johnson * AMD-specific equivalence table 552449e17fSsherrym */ 56adc586deSMark Johnson static ucode_eqtbl_amd_t *ucode_eqtbl_amd; 572449e17fSsherrym 582449e17fSsherrym /* 592449e17fSsherrym * mcpu_ucode_info for the boot CPU. Statically allocated. 602449e17fSsherrym */ 612449e17fSsherrym static struct cpu_ucode_info cpu_ucode_info0; 622449e17fSsherrym 63adc586deSMark Johnson static ucode_file_t ucodefile; 642449e17fSsherrym 65adc586deSMark Johnson static void* ucode_zalloc(processorid_t, size_t); 66adc586deSMark Johnson static void ucode_free(processorid_t, void *, size_t); 67adc586deSMark Johnson 68adc586deSMark Johnson static int ucode_capable_amd(cpu_t *); 69adc586deSMark Johnson static int ucode_capable_intel(cpu_t *); 70adc586deSMark Johnson 71adc586deSMark Johnson static ucode_errno_t ucode_extract_amd(ucode_update_t *, uint8_t *, int); 72adc586deSMark Johnson static ucode_errno_t ucode_extract_intel(ucode_update_t *, uint8_t *, 73adc586deSMark Johnson int); 74adc586deSMark Johnson 75adc586deSMark Johnson static void ucode_file_reset_amd(ucode_file_t *, processorid_t); 76adc586deSMark Johnson static void ucode_file_reset_intel(ucode_file_t *, processorid_t); 77adc586deSMark Johnson 78adc586deSMark Johnson static uint32_t ucode_load_amd(ucode_file_t *, cpu_ucode_info_t *, cpu_t *); 79adc586deSMark Johnson static uint32_t ucode_load_intel(ucode_file_t *, cpu_ucode_info_t *, cpu_t *); 80adc586deSMark Johnson 81882a7af5SMark Johnson #ifdef __xpv 82adc586deSMark Johnson static void ucode_load_xpv(ucode_update_t *); 830ba6f73dSMark Johnson static void ucode_chipset_amd(uint8_t *, int); 84882a7af5SMark Johnson #endif 852449e17fSsherrym 860ba6f73dSMark Johnson static int ucode_equiv_cpu_amd(cpu_t *, uint16_t *); 87adc586deSMark Johnson 88adc586deSMark Johnson static ucode_errno_t ucode_locate_amd(cpu_t *, cpu_ucode_info_t *, 89adc586deSMark Johnson ucode_file_t *); 90adc586deSMark Johnson static ucode_errno_t ucode_locate_intel(cpu_t *, cpu_ucode_info_t *, 91adc586deSMark Johnson ucode_file_t *); 92adc586deSMark Johnson 930ba6f73dSMark Johnson #ifndef __xpv 940ba6f73dSMark Johnson static ucode_errno_t ucode_match_amd(uint16_t, cpu_ucode_info_t *, 95adc586deSMark Johnson ucode_file_amd_t *, int); 960ba6f73dSMark Johnson #endif 97adc586deSMark Johnson static ucode_errno_t ucode_match_intel(int, cpu_ucode_info_t *, 98adc586deSMark Johnson ucode_header_intel_t *, ucode_ext_table_intel_t *); 99adc586deSMark Johnson 100adc586deSMark Johnson static void ucode_read_rev_amd(cpu_ucode_info_t *); 101adc586deSMark Johnson static void ucode_read_rev_intel(cpu_ucode_info_t *); 102adc586deSMark Johnson 103adc586deSMark Johnson static const struct ucode_ops ucode_amd = { 104adc586deSMark Johnson MSR_AMD_PATCHLOADER, 105adc586deSMark Johnson ucode_capable_amd, 106adc586deSMark Johnson ucode_file_reset_amd, 107adc586deSMark Johnson ucode_read_rev_amd, 108adc586deSMark Johnson ucode_load_amd, 109adc586deSMark Johnson ucode_validate_amd, 110adc586deSMark Johnson ucode_extract_amd, 111adc586deSMark Johnson ucode_locate_amd 112adc586deSMark Johnson }; 113adc586deSMark Johnson 114adc586deSMark Johnson static const struct ucode_ops ucode_intel = { 115adc586deSMark Johnson MSR_INTC_UCODE_WRITE, 116adc586deSMark Johnson ucode_capable_intel, 117adc586deSMark Johnson ucode_file_reset_intel, 118adc586deSMark Johnson ucode_read_rev_intel, 119adc586deSMark Johnson ucode_load_intel, 120adc586deSMark Johnson ucode_validate_intel, 121adc586deSMark Johnson ucode_extract_intel, 122adc586deSMark Johnson ucode_locate_intel 123adc586deSMark Johnson }; 124adc586deSMark Johnson 125adc586deSMark Johnson const struct ucode_ops *ucode; 126adc586deSMark Johnson 1272449e17fSsherrym static const char ucode_failure_fmt[] = 12888699bddSsherrym "cpu%d: failed to update microcode from version 0x%x to 0x%x\n"; 1292449e17fSsherrym static const char ucode_success_fmt[] = 13088699bddSsherrym "?cpu%d: microcode has been updated from version 0x%x to 0x%x\n"; 1312449e17fSsherrym 1322449e17fSsherrym /* 1332449e17fSsherrym * Force flag. If set, the first microcode binary that matches 1342449e17fSsherrym * signature and platform id will be used for microcode update, 1352449e17fSsherrym * regardless of version. Should only be used for debugging. 1362449e17fSsherrym */ 1372449e17fSsherrym int ucode_force_update = 0; 1382449e17fSsherrym 1392449e17fSsherrym /* 1402449e17fSsherrym * Allocate space for mcpu_ucode_info in the machcpu structure 1412449e17fSsherrym * for all non-boot CPUs. 1422449e17fSsherrym */ 1432449e17fSsherrym void 1442449e17fSsherrym ucode_alloc_space(cpu_t *cp) 1452449e17fSsherrym { 1462449e17fSsherrym ASSERT(cp->cpu_id != 0); 147a3114836SGerry Liu ASSERT(cp->cpu_m.mcpu_ucode_info == NULL); 1482449e17fSsherrym cp->cpu_m.mcpu_ucode_info = 1492449e17fSsherrym kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP); 1502449e17fSsherrym } 1512449e17fSsherrym 1522449e17fSsherrym void 1532449e17fSsherrym ucode_free_space(cpu_t *cp) 1542449e17fSsherrym { 155a3114836SGerry Liu ASSERT(cp->cpu_m.mcpu_ucode_info != NULL); 156a3114836SGerry Liu ASSERT(cp->cpu_m.mcpu_ucode_info != &cpu_ucode_info0); 1572449e17fSsherrym kmem_free(cp->cpu_m.mcpu_ucode_info, 1582449e17fSsherrym sizeof (*cp->cpu_m.mcpu_ucode_info)); 159a3114836SGerry Liu cp->cpu_m.mcpu_ucode_info = NULL; 1602449e17fSsherrym } 1612449e17fSsherrym 1622449e17fSsherrym /* 1632449e17fSsherrym * Called when we are done with microcode update on all processors to free up 1642449e17fSsherrym * space allocated for the microcode file. 1652449e17fSsherrym */ 1662449e17fSsherrym void 167adc586deSMark Johnson ucode_cleanup() 1682449e17fSsherrym { 169126b0a71SMark Johnson if (ucode == NULL) 170126b0a71SMark Johnson return; 171adc586deSMark Johnson 172adc586deSMark Johnson ucode->file_reset(&ucodefile, -1); 173adc586deSMark Johnson } 174adc586deSMark Johnson 175adc586deSMark Johnson /* 176adc586deSMark Johnson * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is 177adc586deSMark Johnson * allocated with BOP_ALLOC() and does not require a free. 178adc586deSMark Johnson */ 179adc586deSMark Johnson static void* 180adc586deSMark Johnson ucode_zalloc(processorid_t id, size_t size) 181adc586deSMark Johnson { 182adc586deSMark Johnson if (id) 183adc586deSMark Johnson return (kmem_zalloc(size, KM_NOSLEEP)); 184adc586deSMark Johnson 185adc586deSMark Johnson /* BOP_ALLOC() failure results in panic */ 186adc586deSMark Johnson return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE)); 187adc586deSMark Johnson } 188adc586deSMark Johnson 189adc586deSMark Johnson static void 190adc586deSMark Johnson ucode_free(processorid_t id, void* buf, size_t size) 191adc586deSMark Johnson { 192adc586deSMark Johnson if (id) 193adc586deSMark Johnson kmem_free(buf, size); 1942449e17fSsherrym } 1952449e17fSsherrym 1962449e17fSsherrym /* 1972449e17fSsherrym * Check whether or not a processor is capable of microcode operations 1982449e17fSsherrym * Returns 1 if it is capable, 0 if not. 199adc586deSMark Johnson * 200adc586deSMark Johnson * At this point we only support microcode update for: 201adc586deSMark Johnson * - Intel processors family 6 and above, and 202adc586deSMark Johnson * - AMD processors family 0x10 and above. 203adc586deSMark Johnson * 204adc586deSMark Johnson * We also assume that we don't support a mix of Intel and 205adc586deSMark Johnson * AMD processors in the same box. 206adc586deSMark Johnson * 207*79ec9da8SYuri Pankov * An i86xpv guest domain or VM can't update the microcode. 2082449e17fSsherrym */ 209*79ec9da8SYuri Pankov 210*79ec9da8SYuri Pankov #define XPVDOMU_OR_HVM \ 211*79ec9da8SYuri Pankov ((hwenv == HW_XEN_PV && !is_controldom()) || (hwenv & HW_VIRTUAL) != 0) 212*79ec9da8SYuri Pankov 213adc586deSMark Johnson /*ARGSUSED*/ 2142449e17fSsherrym static int 215adc586deSMark Johnson ucode_capable_amd(cpu_t *cp) 2162449e17fSsherrym { 217b9bfdccdSStuart Maybee int hwenv = get_hwenv(); 218b9bfdccdSStuart Maybee 219*79ec9da8SYuri Pankov if (XPVDOMU_OR_HVM) 220adc586deSMark Johnson return (0); 221*79ec9da8SYuri Pankov 2220ba6f73dSMark Johnson return (cpuid_getfamily(cp) >= 0x10); 223adc586deSMark Johnson } 2240ba6f73dSMark Johnson 225adc586deSMark Johnson static int 226adc586deSMark Johnson ucode_capable_intel(cpu_t *cp) 227adc586deSMark Johnson { 228b9bfdccdSStuart Maybee int hwenv = get_hwenv(); 229b9bfdccdSStuart Maybee 230*79ec9da8SYuri Pankov if (XPVDOMU_OR_HVM) 231882a7af5SMark Johnson return (0); 232*79ec9da8SYuri Pankov 233adc586deSMark Johnson return (cpuid_getfamily(cp) >= 6); 2342449e17fSsherrym } 2352449e17fSsherrym 2362449e17fSsherrym /* 2372449e17fSsherrym * Called when it is no longer necessary to keep the microcode around, 2382449e17fSsherrym * or when the cached microcode doesn't match the CPU being processed. 2392449e17fSsherrym */ 2402449e17fSsherrym static void 241adc586deSMark Johnson ucode_file_reset_amd(ucode_file_t *ufp, processorid_t id) 2422449e17fSsherrym { 243adc586deSMark Johnson ucode_file_amd_t *ucodefp = ufp->amd; 2442449e17fSsherrym 2452449e17fSsherrym if (ucodefp == NULL) 2462449e17fSsherrym return; 2472449e17fSsherrym 248adc586deSMark Johnson ucode_free(id, ucodefp, sizeof (ucode_file_amd_t)); 249adc586deSMark Johnson ufp->amd = NULL; 250adc586deSMark Johnson } 251adc586deSMark Johnson 252adc586deSMark Johnson static void 253adc586deSMark Johnson ucode_file_reset_intel(ucode_file_t *ufp, processorid_t id) 254adc586deSMark Johnson { 255adc586deSMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel; 256adc586deSMark Johnson int total_size, body_size; 257adc586deSMark Johnson 258adc586deSMark Johnson if (ucodefp == NULL || ucodefp->uf_header == NULL) 259adc586deSMark Johnson return; 260adc586deSMark Johnson 261adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size); 262adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size); 2632449e17fSsherrym if (ucodefp->uf_body) { 264adc586deSMark Johnson ucode_free(id, ucodefp->uf_body, body_size); 2652449e17fSsherrym ucodefp->uf_body = NULL; 2662449e17fSsherrym } 2672449e17fSsherrym 2682449e17fSsherrym if (ucodefp->uf_ext_table) { 269adc586deSMark Johnson int size = total_size - body_size - UCODE_HEADER_SIZE_INTEL; 270adc586deSMark Johnson 271adc586deSMark Johnson ucode_free(id, ucodefp->uf_ext_table, size); 2722449e17fSsherrym ucodefp->uf_ext_table = NULL; 2732449e17fSsherrym } 2742449e17fSsherrym 275adc586deSMark Johnson ucode_free(id, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL); 276adc586deSMark Johnson ucodefp->uf_header = NULL; 277adc586deSMark Johnson } 278adc586deSMark Johnson 279adc586deSMark Johnson /* 280adc586deSMark Johnson * Find the equivalent CPU id in the equivalence table. 281adc586deSMark Johnson */ 282adc586deSMark Johnson static int 2830ba6f73dSMark Johnson ucode_equiv_cpu_amd(cpu_t *cp, uint16_t *eq_sig) 284adc586deSMark Johnson { 285adc586deSMark Johnson char name[MAXPATHLEN]; 286adc586deSMark Johnson intptr_t fd; 287adc586deSMark Johnson int count; 288adc586deSMark Johnson int offset = 0, cpi_sig = cpuid_getsig(cp); 289adc586deSMark Johnson ucode_eqtbl_amd_t *eqtbl = ucode_eqtbl_amd; 290adc586deSMark Johnson 291adc586deSMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/equivalence-table", 292adc586deSMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp)); 293adc586deSMark Johnson 294adc586deSMark Johnson /* 295adc586deSMark Johnson * No kmem_zalloc() etc. available on boot cpu. 296adc586deSMark Johnson */ 297adc586deSMark Johnson if (cp->cpu_id == 0) { 298adc586deSMark Johnson if ((fd = kobj_open(name)) == -1) 299adc586deSMark Johnson return (EM_OPENFILE); 300adc586deSMark Johnson /* ucode_zalloc() cannot fail on boot cpu */ 301adc586deSMark Johnson eqtbl = ucode_zalloc(cp->cpu_id, sizeof (*eqtbl)); 302adc586deSMark Johnson ASSERT(eqtbl); 303adc586deSMark Johnson do { 304adc586deSMark Johnson count = kobj_read(fd, (int8_t *)eqtbl, 305adc586deSMark Johnson sizeof (*eqtbl), offset); 306adc586deSMark Johnson if (count != sizeof (*eqtbl)) { 307adc586deSMark Johnson (void) kobj_close(fd); 308adc586deSMark Johnson return (EM_HIGHERREV); 309adc586deSMark Johnson } 310adc586deSMark Johnson offset += count; 311adc586deSMark Johnson } while (eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig); 312adc586deSMark Johnson (void) kobj_close(fd); 313adc586deSMark Johnson } 314adc586deSMark Johnson 315adc586deSMark Johnson /* 316adc586deSMark Johnson * If not already done, load the equivalence table. 317adc586deSMark Johnson * Not done on boot CPU. 318adc586deSMark Johnson */ 319adc586deSMark Johnson if (eqtbl == NULL) { 320adc586deSMark Johnson struct _buf *eq; 321adc586deSMark Johnson uint64_t size; 322adc586deSMark Johnson 323adc586deSMark Johnson if ((eq = kobj_open_file(name)) == (struct _buf *)-1) 324adc586deSMark Johnson return (EM_OPENFILE); 325adc586deSMark Johnson 326adc586deSMark Johnson if (kobj_get_filesize(eq, &size) < 0) { 327adc586deSMark Johnson kobj_close_file(eq); 328adc586deSMark Johnson return (EM_OPENFILE); 329adc586deSMark Johnson } 330adc586deSMark Johnson 331adc586deSMark Johnson ucode_eqtbl_amd = kmem_zalloc(size, KM_NOSLEEP); 332adc586deSMark Johnson if (ucode_eqtbl_amd == NULL) { 333adc586deSMark Johnson kobj_close_file(eq); 334adc586deSMark Johnson return (EM_NOMEM); 335adc586deSMark Johnson } 336adc586deSMark Johnson 337adc586deSMark Johnson count = kobj_read_file(eq, (char *)ucode_eqtbl_amd, size, 0); 338adc586deSMark Johnson kobj_close_file(eq); 339adc586deSMark Johnson 340adc586deSMark Johnson if (count != size) 341adc586deSMark Johnson return (EM_FILESIZE); 342adc586deSMark Johnson } 343adc586deSMark Johnson 344adc586deSMark Johnson /* Get the equivalent CPU id. */ 345adc586deSMark Johnson if (cp->cpu_id) 346adc586deSMark Johnson for (eqtbl = ucode_eqtbl_amd; 347adc586deSMark Johnson eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig; 348adc586deSMark Johnson eqtbl++) 349adc586deSMark Johnson ; 350adc586deSMark Johnson 351adc586deSMark Johnson *eq_sig = eqtbl->ue_equiv_cpu; 352adc586deSMark Johnson 353adc586deSMark Johnson /* No equivalent CPU id found, assume outdated microcode file. */ 354adc586deSMark Johnson if (*eq_sig == 0) 355adc586deSMark Johnson return (EM_HIGHERREV); 356adc586deSMark Johnson 357adc586deSMark Johnson return (EM_OK); 3582449e17fSsherrym } 3592449e17fSsherrym 3602449e17fSsherrym /* 3610ba6f73dSMark Johnson * xVM cannot check for the presence of PCI devices. Look for chipset- 3620ba6f73dSMark Johnson * specific microcode patches in the container file and disable them 3630ba6f73dSMark Johnson * by setting their CPU revision to an invalid value. 3640ba6f73dSMark Johnson */ 3650ba6f73dSMark Johnson #ifdef __xpv 3660ba6f73dSMark Johnson static void 3670ba6f73dSMark Johnson ucode_chipset_amd(uint8_t *buf, int size) 3680ba6f73dSMark Johnson { 3690ba6f73dSMark Johnson ucode_header_amd_t *uh; 3700ba6f73dSMark Johnson uint32_t *ptr = (uint32_t *)buf; 3710ba6f73dSMark Johnson int len = 0; 3720ba6f73dSMark Johnson 3730ba6f73dSMark Johnson /* skip to first microcode patch */ 3740ba6f73dSMark Johnson ptr += 2; len = *ptr++; ptr += len >> 2; size -= len; 3750ba6f73dSMark Johnson 3760ba6f73dSMark Johnson while (size >= sizeof (ucode_header_amd_t) + 8) { 3770ba6f73dSMark Johnson ptr++; len = *ptr++; 3780ba6f73dSMark Johnson uh = (ucode_header_amd_t *)ptr; 3790ba6f73dSMark Johnson ptr += len >> 2; size -= len; 3800ba6f73dSMark Johnson 3810ba6f73dSMark Johnson if (uh->uh_nb_id) { 3820ba6f73dSMark Johnson cmn_err(CE_WARN, "ignoring northbridge-specific ucode: " 3830ba6f73dSMark Johnson "chipset id %x, revision %x", 3840ba6f73dSMark Johnson uh->uh_nb_id, uh->uh_nb_rev); 3850ba6f73dSMark Johnson uh->uh_cpu_rev = 0xffff; 3860ba6f73dSMark Johnson } 3870ba6f73dSMark Johnson 3880ba6f73dSMark Johnson if (uh->uh_sb_id) { 3890ba6f73dSMark Johnson cmn_err(CE_WARN, "ignoring southbridge-specific ucode: " 3900ba6f73dSMark Johnson "chipset id %x, revision %x", 3910ba6f73dSMark Johnson uh->uh_sb_id, uh->uh_sb_rev); 3920ba6f73dSMark Johnson uh->uh_cpu_rev = 0xffff; 3930ba6f73dSMark Johnson } 3940ba6f73dSMark Johnson } 3950ba6f73dSMark Johnson } 3960ba6f73dSMark Johnson #endif 3970ba6f73dSMark Johnson 3980ba6f73dSMark Johnson /* 3992449e17fSsherrym * Populate the ucode file structure from microcode file corresponding to 4002449e17fSsherrym * this CPU, if exists. 4012449e17fSsherrym * 4022449e17fSsherrym * Return EM_OK on success, corresponding error code on failure. 4032449e17fSsherrym */ 4040ba6f73dSMark Johnson /*ARGSUSED*/ 4052449e17fSsherrym static ucode_errno_t 406adc586deSMark Johnson ucode_locate_amd(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp) 407adc586deSMark Johnson { 408adc586deSMark Johnson char name[MAXPATHLEN]; 409adc586deSMark Johnson intptr_t fd; 4100ba6f73dSMark Johnson int count, rc; 411adc586deSMark Johnson ucode_file_amd_t *ucodefp = ufp->amd; 412adc586deSMark Johnson 4130ba6f73dSMark Johnson #ifndef __xpv 4140ba6f73dSMark Johnson uint16_t eq_sig = 0; 4150ba6f73dSMark Johnson int i; 4160ba6f73dSMark Johnson 417adc586deSMark Johnson /* get equivalent CPU id */ 418adc586deSMark Johnson if ((rc = ucode_equiv_cpu_amd(cp, &eq_sig)) != EM_OK) 419adc586deSMark Johnson return (rc); 420adc586deSMark Johnson 421adc586deSMark Johnson /* 422adc586deSMark Johnson * Allocate a buffer for the microcode patch. If the buffer has been 423adc586deSMark Johnson * allocated before, check for a matching microcode to avoid loading 424adc586deSMark Johnson * the file again. 425adc586deSMark Johnson */ 426adc586deSMark Johnson if (ucodefp == NULL) 427adc586deSMark Johnson ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp)); 428adc586deSMark Johnson else if (ucode_match_amd(eq_sig, uinfop, ucodefp, sizeof (*ucodefp)) 429adc586deSMark Johnson == EM_OK) 430adc586deSMark Johnson return (EM_OK); 431adc586deSMark Johnson 432adc586deSMark Johnson if (ucodefp == NULL) 433adc586deSMark Johnson return (EM_NOMEM); 434adc586deSMark Johnson 435adc586deSMark Johnson ufp->amd = ucodefp; 436adc586deSMark Johnson 437adc586deSMark Johnson /* 438adc586deSMark Johnson * Find the patch for this CPU. The patch files are named XXXX-YY, where 439adc586deSMark Johnson * XXXX is the equivalent CPU id and YY is the running patch number. 440adc586deSMark Johnson * Patches specific to certain chipsets are guaranteed to have lower 441adc586deSMark Johnson * numbers than less specific patches, so we can just load the first 442adc586deSMark Johnson * patch that matches. 443adc586deSMark Johnson */ 444adc586deSMark Johnson 445adc586deSMark Johnson for (i = 0; i < 0xff; i++) { 446adc586deSMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/%04X-%02X", 447adc586deSMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), eq_sig, i); 448adc586deSMark Johnson if ((fd = kobj_open(name)) == -1) 449adc586deSMark Johnson return (EM_NOMATCH); 450adc586deSMark Johnson count = kobj_read(fd, (char *)ucodefp, sizeof (*ucodefp), 0); 451adc586deSMark Johnson (void) kobj_close(fd); 452adc586deSMark Johnson 453adc586deSMark Johnson if (ucode_match_amd(eq_sig, uinfop, ucodefp, count) == EM_OK) 454adc586deSMark Johnson return (EM_OK); 455adc586deSMark Johnson } 456adc586deSMark Johnson return (EM_NOMATCH); 4570ba6f73dSMark Johnson #else 4580ba6f73dSMark Johnson int size = 0; 4590ba6f73dSMark Johnson char c; 4600ba6f73dSMark Johnson 4610ba6f73dSMark Johnson /* 4620ba6f73dSMark Johnson * The xVM case is special. To support mixed-revision systems, the 4630ba6f73dSMark Johnson * hypervisor will choose which patch to load for which CPU, so the 4640ba6f73dSMark Johnson * whole microcode patch container file will have to be loaded. 4650ba6f73dSMark Johnson * 4660ba6f73dSMark Johnson * Since this code is only run on the boot cpu, we don't have to care 4670ba6f73dSMark Johnson * about failing ucode_zalloc() or freeing allocated memory. 4680ba6f73dSMark Johnson */ 4690ba6f73dSMark Johnson if (cp->cpu_id != 0) 4700ba6f73dSMark Johnson return (EM_INVALIDARG); 4710ba6f73dSMark Johnson 4720ba6f73dSMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/container", 4730ba6f73dSMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp)); 4740ba6f73dSMark Johnson 4750ba6f73dSMark Johnson if ((fd = kobj_open(name)) == -1) 4760ba6f73dSMark Johnson return (EM_OPENFILE); 4770ba6f73dSMark Johnson 4780ba6f73dSMark Johnson /* get the file size by counting bytes */ 4790ba6f73dSMark Johnson do { 4800ba6f73dSMark Johnson count = kobj_read(fd, &c, 1, size); 4810ba6f73dSMark Johnson size += count; 4820ba6f73dSMark Johnson } while (count); 4830ba6f73dSMark Johnson 4840ba6f73dSMark Johnson ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp)); 4850ba6f73dSMark Johnson ASSERT(ucodefp); 4860ba6f73dSMark Johnson ufp->amd = ucodefp; 4870ba6f73dSMark Johnson 4880ba6f73dSMark Johnson ucodefp->usize = size; 4890ba6f73dSMark Johnson ucodefp->ucodep = ucode_zalloc(cp->cpu_id, size); 4900ba6f73dSMark Johnson ASSERT(ucodefp->ucodep); 4910ba6f73dSMark Johnson 4920ba6f73dSMark Johnson /* load the microcode patch container file */ 4930ba6f73dSMark Johnson count = kobj_read(fd, (char *)ucodefp->ucodep, size, 0); 4940ba6f73dSMark Johnson (void) kobj_close(fd); 4950ba6f73dSMark Johnson 4960ba6f73dSMark Johnson if (count != size) 4970ba6f73dSMark Johnson return (EM_FILESIZE); 4980ba6f73dSMark Johnson 4990ba6f73dSMark Johnson /* make sure the container file is valid */ 5000ba6f73dSMark Johnson rc = ucode->validate(ucodefp->ucodep, ucodefp->usize); 5010ba6f73dSMark Johnson 5020ba6f73dSMark Johnson if (rc != EM_OK) 5030ba6f73dSMark Johnson return (rc); 5040ba6f73dSMark Johnson 5050ba6f73dSMark Johnson /* disable chipset-specific patches */ 5060ba6f73dSMark Johnson ucode_chipset_amd(ucodefp->ucodep, ucodefp->usize); 5070ba6f73dSMark Johnson 5080ba6f73dSMark Johnson return (EM_OK); 5090ba6f73dSMark Johnson #endif 510adc586deSMark Johnson } 511adc586deSMark Johnson 512adc586deSMark Johnson static ucode_errno_t 513adc586deSMark Johnson ucode_locate_intel(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp) 5142449e17fSsherrym { 5152449e17fSsherrym char name[MAXPATHLEN]; 5162449e17fSsherrym intptr_t fd; 5172449e17fSsherrym int count; 518adc586deSMark Johnson int header_size = UCODE_HEADER_SIZE_INTEL; 5192449e17fSsherrym int cpi_sig = cpuid_getsig(cp); 5202449e17fSsherrym ucode_errno_t rc = EM_OK; 521adc586deSMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel; 522adc586deSMark Johnson 523adc586deSMark Johnson ASSERT(ucode); 5242449e17fSsherrym 5252449e17fSsherrym /* 5262449e17fSsherrym * If the microcode matches the CPU we are processing, use it. 5272449e17fSsherrym */ 528adc586deSMark Johnson if (ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header, 5292449e17fSsherrym ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) { 5302449e17fSsherrym return (EM_OK); 5312449e17fSsherrym } 5322449e17fSsherrym 5332449e17fSsherrym /* 5342449e17fSsherrym * Look for microcode file with the right name. 5352449e17fSsherrym */ 5362449e17fSsherrym (void) snprintf(name, MAXPATHLEN, "/%s/%s/%08X-%02X", 5372449e17fSsherrym UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), cpi_sig, 5382449e17fSsherrym uinfop->cui_platid); 5392449e17fSsherrym if ((fd = kobj_open(name)) == -1) { 5402449e17fSsherrym return (EM_OPENFILE); 5412449e17fSsherrym } 5422449e17fSsherrym 5432449e17fSsherrym /* 5442449e17fSsherrym * We found a microcode file for the CPU we are processing, 5452449e17fSsherrym * reset the microcode data structure and read in the new 5462449e17fSsherrym * file. 5472449e17fSsherrym */ 548adc586deSMark Johnson ucode->file_reset(ufp, cp->cpu_id); 5492449e17fSsherrym 550adc586deSMark Johnson ucodefp->uf_header = ucode_zalloc(cp->cpu_id, header_size); 551adc586deSMark Johnson if (ucodefp->uf_header == NULL) 552adc586deSMark Johnson return (EM_NOMEM); 553adc586deSMark Johnson 554adc586deSMark Johnson count = kobj_read(fd, (char *)ucodefp->uf_header, header_size, 0); 5552449e17fSsherrym 5562449e17fSsherrym switch (count) { 557adc586deSMark Johnson case UCODE_HEADER_SIZE_INTEL: { 5582449e17fSsherrym 559adc586deSMark Johnson ucode_header_intel_t *uhp = ucodefp->uf_header; 5602449e17fSsherrym uint32_t offset = header_size; 5612449e17fSsherrym int total_size, body_size, ext_size; 5622449e17fSsherrym uint32_t sum = 0; 5632449e17fSsherrym 5642449e17fSsherrym /* 5652449e17fSsherrym * Make sure that the header contains valid fields. 5662449e17fSsherrym */ 567adc586deSMark Johnson if ((rc = ucode_header_validate_intel(uhp)) == EM_OK) { 568adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 569adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 570adc586deSMark Johnson ucodefp->uf_body = ucode_zalloc(cp->cpu_id, body_size); 571adc586deSMark Johnson if (ucodefp->uf_body == NULL) { 5722449e17fSsherrym rc = EM_NOMEM; 5732449e17fSsherrym break; 5742449e17fSsherrym } 5752449e17fSsherrym 5762449e17fSsherrym if (kobj_read(fd, (char *)ucodefp->uf_body, 5772449e17fSsherrym body_size, offset) != body_size) 5782449e17fSsherrym rc = EM_FILESIZE; 5792449e17fSsherrym } 5802449e17fSsherrym 5812449e17fSsherrym if (rc) 5822449e17fSsherrym break; 5832449e17fSsherrym 584adc586deSMark Johnson sum = ucode_checksum_intel(0, header_size, 585adc586deSMark Johnson (uint8_t *)ucodefp->uf_header); 586adc586deSMark Johnson if (ucode_checksum_intel(sum, body_size, ucodefp->uf_body)) { 5872449e17fSsherrym rc = EM_CHECKSUM; 5882449e17fSsherrym break; 5892449e17fSsherrym } 5902449e17fSsherrym 5912449e17fSsherrym /* 5922449e17fSsherrym * Check to see if there is extended signature table. 5932449e17fSsherrym */ 5942449e17fSsherrym offset = body_size + header_size; 5952449e17fSsherrym ext_size = total_size - offset; 5962449e17fSsherrym 5972449e17fSsherrym if (ext_size <= 0) 5982449e17fSsherrym break; 5992449e17fSsherrym 600adc586deSMark Johnson ucodefp->uf_ext_table = ucode_zalloc(cp->cpu_id, ext_size); 601adc586deSMark Johnson if (ucodefp->uf_ext_table == NULL) { 6022449e17fSsherrym rc = EM_NOMEM; 6032449e17fSsherrym break; 6042449e17fSsherrym } 6052449e17fSsherrym 6062449e17fSsherrym if (kobj_read(fd, (char *)ucodefp->uf_ext_table, 6072449e17fSsherrym ext_size, offset) != ext_size) { 6082449e17fSsherrym rc = EM_FILESIZE; 609adc586deSMark Johnson } else if (ucode_checksum_intel(0, ext_size, 6102449e17fSsherrym (uint8_t *)(ucodefp->uf_ext_table))) { 6112449e17fSsherrym rc = EM_CHECKSUM; 6122449e17fSsherrym } else { 6132449e17fSsherrym int i; 6142449e17fSsherrym 615adc586deSMark Johnson ext_size -= UCODE_EXT_TABLE_SIZE_INTEL; 6162449e17fSsherrym for (i = 0; i < ucodefp->uf_ext_table->uet_count; 6172449e17fSsherrym i++) { 618adc586deSMark Johnson if (ucode_checksum_intel(0, 619adc586deSMark Johnson UCODE_EXT_SIG_SIZE_INTEL, 6202449e17fSsherrym (uint8_t *)(&(ucodefp->uf_ext_table-> 6212449e17fSsherrym uet_ext_sig[i])))) { 6222449e17fSsherrym rc = EM_CHECKSUM; 6232449e17fSsherrym break; 6242449e17fSsherrym } 6252449e17fSsherrym } 6262449e17fSsherrym } 6272449e17fSsherrym break; 6282449e17fSsherrym } 6292449e17fSsherrym 6302449e17fSsherrym default: 6312449e17fSsherrym rc = EM_FILESIZE; 6322449e17fSsherrym break; 6332449e17fSsherrym } 6342449e17fSsherrym 6352449e17fSsherrym kobj_close(fd); 6362449e17fSsherrym 6372449e17fSsherrym if (rc != EM_OK) 6382449e17fSsherrym return (rc); 6392449e17fSsherrym 640adc586deSMark Johnson rc = ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header, 6412449e17fSsherrym ucodefp->uf_ext_table); 6422449e17fSsherrym 6432449e17fSsherrym return (rc); 6442449e17fSsherrym } 6452449e17fSsherrym 6460ba6f73dSMark Johnson #ifndef __xpv 647adc586deSMark Johnson static ucode_errno_t 6480ba6f73dSMark Johnson ucode_match_amd(uint16_t eq_sig, cpu_ucode_info_t *uinfop, 6490ba6f73dSMark Johnson ucode_file_amd_t *ucodefp, int size) 650adc586deSMark Johnson { 651adc586deSMark Johnson ucode_header_amd_t *uh; 652adc586deSMark Johnson 653adc586deSMark Johnson if (ucodefp == NULL || size < sizeof (ucode_header_amd_t)) 654adc586deSMark Johnson return (EM_NOMATCH); 655adc586deSMark Johnson 6565e53ed34SHans Rosenfeld uh = &ucodefp->uf_header; 6575e53ed34SHans Rosenfeld 658adc586deSMark Johnson /* 659adc586deSMark Johnson * Don't even think about loading patches that would require code 6605e53ed34SHans Rosenfeld * execution. Does not apply to patches for family 0x14 and beyond. 661adc586deSMark Johnson */ 6625e53ed34SHans Rosenfeld if (uh->uh_cpu_rev < 0x5000 && 6635e53ed34SHans Rosenfeld size > offsetof(ucode_file_amd_t, uf_code_present) && 664adc586deSMark Johnson ucodefp->uf_code_present) 665adc586deSMark Johnson return (EM_NOMATCH); 666adc586deSMark Johnson 667adc586deSMark Johnson if (eq_sig != uh->uh_cpu_rev) 668adc586deSMark Johnson return (EM_NOMATCH); 669adc586deSMark Johnson 670adc586deSMark Johnson if (uh->uh_nb_id) { 671adc586deSMark Johnson cmn_err(CE_WARN, "ignoring northbridge-specific ucode: " 672adc586deSMark Johnson "chipset id %x, revision %x", uh->uh_nb_id, uh->uh_nb_rev); 673adc586deSMark Johnson return (EM_NOMATCH); 674adc586deSMark Johnson } 675adc586deSMark Johnson 676adc586deSMark Johnson if (uh->uh_sb_id) { 677adc586deSMark Johnson cmn_err(CE_WARN, "ignoring southbridge-specific ucode: " 678adc586deSMark Johnson "chipset id %x, revision %x", uh->uh_sb_id, uh->uh_sb_rev); 679adc586deSMark Johnson return (EM_NOMATCH); 680adc586deSMark Johnson } 681adc586deSMark Johnson 6825e53ed34SHans Rosenfeld if (uh->uh_patch_id <= uinfop->cui_rev && !ucode_force_update) 683adc586deSMark Johnson return (EM_HIGHERREV); 684adc586deSMark Johnson 685adc586deSMark Johnson return (EM_OK); 686adc586deSMark Johnson } 6870ba6f73dSMark Johnson #endif 6882449e17fSsherrym 6892449e17fSsherrym /* 6902449e17fSsherrym * Returns 1 if the microcode is for this processor; 0 otherwise. 6912449e17fSsherrym */ 6922449e17fSsherrym static ucode_errno_t 693adc586deSMark Johnson ucode_match_intel(int cpi_sig, cpu_ucode_info_t *uinfop, 694adc586deSMark Johnson ucode_header_intel_t *uhp, ucode_ext_table_intel_t *uetp) 6952449e17fSsherrym { 696adc586deSMark Johnson if (uhp == NULL) 697adc586deSMark Johnson return (EM_NOMATCH); 6982449e17fSsherrym 699adc586deSMark Johnson if (UCODE_MATCH_INTEL(cpi_sig, uhp->uh_signature, 7002449e17fSsherrym uinfop->cui_platid, uhp->uh_proc_flags)) { 7012449e17fSsherrym 7022449e17fSsherrym if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update) 7032449e17fSsherrym return (EM_HIGHERREV); 7042449e17fSsherrym 7052449e17fSsherrym return (EM_OK); 7062449e17fSsherrym } 7072449e17fSsherrym 7082449e17fSsherrym if (uetp != NULL) { 7092449e17fSsherrym int i; 7102449e17fSsherrym 7112449e17fSsherrym for (i = 0; i < uetp->uet_count; i++) { 712adc586deSMark Johnson ucode_ext_sig_intel_t *uesp; 7132449e17fSsherrym 7142449e17fSsherrym uesp = &uetp->uet_ext_sig[i]; 7152449e17fSsherrym 716adc586deSMark Johnson if (UCODE_MATCH_INTEL(cpi_sig, uesp->ues_signature, 7172449e17fSsherrym uinfop->cui_platid, uesp->ues_proc_flags)) { 7182449e17fSsherrym 7192449e17fSsherrym if (uinfop->cui_rev >= uhp->uh_rev && 7202449e17fSsherrym !ucode_force_update) 7212449e17fSsherrym return (EM_HIGHERREV); 7222449e17fSsherrym 7232449e17fSsherrym return (EM_OK); 7242449e17fSsherrym } 7252449e17fSsherrym } 7262449e17fSsherrym } 7272449e17fSsherrym 7282449e17fSsherrym return (EM_NOMATCH); 7292449e17fSsherrym } 7302449e17fSsherrym 7312449e17fSsherrym /*ARGSUSED*/ 7322449e17fSsherrym static int 7332449e17fSsherrym ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3) 7342449e17fSsherrym { 735adc586deSMark Johnson ucode_update_t *uusp = (ucode_update_t *)arg1; 736adc586deSMark Johnson cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info; 7375e53ed34SHans Rosenfeld #ifndef __xpv 7385e53ed34SHans Rosenfeld on_trap_data_t otd; 7395e53ed34SHans Rosenfeld #endif 7402449e17fSsherrym 741adc586deSMark Johnson ASSERT(ucode); 7422449e17fSsherrym ASSERT(uusp->ucodep); 7432449e17fSsherrym 744882a7af5SMark Johnson #ifndef __xpv 7452449e17fSsherrym /* 7462449e17fSsherrym * Check one more time to see if it is really necessary to update 7472449e17fSsherrym * microcode just in case this is a hyperthreaded processor where 7482449e17fSsherrym * the threads share the same microcode. 7492449e17fSsherrym */ 7502449e17fSsherrym if (!ucode_force_update) { 751adc586deSMark Johnson ucode->read_rev(uinfop); 7522449e17fSsherrym uusp->new_rev = uinfop->cui_rev; 7532449e17fSsherrym if (uinfop->cui_rev >= uusp->expected_rev) 7542449e17fSsherrym return (0); 7552449e17fSsherrym } 7562449e17fSsherrym 7575e53ed34SHans Rosenfeld if (!on_trap(&otd, OT_DATA_ACCESS)) 758adc586deSMark Johnson wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep); 7595e53ed34SHans Rosenfeld 7605e53ed34SHans Rosenfeld no_trap(); 761882a7af5SMark Johnson #endif 762adc586deSMark Johnson ucode->read_rev(uinfop); 7632449e17fSsherrym uusp->new_rev = uinfop->cui_rev; 7642449e17fSsherrym 7652449e17fSsherrym return (0); 7662449e17fSsherrym } 7672449e17fSsherrym 768adc586deSMark Johnson /*ARGSUSED*/ 769adc586deSMark Johnson static uint32_t 770adc586deSMark Johnson ucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp) 7712449e17fSsherrym { 772adc586deSMark Johnson ucode_file_amd_t *ucodefp = ufp->amd; 773adc586deSMark Johnson #ifdef __xpv 774adc586deSMark Johnson ucode_update_t uus; 7755e53ed34SHans Rosenfeld #else 7765e53ed34SHans Rosenfeld on_trap_data_t otd; 777adc586deSMark Johnson #endif 778adc586deSMark Johnson 779adc586deSMark Johnson ASSERT(ucode); 780adc586deSMark Johnson ASSERT(ucodefp); 781adc586deSMark Johnson 782adc586deSMark Johnson #ifndef __xpv 7832449e17fSsherrym kpreempt_disable(); 7845e53ed34SHans Rosenfeld if (on_trap(&otd, OT_DATA_ACCESS)) { 7855e53ed34SHans Rosenfeld no_trap(); 7865e53ed34SHans Rosenfeld kpreempt_enable(); 7875e53ed34SHans Rosenfeld return (0); 7885e53ed34SHans Rosenfeld } 789adc586deSMark Johnson wrmsr(ucode->write_msr, (uintptr_t)ucodefp); 7905e53ed34SHans Rosenfeld no_trap(); 791adc586deSMark Johnson ucode->read_rev(uinfop); 7922449e17fSsherrym kpreempt_enable(); 7930ba6f73dSMark Johnson 7940ba6f73dSMark Johnson return (ucodefp->uf_header.uh_patch_id); 795adc586deSMark Johnson #else 7960ba6f73dSMark Johnson uus.ucodep = ucodefp->ucodep; 7970ba6f73dSMark Johnson uus.usize = ucodefp->usize; 798adc586deSMark Johnson ucode_load_xpv(&uus); 799adc586deSMark Johnson ucode->read_rev(uinfop); 800adc586deSMark Johnson uus.new_rev = uinfop->cui_rev; 801adc586deSMark Johnson 8020ba6f73dSMark Johnson return (uus.new_rev); 8030ba6f73dSMark Johnson #endif 804adc586deSMark Johnson } 805adc586deSMark Johnson 806adc586deSMark Johnson /*ARGSUSED2*/ 807adc586deSMark Johnson static uint32_t 808adc586deSMark Johnson ucode_load_intel(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp) 809adc586deSMark Johnson { 810adc586deSMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel; 811adc586deSMark Johnson #ifdef __xpv 812adc586deSMark Johnson uint32_t ext_offset; 813adc586deSMark Johnson uint32_t body_size; 814adc586deSMark Johnson uint32_t ext_size; 815adc586deSMark Johnson uint8_t *ustart; 816adc586deSMark Johnson uint32_t usize; 817adc586deSMark Johnson ucode_update_t uus; 818adc586deSMark Johnson #endif 819adc586deSMark Johnson 820adc586deSMark Johnson ASSERT(ucode); 821adc586deSMark Johnson 822adc586deSMark Johnson #ifdef __xpv 823adc586deSMark Johnson /* 824adc586deSMark Johnson * the hypervisor wants the header, data, and extended 825adc586deSMark Johnson * signature tables. We can only get here from the boot 826adc586deSMark Johnson * CPU (cpu #0), we don't need to free as ucode_zalloc() will 827adc586deSMark Johnson * use BOP_ALLOC(). 828adc586deSMark Johnson */ 829adc586deSMark Johnson usize = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size); 830adc586deSMark Johnson ustart = ucode_zalloc(cp->cpu_id, usize); 831adc586deSMark Johnson ASSERT(ustart); 832adc586deSMark Johnson 833adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size); 834adc586deSMark Johnson ext_offset = body_size + UCODE_HEADER_SIZE_INTEL; 835adc586deSMark Johnson ext_size = usize - ext_offset; 836adc586deSMark Johnson ASSERT(ext_size >= 0); 837adc586deSMark Johnson 838adc586deSMark Johnson (void) memcpy(ustart, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL); 839adc586deSMark Johnson (void) memcpy(&ustart[UCODE_HEADER_SIZE_INTEL], ucodefp->uf_body, 840adc586deSMark Johnson body_size); 841adc586deSMark Johnson if (ext_size > 0) { 842adc586deSMark Johnson (void) memcpy(&ustart[ext_offset], 843adc586deSMark Johnson ucodefp->uf_ext_table, ext_size); 844adc586deSMark Johnson } 845adc586deSMark Johnson uus.ucodep = ustart; 846adc586deSMark Johnson uus.usize = usize; 847adc586deSMark Johnson ucode_load_xpv(&uus); 848adc586deSMark Johnson ucode->read_rev(uinfop); 849adc586deSMark Johnson uus.new_rev = uinfop->cui_rev; 850adc586deSMark Johnson #else 851adc586deSMark Johnson kpreempt_disable(); 852adc586deSMark Johnson wrmsr(ucode->write_msr, (uintptr_t)ucodefp->uf_body); 853adc586deSMark Johnson ucode->read_rev(uinfop); 854adc586deSMark Johnson kpreempt_enable(); 855adc586deSMark Johnson #endif 856adc586deSMark Johnson 857adc586deSMark Johnson return (ucodefp->uf_header->uh_rev); 8582449e17fSsherrym } 8592449e17fSsherrym 860882a7af5SMark Johnson 861882a7af5SMark Johnson #ifdef __xpv 862882a7af5SMark Johnson static void 863adc586deSMark Johnson ucode_load_xpv(ucode_update_t *uusp) 864882a7af5SMark Johnson { 865882a7af5SMark Johnson xen_platform_op_t op; 866882a7af5SMark Johnson int e; 867882a7af5SMark Johnson 868882a7af5SMark Johnson ASSERT(DOMAIN_IS_INITDOMAIN(xen_info)); 869882a7af5SMark Johnson 870882a7af5SMark Johnson kpreempt_disable(); 871882a7af5SMark Johnson op.cmd = XENPF_microcode_update; 872882a7af5SMark Johnson op.interface_version = XENPF_INTERFACE_VERSION; 873882a7af5SMark Johnson /*LINTED: constant in conditional context*/ 874adc586deSMark Johnson set_xen_guest_handle(op.u.microcode.data, uusp->ucodep); 875adc586deSMark Johnson op.u.microcode.length = uusp->usize; 876882a7af5SMark Johnson e = HYPERVISOR_platform_op(&op); 877882a7af5SMark Johnson if (e != 0) { 878882a7af5SMark Johnson cmn_err(CE_WARN, "hypervisor failed to accept uCode update"); 879882a7af5SMark Johnson } 880882a7af5SMark Johnson kpreempt_enable(); 881882a7af5SMark Johnson } 882882a7af5SMark Johnson #endif /* __xpv */ 883882a7af5SMark Johnson 884adc586deSMark Johnson static void 885adc586deSMark Johnson ucode_read_rev_amd(cpu_ucode_info_t *uinfop) 886adc586deSMark Johnson { 887adc586deSMark Johnson uinfop->cui_rev = rdmsr(MSR_AMD_PATCHLEVEL); 888adc586deSMark Johnson } 889882a7af5SMark Johnson 8902449e17fSsherrym static void 891adc586deSMark Johnson ucode_read_rev_intel(cpu_ucode_info_t *uinfop) 8922449e17fSsherrym { 8932449e17fSsherrym struct cpuid_regs crs; 8942449e17fSsherrym 8952449e17fSsherrym /* 8962449e17fSsherrym * The Intel 64 and IA-32 Architecture Software Developer's Manual 8972449e17fSsherrym * recommends that MSR_INTC_UCODE_REV be loaded with 0 first, then 8982449e17fSsherrym * execute cpuid to guarantee the correct reading of this register. 8992449e17fSsherrym */ 9002449e17fSsherrym wrmsr(MSR_INTC_UCODE_REV, 0); 9012449e17fSsherrym (void) __cpuid_insn(&crs); 9022449e17fSsherrym uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT); 9032449e17fSsherrym } 9042449e17fSsherrym 905adc586deSMark Johnson static ucode_errno_t 906adc586deSMark Johnson ucode_extract_amd(ucode_update_t *uusp, uint8_t *ucodep, int size) 907adc586deSMark Johnson { 9080ba6f73dSMark Johnson #ifndef __xpv 909adc586deSMark Johnson uint32_t *ptr = (uint32_t *)ucodep; 910adc586deSMark Johnson ucode_eqtbl_amd_t *eqtbl; 911adc586deSMark Johnson ucode_file_amd_t *ufp; 9120ba6f73dSMark Johnson int count; 9130ba6f73dSMark Johnson int higher = 0; 9140ba6f73dSMark Johnson ucode_errno_t rc = EM_NOMATCH; 9150ba6f73dSMark Johnson uint16_t eq_sig; 916adc586deSMark Johnson 917adc586deSMark Johnson /* skip over magic number & equivalence table header */ 918adc586deSMark Johnson ptr += 2; size -= 8; 919adc586deSMark Johnson 920adc586deSMark Johnson count = *ptr++; size -= 4; 921adc586deSMark Johnson for (eqtbl = (ucode_eqtbl_amd_t *)ptr; 922adc586deSMark Johnson eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != uusp->sig; 923adc586deSMark Johnson eqtbl++) 924adc586deSMark Johnson ; 925adc586deSMark Johnson 926adc586deSMark Johnson eq_sig = eqtbl->ue_equiv_cpu; 927adc586deSMark Johnson 928adc586deSMark Johnson /* No equivalent CPU id found, assume outdated microcode file. */ 929adc586deSMark Johnson if (eq_sig == 0) 930adc586deSMark Johnson return (EM_HIGHERREV); 931adc586deSMark Johnson 932adc586deSMark Johnson /* Use the first microcode patch that matches. */ 933adc586deSMark Johnson do { 934adc586deSMark Johnson ptr += count >> 2; size -= count; 935adc586deSMark Johnson 936adc586deSMark Johnson if (!size) 9370ba6f73dSMark Johnson return (higher ? EM_HIGHERREV : EM_NOMATCH); 938adc586deSMark Johnson 939adc586deSMark Johnson ptr++; size -= 4; 940adc586deSMark Johnson count = *ptr++; size -= 4; 941adc586deSMark Johnson ufp = (ucode_file_amd_t *)ptr; 9420ba6f73dSMark Johnson 9430ba6f73dSMark Johnson rc = ucode_match_amd(eq_sig, &uusp->info, ufp, count); 9440ba6f73dSMark Johnson if (rc == EM_HIGHERREV) 9450ba6f73dSMark Johnson higher = 1; 9460ba6f73dSMark Johnson } while (rc != EM_OK); 947adc586deSMark Johnson 948adc586deSMark Johnson uusp->ucodep = (uint8_t *)ufp; 949adc586deSMark Johnson uusp->usize = count; 950adc586deSMark Johnson uusp->expected_rev = ufp->uf_header.uh_patch_id; 9510ba6f73dSMark Johnson #else 9520ba6f73dSMark Johnson /* 9530ba6f73dSMark Johnson * The hypervisor will choose the patch to load, so there is no way to 9540ba6f73dSMark Johnson * know the "expected revision" in advance. This is especially true on 9550ba6f73dSMark Johnson * mixed-revision systems where more than one patch will be loaded. 9560ba6f73dSMark Johnson */ 9570ba6f73dSMark Johnson uusp->expected_rev = 0; 9580ba6f73dSMark Johnson uusp->ucodep = ucodep; 9590ba6f73dSMark Johnson uusp->usize = size; 9600ba6f73dSMark Johnson 9610ba6f73dSMark Johnson ucode_chipset_amd(ucodep, size); 9620ba6f73dSMark Johnson #endif 963adc586deSMark Johnson 964adc586deSMark Johnson return (EM_OK); 965adc586deSMark Johnson } 966adc586deSMark Johnson 967adc586deSMark Johnson static ucode_errno_t 968adc586deSMark Johnson ucode_extract_intel(ucode_update_t *uusp, uint8_t *ucodep, int size) 969adc586deSMark Johnson { 970adc586deSMark Johnson uint32_t header_size = UCODE_HEADER_SIZE_INTEL; 971adc586deSMark Johnson int remaining; 972adc586deSMark Johnson int found = 0; 973adc586deSMark Johnson ucode_errno_t search_rc = EM_NOMATCH; /* search result */ 974adc586deSMark Johnson 975adc586deSMark Johnson /* 976adc586deSMark Johnson * Go through the whole buffer in case there are 977adc586deSMark Johnson * multiple versions of matching microcode for this 978adc586deSMark Johnson * processor. 979adc586deSMark Johnson */ 980adc586deSMark Johnson for (remaining = size; remaining > 0; ) { 981adc586deSMark Johnson int total_size, body_size, ext_size; 982adc586deSMark Johnson uint8_t *curbuf = &ucodep[size - remaining]; 983adc586deSMark Johnson ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf; 984adc586deSMark Johnson ucode_ext_table_intel_t *uetp = NULL; 985adc586deSMark Johnson ucode_errno_t tmprc; 986adc586deSMark Johnson 987adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 988adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 989adc586deSMark Johnson ext_size = total_size - (header_size + body_size); 990adc586deSMark Johnson 991adc586deSMark Johnson if (ext_size > 0) 992adc586deSMark Johnson uetp = (ucode_ext_table_intel_t *) 993adc586deSMark Johnson &curbuf[header_size + body_size]; 994adc586deSMark Johnson 995adc586deSMark Johnson tmprc = ucode_match_intel(uusp->sig, &uusp->info, uhp, uetp); 996adc586deSMark Johnson 997adc586deSMark Johnson /* 998adc586deSMark Johnson * Since we are searching through a big file 999adc586deSMark Johnson * containing microcode for pretty much all the 1000adc586deSMark Johnson * processors, we are bound to get EM_NOMATCH 1001adc586deSMark Johnson * at one point. However, if we return 1002adc586deSMark Johnson * EM_NOMATCH to users, it will really confuse 1003adc586deSMark Johnson * them. Therefore, if we ever find a match of 1004adc586deSMark Johnson * a lower rev, we will set return code to 1005adc586deSMark Johnson * EM_HIGHERREV. 1006adc586deSMark Johnson */ 1007adc586deSMark Johnson if (tmprc == EM_HIGHERREV) 1008adc586deSMark Johnson search_rc = EM_HIGHERREV; 1009adc586deSMark Johnson 1010adc586deSMark Johnson if (tmprc == EM_OK && 1011adc586deSMark Johnson uusp->expected_rev < uhp->uh_rev) { 1012adc586deSMark Johnson #ifndef __xpv 1013adc586deSMark Johnson uusp->ucodep = (uint8_t *)&curbuf[header_size]; 1014adc586deSMark Johnson #else 1015adc586deSMark Johnson uusp->ucodep = (uint8_t *)curbuf; 1016adc586deSMark Johnson #endif 1017adc586deSMark Johnson uusp->usize = 1018adc586deSMark Johnson UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 1019adc586deSMark Johnson uusp->expected_rev = uhp->uh_rev; 1020adc586deSMark Johnson found = 1; 1021adc586deSMark Johnson } 1022adc586deSMark Johnson 1023adc586deSMark Johnson remaining -= total_size; 1024adc586deSMark Johnson } 1025adc586deSMark Johnson 1026adc586deSMark Johnson if (!found) 1027adc586deSMark Johnson return (search_rc); 1028adc586deSMark Johnson 1029adc586deSMark Johnson return (EM_OK); 1030adc586deSMark Johnson } 10312449e17fSsherrym /* 10322449e17fSsherrym * Entry point to microcode update from the ucode_drv driver. 10332449e17fSsherrym * 10342449e17fSsherrym * Returns EM_OK on success, corresponding error code on failure. 10352449e17fSsherrym */ 10362449e17fSsherrym ucode_errno_t 10372449e17fSsherrym ucode_update(uint8_t *ucodep, int size) 10382449e17fSsherrym { 10392449e17fSsherrym int found = 0; 10402449e17fSsherrym processorid_t id; 1041adc586deSMark Johnson ucode_update_t cached = { 0 }; 1042adc586deSMark Johnson ucode_update_t *cachedp = NULL; 10432449e17fSsherrym ucode_errno_t rc = EM_OK; 10442449e17fSsherrym ucode_errno_t search_rc = EM_NOMATCH; /* search result */ 10452449e17fSsherrym cpuset_t cpuset; 10462449e17fSsherrym 1047adc586deSMark Johnson ASSERT(ucode); 10482449e17fSsherrym ASSERT(ucodep); 10492449e17fSsherrym CPUSET_ZERO(cpuset); 10502449e17fSsherrym 1051adc586deSMark Johnson if (!ucode->capable(CPU)) 10522449e17fSsherrym return (EM_NOTSUP); 10532449e17fSsherrym 10542449e17fSsherrym mutex_enter(&cpu_lock); 10552449e17fSsherrym 10562449e17fSsherrym for (id = 0; id < max_ncpus; id++) { 10572449e17fSsherrym cpu_t *cpu; 1058adc586deSMark Johnson ucode_update_t uus = { 0 }; 1059adc586deSMark Johnson ucode_update_t *uusp = &uus; 10602449e17fSsherrym 10612449e17fSsherrym /* 10622449e17fSsherrym * If there is no such CPU or it is not xcall ready, skip it. 10632449e17fSsherrym */ 10642449e17fSsherrym if ((cpu = cpu_get(id)) == NULL || 10652449e17fSsherrym !(cpu->cpu_flags & CPU_READY)) 10662449e17fSsherrym continue; 10672449e17fSsherrym 10682449e17fSsherrym uusp->sig = cpuid_getsig(cpu); 10692449e17fSsherrym bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info, 10702449e17fSsherrym sizeof (uusp->info)); 10712449e17fSsherrym 10722449e17fSsherrym /* 10732449e17fSsherrym * If the current CPU has the same signature and platform 10742449e17fSsherrym * id as the previous one we processed, reuse the information. 10752449e17fSsherrym */ 10762449e17fSsherrym if (cachedp && cachedp->sig == cpuid_getsig(cpu) && 10772449e17fSsherrym cachedp->info.cui_platid == uusp->info.cui_platid) { 10782449e17fSsherrym uusp->ucodep = cachedp->ucodep; 10792449e17fSsherrym uusp->expected_rev = cachedp->expected_rev; 10802449e17fSsherrym /* 10812449e17fSsherrym * Intuitively we should check here to see whether the 10822449e17fSsherrym * running microcode rev is >= the expected rev, and 10832449e17fSsherrym * quit if it is. But we choose to proceed with the 10842449e17fSsherrym * xcall regardless of the running version so that 10852449e17fSsherrym * the other threads in an HT processor can update 10862449e17fSsherrym * the cpu_ucode_info structure in machcpu. 10872449e17fSsherrym */ 1088adc586deSMark Johnson } else if ((search_rc = ucode->extract(uusp, ucodep, size)) 1089adc586deSMark Johnson == EM_OK) { 10902449e17fSsherrym bcopy(uusp, &cached, sizeof (cached)); 10912449e17fSsherrym cachedp = &cached; 10922449e17fSsherrym found = 1; 10932449e17fSsherrym } 10942449e17fSsherrym 10952449e17fSsherrym /* Nothing to do */ 10962449e17fSsherrym if (uusp->ucodep == NULL) 10972449e17fSsherrym continue; 10982449e17fSsherrym 1099882a7af5SMark Johnson #ifdef __xpv 1100882a7af5SMark Johnson /* 1101882a7af5SMark Johnson * for i86xpv, the hypervisor will update all the CPUs. 1102882a7af5SMark Johnson * the hypervisor wants the header, data, and extended 1103882a7af5SMark Johnson * signature tables. ucode_write will just read in the 1104882a7af5SMark Johnson * updated version on all the CPUs after the update has 1105882a7af5SMark Johnson * completed. 1106882a7af5SMark Johnson */ 1107c9b5d7d2SMark Johnson if (id == 0) { 1108adc586deSMark Johnson ucode_load_xpv(uusp); 1109c9b5d7d2SMark Johnson } 1110882a7af5SMark Johnson #endif 1111882a7af5SMark Johnson 11122449e17fSsherrym CPUSET_ADD(cpuset, id); 11132449e17fSsherrym kpreempt_disable(); 1114f34a7178SJoe Bonasera xc_sync((xc_arg_t)uusp, 0, 0, CPUSET2BV(cpuset), ucode_write); 11152449e17fSsherrym kpreempt_enable(); 11162449e17fSsherrym CPUSET_DEL(cpuset, id); 11172449e17fSsherrym 11185e53ed34SHans Rosenfeld if (uusp->new_rev != 0 && uusp->info.cui_rev == uusp->new_rev && 11195e53ed34SHans Rosenfeld !ucode_force_update) { 11200ba6f73dSMark Johnson rc = EM_HIGHERREV; 11210ba6f73dSMark Johnson } else if ((uusp->new_rev == 0) || (uusp->expected_rev != 0 && 11220ba6f73dSMark Johnson uusp->expected_rev != uusp->new_rev)) { 11232449e17fSsherrym cmn_err(CE_WARN, ucode_failure_fmt, 11242449e17fSsherrym id, uusp->info.cui_rev, uusp->expected_rev); 11252449e17fSsherrym rc = EM_UPDATE; 11260ba6f73dSMark Johnson } else { 11270ba6f73dSMark Johnson cmn_err(CE_CONT, ucode_success_fmt, 11280ba6f73dSMark Johnson id, uusp->info.cui_rev, uusp->new_rev); 11292449e17fSsherrym } 11302449e17fSsherrym } 11312449e17fSsherrym 11322449e17fSsherrym mutex_exit(&cpu_lock); 11332449e17fSsherrym 11342449e17fSsherrym if (!found) 11352449e17fSsherrym rc = search_rc; 11362449e17fSsherrym 11372449e17fSsherrym return (rc); 11382449e17fSsherrym } 11392449e17fSsherrym 11402449e17fSsherrym /* 11412449e17fSsherrym * Initialize mcpu_ucode_info, and perform microcode update if necessary. 11422449e17fSsherrym * This is the entry point from boot path where pointer to CPU structure 11432449e17fSsherrym * is available. 11442449e17fSsherrym * 11452449e17fSsherrym * cpuid_info must be initialized before ucode_check can be called. 11462449e17fSsherrym */ 11472449e17fSsherrym void 11482449e17fSsherrym ucode_check(cpu_t *cp) 11492449e17fSsherrym { 1150adc586deSMark Johnson cpu_ucode_info_t *uinfop; 11512449e17fSsherrym ucode_errno_t rc = EM_OK; 1152adc586deSMark Johnson uint32_t new_rev = 0; 11532449e17fSsherrym 11542449e17fSsherrym ASSERT(cp); 1155a3114836SGerry Liu /* 1156a3114836SGerry Liu * Space statically allocated for BSP, ensure pointer is set 1157a3114836SGerry Liu */ 1158a3114836SGerry Liu if (cp->cpu_id == 0 && cp->cpu_m.mcpu_ucode_info == NULL) 11592449e17fSsherrym cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0; 11602449e17fSsherrym 11612449e17fSsherrym uinfop = cp->cpu_m.mcpu_ucode_info; 11622449e17fSsherrym ASSERT(uinfop); 11632449e17fSsherrym 1164adc586deSMark Johnson /* set up function pointers if not already done */ 1165adc586deSMark Johnson if (!ucode) 1166adc586deSMark Johnson switch (cpuid_getvendor(cp)) { 1167adc586deSMark Johnson case X86_VENDOR_AMD: 1168adc586deSMark Johnson ucode = &ucode_amd; 1169adc586deSMark Johnson break; 1170adc586deSMark Johnson case X86_VENDOR_Intel: 1171adc586deSMark Johnson ucode = &ucode_intel; 1172adc586deSMark Johnson break; 1173adc586deSMark Johnson default: 1174126b0a71SMark Johnson ucode = NULL; 1175adc586deSMark Johnson return; 1176adc586deSMark Johnson } 1177adc586deSMark Johnson 1178adc586deSMark Johnson if (!ucode->capable(cp)) 11792449e17fSsherrym return; 11802449e17fSsherrym 11812449e17fSsherrym /* 11822449e17fSsherrym * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon 11832449e17fSsherrym * (Family 6, model 5 and above) and all processors after. 11842449e17fSsherrym */ 1185adc586deSMark Johnson if ((cpuid_getvendor(cp) == X86_VENDOR_Intel) && 1186adc586deSMark Johnson ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6))) { 11872449e17fSsherrym uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >> 11882449e17fSsherrym INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK); 11892449e17fSsherrym } 11902449e17fSsherrym 1191adc586deSMark Johnson ucode->read_rev(uinfop); 11922449e17fSsherrym 1193c9b5d7d2SMark Johnson #ifdef __xpv 1194c9b5d7d2SMark Johnson /* 1195c9b5d7d2SMark Johnson * for i86xpv, the hypervisor will update all the CPUs. We only need 1196c9b5d7d2SMark Johnson * do do this on one of the CPUs (and there always is a CPU 0). 1197c9b5d7d2SMark Johnson */ 1198c9b5d7d2SMark Johnson if (cp->cpu_id != 0) { 1199c9b5d7d2SMark Johnson return; 1200c9b5d7d2SMark Johnson } 1201c9b5d7d2SMark Johnson #endif 1202c9b5d7d2SMark Johnson 12032449e17fSsherrym /* 12042449e17fSsherrym * Check to see if we need ucode update 12052449e17fSsherrym */ 1206adc586deSMark Johnson if ((rc = ucode->locate(cp, uinfop, &ucodefile)) == EM_OK) { 1207adc586deSMark Johnson new_rev = ucode->load(&ucodefile, uinfop, cp); 1208882a7af5SMark Johnson 1209adc586deSMark Johnson if (uinfop->cui_rev != new_rev) 12102449e17fSsherrym cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id, 1211adc586deSMark Johnson uinfop->cui_rev, new_rev); 12122449e17fSsherrym } 12132449e17fSsherrym 12142449e17fSsherrym /* 12152449e17fSsherrym * If we fail to find a match for any reason, free the file structure 12162449e17fSsherrym * just in case we have read in a partial file. 12172449e17fSsherrym * 12182449e17fSsherrym * Since the scratch memory for holding the microcode for the boot CPU 12192449e17fSsherrym * came from BOP_ALLOC, we will reset the data structure as if we 12202449e17fSsherrym * never did the allocation so we don't have to keep track of this 12212449e17fSsherrym * special chunk of memory. We free the memory used for the rest 12222449e17fSsherrym * of the CPUs in start_other_cpus(). 12232449e17fSsherrym */ 12242449e17fSsherrym if (rc != EM_OK || cp->cpu_id == 0) 1225adc586deSMark Johnson ucode->file_reset(&ucodefile, cp->cpu_id); 12262449e17fSsherrym } 12272449e17fSsherrym 12282449e17fSsherrym /* 12292449e17fSsherrym * Returns microcode revision from the machcpu structure. 12302449e17fSsherrym */ 12312449e17fSsherrym ucode_errno_t 12322449e17fSsherrym ucode_get_rev(uint32_t *revp) 12332449e17fSsherrym { 12342449e17fSsherrym int i; 12352449e17fSsherrym 1236adc586deSMark Johnson ASSERT(ucode); 12372449e17fSsherrym ASSERT(revp); 12382449e17fSsherrym 1239adc586deSMark Johnson if (!ucode->capable(CPU)) 12402449e17fSsherrym return (EM_NOTSUP); 12412449e17fSsherrym 12422449e17fSsherrym mutex_enter(&cpu_lock); 12432449e17fSsherrym for (i = 0; i < max_ncpus; i++) { 12442449e17fSsherrym cpu_t *cpu; 12452449e17fSsherrym 12462449e17fSsherrym if ((cpu = cpu_get(i)) == NULL) 12472449e17fSsherrym continue; 12482449e17fSsherrym 12492449e17fSsherrym revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev; 12502449e17fSsherrym } 12512449e17fSsherrym mutex_exit(&cpu_lock); 12522449e17fSsherrym 12532449e17fSsherrym return (EM_OK); 12542449e17fSsherrym } 1255