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/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/cpuset.h> 36 #include <sys/kernel.h> 37 #include <sys/linker.h> 38 #include <sys/malloc.h> 39 #include <sys/pcpu.h> 40 #include <sys/smp.h> 41 #include <sys/systm.h> 42 43 #include <machine/atomic.h> 44 #include <machine/cpufunc.h> 45 #include <x86/specialreg.h> 46 #include <machine/stdarg.h> 47 #include <x86/ucode.h> 48 #include <x86/x86_smp.h> 49 50 #include <vm/vm.h> 51 #include <vm/pmap.h> 52 #include <vm/vm_extern.h> 53 #include <vm/vm_kern.h> 54 #include <vm/vm_param.h> 55 56 static void *ucode_intel_match(uint8_t *data, size_t *len); 57 static int ucode_intel_verify(struct ucode_intel_header *hdr, 58 size_t resid); 59 60 static struct ucode_ops { 61 const char *vendor; 62 int (*load)(void *, bool, uint64_t *, uint64_t *); 63 void *(*match)(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 72 /* Selected microcode update data. */ 73 static void *early_ucode_data; 74 static void *ucode_data; 75 static struct ucode_ops *ucode_loader; 76 77 /* Variables used for reporting success or failure. */ 78 enum { 79 NO_ERROR, 80 NO_MATCH, 81 VERIFICATION_FAILED, 82 } ucode_error = NO_ERROR; 83 static uint64_t ucode_nrev, ucode_orev; 84 85 static void 86 log_msg(void *arg __unused) 87 { 88 89 if (ucode_nrev != 0) { 90 printf("CPU microcode: updated from %#jx to %#jx\n", 91 (uintmax_t)ucode_orev, (uintmax_t)ucode_nrev); 92 return; 93 } 94 95 switch (ucode_error) { 96 case NO_MATCH: 97 printf("CPU microcode: no matching update found\n"); 98 break; 99 case VERIFICATION_FAILED: 100 printf("CPU microcode: microcode verification failed\n"); 101 break; 102 default: 103 break; 104 } 105 } 106 SYSINIT(ucode_log, SI_SUB_CPU, SI_ORDER_FIRST, log_msg, NULL); 107 108 int 109 ucode_intel_load(void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp) 110 { 111 uint64_t nrev, orev; 112 uint32_t cpuid[4]; 113 114 orev = rdmsr(MSR_BIOS_SIGN) >> 32; 115 116 /* 117 * Perform update. Flush caches first to work around seemingly 118 * undocumented errata applying to some Broadwell CPUs. 119 */ 120 wbinvd(); 121 if (unsafe) 122 wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); 123 else 124 wrmsr(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); 125 wrmsr(MSR_BIOS_SIGN, 0); 126 127 /* 128 * Serialize instruction flow. 129 */ 130 do_cpuid(0, cpuid); 131 132 /* 133 * Verify that the microcode revision changed. 134 */ 135 nrev = rdmsr(MSR_BIOS_SIGN) >> 32; 136 if (nrevp != NULL) 137 *nrevp = nrev; 138 if (orevp != NULL) 139 *orevp = orev; 140 if (nrev <= orev) 141 return (EEXIST); 142 return (0); 143 } 144 145 static int 146 ucode_intel_verify(struct ucode_intel_header *hdr, size_t resid) 147 { 148 uint32_t cksum, *data, size; 149 int i; 150 151 if (resid < sizeof(struct ucode_intel_header)) 152 return (1); 153 size = hdr->total_size; 154 if (size == 0) 155 size = UCODE_INTEL_DEFAULT_DATA_SIZE + 156 sizeof(struct ucode_intel_header); 157 158 if (hdr->header_version != 1) 159 return (1); 160 if (size % 16 != 0) 161 return (1); 162 if (resid < size) 163 return (1); 164 165 cksum = 0; 166 data = (uint32_t *)hdr; 167 for (i = 0; i < size / sizeof(uint32_t); i++) 168 cksum += data[i]; 169 if (cksum != 0) 170 return (1); 171 return (0); 172 } 173 174 static void * 175 ucode_intel_match(uint8_t *data, size_t *len) 176 { 177 struct ucode_intel_header *hdr; 178 struct ucode_intel_extsig_table *table; 179 struct ucode_intel_extsig *entry; 180 uint64_t platformid; 181 size_t resid; 182 uint32_t data_size, flags, regs[4], sig, total_size; 183 int i; 184 185 do_cpuid(1, regs); 186 sig = regs[0]; 187 188 platformid = rdmsr(MSR_IA32_PLATFORM_ID); 189 flags = 1 << ((platformid >> 50) & 0x7); 190 191 for (resid = *len; resid > 0; data += total_size, resid -= total_size) { 192 hdr = (struct ucode_intel_header *)data; 193 if (ucode_intel_verify(hdr, resid) != 0) { 194 ucode_error = VERIFICATION_FAILED; 195 break; 196 } 197 198 data_size = hdr->data_size; 199 total_size = hdr->total_size; 200 if (data_size == 0) 201 data_size = UCODE_INTEL_DEFAULT_DATA_SIZE; 202 if (total_size == 0) 203 total_size = UCODE_INTEL_DEFAULT_DATA_SIZE + 204 sizeof(struct ucode_intel_header); 205 if (data_size > total_size + sizeof(struct ucode_intel_header)) 206 table = (struct ucode_intel_extsig_table *) 207 ((uint8_t *)(hdr + 1) + data_size); 208 else 209 table = NULL; 210 211 if (hdr->processor_signature == sig) { 212 if ((hdr->processor_flags & flags) != 0) { 213 *len = data_size; 214 return (hdr + 1); 215 } 216 } else if (table != NULL) { 217 for (i = 0; i < table->signature_count; i++) { 218 entry = &table->entries[i]; 219 if (entry->processor_signature == sig && 220 (entry->processor_flags & flags) != 0) { 221 *len = data_size; 222 return (hdr + 1); 223 } 224 } 225 } 226 } 227 return (NULL); 228 } 229 230 /* 231 * Release any memory backing unused microcode blobs back to the system. 232 * We copy the selected update and free the entire microcode file. 233 */ 234 static void 235 ucode_release(void *arg __unused) 236 { 237 char *name, *type; 238 caddr_t file; 239 int release; 240 241 if (early_ucode_data == NULL) 242 return; 243 release = 1; 244 TUNABLE_INT_FETCH("debug.ucode.release", &release); 245 if (!release) 246 return; 247 248 restart: 249 file = 0; 250 for (;;) { 251 file = preload_search_next_name(file); 252 if (file == 0) 253 break; 254 type = (char *)preload_search_info(file, MODINFO_TYPE); 255 if (type == NULL || strcmp(type, "cpu_microcode") != 0) 256 continue; 257 258 name = preload_search_info(file, MODINFO_NAME); 259 preload_delete_name(name); 260 goto restart; 261 } 262 } 263 SYSINIT(ucode_release, SI_SUB_SMP + 1, SI_ORDER_ANY, ucode_release, NULL); 264 265 void 266 ucode_load_ap(int cpu) 267 { 268 #ifdef SMP 269 KASSERT(cpu_info[cpu_apic_ids[cpu]].cpu_present, 270 ("cpu %d not present", cpu)); 271 272 if (cpu_info[cpu_apic_ids[cpu]].cpu_hyperthread) 273 return; 274 #endif 275 276 if (ucode_data != NULL) 277 (void)ucode_loader->load(ucode_data, false, NULL, NULL); 278 } 279 280 static void * 281 map_ucode(uintptr_t free, size_t len) 282 { 283 #ifdef __i386__ 284 uintptr_t va; 285 286 for (va = free; va < free + len; va += PAGE_SIZE) 287 pmap_kenter(va, (vm_paddr_t)va); 288 #else 289 (void)len; 290 #endif 291 return ((void *)free); 292 } 293 294 static void 295 unmap_ucode(uintptr_t free, size_t len) 296 { 297 #ifdef __i386__ 298 uintptr_t va; 299 300 for (va = free; va < free + len; va += PAGE_SIZE) 301 pmap_kremove(va); 302 #else 303 (void)free; 304 (void)len; 305 #endif 306 } 307 308 /* 309 * Search for an applicable microcode update, and load it. APs will load the 310 * selected update once they come online. 311 * 312 * "free" is the address of the next free physical page. If a microcode update 313 * is selected, it will be copied to this region prior to loading in order to 314 * satisfy alignment requirements. 315 */ 316 size_t 317 ucode_load_bsp(uintptr_t free) 318 { 319 union { 320 uint32_t regs[4]; 321 char vendor[13]; 322 } cpuid; 323 uint8_t *addr, *fileaddr, *match; 324 char *type; 325 uint64_t nrev, orev; 326 caddr_t file; 327 size_t i, len; 328 int error; 329 330 KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free)); 331 332 do_cpuid(0, cpuid.regs); 333 cpuid.regs[0] = cpuid.regs[1]; 334 cpuid.regs[1] = cpuid.regs[3]; 335 cpuid.vendor[12] = '\0'; 336 for (i = 0; i < nitems(loaders); i++) 337 if (strcmp(cpuid.vendor, loaders[i].vendor) == 0) { 338 ucode_loader = &loaders[i]; 339 break; 340 } 341 if (ucode_loader == NULL) 342 return (0); 343 344 file = 0; 345 fileaddr = match = NULL; 346 for (;;) { 347 file = preload_search_next_name(file); 348 if (file == 0) 349 break; 350 type = (char *)preload_search_info(file, MODINFO_TYPE); 351 if (type == NULL || strcmp(type, "cpu_microcode") != 0) 352 continue; 353 354 fileaddr = preload_fetch_addr(file); 355 len = preload_fetch_size(file); 356 match = ucode_loader->match(fileaddr, &len); 357 if (match != NULL) { 358 addr = map_ucode(free, len); 359 /* We can't use memcpy() before ifunc resolution. */ 360 memcpy_early(addr, match, len); 361 match = addr; 362 363 error = ucode_loader->load(match, false, &nrev, &orev); 364 if (error == 0) { 365 ucode_data = early_ucode_data = match; 366 ucode_nrev = nrev; 367 ucode_orev = orev; 368 return (len); 369 } 370 unmap_ucode(free, len); 371 } 372 } 373 if (fileaddr != NULL && ucode_error == NO_ERROR) 374 ucode_error = NO_MATCH; 375 return (0); 376 } 377 378 /* 379 * Reload microcode following an ACPI resume. 380 */ 381 void 382 ucode_reload(void) 383 { 384 385 ucode_load_ap(PCPU_GET(cpuid)); 386 } 387 388 /* 389 * Replace an existing microcode update. 390 */ 391 void * 392 ucode_update(void *newdata) 393 { 394 395 newdata = (void *)atomic_swap_ptr((void *)&ucode_data, 396 (uintptr_t)newdata); 397 if (newdata == early_ucode_data) 398 newdata = NULL; 399 return (newdata); 400 } 401