6747590 microcode update support for AMD
authorMark Johnson <Mark.Johnson@Sun.COM>
Mon, 15 Sep 2008 15:09:45 -0700
changeset 7605 b4a19682e632
parent 7604 dcba35b25c55
child 7606 473a8020ebec
6747590 microcode update support for AMD Contributed by Hans Rosenfeld <[email protected]>
usr/src/cmd/boot/bootadm/bootadm.c
usr/src/cmd/ucodeadm/ucodeadm.c
usr/src/common/ucode/ucode_utils.c
usr/src/uts/common/sys/ucode.h
usr/src/uts/i86pc/os/microcode.c
usr/src/uts/i86pc/os/mp_startup.c
usr/src/uts/intel/io/ucode_drv.c
usr/src/uts/intel/sys/controlregs.h
usr/src/uts/intel/sys/x86_archext.h
--- a/usr/src/cmd/boot/bootadm/bootadm.c	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/cmd/boot/bootadm/bootadm.c	Mon Sep 15 15:09:45 2008 -0700
@@ -7859,8 +7859,9 @@
 		struct stat fstatus, tstatus;
 		struct utimbuf u_times;
 
-		(void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.txt",
-		    bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr);
+		(void) snprintf(file, PATH_MAX, "%s/%s/%s-ucode.%s",
+		    bam_root, UCODE_INSTALL_PATH, ucode_vendors[i].filestr,
+		    ucode_vendors[i].extstr);
 
 		if (stat(file, &fstatus) != 0 || !(S_ISREG(fstatus.st_mode)))
 			continue;
--- a/usr/src/cmd/ucodeadm/ucodeadm.c	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/cmd/ucodeadm/ucodeadm.c	Mon Sep 15 15:09:45 2008 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/processor.h>
 #include <sys/ucode.h>
@@ -60,6 +58,19 @@
 
 static int	ucode_debug = 0;
 
+static int ucode_convert_amd(const char *, uint8_t *, size_t);
+static int ucode_convert_intel(const char *, uint8_t *, size_t);
+
+static ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *);
+static ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *);
+
+static const struct ucode_ops ucode_ops[] = {
+	{ ucode_convert_intel, ucode_gen_files_intel, ucode_validate_intel },
+	{ ucode_convert_amd, ucode_gen_files_amd, ucode_validate_amd },
+};
+
+const struct ucode_ops *ucode;
+
 static void
 dprintf(const char *format, ...)
 {
@@ -81,20 +92,19 @@
 		    gettext("\t\t Shows running microcode version.\n\n"));
 	}
 
-	(void) fprintf(stderr, "\t%s -u microcode-text-file\n", cmdname);
+	(void) fprintf(stderr, "\t%s -u microcode-file\n", cmdname);
 	if (verbose) {
 		(void) fprintf(stderr, gettext("\t\t Updates microcode to the "
 		    "latest matching version found in\n"
-		    "\t\t microcode-text-file.\n\n"));
+		    "\t\t microcode-file.\n\n"));
 	}
 
-	(void) fprintf(stderr, "\t%s -i [-R path] microcode-text-file\n",
-	    cmdname);
+	(void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname);
 	if (verbose) {
 		(void) fprintf(stderr, gettext("\t\t Installs microcode to be "
-		    "used for subsequent boots. Microcode\n"
-		    "\t\t text file name must start with vendor name, "
-		    "such as \"intel\".\n\n"));
+		    "used for subsequent boots.\n\n"));
+		(void) fprintf(stderr, gettext("Microcode file name must start "
+		    "with vendor name, such as \"intel\" or \"amd\".\n\n"));
 	}
 }
 
@@ -113,7 +123,25 @@
  * Return the number of characters read.
  */
 static int
-ucode_convert(const char *infile, uint8_t *buf, size_t size)
+ucode_convert_amd(const char *infile, uint8_t *buf, size_t size)
+{
+	int fd;
+
+	if (infile == NULL || buf == NULL || size == 0)
+		return (0);
+
+	if ((fd = open(infile, O_RDONLY)) < 0)
+		return (0);
+
+	size = read(fd, buf, size);
+
+	(void) close(fd);
+
+	return (size);
+}
+
+static int
+ucode_convert_intel(const char *infile, uint8_t *buf, size_t size)
 {
 	char	linebuf[LINESIZE];
 	FILE	*infd = NULL;
@@ -173,11 +201,11 @@
  * Returns 0 if no need to update the link; -1 otherwise
  */
 static int
-ucode_should_update(char *filename, uint32_t new_rev)
+ucode_should_update_intel(char *filename, uint32_t new_rev)
 {
 	int		fd;
 	struct stat	statbuf;
-	ucode_header_t	header;
+	ucode_header_intel_t header;
 
 	/*
 	 * If the file or link already exists, check to see if
@@ -205,7 +233,64 @@
  * Generate microcode binary files.  Must be called after ucode_validate().
  */
 static ucode_errno_t
-ucode_gen_files(uint8_t *buf, int size, char *path)
+ucode_gen_files_amd(uint8_t *buf, int size, char *path)
+{
+	/* LINTED: pointer alignment */
+	uint32_t *ptr = (uint32_t *)buf;
+	int plen = strlen(path);
+	int fd, count, counter;
+	ucode_header_amd_t *uh;
+	int last_cpu_rev = 0;
+
+	/* skip over magic number & equivalence table header */
+	ptr += 2; size -= 8;
+
+	count = *ptr++; size -= 4;
+
+	/* equivalence table uses special name */
+	(void) strlcat(path, "/equivalence-table", PATH_MAX);
+
+	for (;;) {
+		dprintf("path = %s\n", path);
+		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC,
+		    S_IRUSR | S_IRGRP | S_IROTH);
+
+		if (fd == -1) {
+			ucode_perror(path, EM_SYS);
+			return (EM_SYS);
+		}
+
+		if (write(fd, ptr, count) != count) {
+			(void) close(fd);
+			ucode_perror(path, EM_SYS);
+			return (EM_SYS);
+		}
+
+		(void) close(fd);
+		ptr += count >> 2; size -= count;
+
+		if (!size)
+			return (EM_OK);
+
+		ptr++; size -= 4;
+		count = *ptr++; size -= 4;
+
+		/* construct name from header information */
+		uh = (ucode_header_amd_t *)ptr;
+
+		if (uh->uh_cpu_rev != last_cpu_rev) {
+			last_cpu_rev = uh->uh_cpu_rev;
+			counter = 0;
+		}
+
+		path[plen] = '\0';
+		(void) snprintf(path + plen, PATH_MAX - plen, "/%04X-%02X",
+		    uh->uh_cpu_rev, counter++);
+	}
+}
+
+static ucode_errno_t
+ucode_gen_files_intel(uint8_t *buf, int size, char *path)
 {
 	int	remaining;
 	char	common_path[PATH_MAX];
@@ -226,11 +311,13 @@
 		char		name[PATH_MAX];
 		int		i;
 		uint8_t		*curbuf = &buf[size - remaining];
-		ucode_header_t	*uhp = (ucode_header_t *)(intptr_t)curbuf;
-		ucode_ext_table_t *extp;
+		ucode_header_intel_t	*uhp;
+		ucode_ext_table_intel_t *extp;
 
-		total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size);
-		body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
+		uhp = (ucode_header_intel_t *)(intptr_t)curbuf;
+
+		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
+		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
 
 		remaining -= total_size;
 
@@ -238,7 +325,7 @@
 		    common_path, uhp->uh_signature, uhp->uh_proc_flags);
 		dprintf("firstname = %s\n", firstname);
 
-		if (ucode_should_update(firstname, uhp->uh_rev) != 0) {
+		if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) {
 			int fd;
 
 			/* Remove the existing one first */
@@ -275,7 +362,7 @@
 			dprintf("proc_flags = %x, platid = %x, name = %s\n",
 			    uhp->uh_proc_flags, platid, name);
 
-			if (ucode_should_update(name, uhp->uh_rev) != 0) {
+			if (ucode_should_update_intel(name, uhp->uh_rev) != 0) {
 
 				/* Remove the existing one first */
 				(void) unlink(name);
@@ -290,17 +377,17 @@
 				break;
 		}
 
-		offset = UCODE_HEADER_SIZE + body_size;
+		offset = UCODE_HEADER_SIZE_INTEL + body_size;
 
 		/* Check to see if there is extended signature table */
 		if (total_size == offset)
 			continue;
 
 		/* There is extended signature table.  More processing. */
-		extp = (ucode_ext_table_t *)(uintptr_t)&curbuf[offset];
+		extp = (ucode_ext_table_intel_t *)(uintptr_t)&curbuf[offset];
 
 		for (i = 0; i < extp->uet_count; i++) {
-			ucode_ext_sig_t *uesp = &extp->uet_ext_sig[i];
+			ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i];
 			int j;
 
 			for (j = 0; j < 8; j++) {
@@ -313,8 +400,8 @@
 				    "%s/%08X-%02X", path, extp->uet_ext_sig[i],
 				    id);
 
-				if (ucode_should_update(name, uhp->uh_rev) !=
-				    0) {
+				if (ucode_should_update_intel(name, uhp->uh_rev)
+				    != 0) {
 
 					/* Remove the existing one first */
 					(void) unlink(name);
@@ -460,6 +547,29 @@
 	 * Convert from text format to binary format
 	 */
 	if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) {
+		int i;
+		UCODE_VENDORS;
+
+		for (i = 0; ucode_vendors[i].filestr != NULL; i++) {
+			dprintf("i = %d, filestr = %s, filename = %s\n",
+			    i, ucode_vendors[i].filestr, filename);
+			if (strncasecmp(ucode_vendors[i].filestr,
+			    basename(filename),
+			    strlen(ucode_vendors[i].filestr)) == 0) {
+				ucode = &ucode_ops[i];
+				(void) strncpy(ucode_vendor_str,
+				    ucode_vendors[i].vendorstr,
+				    sizeof (ucode_vendor_str));
+				break;
+			}
+		}
+
+		if (ucode_vendors[i].filestr == NULL) {
+			rc = EM_NOVENDOR;
+			ucode_perror(basename(filename), rc);
+			goto err_out;
+		}
+
 		if ((stat(filename, &filestat)) < 0) {
 			rc = EM_SYS;
 			ucode_perror(filename, rc);
@@ -479,7 +589,7 @@
 			goto err_out;
 		}
 
-		ucode_size = ucode_convert(filename, buf, filestat.st_size);
+		ucode_size = ucode->convert(filename, buf, filestat.st_size);
 
 		dprintf("ucode_size = %d\n", ucode_size);
 
@@ -489,7 +599,7 @@
 			goto err_out;
 		}
 
-		if ((rc = ucode_validate(buf, ucode_size)) != EM_OK) {
+		if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) {
 			ucode_perror(filename, rc);
 			goto err_out;
 		}
@@ -500,29 +610,6 @@
 	 * "intel" for Intel microcode, and "amd" for AMD microcode.
 	 */
 	if (action & UCODE_OPT_INSTALL) {
-		int i;
-		UCODE_VENDORS;
-
-		for (i = 0; ucode_vendors[i].filestr != NULL; i++) {
-			dprintf("i = %d, filestr = %s, filename = %s\n",
-			    i, ucode_vendors[i].filestr, filename);
-			if (strncasecmp(ucode_vendors[i].filestr,
-			    basename(filename),
-			    strlen(ucode_vendors[i].filestr)) == 0) {
-
-				(void) strncpy(ucode_vendor_str,
-				    ucode_vendors[i].vendorstr,
-				    sizeof (ucode_vendor_str));
-				break;
-			}
-		}
-
-		if (ucode_vendors[i].filestr == NULL) {
-			rc = EM_NOVENDOR;
-			ucode_perror(basename(filename), rc);
-			goto err_out;
-		}
-
 		/*
 		 * If no path is provided by the -R option, put the files in
 		 * /ucode_install_path/ucode_vendor_str/.
@@ -544,7 +631,7 @@
 			goto err_out;
 		}
 
-		rc = ucode_gen_files(buf, ucode_size, path);
+		rc = ucode->gen_files(buf, ucode_size, path);
 
 		goto err_out;
 	}
--- a/usr/src/common/ucode/ucode_utils.c	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/common/ucode/ucode_utils.c	Mon Sep 15 15:09:45 2008 -0700
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/ucode.h>
 #ifdef	_KERNEL
@@ -46,7 +44,7 @@
  * Returns EM_OK on success, EM_HEADER on failure.
  */
 ucode_errno_t
-ucode_header_validate(ucode_header_t *uhp)
+ucode_header_validate_intel(ucode_header_intel_t *uhp)
 {
 	uint32_t header_size, body_size, total_size;
 
@@ -59,9 +57,9 @@
 	if (uhp->uh_header_ver != 0x1)
 		return (EM_HEADER);
 
-	header_size = UCODE_HEADER_SIZE;
-	total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size);
-	body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
+	header_size = UCODE_HEADER_SIZE_INTEL;
+	total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
+	body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
 
 	/*
 	 * The body size field of the microcode code header specifies the size
@@ -91,7 +89,7 @@
 	 */
 	if (total_size > (header_size + body_size)) {
 		if ((total_size - body_size - header_size -
-		    UCODE_EXT_TABLE_SIZE) % UCODE_EXT_SIG_SIZE) {
+		    UCODE_EXT_TABLE_SIZE_INTEL) % UCODE_EXT_SIG_SIZE_INTEL) {
 
 			return (EM_HEADER);
 		}
@@ -104,7 +102,7 @@
  * Returns checksum.
  */
 uint32_t
-ucode_checksum(uint32_t sum, uint32_t size, uint8_t *code)
+ucode_checksum_intel(uint32_t sum, uint32_t size, uint8_t *code)
 {
 	int i;
 	uint32_t *lcode = (uint32_t *)(intptr_t)code;
@@ -117,9 +115,65 @@
 }
 
 ucode_errno_t
-ucode_validate(uint8_t *ucodep, int size)
+ucode_validate_amd(uint8_t *ucodep, int size)
 {
-	uint32_t header_size = UCODE_HEADER_SIZE;
+	/* LINTED: pointer alignment */
+	uint32_t *ptr = (uint32_t *)ucodep;
+	uint32_t count;
+
+	if (ucodep == NULL || size <= 0)
+		return (EM_INVALIDARG);
+
+	/* Magic Number: "AMD\0" */
+	size -= 4;
+	if (*ptr++ != 0x00414d44)
+		return (EM_FILEFORMAT);
+
+	/* equivalence table */
+	size -= 4;
+	if (*ptr++)
+		return (EM_FILEFORMAT);
+
+	size -= 4;
+	if (((count = *ptr++) > size) || (count % 16))
+		return (EM_FILEFORMAT);
+
+	/* LINTED: pointer alignment */
+	ptr = (uint32_t *)(((uint8_t *)ptr) + count);
+	size -= count;
+
+	/*
+	 * minimum valid size:
+	 * - type and size fields (8 bytes)
+	 * - patch header (64 bytes)
+	 * - one patch triad (28 bytes)
+	 */
+	while (size >= 100) {
+		/* microcode patch */
+		size -= 4;
+		if (*ptr++ != 1)
+			return (EM_FILEFORMAT);
+
+		size -= 4;
+		if (((count = *ptr++) > size) ||
+		    ((count - sizeof (ucode_header_amd_t)) % 28))
+			return (EM_FILEFORMAT);
+
+		/* LINTED: pointer alignment */
+		ptr = (uint32_t *)(((uint8_t *)ptr) + count);
+		size -= count;
+	}
+
+	if (size)
+		return (EM_FILEFORMAT);
+
+	return (EM_OK);
+}
+
+ucode_errno_t
+ucode_validate_intel(uint8_t *ucodep, int size)
+{
+	uint32_t header_size = UCODE_HEADER_SIZE_INTEL;
 	int remaining;
 
 	if (ucodep == NULL || size <= 0)
@@ -127,36 +181,38 @@
 
 	for (remaining = size; remaining > 0; ) {
 		uint32_t total_size, body_size, ext_size;
-		ucode_header_t *uhp;
+		ucode_header_intel_t *uhp;
 		uint8_t *curbuf = &ucodep[size - remaining];
 		ucode_errno_t rc;
 
-		uhp = (ucode_header_t *)(intptr_t)curbuf;
+		uhp = (ucode_header_intel_t *)(intptr_t)curbuf;
 
-		if ((rc = ucode_header_validate(uhp)) != EM_OK)
+		if ((rc = ucode_header_validate_intel(uhp)) != EM_OK)
 			return (rc);
 
-		total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size);
+		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
 
-		if (ucode_checksum(0, total_size, curbuf))
+		if (ucode_checksum_intel(0, total_size, curbuf))
 			return (EM_CHECKSUM);
 
-		body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
+		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
 		ext_size = total_size - (header_size + body_size);
 
 		if (ext_size > 0) {
 			uint32_t i;
 
-			if (ucode_checksum(0, ext_size,
+			if (ucode_checksum_intel(0, ext_size,
 			    &curbuf[header_size + body_size])) {
 				return (EM_CHECKSUM);
 			}
 
-			ext_size -= UCODE_EXT_TABLE_SIZE;
-			for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE; i++) {
-				if (ucode_checksum(0, UCODE_EXT_SIG_SIZE,
+			ext_size -= UCODE_EXT_TABLE_SIZE_INTEL;
+			for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE_INTEL;
+			    i++) {
+				if (ucode_checksum_intel(0,
+				    UCODE_EXT_SIG_SIZE_INTEL,
 				    &curbuf[total_size - ext_size +
-				    i * UCODE_EXT_SIG_SIZE])) {
+				    i * UCODE_EXT_SIG_SIZE_INTEL])) {
 
 					return (EM_CHECKSUM);
 				}
--- a/usr/src/uts/common/sys/ucode.h	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/uts/common/sys/ucode.h	Mon Sep 15 15:09:45 2008 -0700
@@ -19,15 +19,16 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_UCODE_H
 #define	_SYS_UCODE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
+#ifdef _KERNEL
+#include <sys/cpuvar.h>
+#endif
 #include <sys/types.h>
 #include <sys/priv.h>
 #include <sys/processor.h>
@@ -92,9 +93,41 @@
 #endif	/* _SYSCALL32_IMPL */
 
 /*
- * Microcode file information
+ * AMD Microcode file information
  */
-typedef struct ucode_header {
+typedef struct ucode_header_amd {
+	uint32_t uh_date;
+	uint32_t uh_patch_id;
+	uint32_t uh_internal; /* patch data id & length, init flag */
+	uint32_t uh_cksum;
+	uint32_t uh_nb_id;
+	uint32_t uh_sb_id;
+	uint16_t uh_cpu_rev;
+	uint8_t  uh_nb_rev;
+	uint8_t  uh_sb_rev;
+	uint32_t uh_bios_rev;
+	uint32_t uh_match[8];
+} ucode_header_amd_t;
+
+typedef struct ucode_file_amd {
+	ucode_header_amd_t uf_header;
+	uint8_t uf_data[896];
+	uint8_t uf_resv[896];
+	uint8_t uf_code_present;
+	uint8_t uf_code[191];
+} ucode_file_amd_t;
+
+typedef struct ucode_eqtbl_amd {
+	uint32_t ue_inst_cpu;
+	uint32_t ue_fixed_mask;
+	uint32_t ue_fixed_comp;
+	uint32_t ue_equiv_cpu;
+} ucode_eqtbl_amd_t;
+
+/*
+ * Intel Microcode file information
+ */
+typedef struct ucode_header_intel {
 	uint32_t	uh_header_ver;
 	uint32_t	uh_rev;
 	uint32_t	uh_date;
@@ -105,25 +138,33 @@
 	uint32_t	uh_body_size;
 	uint32_t	uh_total_size;
 	uint32_t	uh_reserved[3];
-} ucode_header_t;
+} ucode_header_intel_t;
 
-typedef struct ucode_ext_sig {
+typedef struct ucode_ext_sig_intel {
 	uint32_t	ues_signature;
 	uint32_t	ues_proc_flags;
 	uint32_t	ues_checksum;
-} ucode_ext_sig_t;
+} ucode_ext_sig_intel_t;
 
-typedef struct ucode_ext_table {
+typedef struct ucode_ext_table_intel {
 	uint32_t	uet_count;
 	uint32_t	uet_checksum;
 	uint32_t	uet_reserved[3];
-	ucode_ext_sig_t uet_ext_sig[1];
-} ucode_ext_table_t;
+	ucode_ext_sig_intel_t uet_ext_sig[1];
+} ucode_ext_table_intel_t;
 
-typedef struct ucode_file {
-	ucode_header_t		uf_header;
+typedef struct ucode_file_intel {
+	ucode_header_intel_t	*uf_header;
 	uint8_t			*uf_body;
-	ucode_ext_table_t	*uf_ext_table;
+	ucode_ext_table_intel_t	*uf_ext_table;
+} ucode_file_intel_t;
+
+/*
+ * common container
+ */
+typedef union ucode_file {
+	ucode_file_amd_t *amd;
+	ucode_file_intel_t intel;
 } ucode_file_t;
 
 
@@ -139,14 +180,14 @@
 #define	UCODE_MAX_PATH_LEN	(PATH_MAX - UCODE_COMMON_NAME_LEN)
 
 
-#define	UCODE_HEADER_SIZE	(sizeof (struct ucode_header))
-#define	UCODE_EXT_TABLE_SIZE	(20)	/* 20-bytes */
-#define	UCODE_EXT_SIG_SIZE	(sizeof (struct ucode_ext_sig))
+#define	UCODE_HEADER_SIZE_INTEL		(sizeof (struct ucode_header_intel))
+#define	UCODE_EXT_TABLE_SIZE_INTEL	(20)	/* 20-bytes */
+#define	UCODE_EXT_SIG_SIZE_INTEL	(sizeof (struct ucode_ext_sig_intel))
 
 #define	UCODE_KB(a)	((a) << 10)	/* KB */
 #define	UCODE_MB(a)	((a) << 20)	/* MB */
 #define	UCODE_DEFAULT_TOTAL_SIZE	UCODE_KB(2)
-#define	UCODE_DEFAULT_BODY_SIZE		(UCODE_KB(2) - UCODE_HEADER_SIZE)
+#define	UCODE_DEFAULT_BODY_SIZE		(UCODE_KB(2) - UCODE_HEADER_SIZE_INTEL)
 
 /*
  * For a single microcode file, the minimum size is 1K, maximum size is 16K.
@@ -164,35 +205,87 @@
 #define	UCODE_SIZE_CONVERT(size, default_size) \
 	((size) == 0 ? (default_size) : (size))
 
-#define	UCODE_BODY_SIZE(size) \
+#define	UCODE_BODY_SIZE_INTEL(size) \
 	UCODE_SIZE_CONVERT((size), UCODE_DEFAULT_BODY_SIZE)
 
-#define	UCODE_TOTAL_SIZE(size) \
+#define	UCODE_TOTAL_SIZE_INTEL(size)			\
 	UCODE_SIZE_CONVERT((size), UCODE_DEFAULT_TOTAL_SIZE)
 
-#define	UCODE_MATCH(sig1, sig2, pf1, pf2) \
+#define	UCODE_MATCH_INTEL(sig1, sig2, pf1, pf2) \
 	(((sig1) == (sig2)) && \
 	(((pf1) & (pf2)) || (((pf1) == 0) && ((pf2) == 0))))
 
-extern ucode_errno_t ucode_header_validate(ucode_header_t *);
-extern uint32_t ucode_checksum(uint32_t, uint32_t, uint8_t *);
-extern ucode_errno_t ucode_validate(uint8_t *, int);
+extern ucode_errno_t ucode_header_validate_intel(ucode_header_intel_t *);
+extern uint32_t ucode_checksum_intel(uint32_t, uint32_t, uint8_t *);
+
+extern ucode_errno_t ucode_validate_amd(uint8_t *, int);
+extern ucode_errno_t ucode_validate_intel(uint8_t *, int);
+
+#ifdef _KERNEL
 extern ucode_errno_t ucode_get_rev(uint32_t *);
 extern ucode_errno_t ucode_update(uint8_t *, int);
 
+/*
+ * Microcode specific information per core
+ */
+typedef struct cpu_ucode_info {
+	uint32_t	cui_platid;	/* platform id */
+	uint32_t	cui_rev;	/* microcode revision */
+} cpu_ucode_info_t;
+
+/*
+ * Data structure used for xcall
+ */
+typedef struct ucode_update {
+	uint32_t		sig;	/* signature */
+	cpu_ucode_info_t	info;	/* ucode info */
+	uint32_t		expected_rev;
+	uint32_t		new_rev;
+	uint8_t			*ucodep; /* pointer to ucode */
+	uint32_t		usize;
+} ucode_update_t;
+
+/*
+ * Microcode kernel operations
+ */
+struct ucode_ops {
+	uint32_t	write_msr;
+	int		(*capable)(cpu_t *);
+	void		(*file_reset)(ucode_file_t *, processorid_t);
+	void		(*read_rev)(cpu_ucode_info_t *);
+	uint32_t	(*load)(ucode_file_t *, cpu_ucode_info_t *, cpu_t *);
+	ucode_errno_t	(*validate)(uint8_t *, int);
+	ucode_errno_t	(*extract)(ucode_update_t *, uint8_t *, int);
+	ucode_errno_t	(*locate)(cpu_t *, cpu_ucode_info_t *, ucode_file_t *);
+};
+#else
+
 #define	UCODE_MAX_VENDORS_NAME_LEN		20
 
 #define	UCODE_VENDORS				\
 static struct {					\
 	char *filestr;				\
+	char *extstr;				\
 	char *vendorstr;			\
 	int  supported;				\
 } ucode_vendors[] = {				\
-	{ "intel", "GenuineIntel", 1 },		\
-	{ "amd", "AuthenticAMD", 0 },		\
-	{ NULL, NULL, 0 }				\
+	{ "intel", "txt", "GenuineIntel", 1 },	\
+	{ "amd", "bin", "AuthenticAMD", 1 },	\
+	{ NULL, NULL, NULL, 0 }			\
 }
 
+/*
+ * Microcode user operations
+ */
+struct ucode_ops {
+	int		(*convert)(const char *, uint8_t *, size_t);
+	ucode_errno_t	(*gen_files)(uint8_t *, int, char *);
+	ucode_errno_t	(*validate)(uint8_t *, int);
+};
+#endif
+
+extern const struct ucode_ops *ucode;
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/i86pc/os/microcode.c	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/uts/i86pc/os/microcode.c	Mon Sep 15 15:09:45 2008 -0700
@@ -48,42 +48,75 @@
 #endif
 
 /*
- * Microcode specific information per core
+ * AMD-specific equivalence table
  */
-struct cpu_ucode_info {
-	uint32_t	cui_platid;	/* platform id */
-	uint32_t	cui_rev;	/* microcode revision */
-};
-
-/*
- * Data structure used for xcall
- */
-struct ucode_update_struct {
-	uint32_t		sig;	/* signature */
-	struct cpu_ucode_info	info;	/* ucode info */
-	uint32_t		expected_rev;
-	uint32_t		new_rev;
-	uint8_t			*ucodep; /* pointer to ucode body */
-};
+static ucode_eqtbl_amd_t *ucode_eqtbl_amd;
 
 /*
  * mcpu_ucode_info for the boot CPU.  Statically allocated.
  */
 static struct cpu_ucode_info cpu_ucode_info0;
 
-static ucode_file_t ucodefile = { 0 };
+static ucode_file_t ucodefile;
+
+static void* ucode_zalloc(processorid_t, size_t);
+static void ucode_free(processorid_t, void *, size_t);
+
+static int ucode_capable_amd(cpu_t *);
+static int ucode_capable_intel(cpu_t *);
+
+static ucode_errno_t ucode_extract_amd(ucode_update_t *, uint8_t *, int);
+static ucode_errno_t ucode_extract_intel(ucode_update_t *, uint8_t *,
+    int);
+
+static void ucode_file_reset_amd(ucode_file_t *, processorid_t);
+static void ucode_file_reset_intel(ucode_file_t *, processorid_t);
+
+static uint32_t ucode_load_amd(ucode_file_t *, cpu_ucode_info_t *, cpu_t *);
+static uint32_t ucode_load_intel(ucode_file_t *, cpu_ucode_info_t *, cpu_t *);
+
+#ifdef	__xpv
+static void ucode_load_xpv(ucode_update_t *);
+#endif
+
+static int ucode_equiv_cpu_amd(cpu_t *, int *);
+
+static ucode_errno_t ucode_locate_amd(cpu_t *, cpu_ucode_info_t *,
+    ucode_file_t *);
+static ucode_errno_t ucode_locate_intel(cpu_t *, cpu_ucode_info_t *,
+    ucode_file_t *);
 
-static int ucode_capable(cpu_t *);
-static void ucode_file_reset(ucode_file_t *, processorid_t);
-static ucode_errno_t ucode_match(int, struct cpu_ucode_info *,
-    ucode_header_t *, ucode_ext_table_t *);
-static ucode_errno_t ucode_locate(cpu_t *, struct cpu_ucode_info *,
-    ucode_file_t *);
-static void ucode_update_intel(uint8_t *, struct cpu_ucode_info *);
-static void ucode_read_rev(struct cpu_ucode_info *);
-#ifdef	__xpv
-static void ucode_update_xpv(struct ucode_update_struct *, uint8_t *, uint32_t);
-#endif
+static ucode_errno_t ucode_match_amd(int, cpu_ucode_info_t *,
+    ucode_file_amd_t *, int);
+static ucode_errno_t ucode_match_intel(int, cpu_ucode_info_t *,
+    ucode_header_intel_t *, ucode_ext_table_intel_t *);
+
+static void ucode_read_rev_amd(cpu_ucode_info_t *);
+static void ucode_read_rev_intel(cpu_ucode_info_t *);
+
+static const struct ucode_ops ucode_amd = {
+	MSR_AMD_PATCHLOADER,
+	ucode_capable_amd,
+	ucode_file_reset_amd,
+	ucode_read_rev_amd,
+	ucode_load_amd,
+	ucode_validate_amd,
+	ucode_extract_amd,
+	ucode_locate_amd
+};
+
+static const struct ucode_ops ucode_intel = {
+	MSR_INTC_UCODE_WRITE,
+	ucode_capable_intel,
+	ucode_file_reset_intel,
+	ucode_read_rev_intel,
+	ucode_load_intel,
+	ucode_validate_intel,
+	ucode_extract_intel,
+	ucode_locate_intel
+};
+
+const struct ucode_ops *ucode;
 
 static const char ucode_failure_fmt[] =
 	"cpu%d: failed to update microcode from version 0x%x to 0x%x\n";
@@ -122,19 +155,73 @@
  * space allocated for the microcode file.
  */
 void
-ucode_free()
+ucode_cleanup()
 {
-	ucode_file_reset(&ucodefile, -1);
+	ASSERT(ucode);
+
+	ucode->file_reset(&ucodefile, -1);
+}
+
+/*
+ * Allocate/free a buffer used to hold ucode data. Space for the boot CPU is
+ * allocated with BOP_ALLOC() and does not require a free.
+ */
+static void*
+ucode_zalloc(processorid_t id, size_t size)
+{
+	if (id)
+		return (kmem_zalloc(size, KM_NOSLEEP));
+
+	/* BOP_ALLOC() failure results in panic */
+	return (BOP_ALLOC(bootops, NULL, size, MMU_PAGESIZE));
+}
+
+static void
+ucode_free(processorid_t id, void* buf, size_t size)
+{
+	if (id)
+		kmem_free(buf, size);
 }
 
 /*
  * Check whether or not a processor is capable of microcode operations
  * Returns 1 if it is capable, 0 if not.
+ *
+ * At this point we only support microcode update for:
+ * - Intel processors family 6 and above, and
+ * - AMD processors family 0x10 and above.
+ *
+ * We also assume that we don't support a mix of Intel and
+ * AMD processors in the same box.
+ *
+ * An i86xpv guest domain can't update the microcode.
  */
+/*ARGSUSED*/
 static int
-ucode_capable(cpu_t *cp)
+ucode_capable_amd(cpu_t *cp)
 {
-	/* i86xpv guest domain can't update microcode */
+#ifndef	__xpv
+	extern int xpv_is_hvm;
+	if (xpv_is_hvm) {
+		return (0);
+	}
+
+	return (cpuid_getfamily(cp) >= 0x10);
+#else
+	if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
+		return (0);
+	}
+
+	/*
+	 * XXPV - change when microcode loading works in dom0. Don't support
+	 * microcode loading in dom0 right now for AMD.
+	 */
+	return (0);
+#endif
+}
+static int
+ucode_capable_intel(cpu_t *cp)
+{
 #ifndef	__xpv
 	extern int xpv_is_hvm;
 	if (xpv_is_hvm) {
@@ -145,19 +232,7 @@
 		return (0);
 	}
 #endif
-
-	/*
-	 * At this point we only support microcode update for Intel
-	 * processors family 6 and above.
-	 *
-	 * We also assume that we don't support a mix of Intel and
-	 * AMD processors in the same box.
-	 */
-	if (cpuid_getvendor(cp) != X86_VENDOR_Intel ||
-	    cpuid_getfamily(cp) < 6)
-		return (0);
-	else
-		return (1);
+	return (cpuid_getfamily(cp) >= 6);
 }
 
 /*
@@ -165,37 +240,124 @@
  * or when the cached microcode doesn't match the CPU being processed.
  */
 static void
-ucode_file_reset(ucode_file_t *ucodefp, processorid_t id)
+ucode_file_reset_amd(ucode_file_t *ufp, processorid_t id)
 {
-	int total_size, body_size;
+	ucode_file_amd_t *ucodefp = ufp->amd;
 
 	if (ucodefp == NULL)
 		return;
 
-	total_size = UCODE_TOTAL_SIZE(ucodefp->uf_header.uh_total_size);
-	body_size = UCODE_BODY_SIZE(ucodefp->uf_header.uh_body_size);
+	ucode_free(id, ucodefp, sizeof (ucode_file_amd_t));
+	ufp->amd = NULL;
+}
+
+static void
+ucode_file_reset_intel(ucode_file_t *ufp, processorid_t id)
+{
+	ucode_file_intel_t *ucodefp = &ufp->intel;
+	int total_size, body_size;
+
+	if (ucodefp == NULL || ucodefp->uf_header == NULL)
+		return;
+
+	total_size = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size);
+	body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size);
 	if (ucodefp->uf_body) {
-		/*
-		 * Space for the boot CPU is allocated with BOP_ALLOC()
-		 * and does not require a free.
-		 */
-		if (id != 0)
-			kmem_free(ucodefp->uf_body, body_size);
+		ucode_free(id, ucodefp->uf_body, body_size);
 		ucodefp->uf_body = NULL;
 	}
 
 	if (ucodefp->uf_ext_table) {
-		int size = total_size - body_size - UCODE_HEADER_SIZE;
-		/*
-		 * Space for the boot CPU is allocated with BOP_ALLOC()
-		 * and does not require a free.
-		 */
-		if (id != 0)
-			kmem_free(ucodefp->uf_ext_table, size);
+		int size = total_size - body_size - UCODE_HEADER_SIZE_INTEL;
+
+		ucode_free(id, ucodefp->uf_ext_table, size);
 		ucodefp->uf_ext_table = NULL;
 	}
 
-	bzero(&ucodefp->uf_header, UCODE_HEADER_SIZE);
+	ucode_free(id, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL);
+	ucodefp->uf_header = NULL;
+}
+
+/*
+ * Find the equivalent CPU id in the equivalence table.
+ */
+static int
+ucode_equiv_cpu_amd(cpu_t *cp, int *eq_sig)
+{
+	char name[MAXPATHLEN];
+	intptr_t fd;
+	int count;
+	int offset = 0, cpi_sig = cpuid_getsig(cp);
+	ucode_eqtbl_amd_t *eqtbl = ucode_eqtbl_amd;
+
+	(void) snprintf(name, MAXPATHLEN, "/%s/%s/equivalence-table",
+	    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp));
+
+	/*
+	 * No kmem_zalloc() etc. available on boot cpu.
+	 */
+	if (cp->cpu_id == 0) {
+		if ((fd = kobj_open(name)) == -1)
+			return (EM_OPENFILE);
+		/* ucode_zalloc() cannot fail on boot cpu */
+		eqtbl = ucode_zalloc(cp->cpu_id, sizeof (*eqtbl));
+		ASSERT(eqtbl);
+		do {
+			count = kobj_read(fd, (int8_t *)eqtbl,
+			    sizeof (*eqtbl), offset);
+			if (count != sizeof (*eqtbl)) {
+				(void) kobj_close(fd);
+				return (EM_HIGHERREV);
+			}
+			offset += count;
+		} while (eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig);
+		(void) kobj_close(fd);
+	}
+
+	/*
+	 * If not already done, load the equivalence table.
+	 * Not done on boot CPU.
+	 */
+	if (eqtbl == NULL) {
+		struct _buf *eq;
+		uint64_t size;
+
+		if ((eq = kobj_open_file(name)) == (struct _buf *)-1)
+			return (EM_OPENFILE);
+
+		if (kobj_get_filesize(eq, &size) < 0) {
+			kobj_close_file(eq);
+			return (EM_OPENFILE);
+		}
+
+		ucode_eqtbl_amd = kmem_zalloc(size, KM_NOSLEEP);
+		if (ucode_eqtbl_amd == NULL) {
+			kobj_close_file(eq);
+			return (EM_NOMEM);
+		}
+
+		count = kobj_read_file(eq, (char *)ucode_eqtbl_amd, size, 0);
+		kobj_close_file(eq);
+
+		if (count != size)
+			return (EM_FILESIZE);
+	}
+
+	/* Get the equivalent CPU id. */
+	if (cp->cpu_id)
+		for (eqtbl = ucode_eqtbl_amd;
+		    eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != cpi_sig;
+		    eqtbl++)
+			;
+
+	*eq_sig = eqtbl->ue_equiv_cpu;
+	*eq_sig = ((*eq_sig >> 8) & 0xff00) | (*eq_sig & 0xff);
+
+	/* No equivalent CPU id found, assume outdated microcode file. */
+	if (*eq_sig == 0)
+		return (EM_HIGHERREV);
+
+	return (EM_OK);
 }
 
 /*
@@ -205,19 +367,73 @@
  * Return EM_OK on success, corresponding error code on failure.
  */
 static ucode_errno_t
-ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
+ucode_locate_amd(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp)
+{
+	char name[MAXPATHLEN];
+	intptr_t fd;
+	int count, i, rc;
+	int eq_sig = 0;
+	ucode_file_amd_t *ucodefp = ufp->amd;
+
+	/* get equivalent CPU id */
+	if ((rc = ucode_equiv_cpu_amd(cp, &eq_sig)) != EM_OK)
+		return (rc);
+
+	/*
+	 * Allocate a buffer for the microcode patch. If the buffer has been
+	 * allocated before, check for a matching microcode to avoid loading
+	 * the file again.
+	 */
+	if (ucodefp == NULL)
+		ucodefp = ucode_zalloc(cp->cpu_id, sizeof (*ucodefp));
+	else if (ucode_match_amd(eq_sig, uinfop, ucodefp, sizeof (*ucodefp))
+	    == EM_OK)
+		return (EM_OK);
+
+	if (ucodefp == NULL)
+		return (EM_NOMEM);
+
+	ufp->amd = ucodefp;
+
+	/*
+	 * Find the patch for this CPU. The patch files are named XXXX-YY, where
+	 * XXXX is the equivalent CPU id and YY is the running patch number.
+	 * Patches specific to certain chipsets are guaranteed to have lower
+	 * numbers than less specific patches, so we can just load the first
+	 * patch that matches.
+	 */
+
+	for (i = 0; i < 0xff; i++) {
+		(void) snprintf(name, MAXPATHLEN, "/%s/%s/%04X-%02X",
+		    UCODE_INSTALL_PATH, cpuid_getvendorstr(cp), eq_sig, i);
+		if ((fd = kobj_open(name)) == -1)
+			return (EM_NOMATCH);
+		count = kobj_read(fd, (char *)ucodefp, sizeof (*ucodefp), 0);
+		(void) kobj_close(fd);
+
+		if (ucode_match_amd(eq_sig, uinfop, ucodefp, count) == EM_OK)
+			return (EM_OK);
+	}
+	return (EM_NOMATCH);
+}
+
+static ucode_errno_t
+ucode_locate_intel(cpu_t *cp, cpu_ucode_info_t *uinfop, ucode_file_t *ufp)
 {
 	char		name[MAXPATHLEN];
 	intptr_t	fd;
 	int		count;
-	int		header_size = UCODE_HEADER_SIZE;
+	int		header_size = UCODE_HEADER_SIZE_INTEL;
 	int		cpi_sig = cpuid_getsig(cp);
 	ucode_errno_t	rc = EM_OK;
+	ucode_file_intel_t *ucodefp = &ufp->intel;
+
+	ASSERT(ucode);
 
 	/*
 	 * If the microcode matches the CPU we are processing, use it.
 	 */
-	if (ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
+	if (ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header,
 	    ucodefp->uf_ext_table) == EM_OK && ucodefp->uf_body != NULL) {
 		return (EM_OK);
 	}
@@ -237,14 +453,18 @@
 	 * reset the microcode data structure and read in the new
 	 * file.
 	 */
-	ucode_file_reset(ucodefp, cp->cpu_id);
+	ucode->file_reset(ufp, cp->cpu_id);
 
-	count = kobj_read(fd, (char *)&ucodefp->uf_header, header_size, 0);
+	ucodefp->uf_header = ucode_zalloc(cp->cpu_id, header_size);
+	if (ucodefp->uf_header == NULL)
+		return (EM_NOMEM);
+
+	count = kobj_read(fd, (char *)ucodefp->uf_header, header_size, 0);
 
 	switch (count) {
-	case UCODE_HEADER_SIZE: {
+	case UCODE_HEADER_SIZE_INTEL: {
 
-		ucode_header_t	*uhp = &ucodefp->uf_header;
+		ucode_header_intel_t	*uhp = ucodefp->uf_header;
 		uint32_t	offset = header_size;
 		int		total_size, body_size, ext_size;
 		uint32_t	sum = 0;
@@ -252,23 +472,13 @@
 		/*
 		 * Make sure that the header contains valid fields.
 		 */
-		if ((rc = ucode_header_validate(uhp)) == EM_OK) {
-			total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size);
-			body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
-			if (cp->cpu_id != 0) {
-				if ((ucodefp->uf_body = kmem_zalloc(body_size,
-				    KM_NOSLEEP)) == NULL) {
-					rc = EM_NOMEM;
-					break;
-				}
-			} else {
-				/*
-				 * BOP_ALLOC() failure results in panic so we
-				 * don't have to check for NULL return.
-				 */
-				ucodefp->uf_body =
-				    (uint8_t *)BOP_ALLOC(bootops,
-				    NULL, body_size, MMU_PAGESIZE);
+		if ((rc = ucode_header_validate_intel(uhp)) == EM_OK) {
+			total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
+			body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
+			ucodefp->uf_body = ucode_zalloc(cp->cpu_id, body_size);
+			if (ucodefp->uf_body == NULL) {
+				rc = EM_NOMEM;
+				break;
 			}
 
 			if (kobj_read(fd, (char *)ucodefp->uf_body,
@@ -279,9 +489,9 @@
 		if (rc)
 			break;
 
-		sum = ucode_checksum(0, header_size,
-		    (uint8_t *)&ucodefp->uf_header);
-		if (ucode_checksum(sum, body_size, ucodefp->uf_body)) {
+		sum = ucode_checksum_intel(0, header_size,
+		    (uint8_t *)ucodefp->uf_header);
+		if (ucode_checksum_intel(sum, body_size, ucodefp->uf_body)) {
 			rc = EM_CHECKSUM;
 			break;
 		}
@@ -295,35 +505,26 @@
 		if (ext_size <= 0)
 			break;
 
-		if (cp->cpu_id != 0) {
-			if ((ucodefp->uf_ext_table = kmem_zalloc(ext_size,
-			    KM_NOSLEEP)) == NULL) {
-				rc = EM_NOMEM;
-				break;
-			}
-		} else {
-			/*
-			 * BOP_ALLOC() failure results in panic so we
-			 * don't have to check for NULL return.
-			 */
-			ucodefp->uf_ext_table =
-			    (ucode_ext_table_t *)BOP_ALLOC(bootops, NULL,
-			    ext_size, MMU_PAGESIZE);
+		ucodefp->uf_ext_table = ucode_zalloc(cp->cpu_id, ext_size);
+		if (ucodefp->uf_ext_table == NULL) {
+			rc = EM_NOMEM;
+			break;
 		}
 
 		if (kobj_read(fd, (char *)ucodefp->uf_ext_table,
 		    ext_size, offset) != ext_size) {
 			rc = EM_FILESIZE;
-		} else if (ucode_checksum(0, ext_size,
+		} else if (ucode_checksum_intel(0, ext_size,
 		    (uint8_t *)(ucodefp->uf_ext_table))) {
 			rc = EM_CHECKSUM;
 		} else {
 			int i;
 
-			ext_size -= UCODE_EXT_TABLE_SIZE;
+			ext_size -= UCODE_EXT_TABLE_SIZE_INTEL;
 			for (i = 0; i < ucodefp->uf_ext_table->uet_count;
 			    i++) {
-				if (ucode_checksum(0, UCODE_EXT_SIG_SIZE,
+				if (ucode_checksum_intel(0,
+				    UCODE_EXT_SIG_SIZE_INTEL,
 				    (uint8_t *)(&(ucodefp->uf_ext_table->
 				    uet_ext_sig[i])))) {
 					rc = EM_CHECKSUM;
@@ -344,23 +545,63 @@
 	if (rc != EM_OK)
 		return (rc);
 
-	rc = ucode_match(cpi_sig, uinfop, &ucodefp->uf_header,
+	rc = ucode_match_intel(cpi_sig, uinfop, ucodefp->uf_header,
 	    ucodefp->uf_ext_table);
 
 	return (rc);
 }
 
+static ucode_errno_t
+ucode_match_amd(int eq_sig, cpu_ucode_info_t *uinfop, ucode_file_amd_t *ucodefp,
+    int size)
+{
+	ucode_header_amd_t *uh;
+
+	if (ucodefp == NULL || size < sizeof (ucode_header_amd_t))
+		return (EM_NOMATCH);
+
+	/*
+	 * Don't even think about loading patches that would require code
+	 * execution.
+	 */
+	if (size > offsetof(ucode_file_amd_t, uf_code_present) &&
+	    ucodefp->uf_code_present)
+		return (EM_NOMATCH);
+
+	uh = &ucodefp->uf_header;
+
+	if (eq_sig != uh->uh_cpu_rev)
+		return (EM_NOMATCH);
+
+	if (uh->uh_nb_id) {
+		cmn_err(CE_WARN, "ignoring northbridge-specific ucode: "
+		    "chipset id %x, revision %x", uh->uh_nb_id, uh->uh_nb_rev);
+		return (EM_NOMATCH);
+	}
+
+	if (uh->uh_sb_id) {
+		cmn_err(CE_WARN, "ignoring southbridge-specific ucode: "
+		    "chipset id %x, revision %x", uh->uh_sb_id, uh->uh_sb_rev);
+		return (EM_NOMATCH);
+	}
+
+	if (uh->uh_patch_id <= uinfop->cui_rev)
+		return (EM_HIGHERREV);
+
+	return (EM_OK);
+}
 
 /*
  * Returns 1 if the microcode is for this processor; 0 otherwise.
  */
 static ucode_errno_t
-ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,
-    ucode_header_t *uhp, ucode_ext_table_t *uetp)
+ucode_match_intel(int cpi_sig, cpu_ucode_info_t *uinfop,
+    ucode_header_intel_t *uhp, ucode_ext_table_intel_t *uetp)
 {
-	ASSERT(uhp);
+	if (uhp == NULL)
+		return (EM_NOMATCH);
 
-	if (UCODE_MATCH(cpi_sig, uhp->uh_signature,
+	if (UCODE_MATCH_INTEL(cpi_sig, uhp->uh_signature,
 	    uinfop->cui_platid, uhp->uh_proc_flags)) {
 
 		if (uinfop->cui_rev >= uhp->uh_rev && !ucode_force_update)
@@ -373,11 +614,11 @@
 		int i;
 
 		for (i = 0; i < uetp->uet_count; i++) {
-			ucode_ext_sig_t *uesp;
+			ucode_ext_sig_intel_t *uesp;
 
 			uesp = &uetp->uet_ext_sig[i];
 
-			if (UCODE_MATCH(cpi_sig, uesp->ues_signature,
+			if (UCODE_MATCH_INTEL(cpi_sig, uesp->ues_signature,
 			    uinfop->cui_platid, uesp->ues_proc_flags)) {
 
 				if (uinfop->cui_rev >= uhp->uh_rev &&
@@ -396,9 +637,10 @@
 static int
 ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)
 {
-	struct ucode_update_struct *uusp = (struct ucode_update_struct *)arg1;
-	struct cpu_ucode_info *uinfop = CPU->cpu_m.mcpu_ucode_info;
+	ucode_update_t *uusp = (ucode_update_t *)arg1;
+	cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info;
 
+	ASSERT(ucode);
 	ASSERT(uusp->ucodep);
 
 #ifndef	__xpv
@@ -408,65 +650,134 @@
 	 * the threads share the same microcode.
 	 */
 	if (!ucode_force_update) {
-		ucode_read_rev(uinfop);
+		ucode->read_rev(uinfop);
 		uusp->new_rev = uinfop->cui_rev;
 		if (uinfop->cui_rev >= uusp->expected_rev)
 			return (0);
 	}
 
-	wrmsr(MSR_INTC_UCODE_WRITE,
-	    (uint64_t)(intptr_t)(uusp->ucodep));
+	wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep);
 #endif
-	ucode_read_rev(uinfop);
+	ucode->read_rev(uinfop);
 	uusp->new_rev = uinfop->cui_rev;
 
 	return (0);
 }
 
+/*ARGSUSED*/
+static uint32_t
+ucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp)
+{
+	ucode_file_amd_t *ucodefp = ufp->amd;
+#ifdef	__xpv
+	ucode_update_t uus;
+#endif
 
-static void
-ucode_update_intel(uint8_t *ucode_body, struct cpu_ucode_info *uinfop)
+	ASSERT(ucode);
+	ASSERT(ucodefp);
+
+#ifndef	__xpv
+	kpreempt_disable();
+	wrmsr(ucode->write_msr, (uintptr_t)ucodefp);
+	ucode->read_rev(uinfop);
+	kpreempt_enable();
+#else
+	uus.ucodep = (uint8_t *)ucodefp;
+	uus.usize = sizeof (*ucodefp);
+	ucode_load_xpv(&uus);
+	ucode->read_rev(uinfop);
+	uus.new_rev = uinfop->cui_rev;
+#endif
+
+	return (ucodefp->uf_header.uh_patch_id);
+}
+
+/*ARGSUSED2*/
+static uint32_t
+ucode_load_intel(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp)
 {
+	ucode_file_intel_t *ucodefp = &ufp->intel;
+#ifdef __xpv
+	uint32_t ext_offset;
+	uint32_t body_size;
+	uint32_t ext_size;
+	uint8_t *ustart;
+	uint32_t usize;
+	ucode_update_t uus;
+#endif
+
+	ASSERT(ucode);
+
+#ifdef __xpv
+	/*
+	 * the hypervisor wants the header, data, and extended
+	 * signature tables. We can only get here from the boot
+	 * CPU (cpu #0), we don't need to free as ucode_zalloc() will
+	 * use BOP_ALLOC().
+	 */
+	usize = UCODE_TOTAL_SIZE_INTEL(ucodefp->uf_header->uh_total_size);
+	ustart = ucode_zalloc(cp->cpu_id, usize);
+	ASSERT(ustart);
+
+	body_size = UCODE_BODY_SIZE_INTEL(ucodefp->uf_header->uh_body_size);
+	ext_offset = body_size + UCODE_HEADER_SIZE_INTEL;
+	ext_size = usize - ext_offset;
+	ASSERT(ext_size >= 0);
+
+	(void) memcpy(ustart, ucodefp->uf_header, UCODE_HEADER_SIZE_INTEL);
+	(void) memcpy(&ustart[UCODE_HEADER_SIZE_INTEL], ucodefp->uf_body,
+	    body_size);
+	if (ext_size > 0) {
+		(void) memcpy(&ustart[ext_offset],
+		    ucodefp->uf_ext_table, ext_size);
+	}
+	uus.ucodep = ustart;
+	uus.usize = usize;
+	ucode_load_xpv(&uus);
+	ucode->read_rev(uinfop);
+	uus.new_rev = uinfop->cui_rev;
+#else
 	kpreempt_disable();
-	wrmsr(MSR_INTC_UCODE_WRITE, (uint64_t)(uintptr_t)ucode_body);
-	ucode_read_rev(uinfop);
+	wrmsr(ucode->write_msr, (uintptr_t)ucodefp->uf_body);
+	ucode->read_rev(uinfop);
 	kpreempt_enable();
+#endif
+
+	return (ucodefp->uf_header->uh_rev);
 }
 
 
 #ifdef	__xpv
 static void
-ucode_update_xpv(struct ucode_update_struct *uusp, uint8_t *ucode,
-    uint32_t size)
+ucode_load_xpv(ucode_update_t *uusp)
 {
-	struct cpu_ucode_info *uinfop;
 	xen_platform_op_t op;
 	int e;
 
 	ASSERT(DOMAIN_IS_INITDOMAIN(xen_info));
 
 	kpreempt_disable();
-	uinfop = CPU->cpu_m.mcpu_ucode_info;
 	op.cmd = XENPF_microcode_update;
 	op.interface_version = XENPF_INTERFACE_VERSION;
 	/*LINTED: constant in conditional context*/
-	set_xen_guest_handle(op.u.microcode.data, ucode);
-	op.u.microcode.length = size;
+	set_xen_guest_handle(op.u.microcode.data, uusp->ucodep);
+	op.u.microcode.length = uusp->usize;
 	e = HYPERVISOR_platform_op(&op);
 	if (e != 0) {
 		cmn_err(CE_WARN, "hypervisor failed to accept uCode update");
 	}
-	ucode_read_rev(uinfop);
-	if (uusp != NULL) {
-		uusp->new_rev = uinfop->cui_rev;
-	}
 	kpreempt_enable();
 }
 #endif /* __xpv */
 
+static void
+ucode_read_rev_amd(cpu_ucode_info_t *uinfop)
+{
+	uinfop->cui_rev = rdmsr(MSR_AMD_PATCHLEVEL);
+}
 
 static void
-ucode_read_rev(struct cpu_ucode_info *uinfop)
+ucode_read_rev_intel(cpu_ucode_info_t *uinfop)
 {
 	struct cpuid_regs crs;
 
@@ -480,6 +791,113 @@
 	uinfop->cui_rev = (rdmsr(MSR_INTC_UCODE_REV) >> INTC_UCODE_REV_SHIFT);
 }
 
+static ucode_errno_t
+ucode_extract_amd(ucode_update_t *uusp, uint8_t *ucodep, int size)
+{
+	uint32_t *ptr = (uint32_t *)ucodep;
+	ucode_eqtbl_amd_t *eqtbl;
+	ucode_file_amd_t *ufp;
+	int count, eq_sig;
+
+	/* skip over magic number & equivalence table header */
+	ptr += 2; size -= 8;
+
+	count = *ptr++; size -= 4;
+	for (eqtbl = (ucode_eqtbl_amd_t *)ptr;
+	    eqtbl->ue_inst_cpu && eqtbl->ue_inst_cpu != uusp->sig;
+	    eqtbl++)
+		;
+
+	eq_sig = eqtbl->ue_equiv_cpu;
+	eq_sig = ((eq_sig >> 8) & 0xff00) | (eq_sig & 0xff);
+
+	/* No equivalent CPU id found, assume outdated microcode file. */
+	if (eq_sig == 0)
+		return (EM_HIGHERREV);
+
+	/* Use the first microcode patch that matches. */
+	do {
+		ptr += count >> 2; size -= count;
+
+		if (!size)
+			return (EM_NOMATCH);
+
+		ptr++; size -= 4;
+		count = *ptr++; size -= 4;
+		ufp = (ucode_file_amd_t *)ptr;
+	} while (ucode_match_amd(eq_sig, &uusp->info, ufp, count) != EM_OK);
+
+	uusp->ucodep = (uint8_t *)ufp;
+	uusp->usize = count;
+	uusp->expected_rev = ufp->uf_header.uh_patch_id;
+
+	return (EM_OK);
+}
+
+static ucode_errno_t
+ucode_extract_intel(ucode_update_t *uusp, uint8_t *ucodep, int size)
+{
+	uint32_t	header_size = UCODE_HEADER_SIZE_INTEL;
+	int		remaining;
+	int		found = 0;
+	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */
+
+	/*
+	 * Go through the whole buffer in case there are
+	 * multiple versions of matching microcode for this
+	 * processor.
+	 */
+	for (remaining = size; remaining > 0; ) {
+		int	total_size, body_size, ext_size;
+		uint8_t	*curbuf = &ucodep[size - remaining];
+		ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf;
+		ucode_ext_table_intel_t *uetp = NULL;
+		ucode_errno_t tmprc;
+
+		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
+		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
+		ext_size = total_size - (header_size + body_size);
+
+		if (ext_size > 0)
+			uetp = (ucode_ext_table_intel_t *)
+			    &curbuf[header_size + body_size];
+
+		tmprc = ucode_match_intel(uusp->sig, &uusp->info, uhp, uetp);
+
+		/*
+		 * Since we are searching through a big file
+		 * containing microcode for pretty much all the
+		 * processors, we are bound to get EM_NOMATCH
+		 * at one point.  However, if we return
+		 * EM_NOMATCH to users, it will really confuse
+		 * them.  Therefore, if we ever find a match of
+		 * a lower rev, we will set return code to
+		 * EM_HIGHERREV.
+		 */
+		if (tmprc == EM_HIGHERREV)
+			search_rc = EM_HIGHERREV;
+
+		if (tmprc == EM_OK &&
+		    uusp->expected_rev < uhp->uh_rev) {
+#ifndef __xpv
+			uusp->ucodep = (uint8_t *)&curbuf[header_size];
+#else
+			uusp->ucodep = (uint8_t *)curbuf;
+#endif
+			uusp->usize =
+			    UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
+			uusp->expected_rev = uhp->uh_rev;
+			found = 1;
+		}
+
+		remaining -= total_size;
+	}
+
+	if (!found)
+		return (search_rc);
+
+	return (EM_OK);
+}
 /*
  * Entry point to microcode update from the ucode_drv driver.
  *
@@ -488,32 +906,27 @@
 ucode_errno_t
 ucode_update(uint8_t *ucodep, int size)
 {
-	uint32_t	header_size = UCODE_HEADER_SIZE;
-	int		remaining;
 	int		found = 0;
 	processorid_t	id;
-	struct ucode_update_struct cached = { 0 };
-	struct ucode_update_struct *cachedp = NULL;
+	ucode_update_t	cached = { 0 };
+	ucode_update_t	*cachedp = NULL;
 	ucode_errno_t	rc = EM_OK;
 	ucode_errno_t	search_rc = EM_NOMATCH; /* search result */
 	cpuset_t cpuset;
-#ifdef	__xpv
-	uint8_t *ustart;
-	uint32_t usize;
-#endif
 
+	ASSERT(ucode);
 	ASSERT(ucodep);
 	CPUSET_ZERO(cpuset);
 
-	if (!ucode_capable(CPU))
+	if (!ucode->capable(CPU))
 		return (EM_NOTSUP);
 
 	mutex_enter(&cpu_lock);
 
 	for (id = 0; id < max_ncpus; id++) {
 		cpu_t *cpu;
-		struct ucode_update_struct uus = { 0 };
-		struct ucode_update_struct *uusp = &uus;
+		ucode_update_t uus = { 0 };
+		ucode_update_t *uusp = &uus;
 
 		/*
 		 * If there is no such CPU or it is not xcall ready, skip it.
@@ -542,61 +955,11 @@
 			 * the other threads in an HT processor can update
 			 * the cpu_ucode_info structure in machcpu.
 			 */
-		} else {
-			/*
-			 * Go through the whole buffer in case there are
-			 * multiple versions of matching microcode for this
-			 * processor.
-			 */
-			for (remaining = size; remaining > 0; ) {
-				int	total_size, body_size, ext_size;
-				uint8_t	*curbuf = &ucodep[size - remaining];
-				ucode_header_t	*uhp = (ucode_header_t *)curbuf;
-				ucode_ext_table_t *uetp = NULL;
-				ucode_errno_t tmprc;
-
-				total_size =
-				    UCODE_TOTAL_SIZE(uhp->uh_total_size);
-				body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
-				ext_size = total_size -
-				    (header_size + body_size);
-
-				if (ext_size > 0)
-					uetp = (ucode_ext_table_t *)
-					    &curbuf[header_size + body_size];
-
-				tmprc = ucode_match(uusp->sig, &uusp->info,
-				    uhp, uetp);
-
-				/*
-				 * Since we are searching through a big file
-				 * containing microcode for pretty much all the
-				 * processors, we are bound to get EM_NOMATCH
-				 * at one point.  However, if we return
-				 * EM_NOMATCH to users, it will really confuse
-				 * them.  Therefore, if we ever find a match of
-				 * a lower rev, we will set return code to
-				 * EM_HIGHERREV.
-				 */
-				if (tmprc == EM_HIGHERREV)
-					search_rc = EM_HIGHERREV;
-
-				if (tmprc == EM_OK &&
-				    uusp->expected_rev < uhp->uh_rev) {
-					uusp->ucodep = &curbuf[header_size];
-#ifdef	__xpv
-					ustart = (uint8_t *)curbuf;
-					usize = UCODE_TOTAL_SIZE(
-					    uhp->uh_total_size);
-#endif
-					uusp->expected_rev = uhp->uh_rev;
-					bcopy(uusp, &cached, sizeof (cached));
-					cachedp = &cached;
-					found = 1;
-				}
-
-				remaining -= total_size;
-			}
+		} else if ((search_rc = ucode->extract(uusp, ucodep, size))
+		    == EM_OK) {
+			bcopy(uusp, &cached, sizeof (cached));
+			cachedp = &cached;
+			found = 1;
 		}
 
 		/* Nothing to do */
@@ -612,7 +975,7 @@
 		 * completed.
 		 */
 		if (id == 0) {
-			ucode_update_xpv(uusp, ustart, usize);
+			ucode_load_xpv(uusp);
 		}
 #endif
 
@@ -651,15 +1014,9 @@
 void
 ucode_check(cpu_t *cp)
 {
-	struct cpu_ucode_info *uinfop;
+	cpu_ucode_info_t *uinfop;
 	ucode_errno_t rc = EM_OK;
-#ifdef	__xpv
-	uint32_t ext_offset;
-	uint32_t body_size;
-	uint32_t ext_size;
-	uint8_t *ustart;
-	uint32_t usize;
-#endif
+	uint32_t new_rev = 0;
 
 	ASSERT(cp);
 	if (cp->cpu_id == 0)
@@ -668,19 +1025,33 @@
 	uinfop = cp->cpu_m.mcpu_ucode_info;
 	ASSERT(uinfop);
 
-	if (!ucode_capable(cp))
+	/* set up function pointers if not already done */
+	if (!ucode)
+		switch (cpuid_getvendor(cp)) {
+		case X86_VENDOR_AMD:
+			ucode = &ucode_amd;
+			break;
+		case X86_VENDOR_Intel:
+			ucode = &ucode_intel;
+			break;
+		default:
+			return;
+		}
+
+	if (!ucode->capable(cp))
 		return;
 
 	/*
 	 * The MSR_INTC_PLATFORM_ID is supported in Celeron and Xeon
 	 * (Family 6, model 5 and above) and all processors after.
 	 */
-	if ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6)) {
+	if ((cpuid_getvendor(cp) == X86_VENDOR_Intel) &&
+	    ((cpuid_getmodel(cp) >= 5) || (cpuid_getfamily(cp) > 6))) {
 		uinfop->cui_platid = 1 << ((rdmsr(MSR_INTC_PLATFORM_ID) >>
 		    INTC_PLATFORM_ID_SHIFT) & INTC_PLATFORM_ID_MASK);
 	}
 
-	ucode_read_rev(uinfop);
+	ucode->read_rev(uinfop);
 
 #ifdef	__xpv
 	/*
@@ -695,38 +1066,12 @@
 	/*
 	 * Check to see if we need ucode update
 	 */
-	if ((rc = ucode_locate(cp, uinfop, &ucodefile)) == EM_OK) {
-#ifndef	__xpv
-		ucode_update_intel(ucodefile.uf_body, uinfop);
-#else
-		/*
-		 * the hypervisor wants the header, data, and extended
-		 * signature tables. We can only get here from the boot
-		 * CPU (cpu #0), so use BOP_ALLOC. Since we're using BOP_ALLOC,
-		 * We don't need to free.
-		 */
-		usize = UCODE_TOTAL_SIZE(ucodefile.uf_header.uh_total_size);
-		ustart = (uint8_t *)BOP_ALLOC(bootops, NULL, usize,
-		    MMU_PAGESIZE);
+	if ((rc = ucode->locate(cp, uinfop, &ucodefile)) == EM_OK) {
+		new_rev = ucode->load(&ucodefile, uinfop, cp);
 
-		body_size = UCODE_BODY_SIZE(ucodefile.uf_header.uh_body_size);
-		ext_offset = body_size + UCODE_HEADER_SIZE;
-		ext_size = usize - ext_offset;
-		ASSERT(ext_size >= 0);
-
-		(void) memcpy(ustart, &ucodefile.uf_header, UCODE_HEADER_SIZE);
-		(void) memcpy(&ustart[UCODE_HEADER_SIZE], ucodefile.uf_body,
-		    body_size);
-		if (ext_size > 0) {
-			(void) memcpy(&ustart[ext_offset],
-			    ucodefile.uf_ext_table, ext_size);
-		}
-		ucode_update_xpv(NULL, ustart, usize);
-#endif
-
-		if (uinfop->cui_rev != ucodefile.uf_header.uh_rev)
+		if (uinfop->cui_rev != new_rev)
 			cmn_err(CE_WARN, ucode_failure_fmt, cp->cpu_id,
-			    uinfop->cui_rev, ucodefile.uf_header.uh_rev);
+			    uinfop->cui_rev, new_rev);
 	}
 
 	/*
@@ -740,7 +1085,7 @@
 	 * of the CPUs in start_other_cpus().
 	 */
 	if (rc != EM_OK || cp->cpu_id == 0)
-		ucode_file_reset(&ucodefile, cp->cpu_id);
+		ucode->file_reset(&ucodefile, cp->cpu_id);
 }
 
 /*
@@ -751,9 +1096,10 @@
 {
 	int i;
 
+	ASSERT(ucode);
 	ASSERT(revp);
 
-	if (!ucode_capable(CPU))
+	if (!ucode->capable(CPU))
 		return (EM_NOTSUP);
 
 	mutex_enter(&cpu_lock);
--- a/usr/src/uts/i86pc/os/mp_startup.c	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/uts/i86pc/os/mp_startup.c	Mon Sep 15 15:09:45 2008 -0700
@@ -1396,7 +1396,7 @@
 	}
 
 	/* Free the space allocated to hold the microcode file */
-	ucode_free();
+	ucode_cleanup();
 
 	affinity_clear();
 
--- a/usr/src/uts/intel/io/ucode_drv.c	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/uts/intel/io/ucode_drv.c	Mon Sep 15 15:09:45 2008 -0700
@@ -138,6 +138,12 @@
 static int
 ucode_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)
 {
+	/*
+	 * Make sure that the ucode ops pointer has been set up.
+	 */
+	if (!ucode)
+		return (EIO);
+
 	switch (cmd) {
 	case UCODE_GET_VERSION: {
 		int size;
@@ -218,7 +224,7 @@
 			return (EFAULT);
 		}
 
-		if ((rc = ucode_validate(ucodep, size)) != EM_OK) {
+		if ((rc = ucode->validate(ucodep, size)) != EM_OK) {
 			kmem_free(ucodep, size);
 			STRUCT_FSET(h, uw_errno, rc);
 			if (ddi_copyout(STRUCT_BUF(h), (void *)arg,
--- a/usr/src/uts/intel/sys/controlregs.h	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/uts/intel/sys/controlregs.h	Mon Sep 15 15:09:45 2008 -0700
@@ -26,8 +26,6 @@
 #ifndef	_SYS_CONTROLREGS_H
 #define	_SYS_CONTROLREGS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifndef _ASM
 #include <sys/types.h>
 #endif
@@ -224,8 +222,9 @@
  */
 #define	AMD_GH_NB_CFG_EN_ECS		(UINT64_C(1) << 46)
 
-/* AMD */
+/* AMD microcode patch loader */
 #define	MSR_AMD_PATCHLEVEL	0x8b
+#define	MSR_AMD_PATCHLOADER	0xc0010020
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/intel/sys/x86_archext.h	Mon Sep 15 17:45:12 2008 -0400
+++ b/usr/src/uts/intel/sys/x86_archext.h	Mon Sep 15 15:09:45 2008 -0700
@@ -608,7 +608,7 @@
 extern void ucode_alloc_space(struct cpu *);
 extern void ucode_free_space(struct cpu *);
 extern void ucode_check(struct cpu *);
-extern void ucode_free();
+extern void ucode_cleanup();
 
 #if !defined(__xpv)
 extern	char _tsc_mfence_start;