Date: Thu, 16 May 2019 14:42:17 +0000 (UTC) From: Mark Johnston <markj@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r347700 - in stable/11: stand/defaults sys/amd64/amd64 sys/conf sys/dev/cpuctl sys/i386/i386 sys/x86/acpica sys/x86/include sys/x86/x86 Message-ID: <201905161442.x4GEgHRd013192@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: markj Date: Thu May 16 14:42:16 2019 New Revision: 347700 URL: https://svnweb.freebsd.org/changeset/base/347700 Log: MFC r337715, r337751, r337754, r337758, r337813, r338354, r338687, r339124, r341821: Add support for boot-time Intel microcode loading. Added: stable/11/sys/x86/include/ucode.h - copied, changed from r337715, head/sys/x86/include/ucode.h stable/11/sys/x86/x86/ucode.c - copied, changed from r337715, head/sys/x86/x86/ucode.c Modified: stable/11/stand/defaults/loader.conf.5 stable/11/sys/amd64/amd64/machdep.c stable/11/sys/amd64/amd64/mp_machdep.c stable/11/sys/conf/files.amd64 stable/11/sys/conf/files.i386 stable/11/sys/dev/cpuctl/cpuctl.c stable/11/sys/i386/i386/locore.s stable/11/sys/i386/i386/machdep.c stable/11/sys/i386/i386/mp_machdep.c stable/11/sys/x86/acpica/acpi_wakeup.c stable/11/sys/x86/x86/mp_x86.c Directory Properties: stable/11/ (props changed) Modified: stable/11/stand/defaults/loader.conf.5 ============================================================================== --- stable/11/stand/defaults/loader.conf.5 Thu May 16 14:39:48 2019 (r347699) +++ stable/11/stand/defaults/loader.conf.5 Thu May 16 14:42:16 2019 (r347700) @@ -23,7 +23,7 @@ .\" SUCH DAMAGE. .\" .\" $FreeBSD$ -.Dd February 16, 2019 +.Dd May 16, 2019 .Dt LOADER.CONF 5 .Os .Sh NAME @@ -285,6 +285,29 @@ See the entropy entries in .Pq Dq /boot/entropy The name of the very early boot-time entropy cache file. +.It Va cpu_microcode_load +.Pq Dq NO +If set to +.Dq YES , +the microcode update file specified by +.Va cpu_microcode_name +will be loaded and applied very early during boot. +This provides functionality similar to +.Xr cpucontrol 8 +but ensures that CPU features enabled by microcode updates can be +used by the kernel. +The update will be re-applied automatically when resuming from an +ACPI sleep state. +If the update file contains updates for multiple processor models, +the kernel will search for and extract a matching update. +Currently this setting is supported only on Intel +.Dv i386 +and +.Dv amd64 +processors. +It has no effect on other processor types. +.It Va cpu_microcode_name +A path to a microcode update file. .El .Sh OTHER SETTINGS Other settings that may be used in @@ -315,6 +338,7 @@ machine-specific settings for sites with a common load .Sh SEE ALSO .Xr rc.conf 5 , .Xr boot 8 , +.Xr cpucontrol 8 , .Xr loader 8 , .Xr loader.4th 8 .Sh HISTORY Modified: stable/11/sys/amd64/amd64/machdep.c ============================================================================== --- stable/11/sys/amd64/amd64/machdep.c Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/amd64/amd64/machdep.c Thu May 16 14:42:16 2019 (r347700) @@ -131,6 +131,7 @@ __FBSDID("$FreeBSD$"); #include <machine/perfmon.h> #endif #include <machine/tss.h> +#include <x86/ucode.h> #ifdef SMP #include <machine/smp.h> #endif @@ -1577,6 +1578,9 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) int late_console; kmdp = init_ops.parse_preload_data(modulep); + + physfree += ucode_load_bsp(physfree + KERNBASE); + physfree = roundup2(physfree, PAGE_SIZE); identify_cpu1(); identify_hypervisor(); Modified: stable/11/sys/amd64/amd64/mp_machdep.c ============================================================================== --- stable/11/sys/amd64/amd64/mp_machdep.c Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/amd64/amd64/mp_machdep.c Thu May 16 14:42:16 2019 (r347700) @@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$"); #include <machine/smp.h> #include <machine/specialreg.h> #include <machine/tss.h> +#include <x86/ucode.h> #include <machine/cpu.h> #include <x86/init.h> @@ -211,6 +212,9 @@ init_secondary(void) /* Set by the startup code for us to use */ cpu = bootAP; + + /* Update microcode before doing anything else. */ + ucode_load_ap(cpu); /* Init tss */ common_tss[cpu] = common_tss[0]; Modified: stable/11/sys/conf/files.amd64 ============================================================================== --- stable/11/sys/conf/files.amd64 Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/conf/files.amd64 Thu May 16 14:42:16 2019 (r347700) @@ -725,6 +725,7 @@ x86/x86/nexus.c standard x86/x86/pvclock.c standard x86/x86/stack_machdep.c optional ddb | stack x86/x86/tsc.c standard +x86/x86/ucode.c standard x86/x86/delay.c standard x86/xen/hvm.c optional xenhvm x86/xen/xen_intr.c optional xenhvm Modified: stable/11/sys/conf/files.i386 ============================================================================== --- stable/11/sys/conf/files.i386 Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/conf/files.i386 Thu May 16 14:42:16 2019 (r347700) @@ -643,6 +643,7 @@ x86/x86/msi.c optional apic pci x86/x86/nexus.c standard x86/x86/stack_machdep.c optional ddb | stack x86/x86/tsc.c standard +x86/x86/ucode.c standard x86/x86/pvclock.c standard x86/x86/delay.c standard x86/xen/hvm.c optional xenhvm Modified: stable/11/sys/dev/cpuctl/cpuctl.c ============================================================================== --- stable/11/sys/dev/cpuctl/cpuctl.c Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/dev/cpuctl/cpuctl.c Thu May 16 14:42:16 2019 (r347700) @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <machine/cpufunc.h> #include <machine/md_var.h> #include <machine/specialreg.h> +#include <x86/ucode.h> static d_open_t cpuctl_open; static d_ioctl_t cpuctl_ioctl; @@ -331,11 +332,7 @@ static int update_intel(int cpu, cpuctl_update_args_t *args, struct thread *td) { void *ptr; - uint64_t rev0, rev1; - uint32_t tmp[4]; - int is_bound; - int oldcpu; - int ret; + int is_bound, oldcpu, ret; if (args->size == 0 || args->data == NULL) { DPRINTF("[cpuctl,%d]: zero-sized firmware image", __LINE__); @@ -356,34 +353,26 @@ update_intel(int cpu, cpuctl_update_args_t *args, stru DPRINTF("[cpuctl,%d]: copyin %p->%p of %zd bytes failed", __LINE__, args->data, ptr, args->size); ret = EFAULT; - goto fail; + goto out; } oldcpu = td->td_oncpu; is_bound = cpu_sched_is_bound(td); set_cpu(cpu, td); critical_enter(); - rdmsr_safe(MSR_BIOS_SIGN, &rev0); /* Get current microcode revision. */ - /* - * Perform update. Flush caches first to work around seemingly - * undocumented errata applying to some Broadwell CPUs. - */ - wbinvd(); - wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uintptr_t)(ptr)); - wrmsr_safe(MSR_BIOS_SIGN, 0); + ret = ucode_intel_load(ptr, true, NULL, NULL); - /* - * Serialize instruction flow. - */ - do_cpuid(0, tmp); critical_exit(); - rdmsr_safe(MSR_BIOS_SIGN, &rev1); /* Get new microcode revision. */ restore_cpu(oldcpu, is_bound, td); - if (rev1 > rev0) - ret = 0; - else - ret = EEXIST; -fail: + + /* + * Replace any existing update. This ensures that the new update + * will be reloaded automatically during ACPI resume. + */ + if (ret == 0) + ptr = ucode_update(ptr); + +out: free(ptr, M_CPUCTL); return (ret); } Modified: stable/11/sys/i386/i386/locore.s ============================================================================== --- stable/11/sys/i386/i386/locore.s Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/i386/i386/locore.s Thu May 16 14:42:16 2019 (r347700) @@ -486,8 +486,10 @@ olddiskboot: * Identify the CPU and initialize anything special about it * */ -identify_cpu: +ENTRY(identify_cpu) + pushl %ebx + /* Try to toggle alignment check flag; does not exist on 386. */ pushfl popl %eax @@ -607,7 +609,9 @@ trycpuid: /* Use the `cpuid' instruction. */ /* Greater than Pentium...call it a Pentium Pro */ movl $CPU_686,R(cpu) 3: + popl %ebx ret +END(identify_cpu) /********************************************************************** Modified: stable/11/sys/i386/i386/machdep.c ============================================================================== --- stable/11/sys/i386/i386/machdep.c Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/i386/i386/machdep.c Thu May 16 14:42:16 2019 (r347700) @@ -133,6 +133,7 @@ __FBSDID("$FreeBSD$"); #include <machine/reg.h> #include <machine/sigframe.h> #include <machine/specialreg.h> +#include <x86/ucode.h> #include <machine/vm86.h> #include <x86/init.h> #ifdef PERFMON @@ -165,6 +166,7 @@ CTASSERT(offsetof(struct pcpu, pc_curthread) == 0); extern register_t init386(int first); extern void dblfault_handler(void); +void identify_cpu(void); static void cpu_startup(void *); static void fpstate_drop(struct thread *td); @@ -2454,6 +2456,7 @@ init386(int first) struct pcpu *pc; struct xstate_hdr *xhdr; caddr_t kmdp; + size_t ucode_len; int late_console; thread0.td_kstack = proc0kstack; @@ -2484,6 +2487,15 @@ init386(int first) init_static_kenv((char *)bootinfo.bi_envp + KERNBASE, 0); else init_static_kenv(NULL, 0); + + /* + * Re-evaluate CPU features if we loaded a microcode update. + */ + ucode_len = ucode_load_bsp(first); + if (ucode_len != 0) { + identify_cpu(); + first = roundup2(first + ucode_len, PAGE_SIZE); + } identify_hypervisor(); Modified: stable/11/sys/i386/i386/mp_machdep.c ============================================================================== --- stable/11/sys/i386/i386/mp_machdep.c Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/i386/i386/mp_machdep.c Thu May 16 14:42:16 2019 (r347700) @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include <x86/apicreg.h> #include <machine/clock.h> +#include <machine/cpu.h> #include <machine/cputypes.h> #include <x86/mca.h> #include <machine/md_var.h> @@ -78,7 +79,7 @@ __FBSDID("$FreeBSD$"); #include <machine/psl.h> #include <machine/smp.h> #include <machine/specialreg.h> -#include <machine/cpu.h> +#include <x86/ucode.h> #define WARMBOOT_TARGET 0 #define WARMBOOT_OFF (KERNBASE + 0x0467) @@ -228,6 +229,9 @@ init_secondary(void) /* bootAP is set in start_ap() to our ID. */ myid = bootAP; + + /* Update microcode before doing anything else. */ + ucode_load_ap(myid); /* Get per-cpu data */ pc = &__pcpu[myid]; Modified: stable/11/sys/x86/acpica/acpi_wakeup.c ============================================================================== --- stable/11/sys/x86/acpica/acpi_wakeup.c Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/x86/acpica/acpi_wakeup.c Thu May 16 14:42:16 2019 (r347700) @@ -52,10 +52,11 @@ __FBSDID("$FreeBSD$"); #include <machine/clock.h> #include <machine/cpu.h> #include <machine/intr_machdep.h> +#include <machine/md_var.h> #include <x86/mca.h> #include <machine/pcb.h> #include <machine/specialreg.h> -#include <machine/md_var.h> +#include <x86/ucode.h> #ifdef DEV_APIC #include <x86/apicreg.h> @@ -293,6 +294,7 @@ acpi_wakeup_machdep(struct acpi_softc *sc, int state, if (!intr_enabled) { /* Wakeup MD procedures in interrupt disabled context */ if (sleep_result == 1) { + ucode_reload(); pmap_init_pat(); initializecpu(); PCPU_SET(switchtime, 0); Copied and modified: stable/11/sys/x86/include/ucode.h (from r337715, head/sys/x86/include/ucode.h) ============================================================================== --- head/sys/x86/include/ucode.h Mon Aug 13 17:13:09 2018 (r337715, copy source) +++ stable/11/sys/x86/include/ucode.h Thu May 16 14:42:16 2019 (r347700) @@ -58,7 +58,8 @@ struct ucode_intel_extsig_table { } entries[0]; }; -int ucode_intel_load(void *data, bool unsafe); +int ucode_intel_load(void *data, bool unsafe, + uint64_t *nrevp, uint64_t *orevp); size_t ucode_load_bsp(uintptr_t free); void ucode_load_ap(int cpu); void ucode_reload(void); Modified: stable/11/sys/x86/x86/mp_x86.c ============================================================================== --- stable/11/sys/x86/x86/mp_x86.c Thu May 16 14:39:48 2019 (r347699) +++ stable/11/sys/x86/x86/mp_x86.c Thu May 16 14:42:16 2019 (r347700) @@ -65,6 +65,7 @@ __FBSDID("$FreeBSD$"); #include <x86/apicreg.h> #include <machine/clock.h> +#include <machine/cpu.h> #include <machine/cputypes.h> #include <x86/mca.h> #include <machine/md_var.h> @@ -72,7 +73,7 @@ __FBSDID("$FreeBSD$"); #include <machine/psl.h> #include <machine/smp.h> #include <machine/specialreg.h> -#include <machine/cpu.h> +#include <x86/ucode.h> /* lock region used by kernel profiling */ int mcount_lock; @@ -1362,6 +1363,9 @@ cpususpend_handler(void) /* Wait for resume directive */ while (!CPU_ISSET(cpu, &toresume_cpus)) ia32_pause(); + + /* Re-apply microcode updates. */ + ucode_reload(); if (cpu_ops.cpu_resume) cpu_ops.cpu_resume(); Copied and modified: stable/11/sys/x86/x86/ucode.c (from r337715, head/sys/x86/x86/ucode.c) ============================================================================== --- head/sys/x86/x86/ucode.c Mon Aug 13 17:13:09 2018 (r337715, copy source) +++ stable/11/sys/x86/x86/ucode.c Thu May 16 14:42:16 2019 (r347700) @@ -59,7 +59,7 @@ static int ucode_intel_verify(struct ucode_intel_heade static struct ucode_ops { const char *vendor; - int (*load)(void *, bool); + int (*load)(void *, bool, uint64_t *, uint64_t *); void *(*match)(uint8_t *, size_t *); } loaders[] = { { @@ -72,35 +72,46 @@ static struct ucode_ops { /* Selected microcode update data. */ static void *early_ucode_data; static void *ucode_data; +static struct ucode_ops *ucode_loader; -static char errbuf[128]; +/* Variables used for reporting success or failure. */ +enum { + NO_ERROR, + NO_MATCH, + VERIFICATION_FAILED, +} ucode_error = NO_ERROR; +static uint64_t ucode_nrev, ucode_orev; -static void __printflike(1, 2) -log_err(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsnprintf(errbuf, sizeof(errbuf), fmt, ap); - va_end(ap); -} - static void -print_err(void *arg __unused) +log_msg(void *arg __unused) { - if (errbuf[0] != '\0') - printf("microcode load error: %s\n", errbuf); + if (ucode_nrev != 0) { + printf("CPU microcode: updated from %#jx to %#jx\n", + (uintmax_t)ucode_orev, (uintmax_t)ucode_nrev); + return; + } + + switch (ucode_error) { + case NO_MATCH: + printf("CPU microcode: no matching update found\n"); + break; + case VERIFICATION_FAILED: + printf("CPU microcode: microcode verification failed\n"); + break; + default: + break; + } } -SYSINIT(ucode_print_err, SI_SUB_CPU, SI_ORDER_FIRST, print_err, NULL); +SYSINIT(ucode_log, SI_SUB_CPU, SI_ORDER_FIRST, log_msg, NULL); int -ucode_intel_load(void *data, bool unsafe) +ucode_intel_load(void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp) { - uint64_t rev0, rev1; + uint64_t nrev, orev; uint32_t cpuid[4]; - rev0 = rdmsr(MSR_BIOS_SIGN); + orev = rdmsr(MSR_BIOS_SIGN) >> 32; /* * Perform update. Flush caches first to work around seemingly @@ -118,8 +129,15 @@ ucode_intel_load(void *data, bool unsafe) */ do_cpuid(0, cpuid); - rev1 = rdmsr(MSR_BIOS_SIGN); - if (rev1 <= rev0) + /* + * Verify that the microcode revision changed. + */ + nrev = rdmsr(MSR_BIOS_SIGN) >> 32; + if (nrevp != NULL) + *nrevp = nrev; + if (orevp != NULL) + *orevp = orev; + if (nrev <= orev) return (EEXIST); return (0); } @@ -130,36 +148,26 @@ ucode_intel_verify(struct ucode_intel_header *hdr, siz uint32_t cksum, *data, size; int i; - if (resid < sizeof(struct ucode_intel_header)) { - log_err("truncated update header"); + if (resid < sizeof(struct ucode_intel_header)) return (1); - } size = hdr->total_size; if (size == 0) size = UCODE_INTEL_DEFAULT_DATA_SIZE + sizeof(struct ucode_intel_header); - if (hdr->header_version != 1) { - log_err("unexpected header version %u", hdr->header_version); + if (hdr->header_version != 1) return (1); - } - if (size % 16 != 0) { - log_err("unexpected update size %u", hdr->total_size); + if (size % 16 != 0) return (1); - } - if (resid < size) { - log_err("truncated update"); + if (resid < size) return (1); - } cksum = 0; data = (uint32_t *)hdr; for (i = 0; i < size / sizeof(uint32_t); i++) cksum += data[i]; - if (cksum != 0) { - log_err("checksum failed"); + if (cksum != 0) return (1); - } return (0); } @@ -182,8 +190,10 @@ ucode_intel_match(uint8_t *data, size_t *len) for (resid = *len; resid > 0; data += total_size, resid -= total_size) { hdr = (struct ucode_intel_header *)data; - if (ucode_intel_verify(hdr, resid) != 0) + if (ucode_intel_verify(hdr, resid) != 0) { + ucode_error = VERIFICATION_FAILED; break; + } data_size = hdr->data_size; total_size = hdr->total_size; @@ -255,21 +265,26 @@ SYSINIT(ucode_release, SI_SUB_KMEM + 1, SI_ORDER_ANY, void ucode_load_ap(int cpu) { - +#ifdef SMP KASSERT(cpu_info[cpu_apic_ids[cpu]].cpu_present, ("cpu %d not present", cpu)); - if (ucode_data != NULL && !cpu_info[cpu_apic_ids[cpu]].cpu_hyperthread) - (void)ucode_intel_load(ucode_data, false); + if (cpu_info[cpu_apic_ids[cpu]].cpu_hyperthread) + return; +#endif + + if (ucode_data != NULL) + (void)ucode_loader->load(ucode_data, false, NULL, NULL); } static void * -map_ucode(vm_paddr_t free, size_t len) +map_ucode(uintptr_t free, size_t len) { - #ifdef __i386__ - for (vm_paddr_t pa = free; pa < free + len; pa += PAGE_SIZE) - pmap_kenter(pa, pa); + uintptr_t va; + + for (va = free; va < free + len; va += PAGE_SIZE) + pmap_kenter(va, (vm_paddr_t)va); #else (void)len; #endif @@ -277,12 +292,13 @@ map_ucode(vm_paddr_t free, size_t len) } static void -unmap_ucode(vm_paddr_t free, size_t len) +unmap_ucode(uintptr_t free, size_t len) { - #ifdef __i386__ - for (vm_paddr_t pa = free; pa < free + len; pa += PAGE_SIZE) - pmap_kremove((vm_offset_t)pa); + uintptr_t va; + + for (va = free; va < free + len; va += PAGE_SIZE) + pmap_kremove(va); #else (void)free; (void)len; @@ -304,12 +320,12 @@ ucode_load_bsp(uintptr_t free) uint32_t regs[4]; char vendor[13]; } cpuid; - struct ucode_ops *loader; uint8_t *addr, *fileaddr, *match; char *type; + uint64_t nrev, orev; caddr_t file; - size_t len, ucode_len; - int i; + size_t i, len; + int error; KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free)); @@ -317,17 +333,16 @@ ucode_load_bsp(uintptr_t free) cpuid.regs[0] = cpuid.regs[1]; cpuid.regs[1] = cpuid.regs[3]; cpuid.vendor[12] = '\0'; - for (i = 0, loader = NULL; i < nitems(loaders); i++) + for (i = 0; i < nitems(loaders); i++) if (strcmp(cpuid.vendor, loaders[i].vendor) == 0) { - loader = &loaders[i]; + ucode_loader = &loaders[i]; break; } - if (loader == NULL) + if (ucode_loader == NULL) return (0); file = 0; fileaddr = match = NULL; - ucode_len = 0; for (;;) { file = preload_search_next_name(file); if (file == 0) @@ -338,24 +353,27 @@ ucode_load_bsp(uintptr_t free) fileaddr = preload_fetch_addr(file); len = preload_fetch_size(file); - match = loader->match(fileaddr, &len); + match = ucode_loader->match(fileaddr, &len); if (match != NULL) { addr = map_ucode(free, len); - memcpy(addr, match, len); + /* We can't use memcpy() before ifunc resolution. */ + for (i = 0; i < len; i++) + addr[i] = ((volatile uint8_t *)match)[i]; match = addr; - if (loader->load(match, false) == 0) { - ucode_data = match; - ucode_len = len; - early_ucode_data = ucode_data; - break; + error = ucode_loader->load(match, false, &nrev, &orev); + if (error == 0) { + ucode_data = early_ucode_data = match; + ucode_nrev = nrev; + ucode_orev = orev; + return (len); } unmap_ucode(free, len); } } - if (fileaddr != NULL && ucode_data == NULL) - log_err("no matching update found"); - return (ucode_len); + if (fileaddr != NULL && ucode_error == NO_ERROR) + ucode_error = NO_MATCH; + return (0); } /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201905161442.x4GEgHRd013192>