Skip site navigation (1)Skip section navigation (2)
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>