12449e17fSsherrym /* 22449e17fSsherrym * CDDL HEADER START 32449e17fSsherrym * 42449e17fSsherrym * The contents of this file are subject to the terms of the 52449e17fSsherrym * Common Development and Distribution License (the "License"). 62449e17fSsherrym * You may not use this file except in compliance with the License. 72449e17fSsherrym * 82449e17fSsherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92449e17fSsherrym * or http://www.opensolaris.org/os/licensing. 102449e17fSsherrym * See the License for the specific language governing permissions 112449e17fSsherrym * and limitations under the License. 122449e17fSsherrym * 132449e17fSsherrym * When distributing Covered Code, include this CDDL HEADER in each 142449e17fSsherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152449e17fSsherrym * If applicable, add the following below this CDDL HEADER, with the 162449e17fSsherrym * fields enclosed by brackets "[]" replaced with your own identifying 172449e17fSsherrym * information: Portions Copyright [yyyy] [name of copyright owner] 182449e17fSsherrym * 192449e17fSsherrym * CDDL HEADER END 202449e17fSsherrym */ 212449e17fSsherrym /* 22*adc586deSMark Johnson * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 232449e17fSsherrym * Use is subject to license terms. 242449e17fSsherrym */ 252449e17fSsherrym 262449e17fSsherrym #include <sys/types.h> 272449e17fSsherrym #include <sys/processor.h> 282449e17fSsherrym #include <sys/ucode.h> 292449e17fSsherrym #include <sys/ioctl.h> 302449e17fSsherrym #include <sys/stat.h> 312449e17fSsherrym #include <unistd.h> 322449e17fSsherrym #include <dirent.h> 332449e17fSsherrym #include <fcntl.h> 342449e17fSsherrym #include <errno.h> 352449e17fSsherrym #include <stdio.h> 362449e17fSsherrym #include <stdlib.h> 372449e17fSsherrym #include <stdarg.h> 382449e17fSsherrym #include <string.h> 392449e17fSsherrym #include <errno.h> 402449e17fSsherrym #include <syslog.h> 412449e17fSsherrym #include <time.h> 422449e17fSsherrym #include <ctype.h> 432449e17fSsherrym #include <assert.h> 442449e17fSsherrym #include <libgen.h> 452449e17fSsherrym #include <locale.h> 462449e17fSsherrym #include <libintl.h> 472449e17fSsherrym 482449e17fSsherrym #define UCODE_OPT_INSTALL 0x0001 492449e17fSsherrym #define UCODE_OPT_UPDATE 0x0002 502449e17fSsherrym #define UCODE_OPT_VERSION 0x0004 512449e17fSsherrym 522449e17fSsherrym static const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME; 532449e17fSsherrym 542449e17fSsherrym static char *cmdname; 552449e17fSsherrym 562449e17fSsherrym static char ucode_vendor_str[UCODE_MAX_VENDORS_NAME_LEN]; 572449e17fSsherrym static char ucode_install_path[] = UCODE_INSTALL_PATH; 582449e17fSsherrym 592449e17fSsherrym static int ucode_debug = 0; 602449e17fSsherrym 61*adc586deSMark Johnson static int ucode_convert_amd(const char *, uint8_t *, size_t); 62*adc586deSMark Johnson static int ucode_convert_intel(const char *, uint8_t *, size_t); 63*adc586deSMark Johnson 64*adc586deSMark Johnson static ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *); 65*adc586deSMark Johnson static ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *); 66*adc586deSMark Johnson 67*adc586deSMark Johnson static const struct ucode_ops ucode_ops[] = { 68*adc586deSMark Johnson { ucode_convert_intel, ucode_gen_files_intel, ucode_validate_intel }, 69*adc586deSMark Johnson { ucode_convert_amd, ucode_gen_files_amd, ucode_validate_amd }, 70*adc586deSMark Johnson }; 71*adc586deSMark Johnson 72*adc586deSMark Johnson const struct ucode_ops *ucode; 73*adc586deSMark Johnson 742449e17fSsherrym static void 752449e17fSsherrym dprintf(const char *format, ...) 762449e17fSsherrym { 772449e17fSsherrym if (ucode_debug) { 782449e17fSsherrym va_list alist; 792449e17fSsherrym va_start(alist, format); 802449e17fSsherrym (void) vfprintf(stderr, format, alist); 812449e17fSsherrym va_end(alist); 822449e17fSsherrym } 832449e17fSsherrym } 842449e17fSsherrym 852449e17fSsherrym static void 862449e17fSsherrym usage(int verbose) 872449e17fSsherrym { 882449e17fSsherrym (void) fprintf(stderr, gettext("usage:\n")); 892449e17fSsherrym (void) fprintf(stderr, "\t%s -v\n", cmdname); 902449e17fSsherrym if (verbose) { 912449e17fSsherrym (void) fprintf(stderr, 922449e17fSsherrym gettext("\t\t Shows running microcode version.\n\n")); 932449e17fSsherrym } 942449e17fSsherrym 95*adc586deSMark Johnson (void) fprintf(stderr, "\t%s -u microcode-file\n", cmdname); 962449e17fSsherrym if (verbose) { 972449e17fSsherrym (void) fprintf(stderr, gettext("\t\t Updates microcode to the " 982449e17fSsherrym "latest matching version found in\n" 99*adc586deSMark Johnson "\t\t microcode-file.\n\n")); 1002449e17fSsherrym } 1012449e17fSsherrym 102*adc586deSMark Johnson (void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname); 1032449e17fSsherrym if (verbose) { 1042449e17fSsherrym (void) fprintf(stderr, gettext("\t\t Installs microcode to be " 105*adc586deSMark Johnson "used for subsequent boots.\n\n")); 106*adc586deSMark Johnson (void) fprintf(stderr, gettext("Microcode file name must start " 107*adc586deSMark Johnson "with vendor name, such as \"intel\" or \"amd\".\n\n")); 1082449e17fSsherrym } 1092449e17fSsherrym } 1102449e17fSsherrym 1112449e17fSsherrym static void 1122449e17fSsherrym ucode_perror(const char *str, ucode_errno_t rc) 1132449e17fSsherrym { 1142449e17fSsherrym (void) fprintf(stderr, "%s: %s: %s\n", cmdname, str, 1152449e17fSsherrym errno == 0 ? ucode_strerror(rc) : strerror(errno)); 1162449e17fSsherrym errno = 0; 1172449e17fSsherrym } 1182449e17fSsherrym 1192449e17fSsherrym #define LINESIZE 120 /* copyright line sometimes is longer than 80 */ 1202449e17fSsherrym 1212449e17fSsherrym /* 1222449e17fSsherrym * Convert text format microcode release into binary format. 1232449e17fSsherrym * Return the number of characters read. 1242449e17fSsherrym */ 1252449e17fSsherrym static int 126*adc586deSMark Johnson ucode_convert_amd(const char *infile, uint8_t *buf, size_t size) 127*adc586deSMark Johnson { 128*adc586deSMark Johnson int fd; 129*adc586deSMark Johnson 130*adc586deSMark Johnson if (infile == NULL || buf == NULL || size == 0) 131*adc586deSMark Johnson return (0); 132*adc586deSMark Johnson 133*adc586deSMark Johnson if ((fd = open(infile, O_RDONLY)) < 0) 134*adc586deSMark Johnson return (0); 135*adc586deSMark Johnson 136*adc586deSMark Johnson size = read(fd, buf, size); 137*adc586deSMark Johnson 138*adc586deSMark Johnson (void) close(fd); 139*adc586deSMark Johnson 140*adc586deSMark Johnson return (size); 141*adc586deSMark Johnson } 142*adc586deSMark Johnson 143*adc586deSMark Johnson static int 144*adc586deSMark Johnson ucode_convert_intel(const char *infile, uint8_t *buf, size_t size) 1452449e17fSsherrym { 1462449e17fSsherrym char linebuf[LINESIZE]; 1472449e17fSsherrym FILE *infd = NULL; 1482449e17fSsherrym int count = 0, firstline = 1; 1492449e17fSsherrym uint32_t *intbuf = (uint32_t *)(intptr_t)buf; 1502449e17fSsherrym 1512449e17fSsherrym if (infile == NULL || buf == NULL || size == 0) 1522449e17fSsherrym return (0); 1532449e17fSsherrym 1542449e17fSsherrym if ((infd = fopen(infile, "r")) == NULL) 1552449e17fSsherrym return (0); 1562449e17fSsherrym 1572449e17fSsherrym while (fgets(linebuf, LINESIZE, infd)) { 1582449e17fSsherrym 1592449e17fSsherrym /* Check to see if we are processing a binary file */ 1602449e17fSsherrym if (firstline && !isprint(linebuf[0])) { 1612449e17fSsherrym if (fseek(infd, 0, SEEK_SET) == 0) 1622449e17fSsherrym count = fread(buf, 1, size, infd); 1632449e17fSsherrym 1642449e17fSsherrym (void) fclose(infd); 1652449e17fSsherrym return (count); 1662449e17fSsherrym } 1672449e17fSsherrym 1682449e17fSsherrym firstline = 0; 1692449e17fSsherrym 1702449e17fSsherrym /* Skip blank lines */ 1712449e17fSsherrym if (strlen(linebuf) == 1) 1722449e17fSsherrym continue; 1732449e17fSsherrym 1742449e17fSsherrym /* Skip lines with all spaces or tabs */ 1752449e17fSsherrym if (strcspn(linebuf, " \t") == 0) 1762449e17fSsherrym continue; 1772449e17fSsherrym 1782449e17fSsherrym /* Text file. Skip comments. */ 1792449e17fSsherrym if (linebuf[0] == '/') 1802449e17fSsherrym continue; 1812449e17fSsherrym 1822449e17fSsherrym if (sscanf(linebuf, "%x, %x, %x, %x", 1832449e17fSsherrym &intbuf[count], &intbuf[count+1], 1842449e17fSsherrym &intbuf[count+2], &intbuf[count+3]) != 4) 1852449e17fSsherrym break; 1862449e17fSsherrym 1872449e17fSsherrym count += 4; 1882449e17fSsherrym } 1892449e17fSsherrym 1902449e17fSsherrym (void) fclose(infd); 1912449e17fSsherrym 1922449e17fSsherrym /* 1932449e17fSsherrym * If we get here, we are processing a text format file 1942449e17fSsherrym * where "count" is used to count the number of integers 1952449e17fSsherrym * read. Convert it to number of characters read. 1962449e17fSsherrym */ 1972449e17fSsherrym return (count * sizeof (int)); 1982449e17fSsherrym } 1992449e17fSsherrym 2002449e17fSsherrym /* 2012449e17fSsherrym * Returns 0 if no need to update the link; -1 otherwise 2022449e17fSsherrym */ 2032449e17fSsherrym static int 204*adc586deSMark Johnson ucode_should_update_intel(char *filename, uint32_t new_rev) 2052449e17fSsherrym { 2062449e17fSsherrym int fd; 2072449e17fSsherrym struct stat statbuf; 208*adc586deSMark Johnson ucode_header_intel_t header; 2092449e17fSsherrym 2102449e17fSsherrym /* 2112449e17fSsherrym * If the file or link already exists, check to see if 2122449e17fSsherrym * it is necessary to update it. 2132449e17fSsherrym */ 2142449e17fSsherrym if (stat(filename, &statbuf) == 0) { 2152449e17fSsherrym if ((fd = open(filename, O_RDONLY)) == -1) 2162449e17fSsherrym return (-1); 2172449e17fSsherrym 2182449e17fSsherrym if (read(fd, &header, sizeof (header)) == -1) { 2192449e17fSsherrym (void) close(fd); 2202449e17fSsherrym return (-1); 2212449e17fSsherrym } 2222449e17fSsherrym 2232449e17fSsherrym (void) close(fd); 2242449e17fSsherrym 2252449e17fSsherrym if (header.uh_rev >= new_rev) 2262449e17fSsherrym return (0); 2272449e17fSsherrym } 2282449e17fSsherrym 2292449e17fSsherrym return (-1); 2302449e17fSsherrym } 2312449e17fSsherrym 2322449e17fSsherrym /* 2332449e17fSsherrym * Generate microcode binary files. Must be called after ucode_validate(). 2342449e17fSsherrym */ 2352449e17fSsherrym static ucode_errno_t 236*adc586deSMark Johnson ucode_gen_files_amd(uint8_t *buf, int size, char *path) 237*adc586deSMark Johnson { 238*adc586deSMark Johnson /* LINTED: pointer alignment */ 239*adc586deSMark Johnson uint32_t *ptr = (uint32_t *)buf; 240*adc586deSMark Johnson int plen = strlen(path); 241*adc586deSMark Johnson int fd, count, counter; 242*adc586deSMark Johnson ucode_header_amd_t *uh; 243*adc586deSMark Johnson int last_cpu_rev = 0; 244*adc586deSMark Johnson 245*adc586deSMark Johnson /* skip over magic number & equivalence table header */ 246*adc586deSMark Johnson ptr += 2; size -= 8; 247*adc586deSMark Johnson 248*adc586deSMark Johnson count = *ptr++; size -= 4; 249*adc586deSMark Johnson 250*adc586deSMark Johnson /* equivalence table uses special name */ 251*adc586deSMark Johnson (void) strlcat(path, "/equivalence-table", PATH_MAX); 252*adc586deSMark Johnson 253*adc586deSMark Johnson for (;;) { 254*adc586deSMark Johnson dprintf("path = %s\n", path); 255*adc586deSMark Johnson fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 256*adc586deSMark Johnson S_IRUSR | S_IRGRP | S_IROTH); 257*adc586deSMark Johnson 258*adc586deSMark Johnson if (fd == -1) { 259*adc586deSMark Johnson ucode_perror(path, EM_SYS); 260*adc586deSMark Johnson return (EM_SYS); 261*adc586deSMark Johnson } 262*adc586deSMark Johnson 263*adc586deSMark Johnson if (write(fd, ptr, count) != count) { 264*adc586deSMark Johnson (void) close(fd); 265*adc586deSMark Johnson ucode_perror(path, EM_SYS); 266*adc586deSMark Johnson return (EM_SYS); 267*adc586deSMark Johnson } 268*adc586deSMark Johnson 269*adc586deSMark Johnson (void) close(fd); 270*adc586deSMark Johnson ptr += count >> 2; size -= count; 271*adc586deSMark Johnson 272*adc586deSMark Johnson if (!size) 273*adc586deSMark Johnson return (EM_OK); 274*adc586deSMark Johnson 275*adc586deSMark Johnson ptr++; size -= 4; 276*adc586deSMark Johnson count = *ptr++; size -= 4; 277*adc586deSMark Johnson 278*adc586deSMark Johnson /* construct name from header information */ 279*adc586deSMark Johnson uh = (ucode_header_amd_t *)ptr; 280*adc586deSMark Johnson 281*adc586deSMark Johnson if (uh->uh_cpu_rev != last_cpu_rev) { 282*adc586deSMark Johnson last_cpu_rev = uh->uh_cpu_rev; 283*adc586deSMark Johnson counter = 0; 284*adc586deSMark Johnson } 285*adc586deSMark Johnson 286*adc586deSMark Johnson path[plen] = '\0'; 287*adc586deSMark Johnson (void) snprintf(path + plen, PATH_MAX - plen, "/%04X-%02X", 288*adc586deSMark Johnson uh->uh_cpu_rev, counter++); 289*adc586deSMark Johnson } 290*adc586deSMark Johnson } 291*adc586deSMark Johnson 292*adc586deSMark Johnson static ucode_errno_t 293*adc586deSMark Johnson ucode_gen_files_intel(uint8_t *buf, int size, char *path) 2942449e17fSsherrym { 2952449e17fSsherrym int remaining; 2962449e17fSsherrym char common_path[PATH_MAX]; 2972449e17fSsherrym DIR *dirp; 2982449e17fSsherrym struct dirent *dp; 2992449e17fSsherrym 3002449e17fSsherrym (void) snprintf(common_path, PATH_MAX, "%s/%s", path, 3012449e17fSsherrym UCODE_INSTALL_COMMON_PATH); 3022449e17fSsherrym 3032449e17fSsherrym if (mkdirp(common_path, 0755) == -1 && errno != EEXIST) { 3042449e17fSsherrym ucode_perror(common_path, EM_SYS); 3052449e17fSsherrym return (EM_SYS); 3062449e17fSsherrym } 3072449e17fSsherrym 3082449e17fSsherrym for (remaining = size; remaining > 0; ) { 3092449e17fSsherrym uint32_t total_size, body_size, offset; 3102449e17fSsherrym char firstname[PATH_MAX]; 3112449e17fSsherrym char name[PATH_MAX]; 3122449e17fSsherrym int i; 3132449e17fSsherrym uint8_t *curbuf = &buf[size - remaining]; 314*adc586deSMark Johnson ucode_header_intel_t *uhp; 315*adc586deSMark Johnson ucode_ext_table_intel_t *extp; 3162449e17fSsherrym 317*adc586deSMark Johnson uhp = (ucode_header_intel_t *)(intptr_t)curbuf; 318*adc586deSMark Johnson 319*adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 320*adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 3212449e17fSsherrym 3222449e17fSsherrym remaining -= total_size; 3232449e17fSsherrym 3242449e17fSsherrym (void) snprintf(firstname, PATH_MAX, "%s/%08X-%02X", 3252449e17fSsherrym common_path, uhp->uh_signature, uhp->uh_proc_flags); 3262449e17fSsherrym dprintf("firstname = %s\n", firstname); 3272449e17fSsherrym 328*adc586deSMark Johnson if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) { 3292449e17fSsherrym int fd; 3302449e17fSsherrym 3312449e17fSsherrym /* Remove the existing one first */ 3322449e17fSsherrym (void) unlink(firstname); 3332449e17fSsherrym 3342449e17fSsherrym if ((fd = open(firstname, O_WRONLY | O_CREAT | O_TRUNC, 3352449e17fSsherrym S_IRUSR | S_IRGRP | S_IROTH)) == -1) { 3362449e17fSsherrym ucode_perror(firstname, EM_SYS); 3372449e17fSsherrym return (EM_SYS); 3382449e17fSsherrym } 3392449e17fSsherrym 3402449e17fSsherrym if (write(fd, curbuf, total_size) != total_size) { 3412449e17fSsherrym (void) close(fd); 3422449e17fSsherrym ucode_perror(firstname, EM_SYS); 3432449e17fSsherrym return (EM_SYS); 3442449e17fSsherrym } 3452449e17fSsherrym 3462449e17fSsherrym (void) close(fd); 3472449e17fSsherrym } 3482449e17fSsherrym 3492449e17fSsherrym /* 3502449e17fSsherrym * Only 1 byte of the proc_flags field is used, therefore 3512449e17fSsherrym * we only need to match 8 potential platform ids. 3522449e17fSsherrym */ 3532449e17fSsherrym for (i = 0; i < 8; i++) { 3542449e17fSsherrym uint32_t platid = uhp->uh_proc_flags & (1 << i); 3552449e17fSsherrym 3562449e17fSsherrym if (platid == 0 && uhp->uh_proc_flags != 0) 3572449e17fSsherrym continue; 3582449e17fSsherrym 3592449e17fSsherrym (void) snprintf(name, PATH_MAX, 3602449e17fSsherrym "%s/%08X-%02X", path, uhp->uh_signature, platid); 3612449e17fSsherrym 3622449e17fSsherrym dprintf("proc_flags = %x, platid = %x, name = %s\n", 3632449e17fSsherrym uhp->uh_proc_flags, platid, name); 3642449e17fSsherrym 365*adc586deSMark Johnson if (ucode_should_update_intel(name, uhp->uh_rev) != 0) { 3662449e17fSsherrym 3672449e17fSsherrym /* Remove the existing one first */ 3682449e17fSsherrym (void) unlink(name); 3692449e17fSsherrym 3702449e17fSsherrym if (link(firstname, name) == -1) { 3712449e17fSsherrym ucode_perror(name, EM_SYS); 3722449e17fSsherrym return (EM_SYS); 3732449e17fSsherrym } 3742449e17fSsherrym } 3752449e17fSsherrym 3762449e17fSsherrym if (uhp->uh_proc_flags == 0) 3772449e17fSsherrym break; 3782449e17fSsherrym } 3792449e17fSsherrym 380*adc586deSMark Johnson offset = UCODE_HEADER_SIZE_INTEL + body_size; 3812449e17fSsherrym 3822449e17fSsherrym /* Check to see if there is extended signature table */ 3832449e17fSsherrym if (total_size == offset) 3842449e17fSsherrym continue; 3852449e17fSsherrym 3862449e17fSsherrym /* There is extended signature table. More processing. */ 387*adc586deSMark Johnson extp = (ucode_ext_table_intel_t *)(uintptr_t)&curbuf[offset]; 3882449e17fSsherrym 3892449e17fSsherrym for (i = 0; i < extp->uet_count; i++) { 390*adc586deSMark Johnson ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i]; 3912449e17fSsherrym int j; 3922449e17fSsherrym 3932449e17fSsherrym for (j = 0; j < 8; j++) { 3942449e17fSsherrym uint32_t id = uesp->ues_proc_flags & (1 << j); 3952449e17fSsherrym 3962449e17fSsherrym if (id == 0 && uesp->ues_proc_flags) 3972449e17fSsherrym continue; 3982449e17fSsherrym 3992449e17fSsherrym (void) snprintf(name, PATH_MAX, 4002449e17fSsherrym "%s/%08X-%02X", path, extp->uet_ext_sig[i], 4012449e17fSsherrym id); 4022449e17fSsherrym 403*adc586deSMark Johnson if (ucode_should_update_intel(name, uhp->uh_rev) 404*adc586deSMark Johnson != 0) { 4052449e17fSsherrym 4062449e17fSsherrym /* Remove the existing one first */ 4072449e17fSsherrym (void) unlink(name); 4082449e17fSsherrym if (link(firstname, name) == -1) { 4092449e17fSsherrym ucode_perror(name, EM_SYS); 4102449e17fSsherrym return (EM_SYS); 4112449e17fSsherrym } 4122449e17fSsherrym } 4132449e17fSsherrym 4142449e17fSsherrym if (uesp->ues_proc_flags == 0) 4152449e17fSsherrym break; 4162449e17fSsherrym } 4172449e17fSsherrym } 4182449e17fSsherrym 4192449e17fSsherrym } 4202449e17fSsherrym 4212449e17fSsherrym /* 4222449e17fSsherrym * Remove files with no links to them. These are probably 4232449e17fSsherrym * obsolete microcode files. 4242449e17fSsherrym */ 4252449e17fSsherrym if ((dirp = opendir(common_path)) == NULL) { 4262449e17fSsherrym ucode_perror(common_path, EM_SYS); 4272449e17fSsherrym return (EM_SYS); 4282449e17fSsherrym } 4292449e17fSsherrym 4302449e17fSsherrym while ((dp = readdir(dirp)) != NULL) { 4312449e17fSsherrym char filename[PATH_MAX]; 4322449e17fSsherrym struct stat statbuf; 4332449e17fSsherrym 4342449e17fSsherrym (void) snprintf(filename, PATH_MAX, 4352449e17fSsherrym "%s/%s", common_path, dp->d_name); 4362449e17fSsherrym if (stat(filename, &statbuf) == -1) 4372449e17fSsherrym continue; 4382449e17fSsherrym 4392449e17fSsherrym if ((statbuf.st_mode & S_IFMT) == S_IFREG) { 4402449e17fSsherrym if (statbuf.st_nlink == 1) 4412449e17fSsherrym (void) unlink(filename); 4422449e17fSsherrym } 4432449e17fSsherrym } 4442449e17fSsherrym 4452449e17fSsherrym (void) closedir(dirp); 4462449e17fSsherrym 4472449e17fSsherrym return (EM_OK); 4482449e17fSsherrym } 4492449e17fSsherrym 4502449e17fSsherrym /* 4512449e17fSsherrym * Returns 0 on success, 2 on usage error, and 3 on operation error. 4522449e17fSsherrym */ 4532449e17fSsherrym int 4542449e17fSsherrym main(int argc, char *argv[]) 4552449e17fSsherrym { 4562449e17fSsherrym int c; 4572449e17fSsherrym int action = 0; 4582449e17fSsherrym int actcount = 0; 4592449e17fSsherrym char *path = NULL; 4602449e17fSsherrym char *filename = NULL; 4612449e17fSsherrym int errflg = 0; 4622449e17fSsherrym int dev_fd = -1; 4632449e17fSsherrym int fd = -1; 4642449e17fSsherrym int verbose = 0; 4652449e17fSsherrym uint8_t *buf = NULL; 4662449e17fSsherrym ucode_errno_t rc = EM_OK; 4672449e17fSsherrym processorid_t cpuid_max; 4682449e17fSsherrym struct stat filestat; 4692449e17fSsherrym uint32_t ucode_size; 4702449e17fSsherrym 4712449e17fSsherrym (void) setlocale(LC_ALL, ""); 4722449e17fSsherrym 4732449e17fSsherrym #if !defined(TEXT_DOMAIN) 4742449e17fSsherrym #define TEXT_DOMAIN "SYS_TEST" 4752449e17fSsherrym #endif 4762449e17fSsherrym (void) textdomain(TEXT_DOMAIN); 4772449e17fSsherrym 4782449e17fSsherrym cmdname = basename(argv[0]); 4792449e17fSsherrym 4802449e17fSsherrym while ((c = getopt(argc, argv, "idhuvVR:")) != EOF) { 4812449e17fSsherrym switch (c) { 4822449e17fSsherrym 4832449e17fSsherrym case 'i': 4842449e17fSsherrym action |= UCODE_OPT_INSTALL; 4852449e17fSsherrym actcount++; 4862449e17fSsherrym break; 4872449e17fSsherrym 4882449e17fSsherrym case 'u': 4892449e17fSsherrym action |= UCODE_OPT_UPDATE; 4902449e17fSsherrym actcount++; 4912449e17fSsherrym break; 4922449e17fSsherrym 4932449e17fSsherrym case 'v': 4942449e17fSsherrym action |= UCODE_OPT_VERSION; 4952449e17fSsherrym actcount++; 4962449e17fSsherrym break; 4972449e17fSsherrym 4982449e17fSsherrym case 'd': 4992449e17fSsherrym ucode_debug = 1; 5002449e17fSsherrym break; 5012449e17fSsherrym 5022449e17fSsherrym case 'R': 5032449e17fSsherrym if (optarg[0] == '-') 5042449e17fSsherrym errflg++; 5052449e17fSsherrym else if (strlen(optarg) > UCODE_MAX_PATH_LEN) { 5062449e17fSsherrym (void) fprintf(stderr, 5072449e17fSsherrym gettext("Alternate path too long\n")); 5082449e17fSsherrym errflg++; 5092449e17fSsherrym } else if ((path = strdup(optarg)) == NULL) { 5102449e17fSsherrym errflg++; 5112449e17fSsherrym } 5122449e17fSsherrym 5132449e17fSsherrym break; 5142449e17fSsherrym 5152449e17fSsherrym case 'V': 5162449e17fSsherrym verbose = 1; 5172449e17fSsherrym break; 5182449e17fSsherrym 5192449e17fSsherrym case 'h': 5202449e17fSsherrym usage(1); 5212449e17fSsherrym return (0); 5222449e17fSsherrym 5232449e17fSsherrym default: 5242449e17fSsherrym usage(verbose); 5252449e17fSsherrym return (2); 5262449e17fSsherrym } 5272449e17fSsherrym } 5282449e17fSsherrym 5292449e17fSsherrym if (actcount != 1) { 5302449e17fSsherrym (void) fprintf(stderr, gettext("%s: options -v, -i and -u " 5312449e17fSsherrym "are mutually exclusive.\n"), cmdname); 5322449e17fSsherrym usage(verbose); 5332449e17fSsherrym return (2); 5342449e17fSsherrym } 5352449e17fSsherrym 5362449e17fSsherrym if (optind <= argc - 1) 5372449e17fSsherrym filename = argv[optind]; 5382449e17fSsherrym else if (!(action & UCODE_OPT_VERSION)) 5392449e17fSsherrym errflg++; 5402449e17fSsherrym 5412449e17fSsherrym if (errflg || action == 0) { 5422449e17fSsherrym usage(verbose); 5432449e17fSsherrym return (2); 5442449e17fSsherrym } 5452449e17fSsherrym 5462449e17fSsherrym /* 5472449e17fSsherrym * Convert from text format to binary format 5482449e17fSsherrym */ 5492449e17fSsherrym if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) { 550*adc586deSMark Johnson int i; 551*adc586deSMark Johnson UCODE_VENDORS; 552*adc586deSMark Johnson 553*adc586deSMark Johnson for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 554*adc586deSMark Johnson dprintf("i = %d, filestr = %s, filename = %s\n", 555*adc586deSMark Johnson i, ucode_vendors[i].filestr, filename); 556*adc586deSMark Johnson if (strncasecmp(ucode_vendors[i].filestr, 557*adc586deSMark Johnson basename(filename), 558*adc586deSMark Johnson strlen(ucode_vendors[i].filestr)) == 0) { 559*adc586deSMark Johnson ucode = &ucode_ops[i]; 560*adc586deSMark Johnson (void) strncpy(ucode_vendor_str, 561*adc586deSMark Johnson ucode_vendors[i].vendorstr, 562*adc586deSMark Johnson sizeof (ucode_vendor_str)); 563*adc586deSMark Johnson break; 564*adc586deSMark Johnson } 565*adc586deSMark Johnson } 566*adc586deSMark Johnson 567*adc586deSMark Johnson if (ucode_vendors[i].filestr == NULL) { 568*adc586deSMark Johnson rc = EM_NOVENDOR; 569*adc586deSMark Johnson ucode_perror(basename(filename), rc); 570*adc586deSMark Johnson goto err_out; 571*adc586deSMark Johnson } 572*adc586deSMark Johnson 5732449e17fSsherrym if ((stat(filename, &filestat)) < 0) { 5742449e17fSsherrym rc = EM_SYS; 5752449e17fSsherrym ucode_perror(filename, rc); 5762449e17fSsherrym goto err_out; 5772449e17fSsherrym } 5782449e17fSsherrym 5792449e17fSsherrym if ((filestat.st_mode & S_IFMT) != S_IFREG && 5802449e17fSsherrym (filestat.st_mode & S_IFMT) != S_IFLNK) { 5812449e17fSsherrym rc = EM_FILEFORMAT; 5822449e17fSsherrym ucode_perror(filename, rc); 5832449e17fSsherrym goto err_out; 5842449e17fSsherrym } 5852449e17fSsherrym 5862449e17fSsherrym if ((buf = malloc(filestat.st_size)) == NULL) { 5872449e17fSsherrym rc = EM_SYS; 5882449e17fSsherrym ucode_perror(filename, rc); 5892449e17fSsherrym goto err_out; 5902449e17fSsherrym } 5912449e17fSsherrym 592*adc586deSMark Johnson ucode_size = ucode->convert(filename, buf, filestat.st_size); 5932449e17fSsherrym 5942449e17fSsherrym dprintf("ucode_size = %d\n", ucode_size); 5952449e17fSsherrym 5962449e17fSsherrym if (ucode_size == 0) { 5972449e17fSsherrym rc = EM_FILEFORMAT; 5982449e17fSsherrym ucode_perror(filename, rc); 5992449e17fSsherrym goto err_out; 6002449e17fSsherrym } 6012449e17fSsherrym 602*adc586deSMark Johnson if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) { 6032449e17fSsherrym ucode_perror(filename, rc); 6042449e17fSsherrym goto err_out; 6052449e17fSsherrym } 6062449e17fSsherrym } 6072449e17fSsherrym 6082449e17fSsherrym /* 6092449e17fSsherrym * For the install option, the microcode file must start with 6102449e17fSsherrym * "intel" for Intel microcode, and "amd" for AMD microcode. 6112449e17fSsherrym */ 6122449e17fSsherrym if (action & UCODE_OPT_INSTALL) { 6132449e17fSsherrym /* 6142449e17fSsherrym * If no path is provided by the -R option, put the files in 6152449e17fSsherrym * /ucode_install_path/ucode_vendor_str/. 6162449e17fSsherrym */ 6172449e17fSsherrym if (path == NULL) { 6182449e17fSsherrym if ((path = malloc(PATH_MAX)) == NULL) { 6192449e17fSsherrym rc = EM_SYS; 6202449e17fSsherrym ucode_perror("malloc", rc); 6212449e17fSsherrym goto err_out; 6222449e17fSsherrym } 6232449e17fSsherrym 6242449e17fSsherrym (void) snprintf(path, PATH_MAX, "/%s/%s", 6252449e17fSsherrym ucode_install_path, ucode_vendor_str); 6262449e17fSsherrym } 6272449e17fSsherrym 6282449e17fSsherrym if (mkdirp(path, 0755) == -1 && errno != EEXIST) { 6292449e17fSsherrym rc = EM_SYS; 6302449e17fSsherrym ucode_perror(path, rc); 6312449e17fSsherrym goto err_out; 6322449e17fSsherrym } 6332449e17fSsherrym 634*adc586deSMark Johnson rc = ucode->gen_files(buf, ucode_size, path); 6352449e17fSsherrym 6362449e17fSsherrym goto err_out; 6372449e17fSsherrym } 6382449e17fSsherrym 6392449e17fSsherrym if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) { 6402449e17fSsherrym rc = EM_SYS; 6412449e17fSsherrym ucode_perror(ucode_dev, rc); 6422449e17fSsherrym goto err_out; 6432449e17fSsherrym } 6442449e17fSsherrym 6452449e17fSsherrym if (action & UCODE_OPT_VERSION) { 6462449e17fSsherrym int tmprc; 6472449e17fSsherrym uint32_t *revp = NULL; 6482449e17fSsherrym int i; 6492449e17fSsherrym #if defined(_SYSCALL32_IMPL) 6502449e17fSsherrym struct ucode_get_rev_struct32 inf32; 6512449e17fSsherrym #else 6522449e17fSsherrym struct ucode_get_rev_struct info; 6532449e17fSsherrym #endif 6542449e17fSsherrym 6552449e17fSsherrym cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX); 6562449e17fSsherrym 6572449e17fSsherrym if ((revp = (uint32_t *) 6582449e17fSsherrym malloc(cpuid_max * sizeof (uint32_t))) == NULL) { 6592449e17fSsherrym rc = EM_SYS; 6602449e17fSsherrym ucode_perror("malloc", rc); 6612449e17fSsherrym goto err_out; 6622449e17fSsherrym } 6632449e17fSsherrym 6642449e17fSsherrym for (i = 0; i < cpuid_max; i++) 6652449e17fSsherrym revp[i] = (uint32_t)-1; 6662449e17fSsherrym 6672449e17fSsherrym #if defined(_SYSCALL32_IMPL) 6682449e17fSsherrym info32.ugv_rev = (caddr32_t)revp; 6692449e17fSsherrym info32.ugv_size = cpuid_max; 6702449e17fSsherrym info32.ugv_errno = EM_OK; 6712449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info32); 6722449e17fSsherrym rc = info32.ugv_errno; 6732449e17fSsherrym #else 6742449e17fSsherrym info.ugv_rev = revp; 6752449e17fSsherrym info.ugv_size = cpuid_max; 6762449e17fSsherrym info.ugv_errno = EM_OK; 6772449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info); 6782449e17fSsherrym rc = info.ugv_errno; 6792449e17fSsherrym #endif 6802449e17fSsherrym 6812449e17fSsherrym if (tmprc && rc == EM_OK) { 6822449e17fSsherrym rc = EM_SYS; 6832449e17fSsherrym } 6842449e17fSsherrym 6852449e17fSsherrym if (rc == EM_OK) { 6862449e17fSsherrym (void) printf(gettext("CPU\tMicrocode Version\n")); 6872449e17fSsherrym for (i = 0; i < cpuid_max; i++) { 6882449e17fSsherrym if (info.ugv_rev[i] == (uint32_t)-1) 6892449e17fSsherrym continue; 6902449e17fSsherrym (void) printf("%d\t0x%x\n", i, info.ugv_rev[i]); 6912449e17fSsherrym } 6922449e17fSsherrym } else { 6932449e17fSsherrym ucode_perror(gettext("get microcode version"), rc); 6942449e17fSsherrym } 6952449e17fSsherrym 6962449e17fSsherrym if (revp) 6972449e17fSsherrym free(revp); 6982449e17fSsherrym } 6992449e17fSsherrym 7002449e17fSsherrym if (action & UCODE_OPT_UPDATE) { 7012449e17fSsherrym int tmprc; 7022449e17fSsherrym #if defined(_SYSCALL32_IMPL) 7032449e17fSsherrym struct ucode_write_struct32 uw_struct32; 7042449e17fSsherrym #else 7052449e17fSsherrym struct ucode_write_struct uw_struct; 7062449e17fSsherrym #endif 7072449e17fSsherrym 7082449e17fSsherrym #if defined(_SYSCALL32_IMPL) 7092449e17fSsherrym uw_struct32.uw_size = ucode_size; 7102449e17fSsherrym uw_struct32.uw_ucode = (caddr32_t)buf; 7112449e17fSsherrym uw_struct32.uw_errno = EM_OK; 7122449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct32); 7132449e17fSsherrym rc = uw_struct32.uw_errno; 7142449e17fSsherrym 7152449e17fSsherrym #else 7162449e17fSsherrym uw_struct.uw_size = ucode_size; 7172449e17fSsherrym uw_struct.uw_ucode = buf; 7182449e17fSsherrym uw_struct.uw_errno = EM_OK; 7192449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct); 7202449e17fSsherrym rc = uw_struct.uw_errno; 7212449e17fSsherrym #endif 7222449e17fSsherrym 7232449e17fSsherrym if (rc == EM_OK) { 7242449e17fSsherrym if (tmprc) { 7252449e17fSsherrym rc = EM_SYS; 7262449e17fSsherrym ucode_perror(ucode_dev, rc); 7272449e17fSsherrym } 7282449e17fSsherrym } else if (rc == EM_NOMATCH || rc == EM_HIGHERREV) { 7292449e17fSsherrym ucode_perror(filename, rc); 7302449e17fSsherrym } else { 7312449e17fSsherrym ucode_perror(gettext("microcode update"), rc); 7322449e17fSsherrym } 7332449e17fSsherrym } 7342449e17fSsherrym 7352449e17fSsherrym err_out: 7362449e17fSsherrym if (dev_fd != -1) 7372449e17fSsherrym (void) close(dev_fd); 7382449e17fSsherrym 7392449e17fSsherrym if (fd != -1) 7402449e17fSsherrym (void) close(fd); 7412449e17fSsherrym 7422449e17fSsherrym free(buf); 7432449e17fSsherrym free(path); 7442449e17fSsherrym 7452449e17fSsherrym if (rc != EM_OK) 7462449e17fSsherrym return (3); 7472449e17fSsherrym 7482449e17fSsherrym return (0); 7492449e17fSsherrym } 750