1*2449e17fSsherrym /* 2*2449e17fSsherrym * CDDL HEADER START 3*2449e17fSsherrym * 4*2449e17fSsherrym * The contents of this file are subject to the terms of the 5*2449e17fSsherrym * Common Development and Distribution License (the "License"). 6*2449e17fSsherrym * You may not use this file except in compliance with the License. 7*2449e17fSsherrym * 8*2449e17fSsherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2449e17fSsherrym * or http://www.opensolaris.org/os/licensing. 10*2449e17fSsherrym * See the License for the specific language governing permissions 11*2449e17fSsherrym * and limitations under the License. 12*2449e17fSsherrym * 13*2449e17fSsherrym * When distributing Covered Code, include this CDDL HEADER in each 14*2449e17fSsherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2449e17fSsherrym * If applicable, add the following below this CDDL HEADER, with the 16*2449e17fSsherrym * fields enclosed by brackets "[]" replaced with your own identifying 17*2449e17fSsherrym * information: Portions Copyright [yyyy] [name of copyright owner] 18*2449e17fSsherrym * 19*2449e17fSsherrym * CDDL HEADER END 20*2449e17fSsherrym */ 21*2449e17fSsherrym 22*2449e17fSsherrym /* 23*2449e17fSsherrym * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*2449e17fSsherrym * Use is subject to license terms. 25*2449e17fSsherrym */ 26*2449e17fSsherrym 27*2449e17fSsherrym #pragma ident "%Z%%M% %I% %E% SMI" 28*2449e17fSsherrym 29*2449e17fSsherrym #include <sys/asm_linkage.h> 30*2449e17fSsherrym #include <sys/bootconf.h> 31*2449e17fSsherrym #include <sys/cpuvar.h> 32*2449e17fSsherrym #include <sys/cmn_err.h> 33*2449e17fSsherrym #include <sys/controlregs.h> 34*2449e17fSsherrym #include <sys/debug.h> 35*2449e17fSsherrym #include <sys/kobj.h> 36*2449e17fSsherrym #include <sys/kobj_impl.h> 37*2449e17fSsherrym #include <sys/machsystm.h> 38*2449e17fSsherrym #include <sys/param.h> 39*2449e17fSsherrym #include <sys/machparam.h> 40*2449e17fSsherrym #include <sys/promif.h> 41*2449e17fSsherrym #include <sys/sysmacros.h> 42*2449e17fSsherrym #include <sys/systm.h> 43*2449e17fSsherrym #include <sys/types.h> 44*2449e17fSsherrym #include <sys/thread.h> 45*2449e17fSsherrym #include <sys/ucode.h> 46*2449e17fSsherrym #include <sys/x86_archext.h> 47*2449e17fSsherrym #include <sys/x_call.h> 48*2449e17fSsherrym 49*2449e17fSsherrym /* 50*2449e17fSsherrym * Microcode specific information per core 51*2449e17fSsherrym */ 52*2449e17fSsherrym struct cpu_ucode_info { 53*2449e17fSsherrym uint32_t cui_platid; /* platform id */ 54*2449e17fSsherrym uint32_t cui_rev; /* microcode revision */ 55*2449e17fSsherrym }; 56*2449e17fSsherrym 57*2449e17fSsherrym /* 58*2449e17fSsherrym * Data structure used for xcall 59*2449e17fSsherrym */ 60*2449e17fSsherrym struct ucode_update_struct { 61*2449e17fSsherrym uint32_t sig; /* signature */ 62*2449e17fSsherrym struct cpu_ucode_info info; /* ucode info */ 63*2449e17fSsherrym uint32_t expected_rev; 64*2449e17fSsherrym uint32_t new_rev; 65*2449e17fSsherrym uint8_t *ucodep; /* pointer to ucode body */ 66*2449e17fSsherrym }; 67*2449e17fSsherrym 68*2449e17fSsherrym /* 69*2449e17fSsherrym * mcpu_ucode_info for the boot CPU. Statically allocated. 70*2449e17fSsherrym */ 71*2449e17fSsherrym static struct cpu_ucode_info cpu_ucode_info0; 72*2449e17fSsherrym 73*2449e17fSsherrym static ucode_file_t ucodefile = { 0 }; 74*2449e17fSsherrym 75*2449e17fSsherrym static int ucode_capable(cpu_t *); 76*2449e17fSsherrym static void ucode_file_reset(ucode_file_t *, processorid_t); 77*2449e17fSsherrym static ucode_errno_t ucode_match(int, struct cpu_ucode_info *, 78*2449e17fSsherrym ucode_header_t *, ucode_ext_table_t *); 79*2449e17fSsherrym static ucode_errno_t ucode_locate(cpu_t *, struct cpu_ucode_info *, 80*2449e17fSsherrym ucode_file_t *); 81*2449e17fSsherrym static void ucode_update_intel(uint8_t *, struct cpu_ucode_info *); 82*2449e17fSsherrym static void ucode_read_rev(struct cpu_ucode_info *); 83*2449e17fSsherrym 84*2449e17fSsherrym static const char ucode_failure_fmt[] = 85*2449e17fSsherrym "cpu%d: failed to update microcode code from version 0x%x to 0x%x\n"; 86*2449e17fSsherrym static const char ucode_success_fmt[] = 87*2449e17fSsherrym "?cpu%d: microcode code has been updated from version 0x%x to 0x%x\n"; 88*2449e17fSsherrym 89*2449e17fSsherrym /* 90*2449e17fSsherrym * Force flag. If set, the first microcode binary that matches 91*2449e17fSsherrym * signature and platform id will be used for microcode update, 92*2449e17fSsherrym * regardless of version. Should only be used for debugging. 93*2449e17fSsherrym */ 94*2449e17fSsherrym int ucode_force_update = 0; 95*2449e17fSsherrym 96*2449e17fSsherrym /* 97*2449e17fSsherrym * Allocate space for mcpu_ucode_info in the machcpu structure 98*2449e17fSsherrym * for all non-boot CPUs. 99*2449e17fSsherrym */ 100*2449e17fSsherrym void 101*2449e17fSsherrym ucode_alloc_space(cpu_t *cp) 102*2449e17fSsherrym { 103*2449e17fSsherrym ASSERT(cp->cpu_id != 0); 104*2449e17fSsherrym cp->cpu_m.mcpu_ucode_info = 105*2449e17fSsherrym kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP); 106*2449e17fSsherrym } 107*2449e17fSsherrym 108*2449e17fSsherrym void 109*2449e17fSsherrym ucode_free_space(cpu_t *cp) 110*2449e17fSsherrym { 111*2449e17fSsherrym ASSERT(cp->cpu_id != 0); 112*2449e17fSsherrym kmem_free(cp->cpu_m.mcpu_ucode_info, 113*2449e17fSsherrym sizeof (*cp->cpu_m.mcpu_ucode_info)); 114*2449e17fSsherrym } 115*2449e17fSsherrym 116*2449e17fSsherrym /* 117*2449e17fSsherrym * Called when we are done with microcode update on all processors to free up 118*2449e17fSsherrym * space allocated for the microcode file. 119*2449e17fSsherrym */ 120*2449e17fSsherrym void 121*2449e17fSsherrym ucode_free() 122*2449e17fSsherrym { 123*2449e17fSsherrym ucode_file_reset(&ucodefile, -1); 124*2449e17fSsherrym } 125*2449e17fSsherrym 126*2449e17fSsherrym /* 127*2449e17fSsherrym * Check whether or not a processor is capable of microcode operations 128*2449e17fSsherrym * Returns 1 if it is capable, 0 if not. 129*2449e17fSsherrym */ 130*2449e17fSsherrym static int 131*2449e17fSsherrym ucode_capable(cpu_t *cp) 132*2449e17fSsherrym { 133*2449e17fSsherrym /* 134*2449e17fSsherrym * At this point we only support microcode update for Intel 135*2449e17fSsherrym * processors family 6 and above. 136*2449e17fSsherrym * 137*2449e17fSsherrym * We also assume that we don't support a mix of Intel and 138*2449e17fSsherrym * AMD processors in the same box. 139*2449e17fSsherrym */ 140*2449e17fSsherrym if (cpuid_getvendor(cp) != X86_VENDOR_Intel || 141*2449e17fSsherrym cpuid_getfamily(cp) < 6) 142*2449e17fSsherrym return (0); 143*2449e17fSsherrym else 144*2449e17fSsherrym return (1); 145*2449e17fSsherrym } 146*2449e17fSsherrym 147*2449e17fSsherrym /* 148*2449e17fSsherrym * Called when it is no longer necessary to keep the microcode around, 149*2449e17fSsherrym * or when the cached microcode doesn't match the CPU being processed. 150*2449e17fSsherrym */ 151*2449e17fSsherrym static void 152*2449e17fSsherrym ucode_file_reset(ucode_file_t *ucodefp, processorid_t id) 153*2449e17fSsherrym { 154*2449e17fSsherrym int total_size, body_size; 155*2449e17fSsherrym 156*2449e17fSsherrym if (ucodefp == NULL) 157*2449e17fSsherrym return; 158*2449e17fSsherrym 159*2449e17fSsherrym total_size = UCODE_TOTAL_SIZE(ucodefp->uf_header.uh_total_size); 160*2449e17fSsherrym body_size = UCODE_BODY_SIZE(ucodefp->uf_header.uh_body_size); 161*2449e17fSsherrym if (ucodefp->uf_body) { 162*2449e17fSsherrym /* 163*2449e17fSsherrym * Space for the boot CPU is allocated with BOP_ALLOC() 164*2449e17fSsherrym * and does not require a free. 165*2449e17fSsherrym */ 166*2449e17fSsherrym if (id != 0) 167*2449e17fSsherrym kmem_free(ucodefp->uf_body, body_size); 168*2449e17fSsherrym ucodefp->uf_body = NULL; 169*2449e17fSsherrym } 170*2449e17fSsherrym 171*2449e17fSsherrym if (ucodefp->uf_ext_table) { 172*2449e17fSsherrym int size = total_size - body_size - UCODE_HEADER_SIZE; 173*2449e17fSsherrym /* 174*2449e17fSsherrym * Space for the boot CPU is allocated with BOP_ALLOC() 175*2449e17fSsherrym * and does not require a free. 176*2449e17fSsherrym */ 177*2449e17fSsherrym if (id != 0) 178*2449e17fSsherrym kmem_free(ucodefp->uf_ext_table, size); 179*2449e17fSsherrym ucodefp->uf_ext_table = NULL; 180*2449e17fSsherrym } 181*2449e17fSsherrym 182*2449e17fSsherrym bzero(&ucodefp->uf_header, UCODE_HEADER_SIZE); 183*2449e17fSsherrym } 184*2449e17fSsherrym 185*2449e17fSsherrym /* 186*2449e17fSsherrym * Populate the ucode file structure from microcode file corresponding to 187*2449e17fSsherrym * this CPU, if exists. 188*2449e17fSsherrym * 189*2449e17fSsherrym * Return EM_OK on success, corresponding error code on failure. 190*2449e17fSsherrym */ 191*2449e17fSsherrym static ucode_errno_t 192*2449e17fSsherrym ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp) 193*2449e17fSsherrym { 194*2449e17fSsherrym char name[MAXPATHLEN]; 195*2449e17fSsherrym intptr_t fd; 196*2449e17fSsherrym int count; 197*2449e17fSsherrym int header_size = UCODE_HEADER_SIZE; 198*2449e17fSsherrym int cpi_sig = cpuid_getsig(cp); 199*2449e17fSsherrym ucode_errno_t rc = EM_OK; 200*2449e17fSsherrym 201*2449e17fSsherrym /* 202*2449e17fSsherrym * If the microcode matches the CPU we are processing, use it. 203*2449e17fSsherrym */ 204*2449e17fSsherrym if (ucode_match(cpi_sig, uinfop, &ucodefp->uf_header, 205*2449e17fSsherrym ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) { 206*2449e17fSsherrym return (EM_OK); 207*2449e17fSsherrym } 208*2449e17fSsherrym 209*2449e17fSsherrym /* 210*2449e17fSsherrym * Look for microcode file with the right name. 211*2449e17fSsherrym */ 212*2449e17fSsherrym (void) snprintf(name, MAXPATHLEN, "/%s/%s/%08X-%02X", 213*2449e17fSsherrym UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), cpi_sig, 214*2449e17fSsherrym uinfop->cui_platid); 215*2449e17fSsherrym if ((fd = kobj_open(name)) == -1) { 216*2449e17fSsherrym return (EM_OPENFILE); 217*2449e17fSsherrym } 218*2449e17fSsherrym 219*2449e17fSsherrym /* 220*2449e17fSsherrym * We found a microcode file for the CPU we are processing, 221*2449e17fSsherrym * reset the microcode data structure and read in the new 222*2449e17fSsherrym * file. 223*2449e17fSsherrym */ 224*2449e17fSsherrym ucode_file_reset(ucodefp, cp->cpu_id); 225*2449e17fSsherrym 226*2449e17fSsherrym count = kobj_read(fd, (char *)&ucodefp->uf_header, header_size, 0); 227*2449e17fSsherrym 228*2449e17fSsherrym switch (count) { 229*2449e17fSsherrym case UCODE_HEADER_SIZE: { 230*2449e17fSsherrym 231*2449e17fSsherrym ucode_header_t *uhp = &ucodefp->uf_header; 232*2449e17fSsherrym uint32_t offset = header_size; 233*2449e17fSsherrym int total_size, body_size, ext_size; 234*2449e17fSsherrym uint32_t sum = 0; 235*2449e17fSsherrym 236*2449e17fSsherrym /* 237*2449e17fSsherrym * Make sure that the header contains valid fields. 238*2449e17fSsherrym */ 239*2449e17fSsherrym if ((rc = ucode_header_validate(uhp)) == EM_OK) { 240*2449e17fSsherrym total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); 241*2449e17fSsherrym body_size = UCODE_BODY_SIZE(uhp->uh_body_size); 242*2449e17fSsherrym if (cp->cpu_id != 0) { 243*2449e17fSsherrym if ((ucodefp->uf_body = kmem_zalloc(body_size, 244*2449e17fSsherrym KM_NOSLEEP)) == NULL) { 245*2449e17fSsherrym rc = EM_NOMEM; 246*2449e17fSsherrym break; 247*2449e17fSsherrym } 248*2449e17fSsherrym } else { 249*2449e17fSsherrym /* 250*2449e17fSsherrym * BOP_ALLOC() failure results in panic so we 251*2449e17fSsherrym * don't have to check for NULL return. 252*2449e17fSsherrym */ 253*2449e17fSsherrym ucodefp->uf_body = 254*2449e17fSsherrym (uint8_t *)BOP_ALLOC(bootops, 255*2449e17fSsherrym NULL, body_size, MMU_PAGESIZE); 256*2449e17fSsherrym } 257*2449e17fSsherrym 258*2449e17fSsherrym if (kobj_read(fd, (char *)ucodefp->uf_body, 259*2449e17fSsherrym body_size, offset) != body_size) 260*2449e17fSsherrym rc = EM_FILESIZE; 261*2449e17fSsherrym } 262*2449e17fSsherrym 263*2449e17fSsherrym if (rc) 264*2449e17fSsherrym break; 265*2449e17fSsherrym 266*2449e17fSsherrym sum = ucode_checksum(0, header_size, 267*2449e17fSsherrym (uint8_t *)&ucodefp->uf_header); 268*2449e17fSsherrym if (ucode_checksum(sum, body_size, ucodefp->uf_body)) { 269*2449e17fSsherrym rc = EM_CHECKSUM; 270*2449e17fSsherrym break; 271*2449e17fSsherrym } 272*2449e17fSsherrym 273*2449e17fSsherrym /* 274*2449e17fSsherrym * Check to see if there is extended signature table. 275*2449e17fSsherrym */ 276*2449e17fSsherrym offset = body_size + header_size; 277*2449e17fSsherrym ext_size = total_size - offset; 278*2449e17fSsherrym 279*2449e17fSsherrym if (ext_size <= 0) 280*2449e17fSsherrym break; 281*2449e17fSsherrym 282*2449e17fSsherrym if (cp->cpu_id != 0) { 283*2449e17fSsherrym if ((ucodefp->uf_ext_table = kmem_zalloc(ext_size, 284*2449e17fSsherrym KM_NOSLEEP)) == NULL) { 285*2449e17fSsherrym rc = EM_NOMEM; 286*2449e17fSsherrym break; 287*2449e17fSsherrym } 288*2449e17fSsherrym } else { 289*2449e17fSsherrym /* 290*2449e17fSsherrym * BOP_ALLOC() failure results in panic so we 291*2449e17fSsherrym * don't have to check for NULL return. 292*2449e17fSsherrym */ 293*2449e17fSsherrym ucodefp->uf_ext_table = 294*2449e17fSsherrym (ucode_ext_table_t *)BOP_ALLOC(bootops, NULL, 295*2449e17fSsherrym ext_size, MMU_PAGESIZE); 296*2449e17fSsherrym } 297*2449e17fSsherrym 298*2449e17fSsherrym if (kobj_read(fd, (char *)ucodefp->uf_ext_table, 299*2449e17fSsherrym ext_size, offset) != ext_size) { 300*2449e17fSsherrym rc = EM_FILESIZE; 301*2449e17fSsherrym } else if (ucode_checksum(0, ext_size, 302*2449e17fSsherrym (uint8_t *)(ucodefp->uf_ext_table))) { 303*2449e17fSsherrym rc = EM_CHECKSUM; 304*2449e17fSsherrym } else { 305*2449e17fSsherrym int i; 306*2449e17fSsherrym 307*2449e17fSsherrym ext_size -= UCODE_EXT_TABLE_SIZE; 308*2449e17fSsherrym for (i = 0; i < ucodefp->uf_ext_table->uet_count; 309*2449e17fSsherrym i++) { 310*2449e17fSsherrym if (ucode_checksum(0, UCODE_EXT_SIG_SIZE, 311*2449e17fSsherrym (uint8_t *)(&(ucodefp->uf_ext_table-> 312*2449e17fSsherrym uet_ext_sig[i])))) { 313*2449e17fSsherrym rc = EM_CHECKSUM; 314*2449e17fSsherrym break; 315*2449e17fSsherrym } 316*2449e17fSsherrym } 317*2449e17fSsherrym } 318*2449e17fSsherrym break; 319*2449e17fSsherrym } 320*2449e17fSsherrym 321*2449e17fSsherrym default: 322*2449e17fSsherrym rc = EM_FILESIZE; 323*2449e17fSsherrym break; 324*2449e17fSsherrym } 325*2449e17fSsherrym 326*2449e17fSsherrym kobj_close(fd); 327*2449e17fSsherrym 328*2449e17fSsherrym if (rc != EM_OK) 329*2449e17fSsherrym return (rc); 330*2449e17fSsherrym 331*2449e17fSsherrym rc = ucode_match(cpi_sig, uinfop, &ucodefp->uf_header, 332*2449e17fSsherrym ucodefp->uf_ext_table); 333*2449e17fSsherrym 334*2449e17fSsherrym return (rc); 335*2449e17fSsherrym } 336*2449e17fSsherrym 337*2449e17fSsherrym 338*2449e17fSsherrym /* 339*2449e17fSsherrym * Returns 1 if the microcode is for this processor; 0 otherwise. 340*2449e17fSsherrym */ 341*2449e17fSsherrym static ucode_errno_t 342*2449e17fSsherrym ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop, 343*2449e17fSsherrym ucode_header_t *uhp, ucode_ext_table_t *uetp) 344*2449e17fSsherrym { 345*2449e17fSsherrym ASSERT(uhp); 346*2449e17fSsherrym 347*2449e17fSsherrym if (UCODE_MATCH(cpi_sig, uhp->uh_signature, 348*2449e17fSsherrym uinfop->cui_platid, uhp->uh_proc_flags)) { 349*2449e17fSsherrym 350*2449e17fSsherrym if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update) 351*2449e17fSsherrym return (EM_HIGHERREV); 352*2449e17fSsherrym 353*2449e17fSsherrym return (EM_OK); 354*2449e17fSsherrym } 355*2449e17fSsherrym 356*2449e17fSsherrym if (uetp != NULL) { 357*2449e17fSsherrym int i; 358*2449e17fSsherrym 359*2449e17fSsherrym for (i = 0; i < uetp->uet_count; i++) { 360*2449e17fSsherrym ucode_ext_sig_t *uesp; 361*2449e17fSsherrym 362*2449e17fSsherrym uesp = &uetp->uet_ext_sig[i]; 363*2449e17fSsherrym 364*2449e17fSsherrym if (UCODE_MATCH(cpi_sig, uesp->ues_signature, 365*2449e17fSsherrym uinfop->cui_platid, uesp->ues_proc_flags)) { 366*2449e17fSsherrym 367*2449e17fSsherrym if (uinfop->cui_rev >= uhp->uh_rev && 368*2449e17fSsherrym !ucode_force_update) 369*2449e17fSsherrym return (EM_HIGHERREV); 370*2449e17fSsherrym 371*2449e17fSsherrym return (EM_OK); 372*2449e17fSsherrym } 373*2449e17fSsherrym } 374*2449e17fSsherrym } 375*2449e17fSsherrym 376*2449e17fSsherrym return (EM_NOMATCH); 377*2449e17fSsherrym } 378*2449e17fSsherrym 379*2449e17fSsherrym /*ARGSUSED*/ 380*2449e17fSsherrym static int 381*2449e17fSsherrym ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3) 382*2449e17fSsherrym { 383*2449e17fSsherrym struct ucode_update_struct *uusp = (struct ucode_update_struct *)arg1; 384*2449e17fSsherrym struct cpu_ucode_info *uinfop = CPU->cpu_m.mcpu_ucode_info; 385*2449e17fSsherrym 386*2449e17fSsherrym ASSERT(uusp->ucodep); 387*2449e17fSsherrym 388*2449e17fSsherrym /* 389*2449e17fSsherrym * Check one more time to see if it is really necessary to update 390*2449e17fSsherrym * microcode just in case this is a hyperthreaded processor where 391*2449e17fSsherrym * the threads share the same microcode. 392*2449e17fSsherrym */ 393*2449e17fSsherrym if (!ucode_force_update) { 394*2449e17fSsherrym ucode_read_rev(uinfop); 395*2449e17fSsherrym uusp->new_rev = uinfop->cui_rev; 396*2449e17fSsherrym if (uinfop->cui_rev >= uusp->expected_rev) 397*2449e17fSsherrym return (0); 398*2449e17fSsherrym } 399*2449e17fSsherrym 400*2449e17fSsherrym wrmsr(MSR_INTC_UCODE_WRITE, 401*2449e17fSsherrym (uint64_t)(intptr_t)(uusp->ucodep)); 402*2449e17fSsherrym ucode_read_rev(uinfop); 403*2449e17fSsherrym uusp->new_rev = uinfop->cui_rev; 404*2449e17fSsherrym 405*2449e17fSsherrym return (0); 406*2449e17fSsherrym } 407*2449e17fSsherrym 408*2449e17fSsherrym 409*2449e17fSsherrym static void 410*2449e17fSsherrym ucode_update_intel(uint8_t *ucode_body, struct cpu_ucode_info *uinfop) 411*2449e17fSsherrym { 412*2449e17fSsherrym kpreempt_disable(); 413*2449e17fSsherrym wrmsr(MSR_INTC_UCODE_WRITE, (uint64_t)(uintptr_t)ucode_body); 414*2449e17fSsherrym ucode_read_rev(uinfop); 415*2449e17fSsherrym kpreempt_enable(); 416*2449e17fSsherrym } 417*2449e17fSsherrym 418*2449e17fSsherrym static void 419*2449e17fSsherrym ucode_read_rev(struct cpu_ucode_info *uinfop) 420*2449e17fSsherrym { 421*2449e17fSsherrym struct cpuid_regs crs; 422*2449e17fSsherrym 423*2449e17fSsherrym /* 424*2449e17fSsherrym * The Intel 64 and IA-32 Architecture Software Developer's Manual 425*2449e17fSsherrym * recommends that MSR_INTC_UCODE_REV be loaded with 0 first, then 426*2449e17fSsherrym * execute cpuid to guarantee the correct reading of this register. 427*2449e17fSsherrym */ 428*2449e17fSsherrym wrmsr(MSR_INTC_UCODE_REV, 0); 429*2449e17fSsherrym (void) __cpuid_insn(&crs); 430*2449e17fSsherrym uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT); 431*2449e17fSsherrym } 432*2449e17fSsherrym 433*2449e17fSsherrym /* 434*2449e17fSsherrym * Entry point to microcode update from the ucode_drv driver. 435*2449e17fSsherrym * 436*2449e17fSsherrym * Returns EM_OK on success, corresponding error code on failure. 437*2449e17fSsherrym */ 438*2449e17fSsherrym ucode_errno_t 439*2449e17fSsherrym ucode_update(uint8_t *ucodep, int size) 440*2449e17fSsherrym { 441*2449e17fSsherrym uint32_t header_size = UCODE_HEADER_SIZE; 442*2449e17fSsherrym int remaining; 443*2449e17fSsherrym int found = 0; 444*2449e17fSsherrym processorid_t id; 445*2449e17fSsherrym struct ucode_update_struct cached = { 0 }; 446*2449e17fSsherrym struct ucode_update_struct *cachedp = NULL; 447*2449e17fSsherrym ucode_errno_t rc = EM_OK; 448*2449e17fSsherrym ucode_errno_t search_rc = EM_NOMATCH; /* search result */ 449*2449e17fSsherrym cpuset_t cpuset; 450*2449e17fSsherrym 451*2449e17fSsherrym ASSERT(ucodep); 452*2449e17fSsherrym 453*2449e17fSsherrym CPUSET_ZERO(cpuset); 454*2449e17fSsherrym 455*2449e17fSsherrym if (!ucode_capable(CPU)) 456*2449e17fSsherrym return (EM_NOTSUP); 457*2449e17fSsherrym 458*2449e17fSsherrym mutex_enter(&cpu_lock); 459*2449e17fSsherrym 460*2449e17fSsherrym for (id = 0; id < max_ncpus; id++) { 461*2449e17fSsherrym cpu_t *cpu; 462*2449e17fSsherrym struct ucode_update_struct uus = { 0 }; 463*2449e17fSsherrym struct ucode_update_struct *uusp = &uus; 464*2449e17fSsherrym 465*2449e17fSsherrym /* 466*2449e17fSsherrym * If there is no such CPU or it is not xcall ready, skip it. 467*2449e17fSsherrym */ 468*2449e17fSsherrym if ((cpu = cpu_get(id)) == NULL || 469*2449e17fSsherrym !(cpu->cpu_flags & CPU_READY)) 470*2449e17fSsherrym continue; 471*2449e17fSsherrym 472*2449e17fSsherrym uusp->sig = cpuid_getsig(cpu); 473*2449e17fSsherrym bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info, 474*2449e17fSsherrym sizeof (uusp->info)); 475*2449e17fSsherrym 476*2449e17fSsherrym /* 477*2449e17fSsherrym * If the current CPU has the same signature and platform 478*2449e17fSsherrym * id as the previous one we processed, reuse the information. 479*2449e17fSsherrym */ 480*2449e17fSsherrym if (cachedp && cachedp->sig == cpuid_getsig(cpu) && 481*2449e17fSsherrym cachedp->info.cui_platid == uusp->info.cui_platid) { 482*2449e17fSsherrym uusp->ucodep = cachedp->ucodep; 483*2449e17fSsherrym uusp->expected_rev = cachedp->expected_rev; 484*2449e17fSsherrym /* 485*2449e17fSsherrym * Intuitively we should check here to see whether the 486*2449e17fSsherrym * running microcode rev is >= the expected rev, and 487*2449e17fSsherrym * quit if it is. But we choose to proceed with the 488*2449e17fSsherrym * xcall regardless of the running version so that 489*2449e17fSsherrym * the other threads in an HT processor can update 490*2449e17fSsherrym * the cpu_ucode_info structure in machcpu. 491*2449e17fSsherrym */ 492*2449e17fSsherrym } else { 493*2449e17fSsherrym /* 494*2449e17fSsherrym * Go through the whole buffer in case there are 495*2449e17fSsherrym * multiple versions of matching microcode for this 496*2449e17fSsherrym * processor. 497*2449e17fSsherrym */ 498*2449e17fSsherrym for (remaining = size; remaining > 0; ) { 499*2449e17fSsherrym int total_size, body_size, ext_size; 500*2449e17fSsherrym uint8_t *curbuf = &ucodep[size - remaining]; 501*2449e17fSsherrym ucode_header_t *uhp = (ucode_header_t *)curbuf; 502*2449e17fSsherrym ucode_ext_table_t *uetp = NULL; 503*2449e17fSsherrym ucode_errno_t tmprc; 504*2449e17fSsherrym 505*2449e17fSsherrym total_size = 506*2449e17fSsherrym UCODE_TOTAL_SIZE(uhp->uh_total_size); 507*2449e17fSsherrym body_size = UCODE_BODY_SIZE(uhp->uh_body_size); 508*2449e17fSsherrym ext_size = total_size - 509*2449e17fSsherrym (header_size + body_size); 510*2449e17fSsherrym 511*2449e17fSsherrym if (ext_size > 0) 512*2449e17fSsherrym uetp = (ucode_ext_table_t *) 513*2449e17fSsherrym &curbuf[header_size + body_size]; 514*2449e17fSsherrym 515*2449e17fSsherrym tmprc = ucode_match(uusp->sig, &uusp->info, 516*2449e17fSsherrym uhp, uetp); 517*2449e17fSsherrym 518*2449e17fSsherrym /* 519*2449e17fSsherrym * Since we are searching through a big file 520*2449e17fSsherrym * containing microcode for pretty much all the 521*2449e17fSsherrym * processors, we are bound to get EM_NOMATCH 522*2449e17fSsherrym * at one point. However, if we return 523*2449e17fSsherrym * EM_NOMATCH to users, it will really confuse 524*2449e17fSsherrym * them. Therefore, if we ever find a match of 525*2449e17fSsherrym * a lower rev, we will set return code to 526*2449e17fSsherrym * EM_HIGHERREV. 527*2449e17fSsherrym */ 528*2449e17fSsherrym if (tmprc == EM_HIGHERREV) 529*2449e17fSsherrym search_rc = EM_HIGHERREV; 530*2449e17fSsherrym 531*2449e17fSsherrym if (tmprc == EM_OK && 532*2449e17fSsherrym uusp->expected_rev < uhp->uh_rev) { 533*2449e17fSsherrym uusp->ucodep = &curbuf[header_size]; 534*2449e17fSsherrym uusp->expected_rev = uhp->uh_rev; 535*2449e17fSsherrym bcopy(uusp, &cached, sizeof (cached)); 536*2449e17fSsherrym cachedp = &cached; 537*2449e17fSsherrym found = 1; 538*2449e17fSsherrym } 539*2449e17fSsherrym 540*2449e17fSsherrym remaining -= total_size; 541*2449e17fSsherrym } 542*2449e17fSsherrym } 543*2449e17fSsherrym 544*2449e17fSsherrym /* Nothing to do */ 545*2449e17fSsherrym if (uusp->ucodep == NULL) 546*2449e17fSsherrym continue; 547*2449e17fSsherrym 548*2449e17fSsherrym CPUSET_ADD(cpuset, id); 549*2449e17fSsherrym kpreempt_disable(); 550*2449e17fSsherrym xc_sync((xc_arg_t)uusp, 0, 0, X_CALL_HIPRI, cpuset, 551*2449e17fSsherrym ucode_write); 552*2449e17fSsherrym kpreempt_enable(); 553*2449e17fSsherrym CPUSET_DEL(cpuset, id); 554*2449e17fSsherrym 555*2449e17fSsherrym if (uusp->expected_rev == uusp->new_rev) { 556*2449e17fSsherrym cmn_err(CE_CONT, ucode_success_fmt, 557*2449e17fSsherrym id, uusp->info.cui_rev, uusp->expected_rev); 558*2449e17fSsherrym } else { 559*2449e17fSsherrym cmn_err(CE_WARN, ucode_failure_fmt, 560*2449e17fSsherrym id, uusp->info.cui_rev, uusp->expected_rev); 561*2449e17fSsherrym rc = EM_UPDATE; 562*2449e17fSsherrym } 563*2449e17fSsherrym } 564*2449e17fSsherrym 565*2449e17fSsherrym mutex_exit(&cpu_lock); 566*2449e17fSsherrym 567*2449e17fSsherrym if (!found) 568*2449e17fSsherrym rc = search_rc; 569*2449e17fSsherrym 570*2449e17fSsherrym return (rc); 571*2449e17fSsherrym } 572*2449e17fSsherrym 573*2449e17fSsherrym /* 574*2449e17fSsherrym * Initialize mcpu_ucode_info, and perform microcode update if necessary. 575*2449e17fSsherrym * This is the entry point from boot path where pointer to CPU structure 576*2449e17fSsherrym * is available. 577*2449e17fSsherrym * 578*2449e17fSsherrym * cpuid_info must be initialized before ucode_check can be called. 579*2449e17fSsherrym */ 580*2449e17fSsherrym void 581*2449e17fSsherrym ucode_check(cpu_t *cp) 582*2449e17fSsherrym { 583*2449e17fSsherrym #ifdef __xpv 584*2449e17fSsherrym { 585*2449e17fSsherrym This needs to be ported. Only do ucode update from dom0. In 586*2449e17fSsherrym addition figure out how to bind to physical CPUs when doing 587*2449e17fSsherrym it in dom0. 588*2449e17fSsherrym } 589*2449e17fSsherrym #endif /* __xpv */ 590*2449e17fSsherrym 591*2449e17fSsherrym struct cpu_ucode_info *uinfop; 592*2449e17fSsherrym ucode_errno_t rc = EM_OK; 593*2449e17fSsherrym 594*2449e17fSsherrym ASSERT(cp); 595*2449e17fSsherrym if (cp->cpu_id == 0) 596*2449e17fSsherrym cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0; 597*2449e17fSsherrym 598*2449e17fSsherrym uinfop = cp->cpu_m.mcpu_ucode_info; 599*2449e17fSsherrym ASSERT(uinfop); 600*2449e17fSsherrym 601*2449e17fSsherrym if (!ucode_capable(cp)) 602*2449e17fSsherrym return; 603*2449e17fSsherrym 604*2449e17fSsherrym /* 605*2449e17fSsherrym * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon 606*2449e17fSsherrym * (Family 6, model 5 and above) and all processors after. 607*2449e17fSsherrym */ 608*2449e17fSsherrym if ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6)) { 609*2449e17fSsherrym uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >> 610*2449e17fSsherrym INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK); 611*2449e17fSsherrym } 612*2449e17fSsherrym 613*2449e17fSsherrym ucode_read_rev(uinfop); 614*2449e17fSsherrym 615*2449e17fSsherrym /* 616*2449e17fSsherrym * Check to see if we need ucode update 617*2449e17fSsherrym */ 618*2449e17fSsherrym if ((rc = ucode_locate(cp, uinfop, &ucodefile)) == EM_OK) { 619*2449e17fSsherrym ucode_update_intel(ucodefile.uf_body, uinfop); 620*2449e17fSsherrym 621*2449e17fSsherrym if (uinfop->cui_rev != ucodefile.uf_header.uh_rev) 622*2449e17fSsherrym cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id, 623*2449e17fSsherrym uinfop->cui_rev, ucodefile.uf_header.uh_rev); 624*2449e17fSsherrym } 625*2449e17fSsherrym 626*2449e17fSsherrym /* 627*2449e17fSsherrym * If we fail to find a match for any reason, free the file structure 628*2449e17fSsherrym * just in case we have read in a partial file. 629*2449e17fSsherrym * 630*2449e17fSsherrym * Since the scratch memory for holding the microcode for the boot CPU 631*2449e17fSsherrym * came from BOP_ALLOC, we will reset the data structure as if we 632*2449e17fSsherrym * never did the allocation so we don't have to keep track of this 633*2449e17fSsherrym * special chunk of memory. We free the memory used for the rest 634*2449e17fSsherrym * of the CPUs in start_other_cpus(). 635*2449e17fSsherrym */ 636*2449e17fSsherrym if (rc != EM_OK || cp->cpu_id == 0) 637*2449e17fSsherrym ucode_file_reset(&ucodefile, cp->cpu_id); 638*2449e17fSsherrym } 639*2449e17fSsherrym 640*2449e17fSsherrym /* 641*2449e17fSsherrym * Returns microcode revision from the machcpu structure. 642*2449e17fSsherrym */ 643*2449e17fSsherrym ucode_errno_t 644*2449e17fSsherrym ucode_get_rev(uint32_t *revp) 645*2449e17fSsherrym { 646*2449e17fSsherrym int i; 647*2449e17fSsherrym 648*2449e17fSsherrym ASSERT(revp); 649*2449e17fSsherrym 650*2449e17fSsherrym if (!ucode_capable(CPU)) 651*2449e17fSsherrym return (EM_NOTSUP); 652*2449e17fSsherrym 653*2449e17fSsherrym mutex_enter(&cpu_lock); 654*2449e17fSsherrym for (i = 0; i < max_ncpus; i++) { 655*2449e17fSsherrym cpu_t *cpu; 656*2449e17fSsherrym 657*2449e17fSsherrym if ((cpu = cpu_get(i)) == NULL) 658*2449e17fSsherrym continue; 659*2449e17fSsherrym 660*2449e17fSsherrym revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev; 661*2449e17fSsherrym } 662*2449e17fSsherrym mutex_exit(&cpu_lock); 663*2449e17fSsherrym 664*2449e17fSsherrym return (EM_OK); 665*2449e17fSsherrym } 666