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