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);
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;
76 static char errbuf[128];
78 static void __printflike(1, 2)
79 log_err(const char *fmt, ...)
84 vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
89 print_err(void *arg __unused)
92 if (errbuf[0] != '\0')
93 printf("microcode load error: %s\n", errbuf);
95 SYSINIT(ucode_print_err, SI_SUB_CPU, SI_ORDER_FIRST, print_err, NULL);
98 ucode_intel_load(void *data, bool unsafe)
103 rev0 = rdmsr(MSR_BIOS_SIGN);
106 * Perform update. Flush caches first to work around seemingly
107 * undocumented errata applying to some Broadwell CPUs.
111 wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data);
113 wrmsr(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data);
114 wrmsr(MSR_BIOS_SIGN, 0);
117 * Serialize instruction flow.
121 rev1 = rdmsr(MSR_BIOS_SIGN);
128 ucode_intel_verify(struct ucode_intel_header *hdr, size_t resid)
130 uint32_t cksum, *data, size;
133 if (resid < sizeof(struct ucode_intel_header)) {
134 log_err("truncated update header");
137 size = hdr->total_size;
139 size = UCODE_INTEL_DEFAULT_DATA_SIZE +
140 sizeof(struct ucode_intel_header);
142 if (hdr->header_version != 1) {
143 log_err("unexpected header version %u", hdr->header_version);
146 if (size % 16 != 0) {
147 log_err("unexpected update size %u", hdr->total_size);
151 log_err("truncated update");
156 data = (uint32_t *)hdr;
157 for (i = 0; i < size / sizeof(uint32_t); i++)
160 log_err("checksum failed");
167 ucode_intel_match(uint8_t *data, size_t *len)
169 struct ucode_intel_header *hdr;
170 struct ucode_intel_extsig_table *table;
171 struct ucode_intel_extsig *entry;
174 uint32_t data_size, flags, regs[4], sig, total_size;
180 platformid = rdmsr(MSR_IA32_PLATFORM_ID);
181 flags = 1 << ((platformid >> 50) & 0x7);
183 for (resid = *len; resid > 0; data += total_size, resid -= total_size) {
184 hdr = (struct ucode_intel_header *)data;
185 if (ucode_intel_verify(hdr, resid) != 0)
188 data_size = hdr->data_size;
189 total_size = hdr->total_size;
191 data_size = UCODE_INTEL_DEFAULT_DATA_SIZE;
193 total_size = UCODE_INTEL_DEFAULT_DATA_SIZE +
194 sizeof(struct ucode_intel_header);
195 if (data_size > total_size + sizeof(struct ucode_intel_header))
196 table = (struct ucode_intel_extsig_table *)
197 ((uint8_t *)(hdr + 1) + data_size);
201 if (hdr->processor_signature == sig) {
202 if ((hdr->processor_flags & flags) != 0) {
206 } else if (table != NULL) {
207 for (i = 0; i < table->signature_count; i++) {
208 entry = &table->entries[i];
209 if (entry->processor_signature == sig &&
210 (entry->processor_flags & flags) != 0) {
221 * Release any memory backing unused microcode blobs back to the system.
222 * We copy the selected update and free the entire microcode file.
225 ucode_release(void *arg __unused)
231 if (early_ucode_data == NULL)
234 TUNABLE_INT_FETCH("debug.ucode.release", &release);
241 file = preload_search_next_name(file);
244 type = (char *)preload_search_info(file, MODINFO_TYPE);
245 if (type == NULL || strcmp(type, "cpu_microcode") != 0)
248 name = preload_search_info(file, MODINFO_NAME);
249 preload_delete_name(name);
253 SYSINIT(ucode_release, SI_SUB_KMEM + 1, SI_ORDER_ANY, ucode_release, NULL);
256 ucode_load_ap(int cpu)
259 KASSERT(cpu_info[cpu_apic_ids[cpu]].cpu_present,
260 ("cpu %d not present", cpu));
262 if (!cpu_info[cpu_apic_ids[cpu]].cpu_hyperthread)
266 if (ucode_data != NULL)
267 (void)ucode_intel_load(ucode_data, false);
271 map_ucode(vm_paddr_t free, size_t len)
275 for (vm_paddr_t pa = free; pa < free + len; pa += PAGE_SIZE)
280 return ((void *)free);
284 unmap_ucode(vm_paddr_t free, size_t len)
288 for (vm_paddr_t pa = free; pa < free + len; pa += PAGE_SIZE)
289 pmap_kremove((vm_offset_t)pa);
297 * Search for an applicable microcode update, and load it. APs will load the
298 * selected update once they come online.
300 * "free" is the address of the next free physical page. If a microcode update
301 * is selected, it will be copied to this region prior to loading in order to
302 * satisfy alignment requirements.
305 ucode_load_bsp(uintptr_t free)
311 struct ucode_ops *loader;
312 uint8_t *addr, *fileaddr, *match;
315 size_t i, len, ucode_len;
317 KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free));
319 do_cpuid(0, cpuid.regs);
320 cpuid.regs[0] = cpuid.regs[1];
321 cpuid.regs[1] = cpuid.regs[3];
322 cpuid.vendor[12] = '\0';
323 for (i = 0, loader = NULL; i < nitems(loaders); i++)
324 if (strcmp(cpuid.vendor, loaders[i].vendor) == 0) {
325 loader = &loaders[i];
332 fileaddr = match = NULL;
335 file = preload_search_next_name(file);
338 type = (char *)preload_search_info(file, MODINFO_TYPE);
339 if (type == NULL || strcmp(type, "cpu_microcode") != 0)
342 fileaddr = preload_fetch_addr(file);
343 len = preload_fetch_size(file);
344 match = loader->match(fileaddr, &len);
346 addr = map_ucode(free, len);
347 /* We can't use memcpy() before ifunc resolution. */
348 for (i = 0; i < len; i++)
352 if (loader->load(match, false) == 0) {
355 early_ucode_data = ucode_data;
358 unmap_ucode(free, len);
361 if (fileaddr != NULL && ucode_data == NULL)
362 log_err("no matching update found");
367 * Reload microcode following an ACPI resume.
373 ucode_load_ap(PCPU_GET(cpuid));
377 * Replace an existing microcode update.
380 ucode_update(void *newdata)
383 newdata = (void *)atomic_swap_ptr((void *)&ucode_data,
385 if (newdata == early_ucode_data)