1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 The FreeBSD Foundation 5 * 6 * This software was developed by Mark Johnston under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/cpuset.h> 33 #include <sys/kernel.h> 34 #include <sys/linker.h> 35 #include <sys/malloc.h> 36 #include <sys/pcpu.h> 37 #include <sys/smp.h> 38 #include <sys/stdarg.h> 39 #include <sys/systm.h> 40 41 #include <machine/atomic.h> 42 #include <machine/cpufunc.h> 43 #include <machine/md_var.h> 44 #include <x86/specialreg.h> 45 #include <x86/ucode.h> 46 #include <x86/x86_smp.h> 47 48 #include <vm/vm.h> 49 #include <vm/pmap.h> 50 #include <vm/vm_extern.h> 51 #include <vm/vm_kern.h> 52 #include <vm/vm_param.h> 53 54 static const void *ucode_intel_match(const uint8_t *data, size_t *len); 55 static int ucode_intel_verify(const struct ucode_intel_header *hdr, 56 size_t resid); 57 58 static const void *ucode_amd_match(const uint8_t *data, size_t *len); 59 60 static struct ucode_ops { 61 const char *vendor; 62 int (*load)(const void *, ucode_load_how how, uint64_t *, uint64_t *); 63 const void *(*match)(const uint8_t *, size_t *); 64 } loaders[] = { 65 { 66 .vendor = INTEL_VENDOR_ID, 67 .load = ucode_intel_load, 68 .match = ucode_intel_match, 69 }, 70 { 71 .vendor = AMD_VENDOR_ID, 72 .load = ucode_amd_load, 73 .match = ucode_amd_match, 74 }, 75 }; 76 77 /* Selected microcode update data. */ 78 static const void *early_ucode_data; 79 static const void *ucode_data; 80 static struct ucode_ops *ucode_loader; 81 82 /* Variables used for reporting success or failure. */ 83 static enum { 84 NO_ERROR, 85 NO_MATCH, 86 VERIFICATION_FAILED, 87 LOAD_FAILED, 88 } ucode_error = NO_ERROR; 89 static uint64_t ucode_nrev, ucode_orev; 90 91 static void 92 log_msg(void *arg __unused) 93 { 94 95 if (ucode_nrev != 0) { 96 printf("CPU microcode: updated from %#jx to %#jx\n", 97 (uintmax_t)ucode_orev, (uintmax_t)ucode_nrev); 98 return; 99 } 100 101 switch (ucode_error) { 102 case NO_MATCH: 103 printf("CPU microcode: no matching update found\n"); 104 break; 105 case VERIFICATION_FAILED: 106 printf("CPU microcode: microcode verification failed\n"); 107 break; 108 case LOAD_FAILED: 109 printf("CPU microcode load failed. BIOS update advised\n"); 110 break; 111 default: 112 break; 113 } 114 } 115 SYSINIT(ucode_log, SI_SUB_CPU, SI_ORDER_FIRST, log_msg, NULL); 116 117 int 118 ucode_intel_load(const void *data, ucode_load_how how, uint64_t *nrevp, 119 uint64_t *orevp) 120 { 121 uint64_t nrev, orev; 122 uint32_t cpuid[4]; 123 124 orev = rdmsr(MSR_BIOS_SIGN) >> 32; 125 126 /* 127 * Perform update. Flush caches first to work around seemingly 128 * undocumented errata applying to some Broadwell CPUs. 129 */ 130 wbinvd(); 131 switch (how) { 132 case SAFE: 133 wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); 134 break; 135 case EARLY: 136 #ifdef __amd64__ 137 wrmsr_early_safe_start(); 138 if (wrmsr_early_safe(MSR_BIOS_UPDT_TRIG, 139 (uint64_t)(uintptr_t)data) != 0) 140 ucode_error = LOAD_FAILED; 141 wrmsr_early_safe_end(); 142 break; 143 #endif 144 case UNSAFE: 145 wrmsr(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); 146 break; 147 } 148 wrmsr(MSR_BIOS_SIGN, 0); 149 150 /* 151 * Serialize instruction flow. 152 */ 153 do_cpuid(0, cpuid); 154 155 /* 156 * Verify that the microcode revision changed. 157 */ 158 nrev = rdmsr(MSR_BIOS_SIGN) >> 32; 159 if (nrevp != NULL) 160 *nrevp = nrev; 161 if (orevp != NULL) 162 *orevp = orev; 163 if (nrev <= orev) 164 return (EEXIST); 165 return (0); 166 } 167 168 static int 169 ucode_intel_verify(const struct ucode_intel_header *hdr, size_t resid) 170 { 171 const uint32_t *data; 172 uint32_t cksum, size; 173 int i; 174 175 if (resid < sizeof(struct ucode_intel_header)) 176 return (1); 177 size = hdr->total_size; 178 if (size == 0) 179 size = UCODE_INTEL_DEFAULT_DATA_SIZE + 180 sizeof(struct ucode_intel_header); 181 182 if (hdr->header_version != 1) 183 return (1); 184 if (size % 16 != 0) 185 return (1); 186 if (resid < size) 187 return (1); 188 189 cksum = 0; 190 data = (const uint32_t *)hdr; 191 for (i = 0; i < size / sizeof(uint32_t); i++) 192 cksum += data[i]; 193 if (cksum != 0) 194 return (1); 195 return (0); 196 } 197 198 static const void * 199 ucode_intel_match(const uint8_t *data, size_t *len) 200 { 201 const struct ucode_intel_header *hdr; 202 const struct ucode_intel_extsig_table *table; 203 const struct ucode_intel_extsig *entry; 204 uint64_t platformid; 205 size_t resid; 206 uint32_t data_size, flags, regs[4], sig, total_size; 207 208 do_cpuid(1, regs); 209 sig = regs[0]; 210 211 platformid = rdmsr(MSR_IA32_PLATFORM_ID); 212 flags = 1 << ((platformid >> 50) & 0x7); 213 214 for (resid = *len; resid > 0; data += total_size, resid -= total_size) { 215 hdr = (const struct ucode_intel_header *)data; 216 if (ucode_intel_verify(hdr, resid) != 0) { 217 ucode_error = VERIFICATION_FAILED; 218 break; 219 } 220 221 data_size = hdr->data_size; 222 total_size = hdr->total_size; 223 if (data_size == 0) 224 data_size = UCODE_INTEL_DEFAULT_DATA_SIZE; 225 if (total_size == 0) 226 total_size = UCODE_INTEL_DEFAULT_DATA_SIZE + 227 sizeof(struct ucode_intel_header); 228 229 if (total_size > data_size + sizeof(struct ucode_intel_header)) 230 table = (const struct ucode_intel_extsig_table *) 231 ((const uint8_t *)(hdr + 1) + data_size); 232 else 233 table = NULL; 234 235 if (hdr->processor_signature == sig && 236 (hdr->processor_flags & flags) != 0) { 237 *len = data_size; 238 return (hdr + 1); 239 } 240 if (table != NULL) { 241 size_t extsize; 242 243 extsize = total_size - 244 (data_size + sizeof(struct ucode_intel_header)); 245 if (extsize < sizeof(struct ucode_intel_extsig_table)) { 246 ucode_error = VERIFICATION_FAILED; 247 break; 248 } 249 extsize -= sizeof(struct ucode_intel_extsig_table); 250 for (uint32_t i = 0; i < table->signature_count; i++) { 251 if (extsize < sizeof(struct ucode_intel_extsig)) { 252 ucode_error = VERIFICATION_FAILED; 253 goto out; 254 } 255 extsize -= sizeof(struct ucode_intel_extsig); 256 257 entry = &table->entries[i]; 258 if (entry->processor_signature == sig && 259 (entry->processor_flags & flags) != 0) { 260 *len = data_size; 261 return (hdr + 1); 262 } 263 } 264 } 265 } 266 out: 267 return (NULL); 268 } 269 270 int 271 ucode_amd_load(const void *data, ucode_load_how how, uint64_t *nrevp, 272 uint64_t *orevp) 273 { 274 uint64_t nrev, orev; 275 uint32_t cpuid[4]; 276 277 orev = rdmsr(MSR_BIOS_SIGN); 278 279 switch (how) { 280 case SAFE: 281 wrmsr_safe(MSR_K8_UCODE_UPDATE, (uint64_t)(uintptr_t)data); 282 break; 283 case EARLY: 284 #ifdef __amd64__ 285 wrmsr_early_safe_start(); 286 if (wrmsr_early_safe(MSR_K8_UCODE_UPDATE, 287 (uint64_t)(uintptr_t)data) != 0) 288 ucode_error = LOAD_FAILED; 289 wrmsr_early_safe_end(); 290 break; 291 #endif 292 case UNSAFE: 293 wrmsr(MSR_K8_UCODE_UPDATE, (uint64_t)(uintptr_t)data); 294 break; 295 } 296 297 /* 298 * Serialize instruction flow. 299 */ 300 do_cpuid(0, cpuid); 301 302 /* 303 * Verify that the microcode revision changed. 304 */ 305 nrev = rdmsr(MSR_BIOS_SIGN); 306 if (nrevp != NULL) 307 *nrevp = nrev; 308 if (orevp != NULL) 309 *orevp = orev; 310 if (nrev <= orev) 311 return (EEXIST); 312 return (0); 313 314 } 315 316 static const void * 317 ucode_amd_match(const uint8_t *data, size_t *len) 318 { 319 uint32_t signature, revision; 320 uint32_t regs[4]; 321 322 do_cpuid(1, regs); 323 signature = regs[0]; 324 revision = rdmsr(MSR_BIOS_SIGN); 325 326 return (ucode_amd_find("loader blob", signature, &revision, data, *len, 327 len)); 328 } 329 330 /* 331 * Release any memory backing unused microcode blobs back to the system. 332 * We copy the selected update and free the entire microcode file. 333 */ 334 static void 335 ucode_release(void *arg __unused) 336 { 337 char *name, *type; 338 caddr_t file; 339 int release; 340 341 if (early_ucode_data == NULL) 342 return; 343 release = 1; 344 TUNABLE_INT_FETCH("debug.ucode.release", &release); 345 if (!release) 346 return; 347 348 restart: 349 file = 0; 350 for (;;) { 351 file = preload_search_next_name(file); 352 if (file == 0) 353 break; 354 type = (char *)preload_search_info(file, MODINFO_TYPE); 355 if (type == NULL || strcmp(type, "cpu_microcode") != 0) 356 continue; 357 358 name = preload_search_info(file, MODINFO_NAME); 359 preload_delete_name(name); 360 goto restart; 361 } 362 } 363 SYSINIT(ucode_release, SI_SUB_SMP + 1, SI_ORDER_ANY, ucode_release, NULL); 364 365 void 366 ucode_load_ap(int cpu) 367 { 368 #ifdef SMP 369 KASSERT(cpu_info[cpu_apic_ids[cpu]].cpu_present, 370 ("cpu %d not present", cpu)); 371 372 if (cpu_info[cpu_apic_ids[cpu]].cpu_hyperthread) 373 return; 374 #endif 375 376 if (ucode_data != NULL && ucode_error != LOAD_FAILED) 377 (void)ucode_loader->load(ucode_data, UNSAFE, NULL, NULL); 378 } 379 380 static const void * 381 map_ucode(const void *match, uintptr_t free, size_t len) 382 { 383 #ifdef __i386__ 384 uintptr_t va; 385 386 for (va = free; va < free + len; va += PAGE_SIZE) 387 pmap_kenter(va, (vm_paddr_t)va); 388 memcpy_early(free, match, len); 389 return ((const void *)free); 390 #else 391 (void)len; 392 return (match); 393 #endif 394 } 395 396 static void 397 unmap_ucode(uintptr_t free, size_t len) 398 { 399 #ifdef __i386__ 400 uintptr_t va; 401 402 for (va = free; va < free + len; va += PAGE_SIZE) 403 pmap_kremove(va); 404 #else 405 (void)free; 406 (void)len; 407 #endif 408 } 409 410 /* 411 * Search for an applicable microcode update, and load it. APs will load the 412 * selected update once they come online. 413 * 414 * "free" is the address of the next free physical page. If a microcode update 415 * is selected, it will be copied to this region prior to loading in order to 416 * satisfy alignment requirements. 417 */ 418 size_t 419 ucode_load_bsp(uintptr_t free) 420 { 421 union { 422 uint32_t regs[4]; 423 char vendor[13]; 424 } cpuid; 425 const uint8_t *fileaddr, *match; 426 const uint8_t *addr; 427 char *type; 428 uint64_t nrev, orev; 429 caddr_t file; 430 size_t i, len; 431 int error; 432 433 KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free)); 434 435 do_cpuid(0, cpuid.regs); 436 cpuid.regs[0] = cpuid.regs[1]; 437 cpuid.regs[1] = cpuid.regs[3]; 438 cpuid.vendor[12] = '\0'; 439 for (i = 0; i < nitems(loaders); i++) 440 if (strcmp(cpuid.vendor, loaders[i].vendor) == 0) { 441 ucode_loader = &loaders[i]; 442 break; 443 } 444 if (ucode_loader == NULL) 445 return (0); 446 447 file = 0; 448 fileaddr = match = NULL; 449 for (;;) { 450 file = preload_search_next_name(file); 451 if (file == 0) 452 break; 453 type = (char *)preload_search_info(file, MODINFO_TYPE); 454 if (type == NULL || strcmp(type, "cpu_microcode") != 0) 455 continue; 456 457 fileaddr = preload_fetch_addr(file); 458 len = preload_fetch_size(file); 459 match = ucode_loader->match(fileaddr, &len); 460 if (match != NULL) { 461 addr = map_ucode(match, free, len); 462 error = ucode_loader->load(addr, EARLY, &nrev, &orev); 463 if (error == 0) { 464 ucode_data = early_ucode_data = addr; 465 ucode_nrev = nrev; 466 ucode_orev = orev; 467 return (len); 468 } 469 unmap_ucode(free, len); 470 } 471 } 472 if (fileaddr != NULL && ucode_error == NO_ERROR) 473 ucode_error = NO_MATCH; 474 return (0); 475 } 476 477 /* 478 * Reload microcode following an ACPI resume. 479 */ 480 void 481 ucode_reload(void) 482 { 483 484 ucode_load_ap(PCPU_GET(cpuid)); 485 } 486 487 /* 488 * Replace an existing microcode update. 489 */ 490 void * 491 ucode_update(void *newdata) 492 { 493 494 newdata = (void *)atomic_swap_ptr((void *)&ucode_data, 495 (uintptr_t)newdata); 496 if (newdata == early_ucode_data) 497 newdata = NULL; 498 return (newdata); 499 } 500