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
log_msg(void * arg __unused)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
ucode_intel_load(const void * data,ucode_load_how how,uint64_t * nrevp,uint64_t * orevp)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
ucode_intel_verify(const struct ucode_intel_header * hdr,size_t resid)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 *
ucode_intel_match(const uint8_t * data,size_t * len)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
ucode_amd_load(const void * data,ucode_load_how how,uint64_t * nrevp,uint64_t * orevp)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 *
ucode_amd_match(const uint8_t * data,size_t * len)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
ucode_release(void * arg __unused)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
ucode_load_ap(int cpu)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 *
map_ucode(const void * match,uintptr_t free,size_t len)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
unmap_ucode(uintptr_t free,size_t len)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
ucode_load_bsp(uintptr_t free)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
ucode_reload(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 *
ucode_update(void * newdata)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