1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 27 * Copyright (c) 2018, Joyent, Inc. 28 * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. 29 * Copyright 2023 Oxide Computer Company 30 */ 31 32 #include <sys/bootconf.h> 33 #include <sys/cmn_err.h> 34 #include <sys/controlregs.h> 35 #include <sys/utsname.h> 36 #include <sys/debug.h> 37 #include <sys/kobj.h> 38 #include <sys/kobj_impl.h> 39 #include <sys/ontrap.h> 40 #include <sys/systeminfo.h> 41 #include <sys/systm.h> 42 #include <sys/ucode.h> 43 #include <sys/x86_archext.h> 44 #include <sys/x_call.h> 45 46 /* 47 * mcpu_ucode_info for the boot CPU. Statically allocated. 48 */ 49 static struct cpu_ucode_info cpu_ucode_info0; 50 static const ucode_source_t *ucode; 51 static char *ucodepath; 52 static kmutex_t ucode_lock; 53 static bool ucode_cleanup_done = false; 54 55 static const char ucode_failure_fmt[] = 56 "cpu%d: failed to update microcode from version 0x%x to 0x%x"; 57 static const char ucode_success_fmt[] = 58 "?cpu%d: microcode has been updated from version 0x%x to 0x%x\n"; 59 60 SET_DECLARE(ucode_source_set, ucode_source_t); 61 62 /* 63 * Force flag. If set, the first microcode binary that matches 64 * signature and platform id will be used for microcode update, 65 * regardless of version. Should only be used for debugging. 66 */ 67 int ucode_force_update = 0; 68 69 void 70 ucode_init(void) 71 { 72 mutex_init(&ucode_lock, NULL, MUTEX_DEFAULT, NULL); 73 } 74 75 /* 76 * Allocate space for mcpu_ucode_info in the machcpu structure 77 * for all non-boot CPUs. 78 */ 79 void 80 ucode_alloc_space(cpu_t *cp) 81 { 82 ASSERT(cp->cpu_id != 0); 83 ASSERT(cp->cpu_m.mcpu_ucode_info == NULL); 84 cp->cpu_m.mcpu_ucode_info = 85 kmem_zalloc(sizeof (*cp->cpu_m.mcpu_ucode_info), KM_SLEEP); 86 } 87 88 void 89 ucode_free_space(cpu_t *cp) 90 { 91 ASSERT(cp->cpu_m.mcpu_ucode_info != NULL); 92 ASSERT(cp->cpu_m.mcpu_ucode_info != &cpu_ucode_info0); 93 kmem_free(cp->cpu_m.mcpu_ucode_info, 94 sizeof (*cp->cpu_m.mcpu_ucode_info)); 95 cp->cpu_m.mcpu_ucode_info = NULL; 96 } 97 98 const char * 99 ucode_path(void) 100 { 101 ASSERT(ucodepath != NULL); 102 return (ucodepath); 103 } 104 105 /* 106 * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is 107 * allocated with BOP_ALLOC() and does not require a free. 108 */ 109 void * 110 ucode_zalloc(processorid_t id, size_t size) 111 { 112 if (id != 0) 113 return (kmem_zalloc(size, KM_NOSLEEP)); 114 115 /* BOP_ALLOC() failure results in panic */ 116 return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE)); 117 } 118 119 void 120 ucode_free(processorid_t id, void *buf, size_t size) 121 { 122 if (id != 0 && buf != NULL) 123 kmem_free(buf, size); 124 } 125 126 /* 127 * Called to free up space allocated for the microcode file. This is called 128 * from start_other_cpus() after an update attempt has been performed on all 129 * CPUs. 130 */ 131 void 132 ucode_cleanup(void) 133 { 134 mutex_enter(&ucode_lock); 135 if (ucode != NULL) 136 ucode->us_file_reset(-1); 137 ucode_cleanup_done = true; 138 mutex_exit(&ucode_lock); 139 140 /* 141 * We purposefully do not free 'ucodepath' here so that it persists for 142 * any future callers to ucode_check(), such as could occur on systems 143 * that support DR. 144 */ 145 } 146 147 static int 148 ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3) 149 { 150 ucode_update_t *uusp = (ucode_update_t *)arg1; 151 cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info; 152 on_trap_data_t otd; 153 154 ASSERT(ucode != NULL); 155 ASSERT(uusp->ucodep != NULL); 156 157 /* 158 * Check one more time to see if it is really necessary to update 159 * microcode just in case this is a hyperthreaded processor where 160 * the threads share the same microcode. 161 */ 162 if (!ucode_force_update) { 163 ucode->us_read_rev(uinfop); 164 uusp->new_rev = uinfop->cui_rev; 165 if (uinfop->cui_rev >= uusp->expected_rev) 166 return (0); 167 } 168 169 if (!on_trap(&otd, OT_DATA_ACCESS)) { 170 if (ucode->us_invalidate) { 171 /* 172 * On some platforms a cache invalidation is required 173 * for the ucode update to be successful due to the 174 * parts of the processor that the microcode is 175 * updating. 176 */ 177 invalidate_cache(); 178 } 179 wrmsr(ucode->us_write_msr, (uintptr_t)uusp->ucodep); 180 } 181 182 no_trap(); 183 ucode->us_read_rev(uinfop); 184 uusp->new_rev = uinfop->cui_rev; 185 186 return (0); 187 } 188 189 /* 190 * Entry points to microcode update from the 'ucode' driver. 191 */ 192 193 ucode_errno_t 194 ucode_validate(uint8_t *ucodep, int size) 195 { 196 if (ucode == NULL) 197 return (EM_NOTSUP); 198 return (ucode->us_validate(ucodep, size)); 199 } 200 201 ucode_errno_t 202 ucode_update(uint8_t *ucodep, int size) 203 { 204 int found = 0; 205 ucode_update_t cached = { 0 }; 206 ucode_update_t *cachedp = NULL; 207 ucode_errno_t rc = EM_OK; 208 ucode_errno_t search_rc = EM_NOMATCH; /* search result */ 209 cpuset_t cpuset; 210 211 ASSERT(ucode != 0); 212 ASSERT(ucodep != 0); 213 CPUSET_ZERO(cpuset); 214 215 if (!ucode->us_capable(CPU)) 216 return (EM_NOTSUP); 217 218 mutex_enter(&cpu_lock); 219 220 for (processorid_t id = 0; id < max_ncpus; id++) { 221 cpu_t *cpu; 222 ucode_update_t uus = { 0 }; 223 ucode_update_t *uusp = &uus; 224 225 /* 226 * If there is no such CPU or it is not xcall ready, skip it. 227 */ 228 if ((cpu = cpu_get(id)) == NULL || 229 !(cpu->cpu_flags & CPU_READY)) { 230 continue; 231 } 232 233 uusp->sig = cpuid_getsig(cpu); 234 bcopy(cpu->cpu_m.mcpu_ucode_info, &uusp->info, 235 sizeof (uusp->info)); 236 237 /* 238 * If the current CPU has the same signature and platform 239 * id as the previous one we processed, reuse the information. 240 */ 241 if (cachedp && cachedp->sig == cpuid_getsig(cpu) && 242 cachedp->info.cui_platid == uusp->info.cui_platid) { 243 uusp->ucodep = cachedp->ucodep; 244 uusp->expected_rev = cachedp->expected_rev; 245 /* 246 * Intuitively we should check here to see whether the 247 * running microcode rev is >= the expected rev, and 248 * quit if it is. But we choose to proceed with the 249 * xcall regardless of the running version so that 250 * the other threads in an HT processor can update 251 * the cpu_ucode_info structure in machcpu. 252 */ 253 } else if ((search_rc = ucode->us_extract(uusp, ucodep, size)) 254 == EM_OK) { 255 bcopy(uusp, &cached, sizeof (cached)); 256 cachedp = &cached; 257 found = 1; 258 } 259 260 /* Nothing to do */ 261 if (uusp->ucodep == NULL) 262 continue; 263 264 CPUSET_ADD(cpuset, id); 265 kpreempt_disable(); 266 xc_sync((xc_arg_t)uusp, 0, 0, CPUSET2BV(cpuset), ucode_write); 267 kpreempt_enable(); 268 CPUSET_DEL(cpuset, id); 269 270 if (uusp->new_rev != 0 && uusp->info.cui_rev == uusp->new_rev && 271 !ucode_force_update) { 272 rc = EM_HIGHERREV; 273 } else if ((uusp->new_rev == 0) || (uusp->expected_rev != 0 && 274 uusp->expected_rev != uusp->new_rev)) { 275 cmn_err(CE_WARN, ucode_failure_fmt, 276 id, uusp->info.cui_rev, uusp->expected_rev); 277 rc = EM_UPDATE; 278 } else { 279 cmn_err(CE_CONT, ucode_success_fmt, 280 id, uusp->info.cui_rev, uusp->new_rev); 281 } 282 } 283 284 mutex_exit(&cpu_lock); 285 286 if (!found) { 287 rc = search_rc; 288 } else if (rc == EM_OK) { 289 cpuid_post_ucodeadm(); 290 } 291 292 return (rc); 293 } 294 295 /* 296 * Entry point to microcode update from mlsetup() and mp_startup() 297 * Initialize mcpu_ucode_info, and perform microcode update if necessary. 298 * cpuid_info must be initialized before ucode_check can be called. 299 */ 300 void 301 ucode_check(cpu_t *cp) 302 { 303 cpu_ucode_info_t *uinfop; 304 ucode_errno_t rc = EM_OK; 305 bool bsp = (cp->cpu_id == 0); 306 307 ASSERT(cp != NULL); 308 309 mutex_enter(&ucode_lock); 310 311 if (bsp) { 312 /* Space statically allocated for BSP; ensure pointer is set */ 313 if (cp->cpu_m.mcpu_ucode_info == NULL) 314 cp->cpu_m.mcpu_ucode_info = &cpu_ucode_info0; 315 316 /* Set up function pointers if not already done */ 317 if (ucode == NULL) { 318 ucode_source_t **src; 319 320 SET_FOREACH(src, ucode_source_set) { 321 if ((*src)->us_select(cp)) { 322 ucode = *src; 323 break; 324 } 325 } 326 327 if (ucode == NULL) 328 goto out; 329 330 #ifdef DEBUG 331 cmn_err(CE_CONT, "?ucode: selected %s\n", 332 ucode->us_name); 333 #endif 334 } 335 } 336 337 if (ucode == NULL) 338 goto out; 339 340 if (ucodepath == NULL) { 341 size_t sz; 342 char *plat; 343 344 if (bsp) { 345 const char *prop = "impl-arch-name"; 346 int len; 347 348 len = BOP_GETPROPLEN(bootops, prop); 349 350 if (len <= 0) { 351 cmn_err(CE_WARN, 352 "ucode: could not find %s property", prop); 353 goto out; 354 } 355 356 /* 357 * On the BSP, this memory is allocated via BOP_ALLOC() 358 * -- which panics on failure -- and does not need to 359 * be explicitly freed. 360 */ 361 plat = ucode_zalloc(cp->cpu_id, len + 1); 362 (void) BOP_GETPROP(bootops, prop, plat); 363 } else { 364 /* 365 * from common/conf/param.c, already filled in by 366 * setup_ddi() by this point. 367 */ 368 plat = platform; 369 } 370 if (plat[0] == '\0') { 371 /* 372 * If we can't determine the architecture name, 373 * we cannot find microcode files for it. 374 * Return without setting 'ucode'. 375 */ 376 cmn_err(CE_WARN, "ucode: could not determine arch"); 377 goto out; 378 } 379 380 sz = snprintf(NULL, 0, "/platform/%s/ucode", plat) + 1; 381 /* 382 * Note that on the boot CPU, this allocation will be satisfied 383 * via BOP_ALLOC() and the returned address will not be valid 384 * once we come back into this function for the remaining CPUs. 385 * To deal with this, we throw the memory away at the end of 386 * this function if we are the BSP. The next CPU through here 387 * will re-create it using kmem and then it persists. 388 */ 389 ucodepath = ucode_zalloc(cp->cpu_id, sz); 390 if (ucodepath == NULL) { 391 cmn_err(CE_WARN, 392 "ucode: could not allocate memory for path"); 393 goto out; 394 } 395 (void) snprintf(ucodepath, sz, "/platform/%s/ucode", plat); 396 } 397 398 uinfop = cp->cpu_m.mcpu_ucode_info; 399 ASSERT(uinfop != NULL); 400 401 if (!ucode->us_capable(cp)) 402 goto out; 403 404 ucode->us_read_rev(uinfop); 405 406 /* 407 * Check to see if we need ucode update 408 */ 409 if ((rc = ucode->us_locate(cp, uinfop)) == EM_OK) { 410 uint32_t old_rev, new_rev; 411 412 old_rev = uinfop->cui_rev; 413 new_rev = ucode->us_load(uinfop); 414 415 if (uinfop->cui_rev != new_rev) { 416 cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id, 417 old_rev, new_rev); 418 } else { 419 cmn_err(CE_CONT, ucode_success_fmt, cp->cpu_id, 420 old_rev, new_rev); 421 } 422 } 423 424 /* 425 * If we fail to find a match for any reason, free the file structure 426 * just in case we have read in a partial file. 427 * 428 * Since the scratch memory for holding the microcode for the boot CPU 429 * came from BOP_ALLOC, we will reset the data structure as if we 430 * never did the allocation so we don't have to keep track of this 431 * special chunk of memory. We free the memory used for the rest 432 * of the CPUs in start_other_cpus(). 433 * 434 * In case we end up here after ucode_cleanup() has been called, such 435 * as could occur with CPU hotplug, we also clear the memory and reset 436 * the data structure as nothing else will call ucode_cleanup() and we 437 * don't need to cache the data as we do during boot when starting the 438 * APs. 439 */ 440 if (rc != EM_OK || bsp || ucode_cleanup_done) 441 ucode->us_file_reset(cp->cpu_id); 442 443 out: 444 /* 445 * If this is the boot CPU, discard the memory that came from BOP_ALLOC 446 * and was used to build the ucode path. 447 */ 448 if (bsp) 449 ucodepath = NULL; 450 451 mutex_exit(&ucode_lock); 452 } 453 454 /* 455 * Returns microcode revision from the machcpu structure. 456 */ 457 ucode_errno_t 458 ucode_get_rev(uint32_t *revp) 459 { 460 int i; 461 462 ASSERT(ucode != NULL); 463 ASSERT(revp != NULL); 464 465 if (!ucode->us_capable(CPU)) 466 return (EM_NOTSUP); 467 468 mutex_enter(&cpu_lock); 469 for (i = 0; i < max_ncpus; i++) { 470 cpu_t *cpu; 471 472 if ((cpu = cpu_get(i)) == NULL) 473 continue; 474 475 revp[i] = cpu->cpu_m.mcpu_ucode_info->cui_rev; 476 } 477 mutex_exit(&cpu_lock); 478 479 return (EM_OK); 480 } 481