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