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