summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnson <Mark.Johnson@Sun.COM>2008-09-15 15:09:45 -0700
committerMark Johnson <Mark.Johnson@Sun.COM>2008-09-15 15:09:45 -0700
commitadc586debf12d2592024c0b8b9e44ffa104f858c (patch)
tree189b4a865d30882c4001014b69447e6bdaaa46f7
parent875a4abcc45eff5fe347622080ebe938010f5acb (diff)
downloadillumos-joyent-adc586debf12d2592024c0b8b9e44ffa104f858c.tar.gz
6747590 microcode update support for AMD
Contributed by Hans Rosenfeld <hans.rosenfeld@amd.com>
-rw-r--r--usr/src/cmd/boot/bootadm/bootadm.c5
-rw-r--r--usr/src/cmd/ucodeadm/ucodeadm.c189
-rw-r--r--usr/src/common/ucode/ucode_utils.c100
-rw-r--r--usr/src/uts/common/sys/ucode.h147
-rw-r--r--usr/src/uts/i86pc/os/microcode.c826
-rw-r--r--usr/src/uts/i86pc/os/mp_startup.c2
-rw-r--r--usr/src/uts/intel/io/ucode_drv.c8
-rw-r--r--usr/src/uts/intel/sys/controlregs.h5
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h2
9 files changed, 936 insertions, 348 deletions
diff --git a/usr/src/cmd/boot/bootadm/bootadm.c b/usr/src/cmd/boot/bootadm/bootadm.c
index bea2a8a28e..e78f257cae 100644
--- a/usr/src/cmd/boot/bootadm/bootadm.c
+++ b/usr/src/cmd/boot/bootadm/bootadm.c
@@ -7859,8 +7859,9 @@ ucode_install(char *root)
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;
diff --git a/usr/src/cmd/ucodeadm/ucodeadm.c b/usr/src/cmd/ucodeadm/ucodeadm.c
index 0100bd15d7..765099dd09 100644
--- a/usr/src/cmd/ucodeadm/ucodeadm.c
+++ b/usr/src/cmd/ucodeadm/ucodeadm.c
@@ -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 char ucode_install_path[] = UCODE_INSTALL_PATH;
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 @@ usage(int verbose)
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 @@ ucode_perror(const char *str, ucode_errno_t rc)
* 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 @@ ucode_convert(const char *infile, uint8_t *buf, size_t size)
* 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 @@ ucode_should_update(char *filename, uint32_t new_rev)
* 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 @@ ucode_gen_files(uint8_t *buf, int size, char *path)
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;
+
+ uhp = (ucode_header_intel_t *)(intptr_t)curbuf;
- total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size);
- body_size = UCODE_BODY_SIZE(uhp->uh_body_size);
+ 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 @@ ucode_gen_files(uint8_t *buf, int size, char *path)
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 @@ ucode_gen_files(uint8_t *buf, int size, char *path)
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 @@ ucode_gen_files(uint8_t *buf, int size, char *path)
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 @@ ucode_gen_files(uint8_t *buf, int size, char *path)
"%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 @@ main(int argc, char *argv[])
* 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 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
* "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 @@ main(int argc, char *argv[])
goto err_out;
}
- rc = ucode_gen_files(buf, ucode_size, path);
+ rc = ucode->gen_files(buf, ucode_size, path);
goto err_out;
}
diff --git a/usr/src/common/ucode/ucode_utils.c b/usr/src/common/ucode/ucode_utils.c
index 48198a16e9..5878f4a4af 100644
--- a/usr/src/common/ucode/ucode_utils.c
+++ b/usr/src/common/ucode/ucode_utils.c
@@ -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 @@ ucode_header_validate(ucode_header_t *uhp)
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 @@ ucode_header_validate(ucode_header_t *uhp)
*/
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 @@ ucode_header_validate(ucode_header_t *uhp)
* 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_checksum(uint32_t sum, uint32_t size, uint8_t *code)
}
ucode_errno_t
-ucode_validate(uint8_t *ucodep, int size)
+ucode_validate_amd(uint8_t *ucodep, int 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;
+ uint32_t header_size = UCODE_HEADER_SIZE_INTEL;
int remaining;
if (ucodep == NULL || size <= 0)
@@ -127,36 +181,38 @@ ucode_validate(uint8_t *ucodep, int size)
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);
}
diff --git a/usr/src/uts/common/sys/ucode.h b/usr/src/uts/common/sys/ucode.h
index 296a51f961..0f37745cae 100644
--- a/usr/src/uts/common/sys/ucode.h
+++ b/usr/src/uts/common/sys/ucode.h
@@ -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 @@ struct ucode_write_struct32 {
#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 @@ typedef struct ucode_header {
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 @@ typedef struct ucode_file {
#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 @@ typedef struct ucode_file {
#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
diff --git a/usr/src/uts/i86pc/os/microcode.c b/usr/src/uts/i86pc/os/microcode.c
index 6474bcce78..7dd2ef2e55 100644
--- a/usr/src/uts/i86pc/os/microcode.c
+++ b/usr/src/uts/i86pc/os/microcode.c
@@ -48,43 +48,76 @@
#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 *);
-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);
+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 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";
static const char ucode_success_fmt[] =
@@ -122,42 +155,84 @@ ucode_free_space(cpu_t *cp)
* space allocated for the microcode file.
*/
void
-ucode_free()
+ucode_cleanup()
+{
+ 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)
{
- ucode_file_reset(&ucodefile, -1);
+ 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);
}
-#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.
+ * XXPV - change when microcode loading works in dom0. Don't support
+ * microcode loading in dom0 right now for AMD.
*/
- if (cpuid_getvendor(cp) != X86_VENDOR_Intel ||
- cpuid_getfamily(cp) < 6)
+ return (0);
+#endif
+}
+static int
+ucode_capable_intel(cpu_t *cp)
+{
+#ifndef __xpv
+ extern int xpv_is_hvm;
+ if (xpv_is_hvm) {
return (0);
- else
- return (1);
+ }
+#else
+ if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
+ return (0);
+ }
+#endif
+ return (cpuid_getfamily(cp) >= 6);
}
/*
@@ -165,37 +240,124 @@ ucode_capable(cpu_t *cp)
* 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 @@ ucode_file_reset(ucode_file_t *ucodefp, processorid_t id)
* 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 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
* 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);
+
+ 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);
+ 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 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
/*
* 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 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
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 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
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 @@ ucode_locate(cpu_t *cp, struct cpu_ucode_info *uinfop, ucode_file_t *ucodefp)
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 @@ ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,
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 @@ ucode_match(int cpi_sig, struct cpu_ucode_info *uinfop,
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 @@ ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3)
* 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 @@ ucode_read_rev(struct cpu_ucode_info *uinfop)
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_read_rev(struct cpu_ucode_info *uinfop)
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 @@ ucode_update(uint8_t *ucodep, int size)
* 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 @@ ucode_update(uint8_t *ucodep, int size)
* completed.
*/
if (id == 0) {
- ucode_update_xpv(uusp, ustart, usize);
+ ucode_load_xpv(uusp);
}
#endif
@@ -651,15 +1014,9 @@ ucode_update(uint8_t *ucodep, int size)
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 @@ ucode_check(cpu_t *cp)
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 @@ ucode_check(cpu_t *cp)
/*
* 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);
-
- 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 ((rc = ucode->locate(cp, uinfop, &ucodefile)) == EM_OK) {
+ new_rev = ucode->load(&ucodefile, uinfop, cp);
- 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 @@ ucode_check(cpu_t *cp)
* 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 @@ ucode_get_rev(uint32_t *revp)
{
int i;
+ ASSERT(ucode);
ASSERT(revp);
- if (!ucode_capable(CPU))
+ if (!ucode->capable(CPU))
return (EM_NOTSUP);
mutex_enter(&cpu_lock);
diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c
index 55e1d85f6e..10492414be 100644
--- a/usr/src/uts/i86pc/os/mp_startup.c
+++ b/usr/src/uts/i86pc/os/mp_startup.c
@@ -1396,7 +1396,7 @@ start_other_cpus(int cprboot)
}
/* Free the space allocated to hold the microcode file */
- ucode_free();
+ ucode_cleanup();
affinity_clear();
diff --git a/usr/src/uts/intel/io/ucode_drv.c b/usr/src/uts/intel/io/ucode_drv.c
index d71b0bcbe5..6a63bba8a9 100644
--- a/usr/src/uts/intel/io/ucode_drv.c
+++ b/usr/src/uts/intel/io/ucode_drv.c
@@ -138,6 +138,12 @@ ucode_open(dev_t *dev, int flag, int otyp, cred_t *cr)
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 @@ ucode_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)
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,
diff --git a/usr/src/uts/intel/sys/controlregs.h b/usr/src/uts/intel/sys/controlregs.h
index 23e04d3286..dc8ec9c8c5 100644
--- a/usr/src/uts/intel/sys/controlregs.h
+++ b/usr/src/uts/intel/sys/controlregs.h
@@ -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 @@ extern "C" {
*/
#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
}
diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h
index ba8cbf15ea..89f07ce6cc 100644
--- a/usr/src/uts/intel/sys/x86_archext.h
+++ b/usr/src/uts/intel/sys/x86_archext.h
@@ -608,7 +608,7 @@ struct cpu_ucode_info;
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;