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
Mark Johnston
markj at FreeBSD.org
Thu May 16 14:42:20 UTC 2019
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);
}
/*
More information about the svn-src-stable-11
mailing list