summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ucodeadm/ucodeadm.c
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 /usr/src/cmd/ucodeadm/ucodeadm.c
parent875a4abcc45eff5fe347622080ebe938010f5acb (diff)
downloadillumos-joyent-adc586debf12d2592024c0b8b9e44ffa104f858c.tar.gz
6747590 microcode update support for AMD
Contributed by Hans Rosenfeld <hans.rosenfeld@amd.com>
Diffstat (limited to 'usr/src/cmd/ucodeadm/ucodeadm.c')
-rw-r--r--usr/src/cmd/ucodeadm/ucodeadm.c189
1 files changed, 138 insertions, 51 deletions
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;
}