diff options
Diffstat (limited to 'usr/src/cmd/ucodeadm/ucodeadm.c')
| -rw-r--r-- | usr/src/cmd/ucodeadm/ucodeadm.c | 208 |
1 files changed, 180 insertions, 28 deletions
diff --git a/usr/src/cmd/ucodeadm/ucodeadm.c b/usr/src/cmd/ucodeadm/ucodeadm.c index 65f61facea..216b3dc9fb 100644 --- a/usr/src/cmd/ucodeadm/ucodeadm.c +++ b/usr/src/cmd/ucodeadm/ucodeadm.c @@ -25,7 +25,7 @@ /* * Copyright (c) 2018, Joyent, Inc. - * Copyright 2021 OmniOS Community Edition (OmniOSce) Association. + * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. */ #include <sys/types.h> @@ -53,6 +53,7 @@ #define UCODE_OPT_INSTALL 0x0001 #define UCODE_OPT_UPDATE 0x0002 #define UCODE_OPT_VERSION 0x0004 +#define UCODE_OPT_LIST 0x0008 static const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME; @@ -69,9 +70,22 @@ 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 void ucode_list_amd(uint8_t *, int); +static void ucode_list_intel(uint8_t *, int); + 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 }, + { + .convert = ucode_convert_intel, + .gen_files = ucode_gen_files_intel, + .validate = ucode_validate_intel, + .list = ucode_list_intel, + }, + { + .convert = ucode_convert_amd, + .gen_files = ucode_gen_files_amd, + .validate = ucode_validate_amd, + .list = ucode_list_amd, + }, }; const struct ucode_ops *ucode; @@ -104,6 +118,12 @@ usage(int verbose) "\t\t microcode-file.\n\n")); } + (void) fprintf(stderr, "\t%s -l microcode-file\n", cmdname); + if (verbose) { + (void) fprintf(stderr, gettext("\t\t Displays details of the " + "microcode file's contents.\n\n")); + } + (void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname); if (verbose) { (void) fprintf(stderr, gettext("\t\t Installs microcode to be " @@ -126,6 +146,8 @@ ucode_perror(const char *str, ucode_errno_t rc) /* * Convert text format microcode release into binary format. * Return the number of characters read. + * + * AMD microcode is already in binary format. */ static int ucode_convert_amd(const char *infile, uint8_t *buf, size_t size) @@ -151,7 +173,7 @@ ucode_convert_intel(const char *infile, uint8_t *buf, size_t size) char linebuf[LINESIZE]; FILE *infd = NULL; int count = 0, firstline = 1; - uint32_t *intbuf = (uint32_t *)(intptr_t)buf; + uint32_t *intbuf = (uint32_t *)(uintptr_t)buf; if (infile == NULL || buf == NULL || size == 0) return (0); @@ -242,11 +264,10 @@ ucode_gen_files_amd(uint8_t *buf, int size, char *path) { uint32_t *ptr = (uint32_t *)buf; char common_path[PATH_MAX]; - int fd, count, counter; + int fd, count, counter = 0; ucode_header_amd_t *uh; int last_cpu_rev = 0; - /* write container file */ (void) snprintf(common_path, PATH_MAX, "%s/%s", path, "container"); @@ -339,7 +360,7 @@ ucode_gen_files_intel(uint8_t *buf, int size, char *path) ucode_header_intel_t *uhp; ucode_ext_table_intel_t *extp; - uhp = (ucode_header_intel_t *)(intptr_t)curbuf; + uhp = (ucode_header_intel_t *)(uintptr_t)curbuf; total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); @@ -408,7 +429,7 @@ ucode_gen_files_intel(uint8_t *buf, int size, char *path) continue; /* There is extended signature table. More processing. */ - extp = (ucode_ext_table_intel_t *)(uintptr_t)&curbuf[offset]; + extp = (ucode_ext_table_intel_t *)&curbuf[offset]; for (i = 0; i < extp->uet_count; i++) { ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i]; @@ -474,6 +495,118 @@ ucode_gen_files_intel(uint8_t *buf, int size, char *path) return (EM_OK); } +static void +ucode_fms(uint32_t sig, uint8_t *family, uint8_t *model, uint8_t *stepping) +{ + *family = ((sig >> 8) & 0xf) + ((sig >> 20) & 0xff); + *model = ((sig >> 4) & 0xf) | ((sig >> 12) & 0xf0); + *stepping = sig & 0xf; +} + +static void +ucode_list_intel(uint8_t *buf, int size) +{ + int remaining; + + printf("Microcode patches:\n"); + for (remaining = size; remaining > 0; ) { + uint8_t *curbuf = &buf[size - remaining]; + uint8_t family, model, stepping; + uint32_t total_size, body_size, offset; + ucode_header_intel_t *uhp; + ucode_ext_table_intel_t *extp; + + uhp = (ucode_header_intel_t *)(uintptr_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; + + ucode_fms(uhp->uh_signature, &family, &model, &stepping); + + printf( + " %08lX-%02lX -> Family=%02x Model=%02x Stepping=%02x\n", + uhp->uh_signature, uhp->uh_proc_flags, + family, model, stepping); + printf( + " %14s Date=%08lX Bytes=%lu\n", "", + uhp->uh_date, uhp->uh_body_size); + + offset = UCODE_HEADER_SIZE_INTEL + body_size; + + /* Check to see if there is extended signature table */ + if (total_size == offset) + continue; + + printf("Extended Signature Table:\n"); + + extp = (ucode_ext_table_intel_t *)&curbuf[offset]; + + for (uint32_t i = 0; i < extp->uet_count; i++) { + ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i]; + + ucode_fms(uesp->ues_signature, + &family, &model, &stepping); + + printf( + " %08lX-%02lX -> Family=%02x Model=%02x " + "Stepping=%02x\n", + uesp->ues_signature, uesp->ues_proc_flags, + family, model, stepping); + } + } +} + +static void +ucode_list_amd(uint8_t *buf, int size) +{ + ucode_eqtbl_amd_t *eq; + ucode_header_amd_t *uh; + uint32_t tsz; + + /* + * The file has already been validated so we can skip straight to + * the equivalence table. + */ + tsz = *(uint32_t *)(buf + 8); + eq = (ucode_eqtbl_amd_t *)(buf + 12); + size -= 12; + + printf("Equivalence table:\n"); + while (size >= sizeof (ucode_eqtbl_amd_t) && eq->ue_inst_cpu != 0) { + uint8_t family, model, stepping; + + ucode_fms(eq->ue_inst_cpu, &family, &model, &stepping); + + printf( + " %08lX Family=%02x Model=%02x Stepping=%02x -> %04X\n", + eq->ue_inst_cpu, family, model, stepping, eq->ue_equiv_cpu); + eq++; + size -= sizeof (*eq); + } + + /* Move past the equivalence table terminating record */ + eq++; + size -= sizeof (*eq); + buf = (uint8_t *)eq; + + printf("Microcode patches:\n"); + while (size > sizeof (ucode_header_amd_t) + 8) { + tsz = *(uint32_t *)(buf + 4); + uh = (ucode_header_amd_t *)(buf + 8); + + if (uh->uh_cpu_rev == 0) + break; + + printf(" %4X -> Patch=%08lX Date=%08lX Bytes=%lu\n", + uh->uh_cpu_rev, uh->uh_patch_id, uh->uh_date, tsz); + + buf += (tsz + 8); + size -= (tsz + 8); + } +} + /* * Returns 0 on success, 2 on usage error, and 3 on operation error. */ @@ -493,7 +626,7 @@ main(int argc, char *argv[]) ucode_errno_t rc = EM_OK; processorid_t cpuid_max; struct stat filestat; - uint32_t ucode_size; + int ucode_size = 0; (void) setlocale(LC_ALL, ""); @@ -504,7 +637,7 @@ main(int argc, char *argv[]) cmdname = basename(argv[0]); - while ((c = getopt(argc, argv, "idhuvVR:")) != EOF) { + while ((c = getopt(argc, argv, "idhluvVR:")) != EOF) { switch (c) { case 'i': @@ -512,6 +645,11 @@ main(int argc, char *argv[]) actcount++; break; + case 'l': + action |= UCODE_OPT_LIST; + actcount++; + break; + case 'u': action |= UCODE_OPT_UPDATE; actcount++; @@ -527,9 +665,9 @@ main(int argc, char *argv[]) break; case 'R': - if (optarg[0] == '-') + if (optarg[0] == '-') { errflg++; - else if (strlen(optarg) > UCODE_MAX_PATH_LEN) { + } else if (strlen(optarg) > UCODE_MAX_PATH_LEN) { (void) fprintf(stderr, gettext("Alternate path too long\n")); errflg++; @@ -553,8 +691,15 @@ main(int argc, char *argv[]) } } + if (actcount == 0) { + (void) fprintf(stderr, gettext("%s: One of -i, -l, -u or -v " + "must be provided.\n"), cmdname); + usage(verbose); + return (2); + } + if (actcount != 1) { - (void) fprintf(stderr, gettext("%s: options -v, -i and -u " + (void) fprintf(stderr, gettext("%s: options -i, -l, -u and -v " "are mutually exclusive.\n"), cmdname); usage(verbose); return (2); @@ -562,7 +707,7 @@ main(int argc, char *argv[]) if (optind <= argc - 1) filename = argv[optind]; - else if (!(action & UCODE_OPT_VERSION)) + else if (action != UCODE_OPT_VERSION) errflg++; if (errflg || action == 0) { @@ -571,9 +716,11 @@ main(int argc, char *argv[]) } /* - * Convert from text format to binary format + * Convert from the vendor-shipped format (text for Intel, binary + * container for AMD) to individual microcode files. */ - if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) { + if ((action & + (UCODE_OPT_INSTALL | UCODE_OPT_UPDATE | UCODE_OPT_LIST))) { int i; UCODE_VENDORS; @@ -594,26 +741,26 @@ main(int argc, char *argv[]) if (ucode_vendors[i].filestr == NULL) { rc = EM_NOVENDOR; ucode_perror(basename(filename), rc); - goto err_out; + goto out; } if ((stat(filename, &filestat)) < 0) { rc = EM_SYS; ucode_perror(filename, rc); - goto err_out; + goto out; } if ((filestat.st_mode & S_IFMT) != S_IFREG && (filestat.st_mode & S_IFMT) != S_IFLNK) { rc = EM_FILEFORMAT; ucode_perror(filename, rc); - goto err_out; + goto out; } if ((buf = malloc(filestat.st_size)) == NULL) { rc = EM_SYS; ucode_perror(filename, rc); - goto err_out; + goto out; } ucode_size = ucode->convert(filename, buf, filestat.st_size); @@ -623,15 +770,20 @@ main(int argc, char *argv[]) if (ucode_size == 0) { rc = EM_FILEFORMAT; ucode_perror(filename, rc); - goto err_out; + goto out; } if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) { ucode_perror(filename, rc); - goto err_out; + goto out; } } + if (action & UCODE_OPT_LIST) { + ucode->list(buf, ucode_size); + goto out; + } + /* * For the install option, the microcode file must start with * "intel" for Intel microcode, and "amd" for AMD microcode. @@ -645,7 +797,7 @@ main(int argc, char *argv[]) if ((path = malloc(PATH_MAX)) == NULL) { rc = EM_SYS; ucode_perror("malloc", rc); - goto err_out; + goto out; } (void) snprintf(path, PATH_MAX, "/%s/%s", @@ -655,18 +807,18 @@ main(int argc, char *argv[]) if (mkdirp(path, 0755) == -1 && errno != EEXIST) { rc = EM_SYS; ucode_perror(path, rc); - goto err_out; + goto out; } rc = ucode->gen_files(buf, ucode_size, path); - goto err_out; + goto out; } if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) { rc = EM_SYS; ucode_perror(ucode_dev, rc); - goto err_out; + goto out; } if (action & UCODE_OPT_VERSION) { @@ -685,7 +837,7 @@ main(int argc, char *argv[]) malloc(cpuid_max * sizeof (uint32_t))) == NULL) { rc = EM_SYS; ucode_perror("malloc", rc); - goto err_out; + goto out; } for (i = 0; i < cpuid_max; i++) @@ -759,7 +911,7 @@ main(int argc, char *argv[]) } } -err_out: +out: if (dev_fd != -1) (void) close(dev_fd); |
