1*2449e17fSsherrym /* 2*2449e17fSsherrym * CDDL HEADER START 3*2449e17fSsherrym * 4*2449e17fSsherrym * The contents of this file are subject to the terms of the 5*2449e17fSsherrym * Common Development and Distribution License (the "License"). 6*2449e17fSsherrym * You may not use this file except in compliance with the License. 7*2449e17fSsherrym * 8*2449e17fSsherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2449e17fSsherrym * or http://www.opensolaris.org/os/licensing. 10*2449e17fSsherrym * See the License for the specific language governing permissions 11*2449e17fSsherrym * and limitations under the License. 12*2449e17fSsherrym * 13*2449e17fSsherrym * When distributing Covered Code, include this CDDL HEADER in each 14*2449e17fSsherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2449e17fSsherrym * If applicable, add the following below this CDDL HEADER, with the 16*2449e17fSsherrym * fields enclosed by brackets "[]" replaced with your own identifying 17*2449e17fSsherrym * information: Portions Copyright [yyyy] [name of copyright owner] 18*2449e17fSsherrym * 19*2449e17fSsherrym * CDDL HEADER END 20*2449e17fSsherrym */ 21*2449e17fSsherrym /* 22*2449e17fSsherrym * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*2449e17fSsherrym * Use is subject to license terms. 24*2449e17fSsherrym */ 25*2449e17fSsherrym 26*2449e17fSsherrym #pragma ident "%Z%%M% %I% %E% SMI" 27*2449e17fSsherrym 28*2449e17fSsherrym #include <sys/types.h> 29*2449e17fSsherrym #include <sys/processor.h> 30*2449e17fSsherrym #include <sys/ucode.h> 31*2449e17fSsherrym #include <sys/ioctl.h> 32*2449e17fSsherrym #include <sys/stat.h> 33*2449e17fSsherrym #include <unistd.h> 34*2449e17fSsherrym #include <dirent.h> 35*2449e17fSsherrym #include <fcntl.h> 36*2449e17fSsherrym #include <errno.h> 37*2449e17fSsherrym #include <stdio.h> 38*2449e17fSsherrym #include <stdlib.h> 39*2449e17fSsherrym #include <stdarg.h> 40*2449e17fSsherrym #include <string.h> 41*2449e17fSsherrym #include <errno.h> 42*2449e17fSsherrym #include <syslog.h> 43*2449e17fSsherrym #include <time.h> 44*2449e17fSsherrym #include <ctype.h> 45*2449e17fSsherrym #include <assert.h> 46*2449e17fSsherrym #include <libgen.h> 47*2449e17fSsherrym #include <locale.h> 48*2449e17fSsherrym #include <libintl.h> 49*2449e17fSsherrym 50*2449e17fSsherrym #define UCODE_OPT_INSTALL 0x0001 51*2449e17fSsherrym #define UCODE_OPT_UPDATE 0x0002 52*2449e17fSsherrym #define UCODE_OPT_VERSION 0x0004 53*2449e17fSsherrym 54*2449e17fSsherrym static const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME; 55*2449e17fSsherrym 56*2449e17fSsherrym static char *cmdname; 57*2449e17fSsherrym 58*2449e17fSsherrym static char ucode_vendor_str[UCODE_MAX_VENDORS_NAME_LEN]; 59*2449e17fSsherrym static char ucode_install_path[] = UCODE_INSTALL_PATH; 60*2449e17fSsherrym 61*2449e17fSsherrym static int ucode_debug = 0; 62*2449e17fSsherrym 63*2449e17fSsherrym static void 64*2449e17fSsherrym dprintf(const char *format, ...) 65*2449e17fSsherrym { 66*2449e17fSsherrym if (ucode_debug) { 67*2449e17fSsherrym va_list alist; 68*2449e17fSsherrym va_start(alist, format); 69*2449e17fSsherrym (void) vfprintf(stderr, format, alist); 70*2449e17fSsherrym va_end(alist); 71*2449e17fSsherrym } 72*2449e17fSsherrym } 73*2449e17fSsherrym 74*2449e17fSsherrym static void 75*2449e17fSsherrym usage(int verbose) 76*2449e17fSsherrym { 77*2449e17fSsherrym (void) fprintf(stderr, gettext("usage:\n")); 78*2449e17fSsherrym (void) fprintf(stderr, "\t%s -v\n", cmdname); 79*2449e17fSsherrym if (verbose) { 80*2449e17fSsherrym (void) fprintf(stderr, 81*2449e17fSsherrym gettext("\t\t Shows running microcode version.\n\n")); 82*2449e17fSsherrym } 83*2449e17fSsherrym 84*2449e17fSsherrym (void) fprintf(stderr, "\t%s -u microcode-text-file\n", cmdname); 85*2449e17fSsherrym if (verbose) { 86*2449e17fSsherrym (void) fprintf(stderr, gettext("\t\t Updates microcode to the " 87*2449e17fSsherrym "latest matching version found in\n" 88*2449e17fSsherrym "\t\t microcode-text-file.\n\n")); 89*2449e17fSsherrym } 90*2449e17fSsherrym 91*2449e17fSsherrym (void) fprintf(stderr, "\t%s -i [-R path] microcode-text-file\n", 92*2449e17fSsherrym cmdname); 93*2449e17fSsherrym if (verbose) { 94*2449e17fSsherrym (void) fprintf(stderr, gettext("\t\t Installs microcode to be " 95*2449e17fSsherrym "used for subsequent boots. Microcode\n" 96*2449e17fSsherrym "\t\t text file name must start with vendor name, " 97*2449e17fSsherrym "such as \"intel\".\n\n")); 98*2449e17fSsherrym } 99*2449e17fSsherrym } 100*2449e17fSsherrym 101*2449e17fSsherrym static void 102*2449e17fSsherrym ucode_perror(const char *str, ucode_errno_t rc) 103*2449e17fSsherrym { 104*2449e17fSsherrym (void) fprintf(stderr, "%s: %s: %s\n", cmdname, str, 105*2449e17fSsherrym errno == 0 ? ucode_strerror(rc) : strerror(errno)); 106*2449e17fSsherrym errno = 0; 107*2449e17fSsherrym } 108*2449e17fSsherrym 109*2449e17fSsherrym #define LINESIZE 120 /* copyright line sometimes is longer than 80 */ 110*2449e17fSsherrym 111*2449e17fSsherrym /* 112*2449e17fSsherrym * Convert text format microcode release into binary format. 113*2449e17fSsherrym * Return the number of characters read. 114*2449e17fSsherrym */ 115*2449e17fSsherrym static int 116*2449e17fSsherrym ucode_convert(const char *infile, uint8_t *buf, size_t size) 117*2449e17fSsherrym { 118*2449e17fSsherrym char linebuf[LINESIZE]; 119*2449e17fSsherrym FILE *infd = NULL; 120*2449e17fSsherrym int count = 0, firstline = 1; 121*2449e17fSsherrym uint32_t *intbuf = (uint32_t *)(intptr_t)buf; 122*2449e17fSsherrym 123*2449e17fSsherrym if (infile == NULL || buf == NULL || size == 0) 124*2449e17fSsherrym return (0); 125*2449e17fSsherrym 126*2449e17fSsherrym if ((infd = fopen(infile, "r")) == NULL) 127*2449e17fSsherrym return (0); 128*2449e17fSsherrym 129*2449e17fSsherrym while (fgets(linebuf, LINESIZE, infd)) { 130*2449e17fSsherrym 131*2449e17fSsherrym /* Check to see if we are processing a binary file */ 132*2449e17fSsherrym if (firstline && !isprint(linebuf[0])) { 133*2449e17fSsherrym if (fseek(infd, 0, SEEK_SET) == 0) 134*2449e17fSsherrym count = fread(buf, 1, size, infd); 135*2449e17fSsherrym 136*2449e17fSsherrym (void) fclose(infd); 137*2449e17fSsherrym return (count); 138*2449e17fSsherrym } 139*2449e17fSsherrym 140*2449e17fSsherrym firstline = 0; 141*2449e17fSsherrym 142*2449e17fSsherrym /* Skip blank lines */ 143*2449e17fSsherrym if (strlen(linebuf) == 1) 144*2449e17fSsherrym continue; 145*2449e17fSsherrym 146*2449e17fSsherrym /* Skip lines with all spaces or tabs */ 147*2449e17fSsherrym if (strcspn(linebuf, " \t") == 0) 148*2449e17fSsherrym continue; 149*2449e17fSsherrym 150*2449e17fSsherrym /* Text file. Skip comments. */ 151*2449e17fSsherrym if (linebuf[0] == '/') 152*2449e17fSsherrym continue; 153*2449e17fSsherrym 154*2449e17fSsherrym if (sscanf(linebuf, "%x, %x, %x, %x", 155*2449e17fSsherrym &intbuf[count], &intbuf[count+1], 156*2449e17fSsherrym &intbuf[count+2], &intbuf[count+3]) != 4) 157*2449e17fSsherrym break; 158*2449e17fSsherrym 159*2449e17fSsherrym count += 4; 160*2449e17fSsherrym } 161*2449e17fSsherrym 162*2449e17fSsherrym (void) fclose(infd); 163*2449e17fSsherrym 164*2449e17fSsherrym /* 165*2449e17fSsherrym * If we get here, we are processing a text format file 166*2449e17fSsherrym * where "count" is used to count the number of integers 167*2449e17fSsherrym * read. Convert it to number of characters read. 168*2449e17fSsherrym */ 169*2449e17fSsherrym return (count * sizeof (int)); 170*2449e17fSsherrym } 171*2449e17fSsherrym 172*2449e17fSsherrym /* 173*2449e17fSsherrym * Returns 0 if no need to update the link; -1 otherwise 174*2449e17fSsherrym */ 175*2449e17fSsherrym static int 176*2449e17fSsherrym ucode_should_update(char *filename, uint32_t new_rev) 177*2449e17fSsherrym { 178*2449e17fSsherrym int fd; 179*2449e17fSsherrym struct stat statbuf; 180*2449e17fSsherrym ucode_header_t header; 181*2449e17fSsherrym 182*2449e17fSsherrym /* 183*2449e17fSsherrym * If the file or link already exists, check to see if 184*2449e17fSsherrym * it is necessary to update it. 185*2449e17fSsherrym */ 186*2449e17fSsherrym if (stat(filename, &statbuf) == 0) { 187*2449e17fSsherrym if ((fd = open(filename, O_RDONLY)) == -1) 188*2449e17fSsherrym return (-1); 189*2449e17fSsherrym 190*2449e17fSsherrym if (read(fd, &header, sizeof (header)) == -1) { 191*2449e17fSsherrym (void) close(fd); 192*2449e17fSsherrym return (-1); 193*2449e17fSsherrym } 194*2449e17fSsherrym 195*2449e17fSsherrym (void) close(fd); 196*2449e17fSsherrym 197*2449e17fSsherrym if (header.uh_rev >= new_rev) 198*2449e17fSsherrym return (0); 199*2449e17fSsherrym } 200*2449e17fSsherrym 201*2449e17fSsherrym return (-1); 202*2449e17fSsherrym } 203*2449e17fSsherrym 204*2449e17fSsherrym /* 205*2449e17fSsherrym * Generate microcode binary files. Must be called after ucode_validate(). 206*2449e17fSsherrym */ 207*2449e17fSsherrym static ucode_errno_t 208*2449e17fSsherrym ucode_gen_files(uint8_t *buf, int size, char *path) 209*2449e17fSsherrym { 210*2449e17fSsherrym int remaining; 211*2449e17fSsherrym char common_path[PATH_MAX]; 212*2449e17fSsherrym DIR *dirp; 213*2449e17fSsherrym struct dirent *dp; 214*2449e17fSsherrym 215*2449e17fSsherrym (void) snprintf(common_path, PATH_MAX, "%s/%s", path, 216*2449e17fSsherrym UCODE_INSTALL_COMMON_PATH); 217*2449e17fSsherrym 218*2449e17fSsherrym if (mkdirp(common_path, 0755) == -1 && errno != EEXIST) { 219*2449e17fSsherrym ucode_perror(common_path, EM_SYS); 220*2449e17fSsherrym return (EM_SYS); 221*2449e17fSsherrym } 222*2449e17fSsherrym 223*2449e17fSsherrym for (remaining = size; remaining > 0; ) { 224*2449e17fSsherrym uint32_t total_size, body_size, offset; 225*2449e17fSsherrym char firstname[PATH_MAX]; 226*2449e17fSsherrym char name[PATH_MAX]; 227*2449e17fSsherrym int i; 228*2449e17fSsherrym uint8_t *curbuf = &buf[size - remaining]; 229*2449e17fSsherrym ucode_header_t *uhp = (ucode_header_t *)(intptr_t)curbuf; 230*2449e17fSsherrym ucode_ext_table_t *extp; 231*2449e17fSsherrym 232*2449e17fSsherrym total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); 233*2449e17fSsherrym body_size = UCODE_BODY_SIZE(uhp->uh_body_size); 234*2449e17fSsherrym 235*2449e17fSsherrym remaining -= total_size; 236*2449e17fSsherrym 237*2449e17fSsherrym (void) snprintf(firstname, PATH_MAX, "%s/%08X-%02X", 238*2449e17fSsherrym common_path, uhp->uh_signature, uhp->uh_proc_flags); 239*2449e17fSsherrym dprintf("firstname = %s\n", firstname); 240*2449e17fSsherrym 241*2449e17fSsherrym if (ucode_should_update(firstname, uhp->uh_rev) != 0) { 242*2449e17fSsherrym int fd; 243*2449e17fSsherrym 244*2449e17fSsherrym /* Remove the existing one first */ 245*2449e17fSsherrym (void) unlink(firstname); 246*2449e17fSsherrym 247*2449e17fSsherrym if ((fd = open(firstname, O_WRONLY | O_CREAT | O_TRUNC, 248*2449e17fSsherrym S_IRUSR | S_IRGRP | S_IROTH)) == -1) { 249*2449e17fSsherrym ucode_perror(firstname, EM_SYS); 250*2449e17fSsherrym return (EM_SYS); 251*2449e17fSsherrym } 252*2449e17fSsherrym 253*2449e17fSsherrym if (write(fd, curbuf, total_size) != total_size) { 254*2449e17fSsherrym (void) close(fd); 255*2449e17fSsherrym ucode_perror(firstname, EM_SYS); 256*2449e17fSsherrym return (EM_SYS); 257*2449e17fSsherrym } 258*2449e17fSsherrym 259*2449e17fSsherrym (void) close(fd); 260*2449e17fSsherrym } 261*2449e17fSsherrym 262*2449e17fSsherrym /* 263*2449e17fSsherrym * Only 1 byte of the proc_flags field is used, therefore 264*2449e17fSsherrym * we only need to match 8 potential platform ids. 265*2449e17fSsherrym */ 266*2449e17fSsherrym for (i = 0; i < 8; i++) { 267*2449e17fSsherrym uint32_t platid = uhp->uh_proc_flags & (1 << i); 268*2449e17fSsherrym 269*2449e17fSsherrym if (platid == 0 && uhp->uh_proc_flags != 0) 270*2449e17fSsherrym continue; 271*2449e17fSsherrym 272*2449e17fSsherrym (void) snprintf(name, PATH_MAX, 273*2449e17fSsherrym "%s/%08X-%02X", path, uhp->uh_signature, platid); 274*2449e17fSsherrym 275*2449e17fSsherrym dprintf("proc_flags = %x, platid = %x, name = %s\n", 276*2449e17fSsherrym uhp->uh_proc_flags, platid, name); 277*2449e17fSsherrym 278*2449e17fSsherrym if (ucode_should_update(name, uhp->uh_rev) != 0) { 279*2449e17fSsherrym 280*2449e17fSsherrym /* Remove the existing one first */ 281*2449e17fSsherrym (void) unlink(name); 282*2449e17fSsherrym 283*2449e17fSsherrym if (link(firstname, name) == -1) { 284*2449e17fSsherrym ucode_perror(name, EM_SYS); 285*2449e17fSsherrym return (EM_SYS); 286*2449e17fSsherrym } 287*2449e17fSsherrym } 288*2449e17fSsherrym 289*2449e17fSsherrym if (uhp->uh_proc_flags == 0) 290*2449e17fSsherrym break; 291*2449e17fSsherrym } 292*2449e17fSsherrym 293*2449e17fSsherrym offset = UCODE_HEADER_SIZE + body_size; 294*2449e17fSsherrym 295*2449e17fSsherrym /* Check to see if there is extended signature table */ 296*2449e17fSsherrym if (total_size == offset) 297*2449e17fSsherrym continue; 298*2449e17fSsherrym 299*2449e17fSsherrym /* There is extended signature table. More processing. */ 300*2449e17fSsherrym extp = (ucode_ext_table_t *)(uintptr_t)&curbuf[offset]; 301*2449e17fSsherrym 302*2449e17fSsherrym for (i = 0; i < extp->uet_count; i++) { 303*2449e17fSsherrym ucode_ext_sig_t *uesp = &extp->uet_ext_sig[i]; 304*2449e17fSsherrym int j; 305*2449e17fSsherrym 306*2449e17fSsherrym for (j = 0; j < 8; j++) { 307*2449e17fSsherrym uint32_t id = uesp->ues_proc_flags & (1 << j); 308*2449e17fSsherrym 309*2449e17fSsherrym if (id == 0 && uesp->ues_proc_flags) 310*2449e17fSsherrym continue; 311*2449e17fSsherrym 312*2449e17fSsherrym (void) snprintf(name, PATH_MAX, 313*2449e17fSsherrym "%s/%08X-%02X", path, extp->uet_ext_sig[i], 314*2449e17fSsherrym id); 315*2449e17fSsherrym 316*2449e17fSsherrym if (ucode_should_update(name, uhp->uh_rev) != 317*2449e17fSsherrym 0) { 318*2449e17fSsherrym 319*2449e17fSsherrym /* Remove the existing one first */ 320*2449e17fSsherrym (void) unlink(name); 321*2449e17fSsherrym if (link(firstname, name) == -1) { 322*2449e17fSsherrym ucode_perror(name, EM_SYS); 323*2449e17fSsherrym return (EM_SYS); 324*2449e17fSsherrym } 325*2449e17fSsherrym } 326*2449e17fSsherrym 327*2449e17fSsherrym if (uesp->ues_proc_flags == 0) 328*2449e17fSsherrym break; 329*2449e17fSsherrym } 330*2449e17fSsherrym } 331*2449e17fSsherrym 332*2449e17fSsherrym } 333*2449e17fSsherrym 334*2449e17fSsherrym /* 335*2449e17fSsherrym * Remove files with no links to them. These are probably 336*2449e17fSsherrym * obsolete microcode files. 337*2449e17fSsherrym */ 338*2449e17fSsherrym if ((dirp = opendir(common_path)) == NULL) { 339*2449e17fSsherrym ucode_perror(common_path, EM_SYS); 340*2449e17fSsherrym return (EM_SYS); 341*2449e17fSsherrym } 342*2449e17fSsherrym 343*2449e17fSsherrym while ((dp = readdir(dirp)) != NULL) { 344*2449e17fSsherrym char filename[PATH_MAX]; 345*2449e17fSsherrym struct stat statbuf; 346*2449e17fSsherrym 347*2449e17fSsherrym (void) snprintf(filename, PATH_MAX, 348*2449e17fSsherrym "%s/%s", common_path, dp->d_name); 349*2449e17fSsherrym if (stat(filename, &statbuf) == -1) 350*2449e17fSsherrym continue; 351*2449e17fSsherrym 352*2449e17fSsherrym if ((statbuf.st_mode & S_IFMT) == S_IFREG) { 353*2449e17fSsherrym if (statbuf.st_nlink == 1) 354*2449e17fSsherrym (void) unlink(filename); 355*2449e17fSsherrym } 356*2449e17fSsherrym } 357*2449e17fSsherrym 358*2449e17fSsherrym (void) closedir(dirp); 359*2449e17fSsherrym 360*2449e17fSsherrym return (EM_OK); 361*2449e17fSsherrym } 362*2449e17fSsherrym 363*2449e17fSsherrym /* 364*2449e17fSsherrym * Returns 0 on success, 2 on usage error, and 3 on operation error. 365*2449e17fSsherrym */ 366*2449e17fSsherrym int 367*2449e17fSsherrym main(int argc, char *argv[]) 368*2449e17fSsherrym { 369*2449e17fSsherrym int c; 370*2449e17fSsherrym int action = 0; 371*2449e17fSsherrym int actcount = 0; 372*2449e17fSsherrym char *path = NULL; 373*2449e17fSsherrym char *filename = NULL; 374*2449e17fSsherrym int errflg = 0; 375*2449e17fSsherrym int dev_fd = -1; 376*2449e17fSsherrym int fd = -1; 377*2449e17fSsherrym int verbose = 0; 378*2449e17fSsherrym uint8_t *buf = NULL; 379*2449e17fSsherrym ucode_errno_t rc = EM_OK; 380*2449e17fSsherrym processorid_t cpuid_max; 381*2449e17fSsherrym struct stat filestat; 382*2449e17fSsherrym uint32_t ucode_size; 383*2449e17fSsherrym 384*2449e17fSsherrym (void) setlocale(LC_ALL, ""); 385*2449e17fSsherrym 386*2449e17fSsherrym #if !defined(TEXT_DOMAIN) 387*2449e17fSsherrym #define TEXT_DOMAIN "SYS_TEST" 388*2449e17fSsherrym #endif 389*2449e17fSsherrym (void) textdomain(TEXT_DOMAIN); 390*2449e17fSsherrym 391*2449e17fSsherrym cmdname = basename(argv[0]); 392*2449e17fSsherrym 393*2449e17fSsherrym while ((c = getopt(argc, argv, "idhuvVR:")) != EOF) { 394*2449e17fSsherrym switch (c) { 395*2449e17fSsherrym 396*2449e17fSsherrym case 'i': 397*2449e17fSsherrym action |= UCODE_OPT_INSTALL; 398*2449e17fSsherrym actcount++; 399*2449e17fSsherrym break; 400*2449e17fSsherrym 401*2449e17fSsherrym case 'u': 402*2449e17fSsherrym action |= UCODE_OPT_UPDATE; 403*2449e17fSsherrym actcount++; 404*2449e17fSsherrym break; 405*2449e17fSsherrym 406*2449e17fSsherrym case 'v': 407*2449e17fSsherrym action |= UCODE_OPT_VERSION; 408*2449e17fSsherrym actcount++; 409*2449e17fSsherrym break; 410*2449e17fSsherrym 411*2449e17fSsherrym case 'd': 412*2449e17fSsherrym ucode_debug = 1; 413*2449e17fSsherrym break; 414*2449e17fSsherrym 415*2449e17fSsherrym case 'R': 416*2449e17fSsherrym if (optarg[0] == '-') 417*2449e17fSsherrym errflg++; 418*2449e17fSsherrym else if (strlen(optarg) > UCODE_MAX_PATH_LEN) { 419*2449e17fSsherrym (void) fprintf(stderr, 420*2449e17fSsherrym gettext("Alternate path too long\n")); 421*2449e17fSsherrym errflg++; 422*2449e17fSsherrym } else if ((path = strdup(optarg)) == NULL) { 423*2449e17fSsherrym errflg++; 424*2449e17fSsherrym } 425*2449e17fSsherrym 426*2449e17fSsherrym break; 427*2449e17fSsherrym 428*2449e17fSsherrym case 'V': 429*2449e17fSsherrym verbose = 1; 430*2449e17fSsherrym break; 431*2449e17fSsherrym 432*2449e17fSsherrym case 'h': 433*2449e17fSsherrym usage(1); 434*2449e17fSsherrym return (0); 435*2449e17fSsherrym 436*2449e17fSsherrym default: 437*2449e17fSsherrym usage(verbose); 438*2449e17fSsherrym return (2); 439*2449e17fSsherrym } 440*2449e17fSsherrym } 441*2449e17fSsherrym 442*2449e17fSsherrym if (actcount != 1) { 443*2449e17fSsherrym (void) fprintf(stderr, gettext("%s: options -v, -i and -u " 444*2449e17fSsherrym "are mutually exclusive.\n"), cmdname); 445*2449e17fSsherrym usage(verbose); 446*2449e17fSsherrym return (2); 447*2449e17fSsherrym } 448*2449e17fSsherrym 449*2449e17fSsherrym if (optind <= argc - 1) 450*2449e17fSsherrym filename = argv[optind]; 451*2449e17fSsherrym else if (!(action & UCODE_OPT_VERSION)) 452*2449e17fSsherrym errflg++; 453*2449e17fSsherrym 454*2449e17fSsherrym if (errflg || action == 0) { 455*2449e17fSsherrym usage(verbose); 456*2449e17fSsherrym return (2); 457*2449e17fSsherrym } 458*2449e17fSsherrym 459*2449e17fSsherrym /* 460*2449e17fSsherrym * Convert from text format to binary format 461*2449e17fSsherrym */ 462*2449e17fSsherrym if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) { 463*2449e17fSsherrym if ((stat(filename, &filestat)) < 0) { 464*2449e17fSsherrym rc = EM_SYS; 465*2449e17fSsherrym ucode_perror(filename, rc); 466*2449e17fSsherrym goto err_out; 467*2449e17fSsherrym } 468*2449e17fSsherrym 469*2449e17fSsherrym if ((filestat.st_mode & S_IFMT) != S_IFREG && 470*2449e17fSsherrym (filestat.st_mode & S_IFMT) != S_IFLNK) { 471*2449e17fSsherrym rc = EM_FILEFORMAT; 472*2449e17fSsherrym ucode_perror(filename, rc); 473*2449e17fSsherrym goto err_out; 474*2449e17fSsherrym } 475*2449e17fSsherrym 476*2449e17fSsherrym if ((buf = malloc(filestat.st_size)) == NULL) { 477*2449e17fSsherrym rc = EM_SYS; 478*2449e17fSsherrym ucode_perror(filename, rc); 479*2449e17fSsherrym goto err_out; 480*2449e17fSsherrym } 481*2449e17fSsherrym 482*2449e17fSsherrym ucode_size = ucode_convert(filename, buf, filestat.st_size); 483*2449e17fSsherrym 484*2449e17fSsherrym dprintf("ucode_size = %d\n", ucode_size); 485*2449e17fSsherrym 486*2449e17fSsherrym if (ucode_size == 0) { 487*2449e17fSsherrym rc = EM_FILEFORMAT; 488*2449e17fSsherrym ucode_perror(filename, rc); 489*2449e17fSsherrym goto err_out; 490*2449e17fSsherrym } 491*2449e17fSsherrym 492*2449e17fSsherrym if ((rc = ucode_validate(buf, ucode_size)) != EM_OK) { 493*2449e17fSsherrym ucode_perror(filename, rc); 494*2449e17fSsherrym goto err_out; 495*2449e17fSsherrym } 496*2449e17fSsherrym } 497*2449e17fSsherrym 498*2449e17fSsherrym /* 499*2449e17fSsherrym * For the install option, the microcode file must start with 500*2449e17fSsherrym * "intel" for Intel microcode, and "amd" for AMD microcode. 501*2449e17fSsherrym */ 502*2449e17fSsherrym if (action & UCODE_OPT_INSTALL) { 503*2449e17fSsherrym int i; 504*2449e17fSsherrym UCODE_VENDORS; 505*2449e17fSsherrym 506*2449e17fSsherrym for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 507*2449e17fSsherrym dprintf("i = %d, filestr = %s, filename = %s\n", 508*2449e17fSsherrym i, ucode_vendors[i].filestr, filename); 509*2449e17fSsherrym if (strncasecmp(ucode_vendors[i].filestr, 510*2449e17fSsherrym basename(filename), 511*2449e17fSsherrym strlen(ucode_vendors[i].filestr)) == 0) { 512*2449e17fSsherrym 513*2449e17fSsherrym (void) strncpy(ucode_vendor_str, 514*2449e17fSsherrym ucode_vendors[i].vendorstr, 515*2449e17fSsherrym sizeof (ucode_vendor_str)); 516*2449e17fSsherrym break; 517*2449e17fSsherrym } 518*2449e17fSsherrym } 519*2449e17fSsherrym 520*2449e17fSsherrym if (ucode_vendors[i].filestr == NULL) { 521*2449e17fSsherrym rc = EM_NOVENDOR; 522*2449e17fSsherrym ucode_perror(basename(filename), rc); 523*2449e17fSsherrym goto err_out; 524*2449e17fSsherrym } 525*2449e17fSsherrym 526*2449e17fSsherrym /* 527*2449e17fSsherrym * If no path is provided by the -R option, put the files in 528*2449e17fSsherrym * /ucode_install_path/ucode_vendor_str/. 529*2449e17fSsherrym */ 530*2449e17fSsherrym if (path == NULL) { 531*2449e17fSsherrym if ((path = malloc(PATH_MAX)) == NULL) { 532*2449e17fSsherrym rc = EM_SYS; 533*2449e17fSsherrym ucode_perror("malloc", rc); 534*2449e17fSsherrym goto err_out; 535*2449e17fSsherrym } 536*2449e17fSsherrym 537*2449e17fSsherrym (void) snprintf(path, PATH_MAX, "/%s/%s", 538*2449e17fSsherrym ucode_install_path, ucode_vendor_str); 539*2449e17fSsherrym } 540*2449e17fSsherrym 541*2449e17fSsherrym if (mkdirp(path, 0755) == -1 && errno != EEXIST) { 542*2449e17fSsherrym rc = EM_SYS; 543*2449e17fSsherrym ucode_perror(path, rc); 544*2449e17fSsherrym goto err_out; 545*2449e17fSsherrym } 546*2449e17fSsherrym 547*2449e17fSsherrym rc = ucode_gen_files(buf, ucode_size, path); 548*2449e17fSsherrym 549*2449e17fSsherrym goto err_out; 550*2449e17fSsherrym } 551*2449e17fSsherrym 552*2449e17fSsherrym if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) { 553*2449e17fSsherrym rc = EM_SYS; 554*2449e17fSsherrym ucode_perror(ucode_dev, rc); 555*2449e17fSsherrym goto err_out; 556*2449e17fSsherrym } 557*2449e17fSsherrym 558*2449e17fSsherrym if (action & UCODE_OPT_VERSION) { 559*2449e17fSsherrym int tmprc; 560*2449e17fSsherrym uint32_t *revp = NULL; 561*2449e17fSsherrym int i; 562*2449e17fSsherrym #if defined(_SYSCALL32_IMPL) 563*2449e17fSsherrym struct ucode_get_rev_struct32 inf32; 564*2449e17fSsherrym #else 565*2449e17fSsherrym struct ucode_get_rev_struct info; 566*2449e17fSsherrym #endif 567*2449e17fSsherrym 568*2449e17fSsherrym cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX); 569*2449e17fSsherrym 570*2449e17fSsherrym if ((revp = (uint32_t *) 571*2449e17fSsherrym malloc(cpuid_max * sizeof (uint32_t))) == NULL) { 572*2449e17fSsherrym rc = EM_SYS; 573*2449e17fSsherrym ucode_perror("malloc", rc); 574*2449e17fSsherrym goto err_out; 575*2449e17fSsherrym } 576*2449e17fSsherrym 577*2449e17fSsherrym for (i = 0; i < cpuid_max; i++) 578*2449e17fSsherrym revp[i] = (uint32_t)-1; 579*2449e17fSsherrym 580*2449e17fSsherrym #if defined(_SYSCALL32_IMPL) 581*2449e17fSsherrym info32.ugv_rev = (caddr32_t)revp; 582*2449e17fSsherrym info32.ugv_size = cpuid_max; 583*2449e17fSsherrym info32.ugv_errno = EM_OK; 584*2449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info32); 585*2449e17fSsherrym rc = info32.ugv_errno; 586*2449e17fSsherrym #else 587*2449e17fSsherrym info.ugv_rev = revp; 588*2449e17fSsherrym info.ugv_size = cpuid_max; 589*2449e17fSsherrym info.ugv_errno = EM_OK; 590*2449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info); 591*2449e17fSsherrym rc = info.ugv_errno; 592*2449e17fSsherrym #endif 593*2449e17fSsherrym 594*2449e17fSsherrym if (tmprc && rc == EM_OK) { 595*2449e17fSsherrym rc = EM_SYS; 596*2449e17fSsherrym } 597*2449e17fSsherrym 598*2449e17fSsherrym if (rc == EM_OK) { 599*2449e17fSsherrym (void) printf(gettext("CPU\tMicrocode Version\n")); 600*2449e17fSsherrym for (i = 0; i < cpuid_max; i++) { 601*2449e17fSsherrym if (info.ugv_rev[i] == (uint32_t)-1) 602*2449e17fSsherrym continue; 603*2449e17fSsherrym (void) printf("%d\t0x%x\n", i, info.ugv_rev[i]); 604*2449e17fSsherrym } 605*2449e17fSsherrym } else { 606*2449e17fSsherrym ucode_perror(gettext("get microcode version"), rc); 607*2449e17fSsherrym } 608*2449e17fSsherrym 609*2449e17fSsherrym if (revp) 610*2449e17fSsherrym free(revp); 611*2449e17fSsherrym } 612*2449e17fSsherrym 613*2449e17fSsherrym if (action & UCODE_OPT_UPDATE) { 614*2449e17fSsherrym int tmprc; 615*2449e17fSsherrym #if defined(_SYSCALL32_IMPL) 616*2449e17fSsherrym struct ucode_write_struct32 uw_struct32; 617*2449e17fSsherrym #else 618*2449e17fSsherrym struct ucode_write_struct uw_struct; 619*2449e17fSsherrym #endif 620*2449e17fSsherrym 621*2449e17fSsherrym #if defined(_SYSCALL32_IMPL) 622*2449e17fSsherrym uw_struct32.uw_size = ucode_size; 623*2449e17fSsherrym uw_struct32.uw_ucode = (caddr32_t)buf; 624*2449e17fSsherrym uw_struct32.uw_errno = EM_OK; 625*2449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct32); 626*2449e17fSsherrym rc = uw_struct32.uw_errno; 627*2449e17fSsherrym 628*2449e17fSsherrym #else 629*2449e17fSsherrym uw_struct.uw_size = ucode_size; 630*2449e17fSsherrym uw_struct.uw_ucode = buf; 631*2449e17fSsherrym uw_struct.uw_errno = EM_OK; 632*2449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct); 633*2449e17fSsherrym rc = uw_struct.uw_errno; 634*2449e17fSsherrym #endif 635*2449e17fSsherrym 636*2449e17fSsherrym if (rc == EM_OK) { 637*2449e17fSsherrym if (tmprc) { 638*2449e17fSsherrym rc = EM_SYS; 639*2449e17fSsherrym ucode_perror(ucode_dev, rc); 640*2449e17fSsherrym } 641*2449e17fSsherrym } else if (rc == EM_NOMATCH || rc == EM_HIGHERREV) { 642*2449e17fSsherrym ucode_perror(filename, rc); 643*2449e17fSsherrym } else { 644*2449e17fSsherrym ucode_perror(gettext("microcode update"), rc); 645*2449e17fSsherrym } 646*2449e17fSsherrym } 647*2449e17fSsherrym 648*2449e17fSsherrym err_out: 649*2449e17fSsherrym if (dev_fd != -1) 650*2449e17fSsherrym (void) close(dev_fd); 651*2449e17fSsherrym 652*2449e17fSsherrym if (fd != -1) 653*2449e17fSsherrym (void) close(fd); 654*2449e17fSsherrym 655*2449e17fSsherrym free(buf); 656*2449e17fSsherrym free(path); 657*2449e17fSsherrym 658*2449e17fSsherrym if (rc != EM_OK) 659*2449e17fSsherrym return (3); 660*2449e17fSsherrym 661*2449e17fSsherrym return (0); 662*2449e17fSsherrym } 663