14581Ssherrym /* 24581Ssherrym * CDDL HEADER START 34581Ssherrym * 44581Ssherrym * The contents of this file are subject to the terms of the 54581Ssherrym * Common Development and Distribution License (the "License"). 64581Ssherrym * You may not use this file except in compliance with the License. 74581Ssherrym * 84581Ssherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94581Ssherrym * or http://www.opensolaris.org/os/licensing. 104581Ssherrym * See the License for the specific language governing permissions 114581Ssherrym * and limitations under the License. 124581Ssherrym * 134581Ssherrym * When distributing Covered Code, include this CDDL HEADER in each 144581Ssherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154581Ssherrym * If applicable, add the following below this CDDL HEADER, with the 164581Ssherrym * fields enclosed by brackets "[]" replaced with your own identifying 174581Ssherrym * information: Portions Copyright [yyyy] [name of copyright owner] 184581Ssherrym * 194581Ssherrym * CDDL HEADER END 204581Ssherrym */ 214581Ssherrym /* 228647SMark.Johnson@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 234581Ssherrym * Use is subject to license terms. 244581Ssherrym */ 254581Ssherrym 264581Ssherrym #include <sys/types.h> 274581Ssherrym #include <sys/processor.h> 284581Ssherrym #include <sys/ucode.h> 294581Ssherrym #include <sys/ioctl.h> 304581Ssherrym #include <sys/stat.h> 314581Ssherrym #include <unistd.h> 324581Ssherrym #include <dirent.h> 334581Ssherrym #include <fcntl.h> 344581Ssherrym #include <errno.h> 354581Ssherrym #include <stdio.h> 364581Ssherrym #include <stdlib.h> 374581Ssherrym #include <stdarg.h> 384581Ssherrym #include <string.h> 394581Ssherrym #include <errno.h> 404581Ssherrym #include <syslog.h> 414581Ssherrym #include <time.h> 424581Ssherrym #include <ctype.h> 434581Ssherrym #include <assert.h> 444581Ssherrym #include <libgen.h> 454581Ssherrym #include <locale.h> 464581Ssherrym #include <libintl.h> 474581Ssherrym 484581Ssherrym #define UCODE_OPT_INSTALL 0x0001 494581Ssherrym #define UCODE_OPT_UPDATE 0x0002 504581Ssherrym #define UCODE_OPT_VERSION 0x0004 514581Ssherrym 524581Ssherrym static const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME; 534581Ssherrym 544581Ssherrym static char *cmdname; 554581Ssherrym 564581Ssherrym static char ucode_vendor_str[UCODE_MAX_VENDORS_NAME_LEN]; 574581Ssherrym static char ucode_install_path[] = UCODE_INSTALL_PATH; 584581Ssherrym 594581Ssherrym static int ucode_debug = 0; 604581Ssherrym 617605SMark.Johnson@Sun.COM static int ucode_convert_amd(const char *, uint8_t *, size_t); 627605SMark.Johnson@Sun.COM static int ucode_convert_intel(const char *, uint8_t *, size_t); 637605SMark.Johnson@Sun.COM 647605SMark.Johnson@Sun.COM static ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *); 657605SMark.Johnson@Sun.COM static ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *); 667605SMark.Johnson@Sun.COM 677605SMark.Johnson@Sun.COM static const struct ucode_ops ucode_ops[] = { 687605SMark.Johnson@Sun.COM { ucode_convert_intel, ucode_gen_files_intel, ucode_validate_intel }, 697605SMark.Johnson@Sun.COM { ucode_convert_amd, ucode_gen_files_amd, ucode_validate_amd }, 707605SMark.Johnson@Sun.COM }; 717605SMark.Johnson@Sun.COM 727605SMark.Johnson@Sun.COM const struct ucode_ops *ucode; 737605SMark.Johnson@Sun.COM 744581Ssherrym static void 754581Ssherrym dprintf(const char *format, ...) 764581Ssherrym { 774581Ssherrym if (ucode_debug) { 784581Ssherrym va_list alist; 794581Ssherrym va_start(alist, format); 804581Ssherrym (void) vfprintf(stderr, format, alist); 814581Ssherrym va_end(alist); 824581Ssherrym } 834581Ssherrym } 844581Ssherrym 854581Ssherrym static void 864581Ssherrym usage(int verbose) 874581Ssherrym { 884581Ssherrym (void) fprintf(stderr, gettext("usage:\n")); 894581Ssherrym (void) fprintf(stderr, "\t%s -v\n", cmdname); 904581Ssherrym if (verbose) { 914581Ssherrym (void) fprintf(stderr, 924581Ssherrym gettext("\t\t Shows running microcode version.\n\n")); 934581Ssherrym } 944581Ssherrym 957605SMark.Johnson@Sun.COM (void) fprintf(stderr, "\t%s -u microcode-file\n", cmdname); 964581Ssherrym if (verbose) { 974581Ssherrym (void) fprintf(stderr, gettext("\t\t Updates microcode to the " 984581Ssherrym "latest matching version found in\n" 997605SMark.Johnson@Sun.COM "\t\t microcode-file.\n\n")); 1004581Ssherrym } 1014581Ssherrym 1027605SMark.Johnson@Sun.COM (void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname); 1034581Ssherrym if (verbose) { 1044581Ssherrym (void) fprintf(stderr, gettext("\t\t Installs microcode to be " 1057605SMark.Johnson@Sun.COM "used for subsequent boots.\n\n")); 1067605SMark.Johnson@Sun.COM (void) fprintf(stderr, gettext("Microcode file name must start " 1077605SMark.Johnson@Sun.COM "with vendor name, such as \"intel\" or \"amd\".\n\n")); 1084581Ssherrym } 1094581Ssherrym } 1104581Ssherrym 1114581Ssherrym static void 1124581Ssherrym ucode_perror(const char *str, ucode_errno_t rc) 1134581Ssherrym { 1144581Ssherrym (void) fprintf(stderr, "%s: %s: %s\n", cmdname, str, 1154581Ssherrym errno == 0 ? ucode_strerror(rc) : strerror(errno)); 1164581Ssherrym errno = 0; 1174581Ssherrym } 1184581Ssherrym 1194581Ssherrym #define LINESIZE 120 /* copyright line sometimes is longer than 80 */ 1204581Ssherrym 1214581Ssherrym /* 1224581Ssherrym * Convert text format microcode release into binary format. 1234581Ssherrym * Return the number of characters read. 1244581Ssherrym */ 1254581Ssherrym static int 1267605SMark.Johnson@Sun.COM ucode_convert_amd(const char *infile, uint8_t *buf, size_t size) 1277605SMark.Johnson@Sun.COM { 1287605SMark.Johnson@Sun.COM int fd; 1297605SMark.Johnson@Sun.COM 1307605SMark.Johnson@Sun.COM if (infile == NULL || buf == NULL || size == 0) 1317605SMark.Johnson@Sun.COM return (0); 1327605SMark.Johnson@Sun.COM 1337605SMark.Johnson@Sun.COM if ((fd = open(infile, O_RDONLY)) < 0) 1347605SMark.Johnson@Sun.COM return (0); 1357605SMark.Johnson@Sun.COM 1367605SMark.Johnson@Sun.COM size = read(fd, buf, size); 1377605SMark.Johnson@Sun.COM 1387605SMark.Johnson@Sun.COM (void) close(fd); 1397605SMark.Johnson@Sun.COM 1407605SMark.Johnson@Sun.COM return (size); 1417605SMark.Johnson@Sun.COM } 1427605SMark.Johnson@Sun.COM 1437605SMark.Johnson@Sun.COM static int 1447605SMark.Johnson@Sun.COM ucode_convert_intel(const char *infile, uint8_t *buf, size_t size) 1454581Ssherrym { 1464581Ssherrym char linebuf[LINESIZE]; 1474581Ssherrym FILE *infd = NULL; 1484581Ssherrym int count = 0, firstline = 1; 1494581Ssherrym uint32_t *intbuf = (uint32_t *)(intptr_t)buf; 1504581Ssherrym 1514581Ssherrym if (infile == NULL || buf == NULL || size == 0) 1524581Ssherrym return (0); 1534581Ssherrym 1544581Ssherrym if ((infd = fopen(infile, "r")) == NULL) 1554581Ssherrym return (0); 1564581Ssherrym 1574581Ssherrym while (fgets(linebuf, LINESIZE, infd)) { 1584581Ssherrym 1594581Ssherrym /* Check to see if we are processing a binary file */ 1604581Ssherrym if (firstline && !isprint(linebuf[0])) { 1614581Ssherrym if (fseek(infd, 0, SEEK_SET) == 0) 1624581Ssherrym count = fread(buf, 1, size, infd); 1634581Ssherrym 1644581Ssherrym (void) fclose(infd); 1654581Ssherrym return (count); 1664581Ssherrym } 1674581Ssherrym 1684581Ssherrym firstline = 0; 1694581Ssherrym 1704581Ssherrym /* Skip blank lines */ 1714581Ssherrym if (strlen(linebuf) == 1) 1724581Ssherrym continue; 1734581Ssherrym 1744581Ssherrym /* Skip lines with all spaces or tabs */ 1754581Ssherrym if (strcspn(linebuf, " \t") == 0) 1764581Ssherrym continue; 1774581Ssherrym 1784581Ssherrym /* Text file. Skip comments. */ 1794581Ssherrym if (linebuf[0] == '/') 1804581Ssherrym continue; 1814581Ssherrym 1824581Ssherrym if (sscanf(linebuf, "%x, %x, %x, %x", 1834581Ssherrym &intbuf[count], &intbuf[count+1], 1844581Ssherrym &intbuf[count+2], &intbuf[count+3]) != 4) 1854581Ssherrym break; 1864581Ssherrym 1874581Ssherrym count += 4; 1884581Ssherrym } 1894581Ssherrym 1904581Ssherrym (void) fclose(infd); 1914581Ssherrym 1924581Ssherrym /* 1934581Ssherrym * If we get here, we are processing a text format file 1944581Ssherrym * where "count" is used to count the number of integers 1954581Ssherrym * read. Convert it to number of characters read. 1964581Ssherrym */ 1974581Ssherrym return (count * sizeof (int)); 1984581Ssherrym } 1994581Ssherrym 2004581Ssherrym /* 2014581Ssherrym * Returns 0 if no need to update the link; -1 otherwise 2024581Ssherrym */ 2034581Ssherrym static int 2047605SMark.Johnson@Sun.COM ucode_should_update_intel(char *filename, uint32_t new_rev) 2054581Ssherrym { 2064581Ssherrym int fd; 2074581Ssherrym struct stat statbuf; 2087605SMark.Johnson@Sun.COM ucode_header_intel_t header; 2094581Ssherrym 2104581Ssherrym /* 2114581Ssherrym * If the file or link already exists, check to see if 2124581Ssherrym * it is necessary to update it. 2134581Ssherrym */ 2144581Ssherrym if (stat(filename, &statbuf) == 0) { 2154581Ssherrym if ((fd = open(filename, O_RDONLY)) == -1) 2164581Ssherrym return (-1); 2174581Ssherrym 2184581Ssherrym if (read(fd, &header, sizeof (header)) == -1) { 2194581Ssherrym (void) close(fd); 2204581Ssherrym return (-1); 2214581Ssherrym } 2224581Ssherrym 2234581Ssherrym (void) close(fd); 2244581Ssherrym 2254581Ssherrym if (header.uh_rev >= new_rev) 2264581Ssherrym return (0); 2274581Ssherrym } 2284581Ssherrym 2294581Ssherrym return (-1); 2304581Ssherrym } 2314581Ssherrym 2324581Ssherrym /* 2334581Ssherrym * Generate microcode binary files. Must be called after ucode_validate(). 2344581Ssherrym */ 2354581Ssherrym static ucode_errno_t 2367605SMark.Johnson@Sun.COM ucode_gen_files_amd(uint8_t *buf, int size, char *path) 2377605SMark.Johnson@Sun.COM { 2387605SMark.Johnson@Sun.COM /* LINTED: pointer alignment */ 2397605SMark.Johnson@Sun.COM uint32_t *ptr = (uint32_t *)buf; 240*8836SMark.Johnson@Sun.COM char common_path[PATH_MAX]; 2417605SMark.Johnson@Sun.COM int fd, count, counter; 2427605SMark.Johnson@Sun.COM ucode_header_amd_t *uh; 2437605SMark.Johnson@Sun.COM int last_cpu_rev = 0; 2447605SMark.Johnson@Sun.COM 2458647SMark.Johnson@Sun.COM 246*8836SMark.Johnson@Sun.COM /* write container file */ 247*8836SMark.Johnson@Sun.COM (void) snprintf(common_path, PATH_MAX, "%s/%s", path, "container"); 248*8836SMark.Johnson@Sun.COM 249*8836SMark.Johnson@Sun.COM dprintf("path = %s\n", common_path); 250*8836SMark.Johnson@Sun.COM fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC, 2518647SMark.Johnson@Sun.COM S_IRUSR | S_IRGRP | S_IROTH); 2528647SMark.Johnson@Sun.COM 2538647SMark.Johnson@Sun.COM if (fd == -1) { 254*8836SMark.Johnson@Sun.COM ucode_perror(common_path, EM_SYS); 2558647SMark.Johnson@Sun.COM return (EM_SYS); 2568647SMark.Johnson@Sun.COM } 2578647SMark.Johnson@Sun.COM 2588647SMark.Johnson@Sun.COM if (write(fd, buf, size) != size) { 2598647SMark.Johnson@Sun.COM (void) close(fd); 260*8836SMark.Johnson@Sun.COM ucode_perror(common_path, EM_SYS); 2618647SMark.Johnson@Sun.COM return (EM_SYS); 2628647SMark.Johnson@Sun.COM } 2638647SMark.Johnson@Sun.COM 2648647SMark.Johnson@Sun.COM (void) close(fd); 2658647SMark.Johnson@Sun.COM 2667605SMark.Johnson@Sun.COM /* skip over magic number & equivalence table header */ 2677605SMark.Johnson@Sun.COM ptr += 2; size -= 8; 2687605SMark.Johnson@Sun.COM 2697605SMark.Johnson@Sun.COM count = *ptr++; size -= 4; 2707605SMark.Johnson@Sun.COM 2717605SMark.Johnson@Sun.COM /* equivalence table uses special name */ 272*8836SMark.Johnson@Sun.COM (void) snprintf(common_path, PATH_MAX, "%s/%s", path, 273*8836SMark.Johnson@Sun.COM "equivalence-table"); 2747605SMark.Johnson@Sun.COM 2757605SMark.Johnson@Sun.COM for (;;) { 276*8836SMark.Johnson@Sun.COM dprintf("path = %s\n", common_path); 277*8836SMark.Johnson@Sun.COM fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC, 2787605SMark.Johnson@Sun.COM S_IRUSR | S_IRGRP | S_IROTH); 2797605SMark.Johnson@Sun.COM 2807605SMark.Johnson@Sun.COM if (fd == -1) { 281*8836SMark.Johnson@Sun.COM ucode_perror(common_path, EM_SYS); 2827605SMark.Johnson@Sun.COM return (EM_SYS); 2837605SMark.Johnson@Sun.COM } 2847605SMark.Johnson@Sun.COM 2857605SMark.Johnson@Sun.COM if (write(fd, ptr, count) != count) { 2867605SMark.Johnson@Sun.COM (void) close(fd); 287*8836SMark.Johnson@Sun.COM ucode_perror(common_path, EM_SYS); 2887605SMark.Johnson@Sun.COM return (EM_SYS); 2897605SMark.Johnson@Sun.COM } 2907605SMark.Johnson@Sun.COM 2917605SMark.Johnson@Sun.COM (void) close(fd); 2927605SMark.Johnson@Sun.COM ptr += count >> 2; size -= count; 2937605SMark.Johnson@Sun.COM 2947605SMark.Johnson@Sun.COM if (!size) 2957605SMark.Johnson@Sun.COM return (EM_OK); 2967605SMark.Johnson@Sun.COM 2977605SMark.Johnson@Sun.COM ptr++; size -= 4; 2987605SMark.Johnson@Sun.COM count = *ptr++; size -= 4; 2997605SMark.Johnson@Sun.COM 3007605SMark.Johnson@Sun.COM /* construct name from header information */ 3017605SMark.Johnson@Sun.COM uh = (ucode_header_amd_t *)ptr; 3027605SMark.Johnson@Sun.COM 3037605SMark.Johnson@Sun.COM if (uh->uh_cpu_rev != last_cpu_rev) { 3047605SMark.Johnson@Sun.COM last_cpu_rev = uh->uh_cpu_rev; 3057605SMark.Johnson@Sun.COM counter = 0; 3067605SMark.Johnson@Sun.COM } 3077605SMark.Johnson@Sun.COM 308*8836SMark.Johnson@Sun.COM (void) snprintf(common_path, PATH_MAX, "%s/%04X-%02X", path, 3097605SMark.Johnson@Sun.COM uh->uh_cpu_rev, counter++); 3107605SMark.Johnson@Sun.COM } 3117605SMark.Johnson@Sun.COM } 3127605SMark.Johnson@Sun.COM 3137605SMark.Johnson@Sun.COM static ucode_errno_t 3147605SMark.Johnson@Sun.COM ucode_gen_files_intel(uint8_t *buf, int size, char *path) 3154581Ssherrym { 3164581Ssherrym int remaining; 3174581Ssherrym char common_path[PATH_MAX]; 3184581Ssherrym DIR *dirp; 3194581Ssherrym struct dirent *dp; 3204581Ssherrym 3214581Ssherrym (void) snprintf(common_path, PATH_MAX, "%s/%s", path, 3224581Ssherrym UCODE_INSTALL_COMMON_PATH); 3234581Ssherrym 3244581Ssherrym if (mkdirp(common_path, 0755) == -1 && errno != EEXIST) { 3254581Ssherrym ucode_perror(common_path, EM_SYS); 3264581Ssherrym return (EM_SYS); 3274581Ssherrym } 3284581Ssherrym 3294581Ssherrym for (remaining = size; remaining > 0; ) { 3304581Ssherrym uint32_t total_size, body_size, offset; 3314581Ssherrym char firstname[PATH_MAX]; 3324581Ssherrym char name[PATH_MAX]; 3334581Ssherrym int i; 3344581Ssherrym uint8_t *curbuf = &buf[size - remaining]; 3357605SMark.Johnson@Sun.COM ucode_header_intel_t *uhp; 3367605SMark.Johnson@Sun.COM ucode_ext_table_intel_t *extp; 3374581Ssherrym 3387605SMark.Johnson@Sun.COM uhp = (ucode_header_intel_t *)(intptr_t)curbuf; 3397605SMark.Johnson@Sun.COM 3407605SMark.Johnson@Sun.COM total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 3417605SMark.Johnson@Sun.COM body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 3424581Ssherrym 3434581Ssherrym remaining -= total_size; 3444581Ssherrym 3454581Ssherrym (void) snprintf(firstname, PATH_MAX, "%s/%08X-%02X", 3464581Ssherrym common_path, uhp->uh_signature, uhp->uh_proc_flags); 3474581Ssherrym dprintf("firstname = %s\n", firstname); 3484581Ssherrym 3497605SMark.Johnson@Sun.COM if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) { 3504581Ssherrym int fd; 3514581Ssherrym 3524581Ssherrym /* Remove the existing one first */ 3534581Ssherrym (void) unlink(firstname); 3544581Ssherrym 3554581Ssherrym if ((fd = open(firstname, O_WRONLY | O_CREAT | O_TRUNC, 3564581Ssherrym S_IRUSR | S_IRGRP | S_IROTH)) == -1) { 3574581Ssherrym ucode_perror(firstname, EM_SYS); 3584581Ssherrym return (EM_SYS); 3594581Ssherrym } 3604581Ssherrym 3614581Ssherrym if (write(fd, curbuf, total_size) != total_size) { 3624581Ssherrym (void) close(fd); 3634581Ssherrym ucode_perror(firstname, EM_SYS); 3644581Ssherrym return (EM_SYS); 3654581Ssherrym } 3664581Ssherrym 3674581Ssherrym (void) close(fd); 3684581Ssherrym } 3694581Ssherrym 3704581Ssherrym /* 3714581Ssherrym * Only 1 byte of the proc_flags field is used, therefore 3724581Ssherrym * we only need to match 8 potential platform ids. 3734581Ssherrym */ 3744581Ssherrym for (i = 0; i < 8; i++) { 3754581Ssherrym uint32_t platid = uhp->uh_proc_flags & (1 << i); 3764581Ssherrym 3774581Ssherrym if (platid == 0 && uhp->uh_proc_flags != 0) 3784581Ssherrym continue; 3794581Ssherrym 3804581Ssherrym (void) snprintf(name, PATH_MAX, 3814581Ssherrym "%s/%08X-%02X", path, uhp->uh_signature, platid); 3824581Ssherrym 3834581Ssherrym dprintf("proc_flags = %x, platid = %x, name = %s\n", 3844581Ssherrym uhp->uh_proc_flags, platid, name); 3854581Ssherrym 3867605SMark.Johnson@Sun.COM if (ucode_should_update_intel(name, uhp->uh_rev) != 0) { 3874581Ssherrym 3884581Ssherrym /* Remove the existing one first */ 3894581Ssherrym (void) unlink(name); 3904581Ssherrym 3914581Ssherrym if (link(firstname, name) == -1) { 3924581Ssherrym ucode_perror(name, EM_SYS); 3934581Ssherrym return (EM_SYS); 3944581Ssherrym } 3954581Ssherrym } 3964581Ssherrym 3974581Ssherrym if (uhp->uh_proc_flags == 0) 3984581Ssherrym break; 3994581Ssherrym } 4004581Ssherrym 4017605SMark.Johnson@Sun.COM offset = UCODE_HEADER_SIZE_INTEL + body_size; 4024581Ssherrym 4034581Ssherrym /* Check to see if there is extended signature table */ 4044581Ssherrym if (total_size == offset) 4054581Ssherrym continue; 4064581Ssherrym 4074581Ssherrym /* There is extended signature table. More processing. */ 4087605SMark.Johnson@Sun.COM extp = (ucode_ext_table_intel_t *)(uintptr_t)&curbuf[offset]; 4094581Ssherrym 4104581Ssherrym for (i = 0; i < extp->uet_count; i++) { 4117605SMark.Johnson@Sun.COM ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i]; 4124581Ssherrym int j; 4134581Ssherrym 4144581Ssherrym for (j = 0; j < 8; j++) { 4154581Ssherrym uint32_t id = uesp->ues_proc_flags & (1 << j); 4164581Ssherrym 4174581Ssherrym if (id == 0 && uesp->ues_proc_flags) 4184581Ssherrym continue; 4194581Ssherrym 4204581Ssherrym (void) snprintf(name, PATH_MAX, 4214581Ssherrym "%s/%08X-%02X", path, extp->uet_ext_sig[i], 4224581Ssherrym id); 4234581Ssherrym 4247605SMark.Johnson@Sun.COM if (ucode_should_update_intel(name, uhp->uh_rev) 4257605SMark.Johnson@Sun.COM != 0) { 4264581Ssherrym 4274581Ssherrym /* Remove the existing one first */ 4284581Ssherrym (void) unlink(name); 4294581Ssherrym if (link(firstname, name) == -1) { 4304581Ssherrym ucode_perror(name, EM_SYS); 4314581Ssherrym return (EM_SYS); 4324581Ssherrym } 4334581Ssherrym } 4344581Ssherrym 4354581Ssherrym if (uesp->ues_proc_flags == 0) 4364581Ssherrym break; 4374581Ssherrym } 4384581Ssherrym } 4394581Ssherrym 4404581Ssherrym } 4414581Ssherrym 4424581Ssherrym /* 4434581Ssherrym * Remove files with no links to them. These are probably 4444581Ssherrym * obsolete microcode files. 4454581Ssherrym */ 4464581Ssherrym if ((dirp = opendir(common_path)) == NULL) { 4474581Ssherrym ucode_perror(common_path, EM_SYS); 4484581Ssherrym return (EM_SYS); 4494581Ssherrym } 4504581Ssherrym 4514581Ssherrym while ((dp = readdir(dirp)) != NULL) { 4524581Ssherrym char filename[PATH_MAX]; 4534581Ssherrym struct stat statbuf; 4544581Ssherrym 4554581Ssherrym (void) snprintf(filename, PATH_MAX, 4564581Ssherrym "%s/%s", common_path, dp->d_name); 4574581Ssherrym if (stat(filename, &statbuf) == -1) 4584581Ssherrym continue; 4594581Ssherrym 4604581Ssherrym if ((statbuf.st_mode & S_IFMT) == S_IFREG) { 4614581Ssherrym if (statbuf.st_nlink == 1) 4624581Ssherrym (void) unlink(filename); 4634581Ssherrym } 4644581Ssherrym } 4654581Ssherrym 4664581Ssherrym (void) closedir(dirp); 4674581Ssherrym 4684581Ssherrym return (EM_OK); 4694581Ssherrym } 4704581Ssherrym 4714581Ssherrym /* 4724581Ssherrym * Returns 0 on success, 2 on usage error, and 3 on operation error. 4734581Ssherrym */ 4744581Ssherrym int 4754581Ssherrym main(int argc, char *argv[]) 4764581Ssherrym { 4774581Ssherrym int c; 4784581Ssherrym int action = 0; 4794581Ssherrym int actcount = 0; 4804581Ssherrym char *path = NULL; 4814581Ssherrym char *filename = NULL; 4824581Ssherrym int errflg = 0; 4834581Ssherrym int dev_fd = -1; 4844581Ssherrym int fd = -1; 4854581Ssherrym int verbose = 0; 4864581Ssherrym uint8_t *buf = NULL; 4874581Ssherrym ucode_errno_t rc = EM_OK; 4884581Ssherrym processorid_t cpuid_max; 4894581Ssherrym struct stat filestat; 4904581Ssherrym uint32_t ucode_size; 4914581Ssherrym 4924581Ssherrym (void) setlocale(LC_ALL, ""); 4934581Ssherrym 4944581Ssherrym #if !defined(TEXT_DOMAIN) 4954581Ssherrym #define TEXT_DOMAIN "SYS_TEST" 4964581Ssherrym #endif 4974581Ssherrym (void) textdomain(TEXT_DOMAIN); 4984581Ssherrym 4994581Ssherrym cmdname = basename(argv[0]); 5004581Ssherrym 5014581Ssherrym while ((c = getopt(argc, argv, "idhuvVR:")) != EOF) { 5024581Ssherrym switch (c) { 5034581Ssherrym 5044581Ssherrym case 'i': 5054581Ssherrym action |= UCODE_OPT_INSTALL; 5064581Ssherrym actcount++; 5074581Ssherrym break; 5084581Ssherrym 5094581Ssherrym case 'u': 5104581Ssherrym action |= UCODE_OPT_UPDATE; 5114581Ssherrym actcount++; 5124581Ssherrym break; 5134581Ssherrym 5144581Ssherrym case 'v': 5154581Ssherrym action |= UCODE_OPT_VERSION; 5164581Ssherrym actcount++; 5174581Ssherrym break; 5184581Ssherrym 5194581Ssherrym case 'd': 5204581Ssherrym ucode_debug = 1; 5214581Ssherrym break; 5224581Ssherrym 5234581Ssherrym case 'R': 5244581Ssherrym if (optarg[0] == '-') 5254581Ssherrym errflg++; 5264581Ssherrym else if (strlen(optarg) > UCODE_MAX_PATH_LEN) { 5274581Ssherrym (void) fprintf(stderr, 5284581Ssherrym gettext("Alternate path too long\n")); 5294581Ssherrym errflg++; 5304581Ssherrym } else if ((path = strdup(optarg)) == NULL) { 5314581Ssherrym errflg++; 5324581Ssherrym } 5334581Ssherrym 5344581Ssherrym break; 5354581Ssherrym 5364581Ssherrym case 'V': 5374581Ssherrym verbose = 1; 5384581Ssherrym break; 5394581Ssherrym 5404581Ssherrym case 'h': 5414581Ssherrym usage(1); 5424581Ssherrym return (0); 5434581Ssherrym 5444581Ssherrym default: 5454581Ssherrym usage(verbose); 5464581Ssherrym return (2); 5474581Ssherrym } 5484581Ssherrym } 5494581Ssherrym 5504581Ssherrym if (actcount != 1) { 5514581Ssherrym (void) fprintf(stderr, gettext("%s: options -v, -i and -u " 5524581Ssherrym "are mutually exclusive.\n"), cmdname); 5534581Ssherrym usage(verbose); 5544581Ssherrym return (2); 5554581Ssherrym } 5564581Ssherrym 5574581Ssherrym if (optind <= argc - 1) 5584581Ssherrym filename = argv[optind]; 5594581Ssherrym else if (!(action & UCODE_OPT_VERSION)) 5604581Ssherrym errflg++; 5614581Ssherrym 5624581Ssherrym if (errflg || action == 0) { 5634581Ssherrym usage(verbose); 5644581Ssherrym return (2); 5654581Ssherrym } 5664581Ssherrym 5674581Ssherrym /* 5684581Ssherrym * Convert from text format to binary format 5694581Ssherrym */ 5704581Ssherrym if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) { 5717605SMark.Johnson@Sun.COM int i; 5727605SMark.Johnson@Sun.COM UCODE_VENDORS; 5737605SMark.Johnson@Sun.COM 5747605SMark.Johnson@Sun.COM for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 5757605SMark.Johnson@Sun.COM dprintf("i = %d, filestr = %s, filename = %s\n", 5767605SMark.Johnson@Sun.COM i, ucode_vendors[i].filestr, filename); 5777605SMark.Johnson@Sun.COM if (strncasecmp(ucode_vendors[i].filestr, 5787605SMark.Johnson@Sun.COM basename(filename), 5797605SMark.Johnson@Sun.COM strlen(ucode_vendors[i].filestr)) == 0) { 5807605SMark.Johnson@Sun.COM ucode = &ucode_ops[i]; 5817605SMark.Johnson@Sun.COM (void) strncpy(ucode_vendor_str, 5827605SMark.Johnson@Sun.COM ucode_vendors[i].vendorstr, 5837605SMark.Johnson@Sun.COM sizeof (ucode_vendor_str)); 5847605SMark.Johnson@Sun.COM break; 5857605SMark.Johnson@Sun.COM } 5867605SMark.Johnson@Sun.COM } 5877605SMark.Johnson@Sun.COM 5887605SMark.Johnson@Sun.COM if (ucode_vendors[i].filestr == NULL) { 5897605SMark.Johnson@Sun.COM rc = EM_NOVENDOR; 5907605SMark.Johnson@Sun.COM ucode_perror(basename(filename), rc); 5917605SMark.Johnson@Sun.COM goto err_out; 5927605SMark.Johnson@Sun.COM } 5937605SMark.Johnson@Sun.COM 5944581Ssherrym if ((stat(filename, &filestat)) < 0) { 5954581Ssherrym rc = EM_SYS; 5964581Ssherrym ucode_perror(filename, rc); 5974581Ssherrym goto err_out; 5984581Ssherrym } 5994581Ssherrym 6004581Ssherrym if ((filestat.st_mode & S_IFMT) != S_IFREG && 6014581Ssherrym (filestat.st_mode & S_IFMT) != S_IFLNK) { 6024581Ssherrym rc = EM_FILEFORMAT; 6034581Ssherrym ucode_perror(filename, rc); 6044581Ssherrym goto err_out; 6054581Ssherrym } 6064581Ssherrym 6074581Ssherrym if ((buf = malloc(filestat.st_size)) == NULL) { 6084581Ssherrym rc = EM_SYS; 6094581Ssherrym ucode_perror(filename, rc); 6104581Ssherrym goto err_out; 6114581Ssherrym } 6124581Ssherrym 6137605SMark.Johnson@Sun.COM ucode_size = ucode->convert(filename, buf, filestat.st_size); 6144581Ssherrym 6154581Ssherrym dprintf("ucode_size = %d\n", ucode_size); 6164581Ssherrym 6174581Ssherrym if (ucode_size == 0) { 6184581Ssherrym rc = EM_FILEFORMAT; 6194581Ssherrym ucode_perror(filename, rc); 6204581Ssherrym goto err_out; 6214581Ssherrym } 6224581Ssherrym 6237605SMark.Johnson@Sun.COM if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) { 6244581Ssherrym ucode_perror(filename, rc); 6254581Ssherrym goto err_out; 6264581Ssherrym } 6274581Ssherrym } 6284581Ssherrym 6294581Ssherrym /* 6304581Ssherrym * For the install option, the microcode file must start with 6314581Ssherrym * "intel" for Intel microcode, and "amd" for AMD microcode. 6324581Ssherrym */ 6334581Ssherrym if (action & UCODE_OPT_INSTALL) { 6344581Ssherrym /* 6354581Ssherrym * If no path is provided by the -R option, put the files in 6364581Ssherrym * /ucode_install_path/ucode_vendor_str/. 6374581Ssherrym */ 6384581Ssherrym if (path == NULL) { 6394581Ssherrym if ((path = malloc(PATH_MAX)) == NULL) { 6404581Ssherrym rc = EM_SYS; 6414581Ssherrym ucode_perror("malloc", rc); 6424581Ssherrym goto err_out; 6434581Ssherrym } 6444581Ssherrym 6454581Ssherrym (void) snprintf(path, PATH_MAX, "/%s/%s", 6464581Ssherrym ucode_install_path, ucode_vendor_str); 6474581Ssherrym } 6484581Ssherrym 6494581Ssherrym if (mkdirp(path, 0755) == -1 && errno != EEXIST) { 6504581Ssherrym rc = EM_SYS; 6514581Ssherrym ucode_perror(path, rc); 6524581Ssherrym goto err_out; 6534581Ssherrym } 6544581Ssherrym 6557605SMark.Johnson@Sun.COM rc = ucode->gen_files(buf, ucode_size, path); 6564581Ssherrym 6574581Ssherrym goto err_out; 6584581Ssherrym } 6594581Ssherrym 6604581Ssherrym if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) { 6614581Ssherrym rc = EM_SYS; 6624581Ssherrym ucode_perror(ucode_dev, rc); 6634581Ssherrym goto err_out; 6644581Ssherrym } 6654581Ssherrym 6664581Ssherrym if (action & UCODE_OPT_VERSION) { 6674581Ssherrym int tmprc; 6684581Ssherrym uint32_t *revp = NULL; 6694581Ssherrym int i; 6704581Ssherrym #if defined(_SYSCALL32_IMPL) 6714581Ssherrym struct ucode_get_rev_struct32 inf32; 6724581Ssherrym #else 6734581Ssherrym struct ucode_get_rev_struct info; 6744581Ssherrym #endif 6754581Ssherrym 6764581Ssherrym cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX); 6774581Ssherrym 6784581Ssherrym if ((revp = (uint32_t *) 6794581Ssherrym malloc(cpuid_max * sizeof (uint32_t))) == NULL) { 6804581Ssherrym rc = EM_SYS; 6814581Ssherrym ucode_perror("malloc", rc); 6824581Ssherrym goto err_out; 6834581Ssherrym } 6844581Ssherrym 6854581Ssherrym for (i = 0; i < cpuid_max; i++) 6864581Ssherrym revp[i] = (uint32_t)-1; 6874581Ssherrym 6884581Ssherrym #if defined(_SYSCALL32_IMPL) 6894581Ssherrym info32.ugv_rev = (caddr32_t)revp; 6904581Ssherrym info32.ugv_size = cpuid_max; 6914581Ssherrym info32.ugv_errno = EM_OK; 6924581Ssherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info32); 6934581Ssherrym rc = info32.ugv_errno; 6944581Ssherrym #else 6954581Ssherrym info.ugv_rev = revp; 6964581Ssherrym info.ugv_size = cpuid_max; 6974581Ssherrym info.ugv_errno = EM_OK; 6984581Ssherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info); 6994581Ssherrym rc = info.ugv_errno; 7004581Ssherrym #endif 7014581Ssherrym 7024581Ssherrym if (tmprc && rc == EM_OK) { 7034581Ssherrym rc = EM_SYS; 7044581Ssherrym } 7054581Ssherrym 7064581Ssherrym if (rc == EM_OK) { 7074581Ssherrym (void) printf(gettext("CPU\tMicrocode Version\n")); 7084581Ssherrym for (i = 0; i < cpuid_max; i++) { 7094581Ssherrym if (info.ugv_rev[i] == (uint32_t)-1) 7104581Ssherrym continue; 7114581Ssherrym (void) printf("%d\t0x%x\n", i, info.ugv_rev[i]); 7124581Ssherrym } 7134581Ssherrym } else { 7144581Ssherrym ucode_perror(gettext("get microcode version"), rc); 7154581Ssherrym } 7164581Ssherrym 7174581Ssherrym if (revp) 7184581Ssherrym free(revp); 7194581Ssherrym } 7204581Ssherrym 7214581Ssherrym if (action & UCODE_OPT_UPDATE) { 7224581Ssherrym int tmprc; 7234581Ssherrym #if defined(_SYSCALL32_IMPL) 7244581Ssherrym struct ucode_write_struct32 uw_struct32; 7254581Ssherrym #else 7264581Ssherrym struct ucode_write_struct uw_struct; 7274581Ssherrym #endif 7284581Ssherrym 7294581Ssherrym #if defined(_SYSCALL32_IMPL) 7304581Ssherrym uw_struct32.uw_size = ucode_size; 7314581Ssherrym uw_struct32.uw_ucode = (caddr32_t)buf; 7324581Ssherrym uw_struct32.uw_errno = EM_OK; 7334581Ssherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct32); 7344581Ssherrym rc = uw_struct32.uw_errno; 7354581Ssherrym 7364581Ssherrym #else 7374581Ssherrym uw_struct.uw_size = ucode_size; 7384581Ssherrym uw_struct.uw_ucode = buf; 7394581Ssherrym uw_struct.uw_errno = EM_OK; 7404581Ssherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct); 7414581Ssherrym rc = uw_struct.uw_errno; 7424581Ssherrym #endif 7434581Ssherrym 7444581Ssherrym if (rc == EM_OK) { 7454581Ssherrym if (tmprc) { 7464581Ssherrym rc = EM_SYS; 7474581Ssherrym ucode_perror(ucode_dev, rc); 7484581Ssherrym } 7494581Ssherrym } else if (rc == EM_NOMATCH || rc == EM_HIGHERREV) { 7504581Ssherrym ucode_perror(filename, rc); 7514581Ssherrym } else { 7524581Ssherrym ucode_perror(gettext("microcode update"), rc); 7534581Ssherrym } 7544581Ssherrym } 7554581Ssherrym 7564581Ssherrym err_out: 7574581Ssherrym if (dev_fd != -1) 7584581Ssherrym (void) close(dev_fd); 7594581Ssherrym 7604581Ssherrym if (fd != -1) 7614581Ssherrym (void) close(fd); 7624581Ssherrym 7634581Ssherrym free(buf); 7644581Ssherrym free(path); 7654581Ssherrym 7664581Ssherrym if (rc != EM_OK) 7674581Ssherrym return (3); 7684581Ssherrym 7694581Ssherrym return (0); 7704581Ssherrym } 771