svn commit: r338687 - in head/sys: dev/cpuctl x86/include x86/x86

Mark Johnston markj at FreeBSD.org
Fri Sep 14 17:04:37 UTC 2018


Author: markj
Date: Fri Sep 14 17:04:36 2018
New Revision: 338687
URL: https://svnweb.freebsd.org/changeset/base/338687

Log:
  Log a message after a successful boot-time microcode update.
  
  Reviewed by:	kib
  Approved by:	re (delphij)
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D17135

Modified:
  head/sys/dev/cpuctl/cpuctl.c
  head/sys/x86/include/ucode.h
  head/sys/x86/x86/ucode.c

Modified: head/sys/dev/cpuctl/cpuctl.c
==============================================================================
--- head/sys/dev/cpuctl/cpuctl.c	Fri Sep 14 16:25:34 2018	(r338686)
+++ head/sys/dev/cpuctl/cpuctl.c	Fri Sep 14 17:04:36 2018	(r338687)
@@ -362,7 +362,7 @@ update_intel(int cpu, cpuctl_update_args_t *args, stru
 	set_cpu(cpu, td);
 	critical_enter();
 
-	ret = ucode_intel_load(ptr, true);
+	ret = ucode_intel_load(ptr, true, NULL, NULL);
 
 	critical_exit();
 	restore_cpu(oldcpu, is_bound, td);

Modified: head/sys/x86/include/ucode.h
==============================================================================
--- head/sys/x86/include/ucode.h	Fri Sep 14 16:25:34 2018	(r338686)
+++ head/sys/x86/include/ucode.h	Fri Sep 14 17:04:36 2018	(r338687)
@@ -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: head/sys/x86/x86/ucode.c
==============================================================================
--- head/sys/x86/x86/ucode.c	Fri Sep 14 16:25:34 2018	(r338686)
+++ head/sys/x86/x86/ucode.c	Fri Sep 14 17:04:36 2018	(r338687)
@@ -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;
@@ -264,7 +274,7 @@ ucode_load_ap(int cpu)
 #endif
 
 	if (ucode_data != NULL)
-		(void)ucode_intel_load(ucode_data, false);
+		(void)ucode_loader->load(ucode_data, false, NULL, NULL);
 }
 
 static void *
@@ -308,11 +318,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 i, len, ucode_len;
+	size_t i, len;
+	int error;
 
 	KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free));
 
@@ -320,17 +331,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)
@@ -341,7 +351,7 @@ 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);
 			/* We can't use memcpy() before ifunc resolution. */
@@ -349,18 +359,19 @@ ucode_load_bsp(uintptr_t free)
 				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-head mailing list