Module Name:    src
Committed By:   cegger
Date:           Fri Jan 13 16:05:16 UTC 2012

Modified Files:
        src/share/man/man4: options.4
        src/sys/arch/amd64/conf: GENERIC XEN3_DOM0
        src/sys/arch/i386/conf: GENERIC XEN3_DOM0
        src/sys/arch/x86/conf: files.x86
        src/sys/arch/xen/conf: files.xen
        src/sys/kern: kern_cpu.c
        src/sys/secmodel/securelevel: secmodel_securelevel.c
        src/sys/secmodel/suser: secmodel_suser.c
        src/sys/sys: cpu.h cpuio.h kauth.h
        src/usr.sbin/cpuctl: cpuctl.8 cpuctl.c
Added Files:
        src/sys/arch/x86/include: cpu_ucode.h
        src/sys/arch/x86/x86: cpu_ucode.c cpu_ucode_amd.c
        src/sys/arch/xen/xen: xen_ucode.c

Log Message:
Support CPU microcode loading via cpuctl(8).
Implemented and enabled via CPU_UCODE kernel config option
for x86 and Xen Dom0.
Tested on different AMD machines with different
CPU families.

ok wiz@ for the manpages
ok releng@
ok core@ via releng@


To generate a diff of this commit:
cvs rdiff -u -r1.410 -r1.411 src/share/man/man4/options.4
cvs rdiff -u -r1.342 -r1.343 src/sys/arch/amd64/conf/GENERIC
cvs rdiff -u -r1.76 -r1.77 src/sys/arch/amd64/conf/XEN3_DOM0
cvs rdiff -u -r1.1061 -r1.1062 src/sys/arch/i386/conf/GENERIC
cvs rdiff -u -r1.58 -r1.59 src/sys/arch/i386/conf/XEN3_DOM0
cvs rdiff -u -r1.75 -r1.76 src/sys/arch/x86/conf/files.x86
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/include/cpu_ucode.h
cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/cpu_ucode.c \
    src/sys/arch/x86/x86/cpu_ucode_amd.c
cvs rdiff -u -r1.123 -r1.124 src/sys/arch/xen/conf/files.xen
cvs rdiff -u -r0 -r1.1 src/sys/arch/xen/xen/xen_ucode.c
cvs rdiff -u -r1.52 -r1.53 src/sys/kern/kern_cpu.c
cvs rdiff -u -r1.24 -r1.25 \
    src/sys/secmodel/securelevel/secmodel_securelevel.c
cvs rdiff -u -r1.36 -r1.37 src/sys/secmodel/suser/secmodel_suser.c
cvs rdiff -u -r1.33 -r1.34 src/sys/sys/cpu.h
cvs rdiff -u -r1.5 -r1.6 src/sys/sys/cpuio.h
cvs rdiff -u -r1.66 -r1.67 src/sys/sys/kauth.h
cvs rdiff -u -r1.6 -r1.7 src/usr.sbin/cpuctl/cpuctl.8
cvs rdiff -u -r1.19 -r1.20 src/usr.sbin/cpuctl/cpuctl.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/options.4
diff -u src/share/man/man4/options.4:1.410 src/share/man/man4/options.4:1.411
--- src/share/man/man4/options.4:1.410	Mon Jan  9 15:16:31 2012
+++ src/share/man/man4/options.4	Fri Jan 13 16:05:16 2012
@@ -1,4 +1,4 @@
-.\"	$NetBSD: options.4,v 1.410 2012/01/09 15:16:31 drochner Exp $
+.\"	$NetBSD: options.4,v 1.411 2012/01/13 16:05:16 cegger Exp $
 .\"
 .\" Copyright (c) 1996
 .\" 	Perry E. Metzger.  All rights reserved.
@@ -30,7 +30,7 @@
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
 .\"
-.Dd January 9, 2012
+.Dd January 13, 2012
 .Dt OPTIONS 4
 .Os
 .Sh NAME
@@ -1093,6 +1093,9 @@ Synonym of
 .El
 .Ss Miscellaneous Options
 .Bl -ohang
+.It Cd options CPU_UCODE
+Support cpu microcode loading via
+.Xr cpuctl 8 .
 .It Cd options MEMORY_DISK_DYNAMIC
 This option makes the
 .Xr md 4

Index: src/sys/arch/amd64/conf/GENERIC
diff -u src/sys/arch/amd64/conf/GENERIC:1.342 src/sys/arch/amd64/conf/GENERIC:1.343
--- src/sys/arch/amd64/conf/GENERIC:1.342	Sat Dec 31 00:10:06 2011
+++ src/sys/arch/amd64/conf/GENERIC	Fri Jan 13 16:05:14 2012
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.342 2011/12/31 00:10:06 christos Exp $
+# $NetBSD: GENERIC,v 1.343 2012/01/13 16:05:14 cegger Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@ include	"arch/amd64/conf/std.amd64"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.342 $"
+#ident 		"GENERIC-$Revision: 1.343 $"
 
 maxusers	64		# estimated number of users
 
@@ -60,6 +60,8 @@ options 	NTP		# NTP phase/frequency lock
 
 options 	KTRACE		# system call tracing via ktrace(1)
 
+options		CPU_UCODE	# cpu ucode loading support
+
 # Note: SysV IPC parameters could be changed dynamically, see sysctl(8).
 options 	SYSVMSG		# System V-like message queues
 options 	SYSVSEM		# System V-like semaphores

Index: src/sys/arch/amd64/conf/XEN3_DOM0
diff -u src/sys/arch/amd64/conf/XEN3_DOM0:1.76 src/sys/arch/amd64/conf/XEN3_DOM0:1.77
--- src/sys/arch/amd64/conf/XEN3_DOM0:1.76	Sun Dec 18 05:49:23 2011
+++ src/sys/arch/amd64/conf/XEN3_DOM0	Fri Jan 13 16:05:14 2012
@@ -1,4 +1,4 @@
-# $NetBSD: XEN3_DOM0,v 1.76 2011/12/18 05:49:23 dholland Exp $
+# $NetBSD: XEN3_DOM0,v 1.77 2012/01/13 16:05:14 cegger Exp $
 
 include 	"arch/amd64/conf/std.xen"
 
@@ -35,6 +35,8 @@ options 	NTP		# NTP phase/frequency lock
 
 options 	KTRACE		# system call tracing via ktrace(1)
 
+options		CPU_UCODE	# cpu ucode loading support
+
 options 	SYSVMSG		# System V-like message queues
 options 	SYSVSEM		# System V-like semaphores
 options 	SYSVSHM		# System V-like memory sharing

Index: src/sys/arch/i386/conf/GENERIC
diff -u src/sys/arch/i386/conf/GENERIC:1.1061 src/sys/arch/i386/conf/GENERIC:1.1062
--- src/sys/arch/i386/conf/GENERIC:1.1061	Sat Dec 31 00:11:21 2011
+++ src/sys/arch/i386/conf/GENERIC	Fri Jan 13 16:05:14 2012
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.1061 2011/12/31 00:11:21 christos Exp $
+# $NetBSD: GENERIC,v 1.1062 2012/01/13 16:05:14 cegger Exp $
 #
 # GENERIC machine description file
 #
@@ -22,7 +22,7 @@ include 	"arch/i386/conf/std.i386"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.1061 $"
+#ident 		"GENERIC-$Revision: 1.1062 $"
 
 maxusers	64		# estimated number of users
 
@@ -80,6 +80,8 @@ options 	NTP		# NTP phase/frequency lock
 
 options 	KTRACE		# system call tracing via ktrace(1)
 
+options		CPU_UCODE	# cpu ucode loading support
+
 # Note: SysV IPC parameters can be changed dynamically; see sysctl(8).
 options 	SYSVMSG		# System V-like message queues
 options 	SYSVSEM		# System V-like semaphores

Index: src/sys/arch/i386/conf/XEN3_DOM0
diff -u src/sys/arch/i386/conf/XEN3_DOM0:1.58 src/sys/arch/i386/conf/XEN3_DOM0:1.59
--- src/sys/arch/i386/conf/XEN3_DOM0:1.58	Sun Dec 18 05:49:28 2011
+++ src/sys/arch/i386/conf/XEN3_DOM0	Fri Jan 13 16:05:14 2012
@@ -1,4 +1,4 @@
-#	$NetBSD: XEN3_DOM0,v 1.58 2011/12/18 05:49:28 dholland Exp $
+#	$NetBSD: XEN3_DOM0,v 1.59 2012/01/13 16:05:14 cegger Exp $
 #
 #	XEN3_0: Xen 3.0 domain0 kernel
 
@@ -45,6 +45,8 @@ options 	NTP		# NTP phase/frequency lock
 
 options 	KTRACE		# system call tracing via ktrace(1)
 
+options		CPU_UCODE	# cpu ucode loading support
+
 options 	SYSVMSG		# System V-like message queues
 options 	SYSVSEM		# System V-like semaphores
 #options 	SEMMNI=10	# number of semaphore identifiers

Index: src/sys/arch/x86/conf/files.x86
diff -u src/sys/arch/x86/conf/files.x86:1.75 src/sys/arch/x86/conf/files.x86:1.76
--- src/sys/arch/x86/conf/files.x86:1.75	Wed Oct 19 05:22:25 2011
+++ src/sys/arch/x86/conf/files.x86	Fri Jan 13 16:05:14 2012
@@ -1,4 +1,4 @@
-#	$NetBSD: files.x86,v 1.75 2011/10/19 05:22:25 dyoung Exp $
+#	$NetBSD: files.x86,v 1.76 2012/01/13 16:05:14 cegger Exp $
 
 # options for MP configuration through the MP spec
 defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI
@@ -93,6 +93,10 @@ file	arch/x86/x86/x86_autoconf.c
 file	arch/x86/x86/x86_userconf.c		userconf
 file	arch/x86/x86/x86_machdep.c
 
+defflag CPU_UCODE
+file	arch/x86/x86/cpu_ucode.c	cpu_ucode needs-flag
+file	arch/x86/x86/cpu_ucode_amd.c	cpu_ucode needs-flag
+
 define	lapic
 file	arch/x86/x86/lapic.c		lapic needs-flag
 

Index: src/sys/arch/xen/conf/files.xen
diff -u src/sys/arch/xen/conf/files.xen:1.123 src/sys/arch/xen/conf/files.xen:1.124
--- src/sys/arch/xen/conf/files.xen:1.123	Thu Sep 22 23:02:34 2011
+++ src/sys/arch/xen/conf/files.xen	Fri Jan 13 16:05:15 2012
@@ -1,4 +1,4 @@
-#	$NetBSD: files.xen,v 1.123 2011/09/22 23:02:34 jym Exp $
+#	$NetBSD: files.xen,v 1.124 2012/01/13 16:05:15 cegger Exp $
 #	NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp 
 #	NetBSD: files.i386,v 1.254 2004/03/25 23:32:10 jmc Exp 
 
@@ -93,6 +93,10 @@ file	arch/xen/x86/xen_pmap.c
 file	arch/xen/x86/xen_intr.c
 file	arch/xen/x86/xenfunc.c
 
+defflag	CPU_UCODE
+file	arch/xen/xen/xen_ucode.c	dom0ops | cpu_ucode needs-flag
+file	arch/x86/x86/cpu_ucode_amd.c	dom0ops | cpu_ucode needs-flag
+
 file	arch/xen/xen/xen_machdep.c
 file	arch/xen/xen/xen_debug.c
 

Index: src/sys/kern/kern_cpu.c
diff -u src/sys/kern/kern_cpu.c:1.52 src/sys/kern/kern_cpu.c:1.53
--- src/sys/kern/kern_cpu.c:1.52	Sat Oct 29 11:41:32 2011
+++ src/sys/kern/kern_cpu.c	Fri Jan 13 16:05:15 2012
@@ -1,7 +1,7 @@
-/*	$NetBSD: kern_cpu.c,v 1.52 2011/10/29 11:41:32 jym Exp $	*/
+/*	$NetBSD: kern_cpu.c,v 1.53 2012/01/13 16:05:15 cegger Exp $	*/
 
 /*-
- * Copyright (c) 2007, 2008, 2009, 2010 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007, 2008, 2009, 2010, 2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -56,7 +56,9 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.52 2011/10/29 11:41:32 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.53 2012/01/13 16:05:15 cegger Exp $");
+
+#include "opt_cpu_ucode.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -245,6 +247,26 @@ cpuctl_ioctl(dev_t dev, u_long cmd, void
 		*(int *)data = ncpu;
 		break;
 
+#ifdef CPU_UCODE
+	case IOC_CPU_UCODE_GET_VERSION:
+		error = cpu_ucode_get_version(data);
+		break;
+
+	case IOC_CPU_UCODE_APPLY:
+		error = kauth_authorize_machdep(l->l_cred,
+		    KAUTH_MACHDEP_CPU_UCODE_APPLY,
+		    NULL, NULL, NULL, NULL);
+		if (error != 0)
+			break;
+		error = kauth_authorize_system(l->l_cred,
+		    KAUTH_SYSTEM_CPU, KAUTH_REQ_SYSTEM_CPU_UCODE_APPLY,
+		    data, NULL, NULL);
+		if (error != 0)
+			break;
+		error = cpu_ucode_apply(data);
+		break;
+#endif
+
 	default:
 		error = ENOTTY;
 		break;
@@ -507,3 +529,46 @@ cpu_softintr_p(void)
 
 	return (curlwp->l_pflag & LP_INTR) != 0;
 }
+
+#ifdef CPU_UCODE
+int
+cpu_ucode_load(struct cpu_ucode_softc *sc, const char *fwname)
+{
+	firmware_handle_t fwh;
+	int error;
+
+	if (sc->sc_blob != NULL) {
+		firmware_free(sc->sc_blob, 0);
+		sc->sc_blob = NULL;
+		sc->sc_blobsize = 0;
+	}
+
+	error = cpu_ucode_md_open(&fwh, fwname);
+	if (error != 0) {
+		aprint_error("ucode: firmware_open failed: %i\n", error);
+		goto err0;
+	}
+
+	sc->sc_blobsize = firmware_get_size(fwh);
+	sc->sc_blob = firmware_malloc(sc->sc_blobsize);
+	if (sc->sc_blob == NULL) {
+		error = ENOMEM;
+		firmware_close(fwh);
+		goto err0;
+	}
+
+	error = firmware_read(fwh, 0, sc->sc_blob, sc->sc_blobsize);
+	firmware_close(fwh);
+	if (error != 0)
+		goto err1;
+
+	return 0;
+
+err1:
+	firmware_free(sc->sc_blob, 0);
+	sc->sc_blob = NULL;
+	sc->sc_blobsize = 0;
+err0:
+	return error;
+}
+#endif

Index: src/sys/secmodel/securelevel/secmodel_securelevel.c
diff -u src/sys/secmodel/securelevel/secmodel_securelevel.c:1.24 src/sys/secmodel/securelevel/secmodel_securelevel.c:1.25
--- src/sys/secmodel/securelevel/secmodel_securelevel.c:1.24	Mon Dec  5 00:13:30 2011
+++ src/sys/secmodel/securelevel/secmodel_securelevel.c	Fri Jan 13 16:05:15 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: secmodel_securelevel.c,v 1.24 2011/12/05 00:13:30 jym Exp $ */
+/* $NetBSD: secmodel_securelevel.c,v 1.25 2012/01/13 16:05:15 cegger Exp $ */
 /*-
  * Copyright (c) 2006 Elad Efrat <[email protected]>
  * All rights reserved.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.24 2011/12/05 00:13:30 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.25 2012/01/13 16:05:15 cegger Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_insecure.h"
@@ -483,6 +483,11 @@ secmodel_securelevel_machdep_cb(kauth_cr
 			result = KAUTH_RESULT_DENY;
 		break;
 
+	case KAUTH_MACHDEP_CPU_UCODE_APPLY:
+		if (securelevel < 1)
+			result = KAUTH_RESULT_ALLOW;
+		break;
+
 	default:
 		break;
 	}

Index: src/sys/secmodel/suser/secmodel_suser.c
diff -u src/sys/secmodel/suser/secmodel_suser.c:1.36 src/sys/secmodel/suser/secmodel_suser.c:1.37
--- src/sys/secmodel/suser/secmodel_suser.c:1.36	Sun Dec  4 19:25:01 2011
+++ src/sys/secmodel/suser/secmodel_suser.c	Fri Jan 13 16:05:15 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: secmodel_suser.c,v 1.36 2011/12/04 19:25:01 jym Exp $ */
+/* $NetBSD: secmodel_suser.c,v 1.37 2012/01/13 16:05:15 cegger Exp $ */
 /*-
  * Copyright (c) 2006 Elad Efrat <[email protected]>
  * All rights reserved.
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.36 2011/12/04 19:25:01 jym Exp $");
+__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.37 2012/01/13 16:05:15 cegger Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -248,6 +248,7 @@ secmodel_suser_system_cb(kauth_cred_t cr
 	case KAUTH_SYSTEM_CPU:
 		switch (req) {
 		case KAUTH_REQ_SYSTEM_CPU_SETSTATE:
+		case KAUTH_REQ_SYSTEM_CPU_UCODE_APPLY:
 			if (isroot)
 				result = KAUTH_RESULT_ALLOW;
 

Index: src/sys/sys/cpu.h
diff -u src/sys/sys/cpu.h:1.33 src/sys/sys/cpu.h:1.34
--- src/sys/sys/cpu.h:1.33	Sun Aug  7 13:33:02 2011
+++ src/sys/sys/cpu.h	Fri Jan 13 16:05:16 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: cpu.h,v 1.33 2011/08/07 13:33:02 rmind Exp $	*/
+/*	$NetBSD: cpu.h,v 1.34 2012/01/13 16:05:16 cegger Exp $	*/
 
 /*-
  * Copyright (c) 2007 YAMAMOTO Takashi,
@@ -42,6 +42,10 @@ struct cpu_info;
 void cpu_idle(void);
 #endif
 
+#ifdef CPU_UCODE
+#include <dev/firmload.h>
+#endif
+
 /*
  * cpu_need_resched() must always be called with the target CPU
  * locked (via spc_lock() or another route), unless called locally.
@@ -102,6 +106,19 @@ cpu_name(struct cpu_info *ci)
 {
 	return ci->ci_data.cpu_name;
 }
+
+#ifdef CPU_UCODE
+struct cpu_ucode_softc {
+	char *sc_blob;
+	off_t sc_blobsize;
+};
+
+int cpu_ucode_get_version(void *);
+int cpu_ucode_apply(void *);
+int cpu_ucode_load(struct cpu_ucode_softc *, const char *);
+int cpu_ucode_md_open(firmware_handle_t *, const char *);
+#endif
+
 #endif
 #endif	/* !_LOCORE */
 

Index: src/sys/sys/cpuio.h
diff -u src/sys/sys/cpuio.h:1.5 src/sys/sys/cpuio.h:1.6
--- src/sys/sys/cpuio.h:1.5	Sun Sep 11 14:54:49 2011
+++ src/sys/sys/cpuio.h	Fri Jan 13 16:05:16 2012
@@ -1,7 +1,7 @@
-/*	$NetBSD: cpuio.h,v 1.5 2011/09/11 14:54:49 jdc Exp $	*/
+/*	$NetBSD: cpuio.h,v 1.6 2012/01/13 16:05:16 cegger Exp $	*/
 
 /*-
- * Copyright (c) 2007, 2009 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007, 2009, 2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -62,4 +62,12 @@ typedef struct cpustate {
 #define	IOC_CPU_GETCOUNT	_IOR('c', 2, int)
 #define	IOC_CPU_MAPID		_IOWR('c', 3, int)
 
+struct cpu_ucode {
+	uint64_t version;
+	char fwname[PATH_MAX];
+};
+
+#define IOC_CPU_UCODE_GET_VERSION	_IOR('c', 4, struct cpu_ucode)
+#define IOC_CPU_UCODE_APPLY		_IOW('c', 5, struct cpu_ucode)
+
 #endif /* !_SYS_CPUIO_H_ */

Index: src/sys/sys/kauth.h
diff -u src/sys/sys/kauth.h:1.66 src/sys/sys/kauth.h:1.67
--- src/sys/sys/kauth.h:1.66	Sun Dec  4 19:25:01 2011
+++ src/sys/sys/kauth.h	Fri Jan 13 16:05:16 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: kauth.h,v 1.66 2011/12/04 19:25:01 jym Exp $ */
+/* $NetBSD: kauth.h,v 1.67 2012/01/13 16:05:16 cegger Exp $ */
 
 /*-
  * Copyright (c) 2005, 2006 Elad Efrat <[email protected]>  
@@ -109,6 +109,7 @@ enum kauth_system_req {
 	KAUTH_REQ_SYSTEM_CHROOT_CHROOT=1,
 	KAUTH_REQ_SYSTEM_CHROOT_FCHROOT,
 	KAUTH_REQ_SYSTEM_CPU_SETSTATE,
+	KAUTH_REQ_SYSTEM_CPU_UCODE_APPLY,
 	KAUTH_REQ_SYSTEM_DEBUG_IPKDB,
 	KAUTH_REQ_SYSTEM_MOUNT_GET,
 	KAUTH_REQ_SYSTEM_MOUNT_NEW,
@@ -235,6 +236,7 @@ enum kauth_network_req {
  */
 enum {
 	KAUTH_MACHDEP_CACHEFLUSH=1,
+	KAUTH_MACHDEP_CPU_UCODE_APPLY,
 	KAUTH_MACHDEP_IOPERM_GET,
 	KAUTH_MACHDEP_IOPERM_SET,
 	KAUTH_MACHDEP_IOPL,

Index: src/usr.sbin/cpuctl/cpuctl.8
diff -u src/usr.sbin/cpuctl/cpuctl.8:1.6 src/usr.sbin/cpuctl/cpuctl.8:1.7
--- src/usr.sbin/cpuctl/cpuctl.8:1.6	Sun Jun 22 14:50:40 2008
+++ src/usr.sbin/cpuctl/cpuctl.8	Fri Jan 13 16:05:16 2012
@@ -1,6 +1,6 @@
-.\"	$NetBSD: cpuctl.8,v 1.6 2008/06/22 14:50:40 wiz Exp $
+.\"	$NetBSD: cpuctl.8,v 1.7 2012/01/13 16:05:16 cegger Exp $
 .\"
-.\" Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
+.\" Copyright (c) 2007, 2008, 2012 The NetBSD Foundation, Inc.
 .\" All rights reserved.
 .\"
 .\" This code is derived from software contributed to The NetBSD Foundation
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd June 22, 2008
+.Dd January 13, 2012
 .Dt CPUCTL 8
 .Os
 .Sh NAME
@@ -66,11 +66,48 @@ away from individual CPUs.
 At least one CPU in the system must remain on line.
 .It online Ar cpuno
 Set the specified CPU on line, making it available to run unbound LWPs.
+.It ucode Op Ar file
+This applies the microcode patch on all cpus.
+The default filename is used if no filename is specified.
+The
+.Cm identify
+command prints the installed version on that cpu.
+On success the
+.Cm identify
+command show different ucode versions before and after this command.
 .El
+.Sh EXAMPLES
+Run
+.Dl cpuctl identify 0
+and you should see something like this:
+.Bd -literal -offset indent
+cpu0: UCode version: 0x1000080
+.Ed
+.Pp
+After applying the microcode patch with
+.Dl cpuctl ucode
+you can see with
+.Dl cpuctl identify 0
+that the patch got applied:
+.Bd -literal -offset indent
+cpu0: UCode version: 0x1000083
+.Ed
 .Sh FILES
 .Bl -tag -width /dev/cpuctl -compact
 .It Pa /dev/cpuctl
 control device
+.It Pa /libdata/firmware/x86/amd/
+The directory to install the microcode file for AMD CPUs into.
+The default filename is
+.Pa microcode_amd.bin
+for CPU families 0x10 to 0x14.
+The default filename is
+.Pa microcode_amd_famXXh.bin
+where
+.Dv XX
+is the CPU family starting with 15 (hex).
+Get it from
+.Pa http://www.amd64.org/support/microcode.html
 .El
 .Sh SEE ALSO
 .Xr psrset 8 ,

Index: src/usr.sbin/cpuctl/cpuctl.c
diff -u src/usr.sbin/cpuctl/cpuctl.c:1.19 src/usr.sbin/cpuctl/cpuctl.c:1.20
--- src/usr.sbin/cpuctl/cpuctl.c:1.19	Tue Sep 27 11:24:21 2011
+++ src/usr.sbin/cpuctl/cpuctl.c	Fri Jan 13 16:05:16 2012
@@ -1,7 +1,7 @@
-/*	$NetBSD: cpuctl.c,v 1.19 2011/09/27 11:24:21 jruoho Exp $	*/
+/*	$NetBSD: cpuctl.c,v 1.20 2012/01/13 16:05:16 cegger Exp $	*/
 
 /*-
- * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007, 2008, 2009, 2012 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -31,7 +31,7 @@
 
 #ifndef lint
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: cpuctl.c,v 1.19 2011/09/27 11:24:21 jruoho Exp $");
+__RCSID("$NetBSD: cpuctl.c,v 1.20 2012/01/13 16:05:16 cegger Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -63,19 +63,22 @@ static void	cpu_offline(char **);
 static void	cpu_online(char **);
 static void	cpu_intr(char **);
 static void	cpu_nointr(char **);
+static void	cpu_ucode(char **);
 
 static struct cmdtab {
 	const char	*label;
 	int	takesargs;
+	int	argsoptional;
 	void	(*func)(char **);
 } const cpu_cmdtab[] = {
-	{ "identify", 1, cpu_identify },
-	{ "list", 0, cpu_list },
-	{ "offline", 1, cpu_offline },
-	{ "online", 1, cpu_online },
-	{ "intr", 1, cpu_intr },
-	{ "nointr", 1, cpu_nointr },
-	{ NULL, 0, NULL },
+	{ "identify", 1, 0, cpu_identify },
+	{ "list", 0, 0, cpu_list },
+	{ "offline", 1, 0, cpu_offline },
+	{ "online", 1, 0, cpu_online },
+	{ "intr", 1, 0, cpu_intr },
+	{ "nointr", 1, 0, cpu_nointr },
+	{ "ucode", 1, 1, cpu_ucode },
+	{ NULL, 0, 0, NULL },
 };
 
 static int	fd;
@@ -93,8 +96,11 @@ main(int argc, char **argv)
 
 	for (ct = cpu_cmdtab; ct->label != NULL; ct++) {
 		if (strcmp(argv[1], ct->label) == 0) {
-			if ((ct->takesargs == 0) ^ (argv[2] == NULL))
-			    	usage();
+			if (!ct->argsoptional &&
+			    ((ct->takesargs == 0) ^ (argv[2] == NULL)))
+			{
+				usage();
+			}
 			(*ct->func)(argv + 2);
 			break;
 		}
@@ -119,6 +125,7 @@ usage(void)
 	fprintf(stderr, "       %s online cpuno\n", progname);
 	fprintf(stderr, "       %s intr cpuno\n", progname);
 	fprintf(stderr, "       %s nointr cpuno\n", progname);
+	fprintf(stderr, "       %s ucode [file]\n", progname);
 	exit(EXIT_FAILURE);
 	/* NOTREACHED */
 }
@@ -181,11 +188,34 @@ cpu_nointr(char **argv)
 }
 
 static void
+cpu_ucode(char **argv)
+{
+	int error;
+	struct cpu_ucode uc;
+
+	if (argv[0] != NULL)
+		strlcpy(uc.fwname, argv[0], sizeof(uc.fwname));
+	else
+		memset(uc.fwname, '\0', sizeof(uc.fwname));
+
+	error = ioctl(fd, IOC_CPU_UCODE_APPLY, &uc);
+	if (error < 0) {
+		if (uc.fwname[0])
+			err(EXIT_FAILURE, "%s", uc.fwname);
+		else
+			err(EXIT_FAILURE, "IOC_CPU_UCODE_APPLY");
+	}
+}
+
+
+static void
 cpu_identify(char **argv)
 {
 	char name[32];
 	unsigned int id, np;
 	cpuset_t *cpuset;
+	struct cpu_ucode ucode;
+	char ucbuf[16];
 
 	np = sysconf(_SC_NPROCESSORS_CONF);
 	id = getcpuid(argv);
@@ -209,6 +239,16 @@ cpu_identify(char **argv)
 		cpuset_destroy(cpuset);
 	}
 	identifycpu(name);
+
+	if (ioctl(fd, IOC_CPU_UCODE_GET_VERSION, &ucode) < 0)
+		ucode.version = (uint64_t)-1;
+	if (ucode.version == (uint64_t)-1)
+		strcpy(ucbuf, "?");
+	else
+		snprintf(ucbuf, sizeof(ucbuf), "0x%"PRIx64,
+		    ucode.version);
+
+	printf("%s: UCode version: %s\n", name, ucbuf);
 }
 
 static u_int
@@ -263,11 +303,13 @@ cpu_list(char **argv)
 			strcpy(ibuf, "?");
 		else
 			snprintf(ibuf, sizeof(ibuf), "%d", cs.cs_intrcnt - 1);
+
 		lastmod = (time_t)cs.cs_lastmod |
 		    ((time_t)cs.cs_lastmodhi << 32);
 		ts = asctime(localtime(&lastmod));
 		ts[strlen(ts) - 1] = '\0';
-		printf("%-4d %-4x %-12s %-10s %s %s\n", i, cs.cs_hwid, state,
+		printf("%-4d %-4x %-12s %-10s %s %-5s\n",
+		   i, cs.cs_hwid, state,
 		   intr, ts, ibuf);
 	}
 }

Added files:

Index: src/sys/arch/x86/include/cpu_ucode.h
diff -u /dev/null src/sys/arch/x86/include/cpu_ucode.h:1.1
--- /dev/null	Fri Jan 13 16:05:16 2012
+++ src/sys/arch/x86/include/cpu_ucode.h	Fri Jan 13 16:05:14 2012
@@ -0,0 +1,42 @@
+/* $NetBSD: cpu_ucode.h,v 1.1 2012/01/13 16:05:14 cegger Exp $ */
+/*
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *      
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _X86_CPU_UCODE_H_
+#define _X86_CPU_UCODE_H_
+
+#include <sys/cpu.h>
+#include <sys/cpuio.h>
+#include <dev/firmload.h>
+
+int cpu_ucode_amd_get_version(struct cpu_ucode *);
+int cpu_ucode_amd_firmware_open(firmware_handle_t *, const char *);
+int cpu_ucode_amd_apply(struct cpu_ucode_softc *);
+
+#endif

Index: src/sys/arch/x86/x86/cpu_ucode.c
diff -u /dev/null src/sys/arch/x86/x86/cpu_ucode.c:1.1
--- /dev/null	Fri Jan 13 16:05:16 2012
+++ src/sys/arch/x86/x86/cpu_ucode.c	Fri Jan 13 16:05:15 2012
@@ -0,0 +1,102 @@
+/* $NetBSD: cpu_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $ */
+/*
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: cpu_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $");
+
+#include "opt_cpu_ucode.h"
+
+#include <sys/param.h>
+#include <sys/cpuio.h>
+#include <sys/cpu.h>
+
+#include <dev/firmload.h>
+
+#include <machine/cpuvar.h>
+#include <machine/cputypes.h>
+
+#include <x86/cpu_ucode.h>
+
+static struct cpu_ucode_softc ucode_softc;
+
+int
+cpu_ucode_get_version(void *data)
+{
+	struct cpu_ucode *ucode = data;
+
+	switch (cpu_vendor) {
+	case CPUVENDOR_AMD:
+		return cpu_ucode_amd_get_version(ucode);
+	default:
+		ucode->version = (uint64_t)-1;
+		return EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+int
+cpu_ucode_md_open(firmware_handle_t *fwh, const char *fwname)
+{
+	switch (cpu_vendor) {
+	case CPUVENDOR_AMD:
+		return cpu_ucode_amd_firmware_open(fwh, fwname);
+	case CPUVENDOR_INTEL:
+		return EOPNOTSUPP; /* not yet supported */
+	default:
+		return EOPNOTSUPP;
+	}
+}
+
+int
+cpu_ucode_apply(void *data)
+{
+	struct cpu_ucode *ucode = data;
+	struct cpu_ucode_softc *sc = &ucode_softc;
+	int error;
+
+	error = cpu_ucode_load(sc, ucode->fwname);
+	if (error)
+		return error;
+
+	switch (cpu_vendor) {
+	case CPUVENDOR_AMD:
+		error = cpu_ucode_amd_apply(sc);
+		break;
+	default:
+		return EOPNOTSUPP;
+	}
+
+	if (sc->sc_blob != NULL)
+		firmware_free(sc->sc_blob, 0);
+	sc->sc_blob = NULL;
+	sc->sc_blobsize = 0;
+	return error;
+}
Index: src/sys/arch/x86/x86/cpu_ucode_amd.c
diff -u /dev/null src/sys/arch/x86/x86/cpu_ucode_amd.c:1.1
--- /dev/null	Fri Jan 13 16:05:16 2012
+++ src/sys/arch/x86/x86/cpu_ucode_amd.c	Fri Jan 13 16:05:15 2012
@@ -0,0 +1,292 @@
+/* $NetBSD: cpu_ucode_amd.c,v 1.1 2012/01/13 16:05:15 cegger Exp $ */
+/*
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: cpu_ucode_amd.c,v 1.1 2012/01/13 16:05:15 cegger Exp $");
+
+#include "opt_xen.h"
+#include "opt_cpu_ucode.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/cpuio.h>
+#include <sys/cpu.h>
+#include <sys/kmem.h>
+#include <sys/xcall.h>
+
+#include <machine/cpufunc.h>
+#include <machine/specialreg.h>
+#include <x86/cpu_ucode.h>
+
+struct microcode_amd_header {
+	uint32_t ah_data_code;
+	uint32_t ah_patch_id;
+	uint8_t ah_patch_data_id[2];
+	uint8_t ah_patch_data_len;
+	uint8_t ah_init_flag;
+	uint32_t ah_patch_data_checksum;
+	uint32_t ah_nb_dev_id;
+	uint32_t ah_sb_dev_id;
+	uint16_t ah_processor_rev_id;
+	uint8_t ah_nb_rev_id;
+	uint8_t ah_sb_rev_id;
+	uint8_t ah_bios_api_rev;
+	uint8_t ah_reserved[3];
+	uint32_t ah_match_reg[8];
+} __packed;
+
+/* equivalence cpu table */
+struct microcode_amd_equiv_cpu_table {
+	uint32_t ect_installed_cpu;
+	uint32_t ect_fixed_errata_mask;
+	uint32_t ect_fixed_errata_compare;
+	uint16_t ect_equiv_cpu;
+	uint16_t ect_reserved;
+};
+
+#define UCODE_MAGIC	0x00414d44
+
+struct microcode_amd {
+	uint8_t *mpb; /* microcode patch block */
+	size_t mpb_size;
+	struct microcode_amd_equiv_cpu_table *ect;
+	size_t ect_size;
+};
+
+struct mpbhdr {
+#define UCODE_TYPE_EQUIV	0
+#define UCODE_TYPE_PATCH	1
+	uint32_t mpb_type;
+	uint32_t mpb_len;
+	uint32_t mpb_data[];
+};
+
+static uint32_t
+amd_cpufamily(void)
+{
+	uint32_t family;
+	struct cpu_info *ci = curcpu();
+
+	family = CPUID2FAMILY(ci->ci_signature);
+	if (family == 0xf)
+		family += CPUID2EXTFAMILY(ci->ci_signature);
+
+	return family;
+}
+
+int
+cpu_ucode_amd_get_version(struct cpu_ucode *ucode)
+{
+	if (amd_cpufamily() < 0x10) {
+		ucode->version = (uint64_t)-1;
+		return EOPNOTSUPP;
+	}
+
+	ucode->version = rdmsr(MSR_UCODE_AMD_PATCHLEVEL);
+	return 0;
+}
+
+int
+cpu_ucode_amd_firmware_open(firmware_handle_t *fwh, const char *fwname)
+{
+	const char *fw_path = "x86/amd";
+	char _fwname[32];
+	int error;
+
+	if (fwname != NULL && fwname[0] != '\0')
+		return firmware_open(fw_path, fwname, fwh);
+
+	snprintf(_fwname, sizeof(_fwname), "microcode_amd_fam%xh.bin",
+	    amd_cpufamily());
+
+	error = firmware_open(fw_path, _fwname, fwh);
+	if (error == 0)
+		return 0;
+
+	return firmware_open(fw_path, "microcode_amd.bin", fwh);
+}
+
+#ifndef XEN
+struct mc_buf {
+	uint8_t *mc_buf;
+	uint32_t mc_equiv_cpuid;
+	struct mpbhdr *mc_mpbuf;
+	struct microcode_amd *mc_amd;
+	int mc_error;
+};
+
+static void
+cpu_apply_cb(void *arg0, void *arg1)
+{
+	int error = 0;
+	const struct cpu_ucode_softc *sc = arg0;
+	struct microcode_amd mc_amd;
+	struct mc_buf mc;
+	device_t dev;
+
+	memcpy(&mc, arg1, sizeof(mc));
+	mc_amd.mpb = mc.mc_amd->mpb;
+	mc_amd.mpb_size = mc.mc_amd->mpb_size;
+
+	dev = curcpu()->ci_dev;
+
+	do {
+		uint64_t patchlevel;
+		struct microcode_amd_header *hdr;
+
+		if (mc.mc_mpbuf->mpb_type != UCODE_TYPE_PATCH) {
+			aprint_debug_dev(dev, "ucode: patch type expected\n");
+			goto next;
+		}
+
+		hdr = (struct microcode_amd_header *)mc_amd.mpb;
+		if (hdr->ah_processor_rev_id != mc.mc_equiv_cpuid) {
+			aprint_debug_dev(dev, "ucode: patch does not"
+			    "match this cpu "
+			    "(patch is for cpu id %x, cpu id is %x)\n",
+			    hdr->ah_processor_rev_id, mc.mc_equiv_cpuid);
+			goto next;
+		}
+
+		patchlevel = rdmsr(MSR_UCODE_AMD_PATCHLEVEL);
+		if (hdr->ah_patch_id <= patchlevel)
+			goto next;
+
+		/* found matching microcode update */
+		wrmsr(MSR_UCODE_AMD_PATCHLOADER, (u_long)hdr);
+
+		/* check current patch id and patch's id for match */
+		if (patchlevel == rdmsr(MSR_UCODE_AMD_PATCHLEVEL)) {
+			aprint_debug_dev(dev, "ucode: update from revision "
+			    "0x%"PRIx64" to 0x%x failed\n",
+			    patchlevel, hdr->ah_patch_id);
+			error = EIO;
+			goto out;
+		} else {
+			/* Success */
+			error = 0;
+			goto out;
+		}
+
+next:
+		mc.mc_buf += mc.mc_mpbuf->mpb_len +
+		    sizeof(mc.mc_mpbuf->mpb_type) +
+		    sizeof(mc.mc_mpbuf->mpb_len);
+		mc.mc_mpbuf = (struct mpbhdr *)mc.mc_buf;
+		mc_amd.mpb = (uint8_t *)mc.mc_mpbuf->mpb_data;
+		mc_amd.mpb_size = mc.mc_mpbuf->mpb_len;
+
+	} while ((uintptr_t)((mc.mc_buf) - (uint8_t *)sc->sc_blob) < sc->sc_blobsize);
+	aprint_error_dev(dev, "ucode: No newer patch available "
+	    "for this cpu than is already installed.\n");
+	error = ENOENT;
+
+out:
+	if (error)
+		((struct mc_buf *)(arg1))->mc_error = error;
+}
+
+int
+cpu_ucode_amd_apply(struct cpu_ucode_softc *sc)
+{
+	int i, error = 0;
+	uint32_t *magic;
+	uint32_t cpu_signature;
+	uint32_t equiv_cpuid = 0;
+	struct mc_buf mc;
+	int where;
+
+	cpu_signature = curcpu()->ci_signature;
+
+	KASSERT(sc->sc_blob != NULL);
+	magic = (uint32_t *)sc->sc_blob;
+	if (*magic != UCODE_MAGIC) {
+		aprint_error("ucode: wrong file magic\n");
+		return EINVAL;
+	}
+
+	mc.mc_buf = &sc->sc_blob[sizeof(*magic)];
+	mc.mc_mpbuf = (struct mpbhdr *)mc.mc_buf;
+
+	/* equivalence table is expected to come first */
+	if (mc.mc_mpbuf->mpb_type != UCODE_TYPE_EQUIV) {
+		aprint_error("ucode: missing equivalence table\n");
+		return EINVAL;
+	}
+
+	mc.mc_amd = kmem_zalloc(sizeof(*mc.mc_amd), KM_NOSLEEP);
+	if (mc.mc_amd == NULL)
+		return ENOMEM;
+
+	mc.mc_amd->ect = kmem_alloc(mc.mc_mpbuf->mpb_len, KM_NOSLEEP);
+	if (mc.mc_amd->ect == NULL) {
+		error = ENOMEM;
+		goto err0;
+	}
+
+	memcpy(mc.mc_amd->ect, mc.mc_mpbuf->mpb_data, mc.mc_mpbuf->mpb_len);
+	mc.mc_amd->ect_size = mc.mc_mpbuf->mpb_len;
+
+	/* check if there is a patch for this cpu present */
+	for (i = 0; mc.mc_amd->ect[i].ect_installed_cpu != 0; i++) {
+		if (cpu_signature == mc.mc_amd->ect[i].ect_installed_cpu) {
+			/* keep extended family and extended model */
+			equiv_cpuid = mc.mc_amd->ect[i].ect_equiv_cpu & 0xffff;
+			break;
+		}
+	}
+	if (equiv_cpuid == 0) {
+		aprint_error("ucode: No patch available for this cpu\n");
+		error = ENOENT;
+		goto err1;
+	}
+
+	mc.mc_equiv_cpuid = equiv_cpuid;
+	mc.mc_buf += mc.mc_mpbuf->mpb_len + sizeof(mc.mc_mpbuf->mpb_type) +
+	    sizeof(mc.mc_mpbuf->mpb_len);
+	mc.mc_mpbuf = (struct mpbhdr *)mc.mc_buf;
+	mc.mc_amd->mpb = (uint8_t *)mc.mc_mpbuf->mpb_data;
+	mc.mc_amd->mpb_size = mc.mc_mpbuf->mpb_len;
+
+	/* Apply it on all cpus */
+	mc.mc_error = 0;
+	where = xc_broadcast(XC_HIGHPRI, cpu_apply_cb, sc, &mc);
+
+	/* Wait for completion */
+	xc_wait(where);
+	error = mc.mc_error;
+
+err1:
+	kmem_free(mc.mc_amd->ect, mc.mc_amd->ect_size);
+err0:
+	kmem_free(mc.mc_amd, sizeof(*mc.mc_amd));
+	return error;
+}
+#endif

Index: src/sys/arch/xen/xen/xen_ucode.c
diff -u /dev/null src/sys/arch/xen/xen/xen_ucode.c:1.1
--- /dev/null	Fri Jan 13 16:05:16 2012
+++ src/sys/arch/xen/xen/xen_ucode.c	Fri Jan 13 16:05:15 2012
@@ -0,0 +1,101 @@
+/* $NetBSD: xen_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $ */
+/*
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: xen_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $");
+
+#include "opt_cpu_ucode.h"
+
+#include <sys/param.h>
+#include <sys/cpuio.h>
+#include <sys/cpu.h>
+
+#include <dev/firmload.h>
+
+#include <machine/cpuvar.h>
+#include <machine/cputypes.h>
+
+#include <x86/cpu_ucode.h>
+
+static struct cpu_ucode_softc ucode_softc;
+
+int
+cpu_ucode_get_version(void *data)
+{
+	struct cpu_ucode *ucode = data;
+
+	switch (cpu_vendor) {
+	case CPUVENDOR_AMD:
+		return cpu_ucode_amd_get_version(ucode);
+	default:
+		ucode->version = (uint64_t)-1;
+		return EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+int
+cpu_ucode_md_open(firmware_handle_t *fwh, const char *fwname)
+{
+	switch (cpu_vendor) {
+	case CPUVENDOR_AMD:
+		return cpu_ucode_amd_firmware_open(fwh, fwname);
+	case CPUVENDOR_INTEL:
+		return EOPNOTSUPP; /* not yet supported */
+	default:
+		return EOPNOTSUPP;
+	}
+}
+
+int
+cpu_ucode_apply(void *data)
+{
+	struct cpu_ucode *ucode = data;
+	struct cpu_ucode_softc *sc = &ucode_softc;
+	struct xen_platform_op op;
+	int error;
+
+	error = cpu_ucode_load(sc, ucode->fwname);
+	if (error)
+		return error;
+
+	op.cmd = XENPF_microcode_update;
+	set_xen_guest_handle(op.u.microcode.data, sc->sc_blob);
+	op.u.microcode.length = sc->sc_blobsize;
+
+	error = -HYPERVISOR_platform_op(&op);
+
+	if (sc->sc_blob)
+		firmware_free(sc->sc_blob, 0);
+	sc->sc_blob = NULL;
+	sc->sc_blobsize = 0;
+	return error;
+}

Reply via email to