2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 The FreeBSD Foundation
6 * This software was developed by Mark Johnston under sponsorship from
7 * the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
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>
41 #include <sys/systm.h>
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>
52 #include <vm/vm_extern.h>
53 #include <vm/vm_kern.h>
54 #include <vm/vm_param.h>
56 static void *ucode_intel_match(uint8_t *data, size_t *len);
57 static int ucode_intel_verify(struct ucode_intel_header *hdr,
60 static struct ucode_ops {
62 int (*load)(void *, bool, uint64_t *, uint64_t *);
63 void *(*match)(uint8_t *, size_t *);
66 .vendor = INTEL_VENDOR_ID,
67 .load = ucode_intel_load,
68 .match = ucode_intel_match,
72 /* Selected microcode update data. */
73 static void *early_ucode_data;
74 static void *ucode_data;
75 static struct ucode_ops *ucode_loader;
77 /* Variables used for reporting success or failure. */
82 } ucode_error = NO_ERROR;
83 static uint64_t ucode_nrev, ucode_orev;
86 log_msg(void *arg __unused)
89 if (ucode_nrev != 0) {
90 printf("CPU microcode: updated from %#jx to %#jx\n",
91 (uintmax_t)ucode_orev, (uintmax_t)ucode_nrev);
95 switch (ucode_error) {
97 printf("CPU microcode: no matching update found\n");
99 case VERIFICATION_FAILED:
100 printf("CPU microcode: microcode verification failed\n");
106 SYSINIT(ucode_log, SI_SUB_CPU, SI_ORDER_FIRST, log_msg, NULL);
109 ucode_intel_load(void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp)
114 orev = rdmsr(MSR_BIOS_SIGN) >> 32;
117 * Perform update. Flush caches first to work around seemingly
118 * undocumented errata applying to some Broadwell CPUs.
122 wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data);
124 wrmsr(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data);
125 wrmsr(MSR_BIOS_SIGN, 0);
128 * Serialize instruction flow.
133 * Verify that the microcode revision changed.
135 nrev = rdmsr(MSR_BIOS_SIGN) >> 32;
146 ucode_intel_verify(struct ucode_intel_header *hdr, size_t resid)
148 uint32_t cksum, *data, size;
151 if (resid < sizeof(struct ucode_intel_header))
153 size = hdr->total_size;
155 size = UCODE_INTEL_DEFAULT_DATA_SIZE +
156 sizeof(struct ucode_intel_header);
158 if (hdr->header_version != 1)
166 data = (uint32_t *)hdr;
167 for (i = 0; i < size / sizeof(uint32_t); i++)
175 ucode_intel_match(uint8_t *data, size_t *len)
177 struct ucode_intel_header *hdr;
178 struct ucode_intel_extsig_table *table;
179 struct ucode_intel_extsig *entry;
182 uint32_t data_size, flags, regs[4], sig, total_size;
188 platformid = rdmsr(MSR_IA32_PLATFORM_ID);
189 flags = 1 << ((platformid >> 50) & 0x7);
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;
198 data_size = hdr->data_size;
199 total_size = hdr->total_size;
201 data_size = UCODE_INTEL_DEFAULT_DATA_SIZE;
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);
211 if (hdr->processor_signature == sig) {
212 if ((hdr->processor_flags & flags) != 0) {
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) {
231 * Release any memory backing unused microcode blobs back to the system.
232 * We copy the selected update and free the entire microcode file.
235 ucode_release(void *arg __unused)
241 if (early_ucode_data == NULL)
244 TUNABLE_INT_FETCH("debug.ucode.release", &release);
251 file = preload_search_next_name(file);
254 type = (char *)preload_search_info(file, MODINFO_TYPE);
255 if (type == NULL || strcmp(type, "cpu_microcode") != 0)
258 name = preload_search_info(file, MODINFO_NAME);
259 preload_delete_name(name);
263 SYSINIT(ucode_release, SI_SUB_SMP + 1, SI_ORDER_ANY, ucode_release, NULL);
266 ucode_load_ap(int cpu)
269 KASSERT(cpu_info[cpu_apic_ids[cpu]].cpu_present,
270 ("cpu %d not present", cpu));
272 if (cpu_info[cpu_apic_ids[cpu]].cpu_hyperthread)
276 if (ucode_data != NULL)
277 (void)ucode_loader->load(ucode_data, false, NULL, NULL);
281 map_ucode(uintptr_t free, size_t len)
286 for (va = free; va < free + len; va += PAGE_SIZE)
287 pmap_kenter(va, (vm_paddr_t)va);
291 return ((void *)free);
295 unmap_ucode(uintptr_t free, size_t len)
300 for (va = free; va < free + len; va += PAGE_SIZE)
309 * Search for an applicable microcode update, and load it. APs will load the
310 * selected update once they come online.
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.
317 ucode_load_bsp(uintptr_t free)
323 uint8_t *addr, *fileaddr, *match;
330 KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free));
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];
341 if (ucode_loader == NULL)
345 fileaddr = match = NULL;
347 file = preload_search_next_name(file);
350 type = (char *)preload_search_info(file, MODINFO_TYPE);
351 if (type == NULL || strcmp(type, "cpu_microcode") != 0)
354 fileaddr = preload_fetch_addr(file);
355 len = preload_fetch_size(file);
356 match = ucode_loader->match(fileaddr, &len);
358 addr = map_ucode(free, len);
359 /* We can't use memcpy() before ifunc resolution. */
360 memcpy_early(addr, match, len);
363 error = ucode_loader->load(match, false, &nrev, &orev);
365 ucode_data = early_ucode_data = match;
370 unmap_ucode(free, len);
373 if (fileaddr != NULL && ucode_error == NO_ERROR)
374 ucode_error = NO_MATCH;
379 * Reload microcode following an ACPI resume.
385 ucode_load_ap(PCPU_GET(cpuid));
389 * Replace an existing microcode update.
392 ucode_update(void *newdata)
395 newdata = (void *)atomic_swap_ptr((void *)&ucode_data,
397 if (newdata == early_ucode_data)