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 /* 2388699bddSsherrym * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 242449e17fSsherrym * Use is subject to license terms. 252449e17fSsherrym */ 262449e17fSsherrym 272449e17fSsherrym #include <sys/asm_linkage.h> 282449e17fSsherrym #include <sys/bootconf.h> 292449e17fSsherrym #include <sys/cpuvar.h> 302449e17fSsherrym #include <sys/cmn_err.h> 312449e17fSsherrym #include <sys/controlregs.h> 322449e17fSsherrym #include <sys/debug.h> 332449e17fSsherrym #include <sys/kobj.h> 342449e17fSsherrym #include <sys/kobj_impl.h> 352449e17fSsherrym #include <sys/machsystm.h> 362449e17fSsherrym #include <sys/param.h> 372449e17fSsherrym #include <sys/machparam.h> 382449e17fSsherrym #include <sys/promif.h> 392449e17fSsherrym #include <sys/sysmacros.h> 402449e17fSsherrym #include <sys/systm.h> 412449e17fSsherrym #include <sys/types.h> 422449e17fSsherrym #include <sys/thread.h> 432449e17fSsherrym #include <sys/ucode.h> 442449e17fSsherrym #include <sys/x86_archext.h> 452449e17fSsherrym #include <sys/x_call.h> 46843e1988Sjohnlev #ifdef __xpv 47843e1988Sjohnlev #include <sys/hypervisor.h> 48843e1988Sjohnlev #endif 492449e17fSsherrym 502449e17fSsherrym /* 51*adc586deSMark Johnson * AMD-specific equivalence table 522449e17fSsherrym */ 53*adc586deSMark Johnson static ucode_eqtbl_amd_t *ucode_eqtbl_amd; 542449e17fSsherrym 552449e17fSsherrym /* 562449e17fSsherrym * mcpu_ucode_info for the boot CPU. Statically allocated. 572449e17fSsherrym */ 582449e17fSsherrym static struct cpu_ucode_info cpu_ucode_info0; 592449e17fSsherrym 60*adc586deSMark Johnson static ucode_file_t ucodefile; 612449e17fSsherrym 62*adc586deSMark Johnson static void* ucode_zalloc(processorid_t, size_t); 63*adc586deSMark Johnson static void ucode_free(processorid_t, void *, size_t); 64*adc586deSMark Johnson 65*adc586deSMark Johnson static int ucode_capable_amd(cpu_t *); 66*adc586deSMark Johnson static int ucode_capable_intel(cpu_t *); 67*adc586deSMark Johnson 68*adc586deSMark Johnson static ucode_errno_t ucode_extract_amd(ucode_update_t *, uint8_t *, int); 69*adc586deSMark Johnson static ucode_errno_t ucode_extract_intel(ucode_update_t *, uint8_t *, 70*adc586deSMark Johnson int); 71*adc586deSMark Johnson 72*adc586deSMark Johnson static void ucode_file_reset_amd(ucode_file_t *, processorid_t); 73*adc586deSMark Johnson static void ucode_file_reset_intel(ucode_file_t *, processorid_t); 74*adc586deSMark Johnson 75*adc586deSMark Johnson static uint32_t ucode_load_amd(ucode_file_t *, cpu_ucode_info_t *, cpu_t *); 76*adc586deSMark Johnson static uint32_t ucode_load_intel(ucode_file_t *, cpu_ucode_info_t *, cpu_t *); 77*adc586deSMark Johnson 78882a7af5SMark Johnson #ifdef __xpv 79*adc586deSMark Johnson static void ucode_load_xpv(ucode_update_t *); 80882a7af5SMark Johnson #endif 812449e17fSsherrym 82*adc586deSMark Johnson static int ucode_equiv_cpu_amd(cpu_t *, int *); 83*adc586deSMark Johnson 84*adc586deSMark Johnson static ucode_errno_t ucode_locate_amd(cpu_t *, cpu_ucode_info_t *, 85*adc586deSMark Johnson ucode_file_t *); 86*adc586deSMark Johnson static ucode_errno_t ucode_locate_intel(cpu_t *, cpu_ucode_info_t *, 87*adc586deSMark Johnson ucode_file_t *); 88*adc586deSMark Johnson 89*adc586deSMark Johnson static ucode_errno_t ucode_match_amd(int, cpu_ucode_info_t *, 90*adc586deSMark Johnson ucode_file_amd_t *, int); 91*adc586deSMark Johnson static ucode_errno_t ucode_match_intel(int, cpu_ucode_info_t *, 92*adc586deSMark Johnson ucode_header_intel_t *, ucode_ext_table_intel_t *); 93*adc586deSMark Johnson 94*adc586deSMark Johnson static void ucode_read_rev_amd(cpu_ucode_info_t *); 95*adc586deSMark Johnson static void ucode_read_rev_intel(cpu_ucode_info_t *); 96*adc586deSMark Johnson 97*adc586deSMark Johnson static const struct ucode_ops ucode_amd = { 98*adc586deSMark Johnson MSR_AMD_PATCHLOADER, 99*adc586deSMark Johnson ucode_capable_amd, 100*adc586deSMark Johnson ucode_file_reset_amd, 101*adc586deSMark Johnson ucode_read_rev_amd, 102*adc586deSMark Johnson ucode_load_amd, 103*adc586deSMark Johnson ucode_validate_amd, 104*adc586deSMark Johnson ucode_extract_amd, 105*adc586deSMark Johnson ucode_locate_amd 106*adc586deSMark Johnson }; 107*adc586deSMark Johnson 108*adc586deSMark Johnson static const struct ucode_ops ucode_intel = { 109*adc586deSMark Johnson MSR_INTC_UCODE_WRITE, 110*adc586deSMark Johnson ucode_capable_intel, 111*adc586deSMark Johnson ucode_file_reset_intel, 112*adc586deSMark Johnson ucode_read_rev_intel, 113*adc586deSMark Johnson ucode_load_intel, 114*adc586deSMark Johnson ucode_validate_intel, 115*adc586deSMark Johnson ucode_extract_intel, 116*adc586deSMark Johnson ucode_locate_intel 117*adc586deSMark Johnson }; 118*adc586deSMark Johnson 119*adc586deSMark Johnson const struct ucode_ops *ucode; 120*adc586deSMark Johnson 1212449e17fSsherrym static const char ucode_failure_fmt[] = 12288699bddSsherrym "cpu%d: failed to update microcode from version 0x%x to 0x%x\n"; 1232449e17fSsherrym static const char ucode_success_fmt[] = 12488699bddSsherrym "?cpu%d: microcode has been updated from version 0x%x to 0x%x\n"; 1252449e17fSsherrym 1262449e17fSsherrym /* 1272449e17fSsherrym * Force flag. If set, the first microcode binary that matches 1282449e17fSsherrym * signature and platform id will be used for microcode update, 1292449e17fSsherrym * regardless of version. Should only be used for debugging. 1302449e17fSsherrym */ 1312449e17fSsherrym int ucode_force_update = 0; 1322449e17fSsherrym 1332449e17fSsherrym /* 1342449e17fSsherrym * Allocate space for mcpu_ucode_info in the machcpu structure 1352449e17fSsherrym * for all non-boot CPUs. 1362449e17fSsherrym */ 1372449e17fSsherrym void 1382449e17fSsherrym ucode_alloc_space(cpu_t *cp) 1392449e17fSsherrym { 1402449e17fSsherrym ASSERT(cp->cpu_id != 0); 1412449e17fSsherrym cp->cpu_m.mcpu_ucode_info = 1422449e17fSsherrym kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP); 1432449e17fSsherrym } 1442449e17fSsherrym 1452449e17fSsherrym void 1462449e17fSsherrym ucode_free_space(cpu_t *cp) 1472449e17fSsherrym { 1482449e17fSsherrym ASSERT(cp->cpu_id != 0); 1492449e17fSsherrym kmem_free(cp->cpu_m.mcpu_ucode_info, 1502449e17fSsherrym sizeof (*cp->cpu_m.mcpu_ucode_info)); 1512449e17fSsherrym } 1522449e17fSsherrym 1532449e17fSsherrym /* 1542449e17fSsherrym * Called when we are done with microcode update on all processors to free up 1552449e17fSsherrym * space allocated for the microcode file. 1562449e17fSsherrym */ 1572449e17fSsherrym void 158*adc586deSMark Johnson ucode_cleanup() 1592449e17fSsherrym { 160*adc586deSMark Johnson ASSERT(ucode); 161*adc586deSMark Johnson 162*adc586deSMark Johnson ucode->file_reset(&ucodefile, -1); 163*adc586deSMark Johnson } 164*adc586deSMark Johnson 165*adc586deSMark Johnson /* 166*adc586deSMark Johnson * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is 167*adc586deSMark Johnson * allocated with BOP_ALLOC() and does not require a free. 168*adc586deSMark Johnson */ 169*adc586deSMark Johnson static void* 170*adc586deSMark Johnson ucode_zalloc(processorid_t id, size_t size) 171*adc586deSMark Johnson { 172*adc586deSMark Johnson if (id) 173*adc586deSMark Johnson return (kmem_zalloc(size, KM_NOSLEEP)); 174*adc586deSMark Johnson 175*adc586deSMark Johnson /* BOP_ALLOC() failure results in panic */ 176*adc586deSMark Johnson return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE)); 177*adc586deSMark Johnson } 178*adc586deSMark Johnson 179*adc586deSMark Johnson static void 180*adc586deSMark Johnson ucode_free(processorid_t id, void* buf, size_t size) 181*adc586deSMark Johnson { 182*adc586deSMark Johnson if (id) 183*adc586deSMark Johnson kmem_free(buf, size); 1842449e17fSsherrym } 1852449e17fSsherrym 1862449e17fSsherrym /* 1872449e17fSsherrym * Check whether or not a processor is capable of microcode operations 1882449e17fSsherrym * Returns 1 if it is capable, 0 if not. 189*adc586deSMark Johnson * 190*adc586deSMark Johnson * At this point we only support microcode update for: 191*adc586deSMark Johnson * - Intel processors family 6 and above, and 192*adc586deSMark Johnson * - AMD processors family 0x10 and above. 193*adc586deSMark Johnson * 194*adc586deSMark Johnson * We also assume that we don't support a mix of Intel and 195*adc586deSMark Johnson * AMD processors in the same box. 196*adc586deSMark Johnson * 197*adc586deSMark Johnson * An i86xpv guest domain can't update the microcode. 1982449e17fSsherrym */ 199*adc586deSMark Johnson /*ARGSUSED*/ 2002449e17fSsherrym static int 201*adc586deSMark Johnson ucode_capable_amd(cpu_t *cp) 2022449e17fSsherrym { 203*adc586deSMark Johnson #ifndef __xpv 204*adc586deSMark Johnson extern int xpv_is_hvm; 205*adc586deSMark Johnson if (xpv_is_hvm) { 206*adc586deSMark Johnson return (0); 207*adc586deSMark Johnson } 208*adc586deSMark Johnson 209*adc586deSMark Johnson return (cpuid_getfamily(cp) >= 0x10); 210*adc586deSMark Johnson #else 211*adc586deSMark Johnson if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 212*adc586deSMark Johnson return (0); 213*adc586deSMark Johnson } 214*adc586deSMark Johnson 215*adc586deSMark Johnson /* 216*adc586deSMark Johnson * XXPV - change when microcode loading works in dom0. Don't support 217*adc586deSMark Johnson * microcode loading in dom0 right now for AMD. 218*adc586deSMark Johnson */ 219*adc586deSMark Johnson return (0); 220*adc586deSMark Johnson #endif 221*adc586deSMark Johnson } 222*adc586deSMark Johnson static int 223*adc586deSMark Johnson ucode_capable_intel(cpu_t *cp) 224*adc586deSMark Johnson { 225882a7af5SMark Johnson #ifndef __xpv 226882a7af5SMark Johnson extern int xpv_is_hvm; 227882a7af5SMark Johnson if (xpv_is_hvm) { 228882a7af5SMark Johnson return (0); 229882a7af5SMark Johnson } 230882a7af5SMark Johnson #else 231843e1988Sjohnlev if (!DOMAIN_IS_INITDOMAIN(xen_info)) { 232843e1988Sjohnlev return (0); 233843e1988Sjohnlev } 234843e1988Sjohnlev #endif 235*adc586deSMark Johnson return (cpuid_getfamily(cp) >= 6); 2362449e17fSsherrym } 2372449e17fSsherrym 2382449e17fSsherrym /* 2392449e17fSsherrym * Called when it is no longer necessary to keep the microcode around, 2402449e17fSsherrym * or when the cached microcode doesn't match the CPU being processed. 2412449e17fSsherrym */ 2422449e17fSsherrym static void 243*adc586deSMark Johnson ucode_file_reset_amd(ucode_file_t *ufp, processorid_t id) 2442449e17fSsherrym { 245*adc586deSMark Johnson ucode_file_amd_t *ucodefp = ufp->amd; 2462449e17fSsherrym 2472449e17fSsherrym if (ucodefp == NULL) 2482449e17fSsherrym return; 2492449e17fSsherrym 250*adc586deSMark Johnson ucode_free(id, ucodefp, sizeof (ucode_file_amd_t)); 251*adc586deSMark Johnson ufp->amd = NULL; 252*adc586deSMark Johnson } 253*adc586deSMark Johnson 254*adc586deSMark Johnson static void 255*adc586deSMark Johnson ucode_file_reset_intel(ucode_file_t *ufp, processorid_t id) 256*adc586deSMark Johnson { 257*adc586deSMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel; 258*adc586deSMark Johnson int total_size, body_size; 259*adc586deSMark Johnson 260*adc586deSMark Johnson if (ucodefp == NULL || ucodefp->uf_header == NULL) 261*adc586deSMark Johnson return; 262*adc586deSMark Johnson 263*adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size); 264*adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size); 2652449e17fSsherrym if (ucodefp->uf_body) { 266*adc586deSMark Johnson ucode_free(id, ucodefp->uf_body, body_size); 2672449e17fSsherrym ucodefp->uf_body = NULL; 2682449e17fSsherrym } 2692449e17fSsherrym 2702449e17fSsherrym if (ucodefp->uf_ext_table) { 271*adc586deSMark Johnson int size = total_size - body_size - UCODE_HEADER_SIZE_INTEL; 272*adc586deSMark Johnson 273*adc586deSMark Johnson ucode_free(id, ucodefp->uf_ext_table, size); 2742449e17fSsherrym ucodefp->uf_ext_table = NULL; 2752449e17fSsherrym } 2762449e17fSsherrym 277*adc586deSMark Johnson ucode_free(id, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL); 278*adc586deSMark Johnson ucodefp->uf_header = NULL; 279*adc586deSMark Johnson } 280*adc586deSMark Johnson 281*adc586deSMark Johnson /* 282*adc586deSMark Johnson * Find the equivalent CPU id in the equivalence table. 283*adc586deSMark Johnson */ 284*adc586deSMark Johnson static int 285*adc586deSMark Johnson ucode_equiv_cpu_amd(cpu_t *cp, int *eq_sig) 286*adc586deSMark Johnson { 287*adc586deSMark Johnson char name[MAXPATHLEN]; 288*adc586deSMark Johnson intptr_t fd; 289*adc586deSMark Johnson int count; 290*adc586deSMark Johnson int offset = 0, cpi_sig = cpuid_getsig(cp); 291*adc586deSMark Johnson ucode_eqtbl_amd_t *eqtbl = ucode_eqtbl_amd; 292*adc586deSMark Johnson 293*adc586deSMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/equivalence-table", 294*adc586deSMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp)); 295*adc586deSMark Johnson 296*adc586deSMark Johnson /* 297*adc586deSMark Johnson * No kmem_zalloc() etc. available on boot cpu. 298*adc586deSMark Johnson */ 299*adc586deSMark Johnson if (cp->cpu_id == 0) { 300*adc586deSMark Johnson if ((fd = kobj_open(name)) == -1) 301*adc586deSMark Johnson return (EM_OPENFILE); 302*adc586deSMark Johnson /* ucode_zalloc() cannot fail on boot cpu */ 303*adc586deSMark Johnson eqtbl = ucode_zalloc(cp->cpu_id, sizeof (*eqtbl)); 304*adc586deSMark Johnson ASSERT(eqtbl); 305*adc586deSMark Johnson do { 306*adc586deSMark Johnson count = kobj_read(fd, (int8_t *)eqtbl, 307*adc586deSMark Johnson sizeof (*eqtbl), offset); 308*adc586deSMark Johnson if (count != sizeof (*eqtbl)) { 309*adc586deSMark Johnson (void) kobj_close(fd); 310*adc586deSMark Johnson return (EM_HIGHERREV); 311*adc586deSMark Johnson } 312*adc586deSMark Johnson offset += count; 313*adc586deSMark Johnson } while (eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig); 314*adc586deSMark Johnson (void) kobj_close(fd); 315*adc586deSMark Johnson } 316*adc586deSMark Johnson 317*adc586deSMark Johnson /* 318*adc586deSMark Johnson * If not already done, load the equivalence table. 319*adc586deSMark Johnson * Not done on boot CPU. 320*adc586deSMark Johnson */ 321*adc586deSMark Johnson if (eqtbl == NULL) { 322*adc586deSMark Johnson struct _buf *eq; 323*adc586deSMark Johnson uint64_t size; 324*adc586deSMark Johnson 325*adc586deSMark Johnson if ((eq = kobj_open_file(name)) == (struct _buf *)-1) 326*adc586deSMark Johnson return (EM_OPENFILE); 327*adc586deSMark Johnson 328*adc586deSMark Johnson if (kobj_get_filesize(eq, &size) < 0) { 329*adc586deSMark Johnson kobj_close_file(eq); 330*adc586deSMark Johnson return (EM_OPENFILE); 331*adc586deSMark Johnson } 332*adc586deSMark Johnson 333*adc586deSMark Johnson ucode_eqtbl_amd = kmem_zalloc(size, KM_NOSLEEP); 334*adc586deSMark Johnson if (ucode_eqtbl_amd == NULL) { 335*adc586deSMark Johnson kobj_close_file(eq); 336*adc586deSMark Johnson return (EM_NOMEM); 337*adc586deSMark Johnson } 338*adc586deSMark Johnson 339*adc586deSMark Johnson count = kobj_read_file(eq, (char *)ucode_eqtbl_amd, size, 0); 340*adc586deSMark Johnson kobj_close_file(eq); 341*adc586deSMark Johnson 342*adc586deSMark Johnson if (count != size) 343*adc586deSMark Johnson return (EM_FILESIZE); 344*adc586deSMark Johnson } 345*adc586deSMark Johnson 346*adc586deSMark Johnson /* Get the equivalent CPU id. */ 347*adc586deSMark Johnson if (cp->cpu_id) 348*adc586deSMark Johnson for (eqtbl = ucode_eqtbl_amd; 349*adc586deSMark Johnson eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig; 350*adc586deSMark Johnson eqtbl++) 351*adc586deSMark Johnson ; 352*adc586deSMark Johnson 353*adc586deSMark Johnson *eq_sig = eqtbl->ue_equiv_cpu; 354*adc586deSMark Johnson *eq_sig = ((*eq_sig >> 8) & 0xff00) | (*eq_sig & 0xff); 355*adc586deSMark Johnson 356*adc586deSMark Johnson /* No equivalent CPU id found, assume outdated microcode file. */ 357*adc586deSMark Johnson if (*eq_sig == 0) 358*adc586deSMark Johnson return (EM_HIGHERREV); 359*adc586deSMark Johnson 360*adc586deSMark Johnson return (EM_OK); 3612449e17fSsherrym } 3622449e17fSsherrym 3632449e17fSsherrym /* 3642449e17fSsherrym * Populate the ucode file structure from microcode file corresponding to 3652449e17fSsherrym * this CPU, if exists. 3662449e17fSsherrym * 3672449e17fSsherrym * Return EM_OK on success, corresponding error code on failure. 3682449e17fSsherrym */ 3692449e17fSsherrym static ucode_errno_t 370*adc586deSMark Johnson ucode_locate_amd(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp) 371*adc586deSMark Johnson { 372*adc586deSMark Johnson char name[MAXPATHLEN]; 373*adc586deSMark Johnson intptr_t fd; 374*adc586deSMark Johnson int count, i, rc; 375*adc586deSMark Johnson int eq_sig = 0; 376*adc586deSMark Johnson ucode_file_amd_t *ucodefp = ufp->amd; 377*adc586deSMark Johnson 378*adc586deSMark Johnson /* get equivalent CPU id */ 379*adc586deSMark Johnson if ((rc = ucode_equiv_cpu_amd(cp, &eq_sig)) != EM_OK) 380*adc586deSMark Johnson return (rc); 381*adc586deSMark Johnson 382*adc586deSMark Johnson /* 383*adc586deSMark Johnson * Allocate a buffer for the microcode patch. If the buffer has been 384*adc586deSMark Johnson * allocated before, check for a matching microcode to avoid loading 385*adc586deSMark Johnson * the file again. 386*adc586deSMark Johnson */ 387*adc586deSMark Johnson if (ucodefp == NULL) 388*adc586deSMark Johnson ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp)); 389*adc586deSMark Johnson else if (ucode_match_amd(eq_sig, uinfop, ucodefp, sizeof (*ucodefp)) 390*adc586deSMark Johnson == EM_OK) 391*adc586deSMark Johnson return (EM_OK); 392*adc586deSMark Johnson 393*adc586deSMark Johnson if (ucodefp == NULL) 394*adc586deSMark Johnson return (EM_NOMEM); 395*adc586deSMark Johnson 396*adc586deSMark Johnson ufp->amd = ucodefp; 397*adc586deSMark Johnson 398*adc586deSMark Johnson /* 399*adc586deSMark Johnson * Find the patch for this CPU. The patch files are named XXXX-YY, where 400*adc586deSMark Johnson * XXXX is the equivalent CPU id and YY is the running patch number. 401*adc586deSMark Johnson * Patches specific to certain chipsets are guaranteed to have lower 402*adc586deSMark Johnson * numbers than less specific patches, so we can just load the first 403*adc586deSMark Johnson * patch that matches. 404*adc586deSMark Johnson */ 405*adc586deSMark Johnson 406*adc586deSMark Johnson for (i = 0; i < 0xff; i++) { 407*adc586deSMark Johnson (void) snprintf(name, MAXPATHLEN, "/%s/%s/%04X-%02X", 408*adc586deSMark Johnson UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), eq_sig, i); 409*adc586deSMark Johnson if ((fd = kobj_open(name)) == -1) 410*adc586deSMark Johnson return (EM_NOMATCH); 411*adc586deSMark Johnson count = kobj_read(fd, (char *)ucodefp, sizeof (*ucodefp), 0); 412*adc586deSMark Johnson (void) kobj_close(fd); 413*adc586deSMark Johnson 414*adc586deSMark Johnson if (ucode_match_amd(eq_sig, uinfop, ucodefp, count) == EM_OK) 415*adc586deSMark Johnson return (EM_OK); 416*adc586deSMark Johnson } 417*adc586deSMark Johnson return (EM_NOMATCH); 418*adc586deSMark Johnson } 419*adc586deSMark Johnson 420*adc586deSMark Johnson static ucode_errno_t 421*adc586deSMark Johnson ucode_locate_intel(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp) 4222449e17fSsherrym { 4232449e17fSsherrym char name[MAXPATHLEN]; 4242449e17fSsherrym intptr_t fd; 4252449e17fSsherrym int count; 426*adc586deSMark Johnson int header_size = UCODE_HEADER_SIZE_INTEL; 4272449e17fSsherrym int cpi_sig = cpuid_getsig(cp); 4282449e17fSsherrym ucode_errno_t rc = EM_OK; 429*adc586deSMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel; 430*adc586deSMark Johnson 431*adc586deSMark Johnson ASSERT(ucode); 4322449e17fSsherrym 4332449e17fSsherrym /* 4342449e17fSsherrym * If the microcode matches the CPU we are processing, use it. 4352449e17fSsherrym */ 436*adc586deSMark Johnson if (ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header, 4372449e17fSsherrym ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) { 4382449e17fSsherrym return (EM_OK); 4392449e17fSsherrym } 4402449e17fSsherrym 4412449e17fSsherrym /* 4422449e17fSsherrym * Look for microcode file with the right name. 4432449e17fSsherrym */ 4442449e17fSsherrym (void) snprintf(name, MAXPATHLEN, "/%s/%s/%08X-%02X", 4452449e17fSsherrym UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), cpi_sig, 4462449e17fSsherrym uinfop->cui_platid); 4472449e17fSsherrym if ((fd = kobj_open(name)) == -1) { 4482449e17fSsherrym return (EM_OPENFILE); 4492449e17fSsherrym } 4502449e17fSsherrym 4512449e17fSsherrym /* 4522449e17fSsherrym * We found a microcode file for the CPU we are processing, 4532449e17fSsherrym * reset the microcode data structure and read in the new 4542449e17fSsherrym * file. 4552449e17fSsherrym */ 456*adc586deSMark Johnson ucode->file_reset(ufp, cp->cpu_id); 4572449e17fSsherrym 458*adc586deSMark Johnson ucodefp->uf_header = ucode_zalloc(cp->cpu_id, header_size); 459*adc586deSMark Johnson if (ucodefp->uf_header == NULL) 460*adc586deSMark Johnson return (EM_NOMEM); 461*adc586deSMark Johnson 462*adc586deSMark Johnson count = kobj_read(fd, (char *)ucodefp->uf_header, header_size, 0); 4632449e17fSsherrym 4642449e17fSsherrym switch (count) { 465*adc586deSMark Johnson case UCODE_HEADER_SIZE_INTEL: { 4662449e17fSsherrym 467*adc586deSMark Johnson ucode_header_intel_t *uhp = ucodefp->uf_header; 4682449e17fSsherrym uint32_t offset = header_size; 4692449e17fSsherrym int total_size, body_size, ext_size; 4702449e17fSsherrym uint32_t sum = 0; 4712449e17fSsherrym 4722449e17fSsherrym /* 4732449e17fSsherrym * Make sure that the header contains valid fields. 4742449e17fSsherrym */ 475*adc586deSMark Johnson if ((rc = ucode_header_validate_intel(uhp)) == EM_OK) { 476*adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 477*adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 478*adc586deSMark Johnson ucodefp->uf_body = ucode_zalloc(cp->cpu_id, body_size); 479*adc586deSMark Johnson if (ucodefp->uf_body == NULL) { 4802449e17fSsherrym rc = EM_NOMEM; 4812449e17fSsherrym break; 4822449e17fSsherrym } 4832449e17fSsherrym 4842449e17fSsherrym if (kobj_read(fd, (char *)ucodefp->uf_body, 4852449e17fSsherrym body_size, offset) != body_size) 4862449e17fSsherrym rc = EM_FILESIZE; 4872449e17fSsherrym } 4882449e17fSsherrym 4892449e17fSsherrym if (rc) 4902449e17fSsherrym break; 4912449e17fSsherrym 492*adc586deSMark Johnson sum = ucode_checksum_intel(0, header_size, 493*adc586deSMark Johnson (uint8_t *)ucodefp->uf_header); 494*adc586deSMark Johnson if (ucode_checksum_intel(sum, body_size, ucodefp->uf_body)) { 4952449e17fSsherrym rc = EM_CHECKSUM; 4962449e17fSsherrym break; 4972449e17fSsherrym } 4982449e17fSsherrym 4992449e17fSsherrym /* 5002449e17fSsherrym * Check to see if there is extended signature table. 5012449e17fSsherrym */ 5022449e17fSsherrym offset = body_size + header_size; 5032449e17fSsherrym ext_size = total_size - offset; 5042449e17fSsherrym 5052449e17fSsherrym if (ext_size <= 0) 5062449e17fSsherrym break; 5072449e17fSsherrym 508*adc586deSMark Johnson ucodefp->uf_ext_table = ucode_zalloc(cp->cpu_id, ext_size); 509*adc586deSMark Johnson if (ucodefp->uf_ext_table == NULL) { 5102449e17fSsherrym rc = EM_NOMEM; 5112449e17fSsherrym break; 5122449e17fSsherrym } 5132449e17fSsherrym 5142449e17fSsherrym if (kobj_read(fd, (char *)ucodefp->uf_ext_table, 5152449e17fSsherrym ext_size, offset) != ext_size) { 5162449e17fSsherrym rc = EM_FILESIZE; 517*adc586deSMark Johnson } else if (ucode_checksum_intel(0, ext_size, 5182449e17fSsherrym (uint8_t *)(ucodefp->uf_ext_table))) { 5192449e17fSsherrym rc = EM_CHECKSUM; 5202449e17fSsherrym } else { 5212449e17fSsherrym int i; 5222449e17fSsherrym 523*adc586deSMark Johnson ext_size -= UCODE_EXT_TABLE_SIZE_INTEL; 5242449e17fSsherrym for (i = 0; i < ucodefp->uf_ext_table->uet_count; 5252449e17fSsherrym i++) { 526*adc586deSMark Johnson if (ucode_checksum_intel(0, 527*adc586deSMark Johnson UCODE_EXT_SIG_SIZE_INTEL, 5282449e17fSsherrym (uint8_t *)(&(ucodefp->uf_ext_table-> 5292449e17fSsherrym uet_ext_sig[i])))) { 5302449e17fSsherrym rc = EM_CHECKSUM; 5312449e17fSsherrym break; 5322449e17fSsherrym } 5332449e17fSsherrym } 5342449e17fSsherrym } 5352449e17fSsherrym break; 5362449e17fSsherrym } 5372449e17fSsherrym 5382449e17fSsherrym default: 5392449e17fSsherrym rc = EM_FILESIZE; 5402449e17fSsherrym break; 5412449e17fSsherrym } 5422449e17fSsherrym 5432449e17fSsherrym kobj_close(fd); 5442449e17fSsherrym 5452449e17fSsherrym if (rc != EM_OK) 5462449e17fSsherrym return (rc); 5472449e17fSsherrym 548*adc586deSMark Johnson rc = ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header, 5492449e17fSsherrym ucodefp->uf_ext_table); 5502449e17fSsherrym 5512449e17fSsherrym return (rc); 5522449e17fSsherrym } 5532449e17fSsherrym 554*adc586deSMark Johnson static ucode_errno_t 555*adc586deSMark Johnson ucode_match_amd(int eq_sig, cpu_ucode_info_t *uinfop, ucode_file_amd_t *ucodefp, 556*adc586deSMark Johnson int size) 557*adc586deSMark Johnson { 558*adc586deSMark Johnson ucode_header_amd_t *uh; 559*adc586deSMark Johnson 560*adc586deSMark Johnson if (ucodefp == NULL || size < sizeof (ucode_header_amd_t)) 561*adc586deSMark Johnson return (EM_NOMATCH); 562*adc586deSMark Johnson 563*adc586deSMark Johnson /* 564*adc586deSMark Johnson * Don't even think about loading patches that would require code 565*adc586deSMark Johnson * execution. 566*adc586deSMark Johnson */ 567*adc586deSMark Johnson if (size > offsetof(ucode_file_amd_t, uf_code_present) && 568*adc586deSMark Johnson ucodefp->uf_code_present) 569*adc586deSMark Johnson return (EM_NOMATCH); 570*adc586deSMark Johnson 571*adc586deSMark Johnson uh = &ucodefp->uf_header; 572*adc586deSMark Johnson 573*adc586deSMark Johnson if (eq_sig != uh->uh_cpu_rev) 574*adc586deSMark Johnson return (EM_NOMATCH); 575*adc586deSMark Johnson 576*adc586deSMark Johnson if (uh->uh_nb_id) { 577*adc586deSMark Johnson cmn_err(CE_WARN, "ignoring northbridge-specific ucode: " 578*adc586deSMark Johnson "chipset id %x, revision %x", uh->uh_nb_id, uh->uh_nb_rev); 579*adc586deSMark Johnson return (EM_NOMATCH); 580*adc586deSMark Johnson } 581*adc586deSMark Johnson 582*adc586deSMark Johnson if (uh->uh_sb_id) { 583*adc586deSMark Johnson cmn_err(CE_WARN, "ignoring southbridge-specific ucode: " 584*adc586deSMark Johnson "chipset id %x, revision %x", uh->uh_sb_id, uh->uh_sb_rev); 585*adc586deSMark Johnson return (EM_NOMATCH); 586*adc586deSMark Johnson } 587*adc586deSMark Johnson 588*adc586deSMark Johnson if (uh->uh_patch_id <= uinfop->cui_rev) 589*adc586deSMark Johnson return (EM_HIGHERREV); 590*adc586deSMark Johnson 591*adc586deSMark Johnson return (EM_OK); 592*adc586deSMark Johnson } 5932449e17fSsherrym 5942449e17fSsherrym /* 5952449e17fSsherrym * Returns 1 if the microcode is for this processor; 0 otherwise. 5962449e17fSsherrym */ 5972449e17fSsherrym static ucode_errno_t 598*adc586deSMark Johnson ucode_match_intel(int cpi_sig, cpu_ucode_info_t *uinfop, 599*adc586deSMark Johnson ucode_header_intel_t *uhp, ucode_ext_table_intel_t *uetp) 6002449e17fSsherrym { 601*adc586deSMark Johnson if (uhp == NULL) 602*adc586deSMark Johnson return (EM_NOMATCH); 6032449e17fSsherrym 604*adc586deSMark Johnson if (UCODE_MATCH_INTEL(cpi_sig, uhp->uh_signature, 6052449e17fSsherrym uinfop->cui_platid, uhp->uh_proc_flags)) { 6062449e17fSsherrym 6072449e17fSsherrym if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update) 6082449e17fSsherrym return (EM_HIGHERREV); 6092449e17fSsherrym 6102449e17fSsherrym return (EM_OK); 6112449e17fSsherrym } 6122449e17fSsherrym 6132449e17fSsherrym if (uetp != NULL) { 6142449e17fSsherrym int i; 6152449e17fSsherrym 6162449e17fSsherrym for (i = 0; i < uetp->uet_count; i++) { 617*adc586deSMark Johnson ucode_ext_sig_intel_t *uesp; 6182449e17fSsherrym 6192449e17fSsherrym uesp = &uetp->uet_ext_sig[i]; 6202449e17fSsherrym 621*adc586deSMark Johnson if (UCODE_MATCH_INTEL(cpi_sig, uesp->ues_signature, 6222449e17fSsherrym uinfop->cui_platid, uesp->ues_proc_flags)) { 6232449e17fSsherrym 6242449e17fSsherrym if (uinfop->cui_rev >= uhp->uh_rev && 6252449e17fSsherrym !ucode_force_update) 6262449e17fSsherrym return (EM_HIGHERREV); 6272449e17fSsherrym 6282449e17fSsherrym return (EM_OK); 6292449e17fSsherrym } 6302449e17fSsherrym } 6312449e17fSsherrym } 6322449e17fSsherrym 6332449e17fSsherrym return (EM_NOMATCH); 6342449e17fSsherrym } 6352449e17fSsherrym 6362449e17fSsherrym /*ARGSUSED*/ 6372449e17fSsherrym static int 6382449e17fSsherrym ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3) 6392449e17fSsherrym { 640*adc586deSMark Johnson ucode_update_t *uusp = (ucode_update_t *)arg1; 641*adc586deSMark Johnson cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info; 6422449e17fSsherrym 643*adc586deSMark Johnson ASSERT(ucode); 6442449e17fSsherrym ASSERT(uusp->ucodep); 6452449e17fSsherrym 646882a7af5SMark Johnson #ifndef __xpv 6472449e17fSsherrym /* 6482449e17fSsherrym * Check one more time to see if it is really necessary to update 6492449e17fSsherrym * microcode just in case this is a hyperthreaded processor where 6502449e17fSsherrym * the threads share the same microcode. 6512449e17fSsherrym */ 6522449e17fSsherrym if (!ucode_force_update) { 653*adc586deSMark Johnson ucode->read_rev(uinfop); 6542449e17fSsherrym uusp->new_rev = uinfop->cui_rev; 6552449e17fSsherrym if (uinfop->cui_rev >= uusp->expected_rev) 6562449e17fSsherrym return (0); 6572449e17fSsherrym } 6582449e17fSsherrym 659*adc586deSMark Johnson wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep); 660882a7af5SMark Johnson #endif 661*adc586deSMark Johnson ucode->read_rev(uinfop); 6622449e17fSsherrym uusp->new_rev = uinfop->cui_rev; 6632449e17fSsherrym 6642449e17fSsherrym return (0); 6652449e17fSsherrym } 6662449e17fSsherrym 667*adc586deSMark Johnson /*ARGSUSED*/ 668*adc586deSMark Johnson static uint32_t 669*adc586deSMark Johnson ucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp) 6702449e17fSsherrym { 671*adc586deSMark Johnson ucode_file_amd_t *ucodefp = ufp->amd; 672*adc586deSMark Johnson #ifdef __xpv 673*adc586deSMark Johnson ucode_update_t uus; 674*adc586deSMark Johnson #endif 675*adc586deSMark Johnson 676*adc586deSMark Johnson ASSERT(ucode); 677*adc586deSMark Johnson ASSERT(ucodefp); 678*adc586deSMark Johnson 679*adc586deSMark Johnson #ifndef __xpv 6802449e17fSsherrym kpreempt_disable(); 681*adc586deSMark Johnson wrmsr(ucode->write_msr, (uintptr_t)ucodefp); 682*adc586deSMark Johnson ucode->read_rev(uinfop); 6832449e17fSsherrym kpreempt_enable(); 684*adc586deSMark Johnson #else 685*adc586deSMark Johnson uus.ucodep = (uint8_t *)ucodefp; 686*adc586deSMark Johnson uus.usize = sizeof (*ucodefp); 687*adc586deSMark Johnson ucode_load_xpv(&uus); 688*adc586deSMark Johnson ucode->read_rev(uinfop); 689*adc586deSMark Johnson uus.new_rev = uinfop->cui_rev; 690*adc586deSMark Johnson #endif 691*adc586deSMark Johnson 692*adc586deSMark Johnson return (ucodefp->uf_header.uh_patch_id); 693*adc586deSMark Johnson } 694*adc586deSMark Johnson 695*adc586deSMark Johnson /*ARGSUSED2*/ 696*adc586deSMark Johnson static uint32_t 697*adc586deSMark Johnson ucode_load_intel(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp) 698*adc586deSMark Johnson { 699*adc586deSMark Johnson ucode_file_intel_t *ucodefp = &ufp->intel; 700*adc586deSMark Johnson #ifdef __xpv 701*adc586deSMark Johnson uint32_t ext_offset; 702*adc586deSMark Johnson uint32_t body_size; 703*adc586deSMark Johnson uint32_t ext_size; 704*adc586deSMark Johnson uint8_t *ustart; 705*adc586deSMark Johnson uint32_t usize; 706*adc586deSMark Johnson ucode_update_t uus; 707*adc586deSMark Johnson #endif 708*adc586deSMark Johnson 709*adc586deSMark Johnson ASSERT(ucode); 710*adc586deSMark Johnson 711*adc586deSMark Johnson #ifdef __xpv 712*adc586deSMark Johnson /* 713*adc586deSMark Johnson * the hypervisor wants the header, data, and extended 714*adc586deSMark Johnson * signature tables. We can only get here from the boot 715*adc586deSMark Johnson * CPU (cpu #0), we don't need to free as ucode_zalloc() will 716*adc586deSMark Johnson * use BOP_ALLOC(). 717*adc586deSMark Johnson */ 718*adc586deSMark Johnson usize = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size); 719*adc586deSMark Johnson ustart = ucode_zalloc(cp->cpu_id, usize); 720*adc586deSMark Johnson ASSERT(ustart); 721*adc586deSMark Johnson 722*adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size); 723*adc586deSMark Johnson ext_offset = body_size + UCODE_HEADER_SIZE_INTEL; 724*adc586deSMark Johnson ext_size = usize - ext_offset; 725*adc586deSMark Johnson ASSERT(ext_size >= 0); 726*adc586deSMark Johnson 727*adc586deSMark Johnson (void) memcpy(ustart, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL); 728*adc586deSMark Johnson (void) memcpy(&ustart[UCODE_HEADER_SIZE_INTEL], ucodefp->uf_body, 729*adc586deSMark Johnson body_size); 730*adc586deSMark Johnson if (ext_size > 0) { 731*adc586deSMark Johnson (void) memcpy(&ustart[ext_offset], 732*adc586deSMark Johnson ucodefp->uf_ext_table, ext_size); 733*adc586deSMark Johnson } 734*adc586deSMark Johnson uus.ucodep = ustart; 735*adc586deSMark Johnson uus.usize = usize; 736*adc586deSMark Johnson ucode_load_xpv(&uus); 737*adc586deSMark Johnson ucode->read_rev(uinfop); 738*adc586deSMark Johnson uus.new_rev = uinfop->cui_rev; 739*adc586deSMark Johnson #else 740*adc586deSMark Johnson kpreempt_disable(); 741*adc586deSMark Johnson wrmsr(ucode->write_msr, (uintptr_t)ucodefp->uf_body); 742*adc586deSMark Johnson ucode->read_rev(uinfop); 743*adc586deSMark Johnson kpreempt_enable(); 744*adc586deSMark Johnson #endif 745*adc586deSMark Johnson 746*adc586deSMark Johnson return (ucodefp->uf_header->uh_rev); 7472449e17fSsherrym } 7482449e17fSsherrym 749882a7af5SMark Johnson 750882a7af5SMark Johnson #ifdef __xpv 751882a7af5SMark Johnson static void 752*adc586deSMark Johnson ucode_load_xpv(ucode_update_t *uusp) 753882a7af5SMark Johnson { 754882a7af5SMark Johnson xen_platform_op_t op; 755882a7af5SMark Johnson int e; 756882a7af5SMark Johnson 757882a7af5SMark Johnson ASSERT(DOMAIN_IS_INITDOMAIN(xen_info)); 758882a7af5SMark Johnson 759882a7af5SMark Johnson kpreempt_disable(); 760882a7af5SMark Johnson op.cmd = XENPF_microcode_update; 761882a7af5SMark Johnson op.interface_version = XENPF_INTERFACE_VERSION; 762882a7af5SMark Johnson /*LINTED: constant in conditional context*/ 763*adc586deSMark Johnson set_xen_guest_handle(op.u.microcode.data, uusp->ucodep); 764*adc586deSMark Johnson op.u.microcode.length = uusp->usize; 765882a7af5SMark Johnson e = HYPERVISOR_platform_op(&op); 766882a7af5SMark Johnson if (e != 0) { 767882a7af5SMark Johnson cmn_err(CE_WARN, "hypervisor failed to accept uCode update"); 768882a7af5SMark Johnson } 769882a7af5SMark Johnson kpreempt_enable(); 770882a7af5SMark Johnson } 771882a7af5SMark Johnson #endif /* __xpv */ 772882a7af5SMark Johnson 773*adc586deSMark Johnson static void 774*adc586deSMark Johnson ucode_read_rev_amd(cpu_ucode_info_t *uinfop) 775*adc586deSMark Johnson { 776*adc586deSMark Johnson uinfop->cui_rev = rdmsr(MSR_AMD_PATCHLEVEL); 777*adc586deSMark Johnson } 778882a7af5SMark Johnson 7792449e17fSsherrym static void 780*adc586deSMark Johnson ucode_read_rev_intel(cpu_ucode_info_t *uinfop) 7812449e17fSsherrym { 7822449e17fSsherrym struct cpuid_regs crs; 7832449e17fSsherrym 7842449e17fSsherrym /* 7852449e17fSsherrym * The Intel 64 and IA-32 Architecture Software Developer's Manual 7862449e17fSsherrym * recommends that MSR_INTC_UCODE_REV be loaded with 0 first, then 7872449e17fSsherrym * execute cpuid to guarantee the correct reading of this register. 7882449e17fSsherrym */ 7892449e17fSsherrym wrmsr(MSR_INTC_UCODE_REV, 0); 7902449e17fSsherrym (void) __cpuid_insn(&crs); 7912449e17fSsherrym uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT); 7922449e17fSsherrym } 7932449e17fSsherrym 794*adc586deSMark Johnson static ucode_errno_t 795*adc586deSMark Johnson ucode_extract_amd(ucode_update_t *uusp, uint8_t *ucodep, int size) 796*adc586deSMark Johnson { 797*adc586deSMark Johnson uint32_t *ptr = (uint32_t *)ucodep; 798*adc586deSMark Johnson ucode_eqtbl_amd_t *eqtbl; 799*adc586deSMark Johnson ucode_file_amd_t *ufp; 800*adc586deSMark Johnson int count, eq_sig; 801*adc586deSMark Johnson 802*adc586deSMark Johnson /* skip over magic number & equivalence table header */ 803*adc586deSMark Johnson ptr += 2; size -= 8; 804*adc586deSMark Johnson 805*adc586deSMark Johnson count = *ptr++; size -= 4; 806*adc586deSMark Johnson for (eqtbl = (ucode_eqtbl_amd_t *)ptr; 807*adc586deSMark Johnson eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != uusp->sig; 808*adc586deSMark Johnson eqtbl++) 809*adc586deSMark Johnson ; 810*adc586deSMark Johnson 811*adc586deSMark Johnson eq_sig = eqtbl->ue_equiv_cpu; 812*adc586deSMark Johnson eq_sig = ((eq_sig >> 8) & 0xff00) | (eq_sig & 0xff); 813*adc586deSMark Johnson 814*adc586deSMark Johnson /* No equivalent CPU id found, assume outdated microcode file. */ 815*adc586deSMark Johnson if (eq_sig == 0) 816*adc586deSMark Johnson return (EM_HIGHERREV); 817*adc586deSMark Johnson 818*adc586deSMark Johnson /* Use the first microcode patch that matches. */ 819*adc586deSMark Johnson do { 820*adc586deSMark Johnson ptr += count >> 2; size -= count; 821*adc586deSMark Johnson 822*adc586deSMark Johnson if (!size) 823*adc586deSMark Johnson return (EM_NOMATCH); 824*adc586deSMark Johnson 825*adc586deSMark Johnson ptr++; size -= 4; 826*adc586deSMark Johnson count = *ptr++; size -= 4; 827*adc586deSMark Johnson ufp = (ucode_file_amd_t *)ptr; 828*adc586deSMark Johnson } while (ucode_match_amd(eq_sig, &uusp->info, ufp, count) != EM_OK); 829*adc586deSMark Johnson 830*adc586deSMark Johnson uusp->ucodep = (uint8_t *)ufp; 831*adc586deSMark Johnson uusp->usize = count; 832*adc586deSMark Johnson uusp->expected_rev = ufp->uf_header.uh_patch_id; 833*adc586deSMark Johnson 834*adc586deSMark Johnson return (EM_OK); 835*adc586deSMark Johnson } 836*adc586deSMark Johnson 837*adc586deSMark Johnson static ucode_errno_t 838*adc586deSMark Johnson ucode_extract_intel(ucode_update_t *uusp, uint8_t *ucodep, int size) 839*adc586deSMark Johnson { 840*adc586deSMark Johnson uint32_t header_size = UCODE_HEADER_SIZE_INTEL; 841*adc586deSMark Johnson int remaining; 842*adc586deSMark Johnson int found = 0; 843*adc586deSMark Johnson ucode_errno_t search_rc = EM_NOMATCH; /* search result */ 844*adc586deSMark Johnson 845*adc586deSMark Johnson /* 846*adc586deSMark Johnson * Go through the whole buffer in case there are 847*adc586deSMark Johnson * multiple versions of matching microcode for this 848*adc586deSMark Johnson * processor. 849*adc586deSMark Johnson */ 850*adc586deSMark Johnson for (remaining = size; remaining > 0; ) { 851*adc586deSMark Johnson int total_size, body_size, ext_size; 852*adc586deSMark Johnson uint8_t *curbuf = &ucodep[size - remaining]; 853*adc586deSMark Johnson ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf; 854*adc586deSMark Johnson ucode_ext_table_intel_t *uetp = NULL; 855*adc586deSMark Johnson ucode_errno_t tmprc; 856*adc586deSMark Johnson 857*adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 858*adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 859*adc586deSMark Johnson ext_size = total_size - (header_size + body_size); 860*adc586deSMark Johnson 861*adc586deSMark Johnson if (ext_size > 0) 862*adc586deSMark Johnson uetp = (ucode_ext_table_intel_t *) 863*adc586deSMark Johnson &curbuf[header_size + body_size]; 864*adc586deSMark Johnson 865*adc586deSMark Johnson tmprc = ucode_match_intel(uusp->sig, &uusp->info, uhp, uetp); 866*adc586deSMark Johnson 867*adc586deSMark Johnson /* 868*adc586deSMark Johnson * Since we are searching through a big file 869*adc586deSMark Johnson * containing microcode for pretty much all the 870*adc586deSMark Johnson * processors, we are bound to get EM_NOMATCH 871*adc586deSMark Johnson * at one point. However, if we return 872*adc586deSMark Johnson * EM_NOMATCH to users, it will really confuse 873*adc586deSMark Johnson * them. Therefore, if we ever find a match of 874*adc586deSMark Johnson * a lower rev, we will set return code to 875*adc586deSMark Johnson * EM_HIGHERREV. 876*adc586deSMark Johnson */ 877*adc586deSMark Johnson if (tmprc == EM_HIGHERREV) 878*adc586deSMark Johnson search_rc = EM_HIGHERREV; 879*adc586deSMark Johnson 880*adc586deSMark Johnson if (tmprc == EM_OK && 881*adc586deSMark Johnson uusp->expected_rev < uhp->uh_rev) { 882*adc586deSMark Johnson #ifndef __xpv 883*adc586deSMark Johnson uusp->ucodep = (uint8_t *)&curbuf[header_size]; 884*adc586deSMark Johnson #else 885*adc586deSMark Johnson uusp->ucodep = (uint8_t *)curbuf; 886*adc586deSMark Johnson #endif 887*adc586deSMark Johnson uusp->usize = 888*adc586deSMark Johnson UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 889*adc586deSMark Johnson uusp->expected_rev = uhp->uh_rev; 890*adc586deSMark Johnson found = 1; 891*adc586deSMark Johnson } 892*adc586deSMark Johnson 893*adc586deSMark Johnson remaining -= total_size; 894*adc586deSMark Johnson } 895*adc586deSMark Johnson 896*adc586deSMark Johnson if (!found) 897*adc586deSMark Johnson return (search_rc); 898*adc586deSMark Johnson 899*adc586deSMark Johnson return (EM_OK); 900*adc586deSMark Johnson } 9012449e17fSsherrym /* 9022449e17fSsherrym * Entry point to microcode update from the ucode_drv driver. 9032449e17fSsherrym * 9042449e17fSsherrym * Returns EM_OK on success, corresponding error code on failure. 9052449e17fSsherrym */ 9062449e17fSsherrym ucode_errno_t 9072449e17fSsherrym ucode_update(uint8_t *ucodep, int size) 9082449e17fSsherrym { 9092449e17fSsherrym int found = 0; 9102449e17fSsherrym processorid_t id; 911*adc586deSMark Johnson ucode_update_t cached = { 0 }; 912*adc586deSMark Johnson ucode_update_t *cachedp = NULL; 9132449e17fSsherrym ucode_errno_t rc = EM_OK; 9142449e17fSsherrym ucode_errno_t search_rc = EM_NOMATCH; /* search result */ 9152449e17fSsherrym cpuset_t cpuset; 9162449e17fSsherrym 917*adc586deSMark Johnson ASSERT(ucode); 9182449e17fSsherrym ASSERT(ucodep); 9192449e17fSsherrym CPUSET_ZERO(cpuset); 9202449e17fSsherrym 921*adc586deSMark Johnson if (!ucode->capable(CPU)) 9222449e17fSsherrym return (EM_NOTSUP); 9232449e17fSsherrym 9242449e17fSsherrym mutex_enter(&cpu_lock); 9252449e17fSsherrym 9262449e17fSsherrym for (id = 0; id < max_ncpus; id++) { 9272449e17fSsherrym cpu_t *cpu; 928*adc586deSMark Johnson ucode_update_t uus = { 0 }; 929*adc586deSMark Johnson ucode_update_t *uusp = &uus; 9302449e17fSsherrym 9312449e17fSsherrym /* 9322449e17fSsherrym * If there is no such CPU or it is not xcall ready, skip it. 9332449e17fSsherrym */ 9342449e17fSsherrym if ((cpu = cpu_get(id)) == NULL || 9352449e17fSsherrym !(cpu->cpu_flags & CPU_READY)) 9362449e17fSsherrym continue; 9372449e17fSsherrym 9382449e17fSsherrym uusp->sig = cpuid_getsig(cpu); 9392449e17fSsherrym bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info, 9402449e17fSsherrym sizeof (uusp->info)); 9412449e17fSsherrym 9422449e17fSsherrym /* 9432449e17fSsherrym * If the current CPU has the same signature and platform 9442449e17fSsherrym * id as the previous one we processed, reuse the information. 9452449e17fSsherrym */ 9462449e17fSsherrym if (cachedp && cachedp->sig == cpuid_getsig(cpu) && 9472449e17fSsherrym cachedp->info.cui_platid == uusp->info.cui_platid) { 9482449e17fSsherrym uusp->ucodep = cachedp->ucodep; 9492449e17fSsherrym uusp->expected_rev = cachedp->expected_rev; 9502449e17fSsherrym /* 9512449e17fSsherrym * Intuitively we should check here to see whether the 9522449e17fSsherrym * running microcode rev is >= the expected rev, and 9532449e17fSsherrym * quit if it is. But we choose to proceed with the 9542449e17fSsherrym * xcall regardless of the running version so that 9552449e17fSsherrym * the other threads in an HT processor can update 9562449e17fSsherrym * the cpu_ucode_info structure in machcpu. 9572449e17fSsherrym */ 958*adc586deSMark Johnson } else if ((search_rc = ucode->extract(uusp, ucodep, size)) 959*adc586deSMark Johnson == EM_OK) { 9602449e17fSsherrym bcopy(uusp, &cached, sizeof (cached)); 9612449e17fSsherrym cachedp = &cached; 9622449e17fSsherrym found = 1; 9632449e17fSsherrym } 9642449e17fSsherrym 9652449e17fSsherrym /* Nothing to do */ 9662449e17fSsherrym if (uusp->ucodep == NULL) 9672449e17fSsherrym continue; 9682449e17fSsherrym 969882a7af5SMark Johnson #ifdef __xpv 970882a7af5SMark Johnson /* 971882a7af5SMark Johnson * for i86xpv, the hypervisor will update all the CPUs. 972882a7af5SMark Johnson * the hypervisor wants the header, data, and extended 973882a7af5SMark Johnson * signature tables. ucode_write will just read in the 974882a7af5SMark Johnson * updated version on all the CPUs after the update has 975882a7af5SMark Johnson * completed. 976882a7af5SMark Johnson */ 977c9b5d7d2SMark Johnson if (id == 0) { 978*adc586deSMark Johnson ucode_load_xpv(uusp); 979c9b5d7d2SMark Johnson } 980882a7af5SMark Johnson #endif 981882a7af5SMark Johnson 9822449e17fSsherrym CPUSET_ADD(cpuset, id); 9832449e17fSsherrym kpreempt_disable(); 9842449e17fSsherrym xc_sync((xc_arg_t)uusp, 0, 0, X_CALL_HIPRI, cpuset, 9852449e17fSsherrym ucode_write); 9862449e17fSsherrym kpreempt_enable(); 9872449e17fSsherrym CPUSET_DEL(cpuset, id); 9882449e17fSsherrym 9892449e17fSsherrym if (uusp->expected_rev == uusp->new_rev) { 9902449e17fSsherrym cmn_err(CE_CONT, ucode_success_fmt, 9912449e17fSsherrym id, uusp->info.cui_rev, uusp->expected_rev); 9922449e17fSsherrym } else { 9932449e17fSsherrym cmn_err(CE_WARN, ucode_failure_fmt, 9942449e17fSsherrym id, uusp->info.cui_rev, uusp->expected_rev); 9952449e17fSsherrym rc = EM_UPDATE; 9962449e17fSsherrym } 9972449e17fSsherrym } 9982449e17fSsherrym 9992449e17fSsherrym mutex_exit(&cpu_lock); 10002449e17fSsherrym 10012449e17fSsherrym if (!found) 10022449e17fSsherrym rc = search_rc; 10032449e17fSsherrym 10042449e17fSsherrym return (rc); 10052449e17fSsherrym } 10062449e17fSsherrym 10072449e17fSsherrym /* 10082449e17fSsherrym * Initialize mcpu_ucode_info, and perform microcode update if necessary. 10092449e17fSsherrym * This is the entry point from boot path where pointer to CPU structure 10102449e17fSsherrym * is available. 10112449e17fSsherrym * 10122449e17fSsherrym * cpuid_info must be initialized before ucode_check can be called. 10132449e17fSsherrym */ 10142449e17fSsherrym void 10152449e17fSsherrym ucode_check(cpu_t *cp) 10162449e17fSsherrym { 1017*adc586deSMark Johnson cpu_ucode_info_t *uinfop; 10182449e17fSsherrym ucode_errno_t rc = EM_OK; 1019*adc586deSMark Johnson uint32_t new_rev = 0; 10202449e17fSsherrym 10212449e17fSsherrym ASSERT(cp); 10222449e17fSsherrym if (cp->cpu_id == 0) 10232449e17fSsherrym cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0; 10242449e17fSsherrym 10252449e17fSsherrym uinfop = cp->cpu_m.mcpu_ucode_info; 10262449e17fSsherrym ASSERT(uinfop); 10272449e17fSsherrym 1028*adc586deSMark Johnson /* set up function pointers if not already done */ 1029*adc586deSMark Johnson if (!ucode) 1030*adc586deSMark Johnson switch (cpuid_getvendor(cp)) { 1031*adc586deSMark Johnson case X86_VENDOR_AMD: 1032*adc586deSMark Johnson ucode = &ucode_amd; 1033*adc586deSMark Johnson break; 1034*adc586deSMark Johnson case X86_VENDOR_Intel: 1035*adc586deSMark Johnson ucode = &ucode_intel; 1036*adc586deSMark Johnson break; 1037*adc586deSMark Johnson default: 1038*adc586deSMark Johnson return; 1039*adc586deSMark Johnson } 1040*adc586deSMark Johnson 1041*adc586deSMark Johnson if (!ucode->capable(cp)) 10422449e17fSsherrym return; 10432449e17fSsherrym 10442449e17fSsherrym /* 10452449e17fSsherrym * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon 10462449e17fSsherrym * (Family 6, model 5 and above) and all processors after. 10472449e17fSsherrym */ 1048*adc586deSMark Johnson if ((cpuid_getvendor(cp) == X86_VENDOR_Intel) && 1049*adc586deSMark Johnson ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6))) { 10502449e17fSsherrym uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >> 10512449e17fSsherrym INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK); 10522449e17fSsherrym } 10532449e17fSsherrym 1054*adc586deSMark Johnson ucode->read_rev(uinfop); 10552449e17fSsherrym 1056c9b5d7d2SMark Johnson #ifdef __xpv 1057c9b5d7d2SMark Johnson /* 1058c9b5d7d2SMark Johnson * for i86xpv, the hypervisor will update all the CPUs. We only need 1059c9b5d7d2SMark Johnson * do do this on one of the CPUs (and there always is a CPU 0). 1060c9b5d7d2SMark Johnson */ 1061c9b5d7d2SMark Johnson if (cp->cpu_id != 0) { 1062c9b5d7d2SMark Johnson return; 1063c9b5d7d2SMark Johnson } 1064c9b5d7d2SMark Johnson #endif 1065c9b5d7d2SMark Johnson 10662449e17fSsherrym /* 10672449e17fSsherrym * Check to see if we need ucode update 10682449e17fSsherrym */ 1069*adc586deSMark Johnson if ((rc = ucode->locate(cp, uinfop, &ucodefile)) == EM_OK) { 1070*adc586deSMark Johnson new_rev = ucode->load(&ucodefile, uinfop, cp); 1071882a7af5SMark Johnson 1072*adc586deSMark Johnson if (uinfop->cui_rev != new_rev) 10732449e17fSsherrym cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id, 1074*adc586deSMark Johnson uinfop->cui_rev, new_rev); 10752449e17fSsherrym } 10762449e17fSsherrym 10772449e17fSsherrym /* 10782449e17fSsherrym * If we fail to find a match for any reason, free the file structure 10792449e17fSsherrym * just in case we have read in a partial file. 10802449e17fSsherrym * 10812449e17fSsherrym * Since the scratch memory for holding the microcode for the boot CPU 10822449e17fSsherrym * came from BOP_ALLOC, we will reset the data structure as if we 10832449e17fSsherrym * never did the allocation so we don't have to keep track of this 10842449e17fSsherrym * special chunk of memory. We free the memory used for the rest 10852449e17fSsherrym * of the CPUs in start_other_cpus(). 10862449e17fSsherrym */ 10872449e17fSsherrym if (rc != EM_OK || cp->cpu_id == 0) 1088*adc586deSMark Johnson ucode->file_reset(&ucodefile, cp->cpu_id); 10892449e17fSsherrym } 10902449e17fSsherrym 10912449e17fSsherrym /* 10922449e17fSsherrym * Returns microcode revision from the machcpu structure. 10932449e17fSsherrym */ 10942449e17fSsherrym ucode_errno_t 10952449e17fSsherrym ucode_get_rev(uint32_t *revp) 10962449e17fSsherrym { 10972449e17fSsherrym int i; 10982449e17fSsherrym 1099*adc586deSMark Johnson ASSERT(ucode); 11002449e17fSsherrym ASSERT(revp); 11012449e17fSsherrym 1102*adc586deSMark Johnson if (!ucode->capable(CPU)) 11032449e17fSsherrym return (EM_NOTSUP); 11042449e17fSsherrym 11052449e17fSsherrym mutex_enter(&cpu_lock); 11062449e17fSsherrym for (i = 0; i < max_ncpus; i++) { 11072449e17fSsherrym cpu_t *cpu; 11082449e17fSsherrym 11092449e17fSsherrym if ((cpu = cpu_get(i)) == NULL) 11102449e17fSsherrym continue; 11112449e17fSsherrym 11122449e17fSsherrym revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev; 11132449e17fSsherrym } 11142449e17fSsherrym mutex_exit(&cpu_lock); 11152449e17fSsherrym 11162449e17fSsherrym return (EM_OK); 11172449e17fSsherrym } 1118