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 /* 27 * Copyright (c) 2018, Joyent, Inc. 28 * Copyright 2022 OmniOS Community Edition (OmniOSce) Association. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/processor.h> 33 #include <sys/ucode.h> 34 #include <sys/ioctl.h> 35 #include <sys/stat.h> 36 #include <unistd.h> 37 #include <dirent.h> 38 #include <fcntl.h> 39 #include <errno.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <stdarg.h> 43 #include <string.h> 44 #include <errno.h> 45 #include <syslog.h> 46 #include <time.h> 47 #include <ctype.h> 48 #include <assert.h> 49 #include <libgen.h> 50 #include <locale.h> 51 #include <libintl.h> 52 53 #define UCODE_OPT_INSTALL 0x0001 54 #define UCODE_OPT_UPDATE 0x0002 55 #define UCODE_OPT_VERSION 0x0004 56 #define UCODE_OPT_LIST 0x0008 57 58 static const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME; 59 60 static char *cmdname; 61 62 static char ucode_vendor_str[UCODE_MAX_VENDORS_NAME_LEN]; 63 static char ucode_install_path[] = UCODE_INSTALL_PATH; 64 65 static int ucode_debug = 0; 66 67 static int ucode_convert_amd(const char *, uint8_t *, size_t); 68 static int ucode_convert_intel(const char *, uint8_t *, size_t); 69 70 static ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *); 71 static ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *); 72 73 static void ucode_list_amd(uint8_t *, int); 74 static void ucode_list_intel(uint8_t *, int); 75 76 static const struct ucode_ops ucode_ops[] = { 77 { 78 .convert = ucode_convert_intel, 79 .gen_files = ucode_gen_files_intel, 80 .validate = ucode_validate_intel, 81 .list = ucode_list_intel, 82 }, 83 { 84 .convert = ucode_convert_amd, 85 .gen_files = ucode_gen_files_amd, 86 .validate = ucode_validate_amd, 87 .list = ucode_list_amd, 88 }, 89 }; 90 91 const struct ucode_ops *ucode; 92 93 static void 94 dprintf(const char *format, ...) 95 { 96 if (ucode_debug) { 97 va_list alist; 98 va_start(alist, format); 99 (void) vfprintf(stderr, format, alist); 100 va_end(alist); 101 } 102 } 103 104 static void 105 usage(int verbose) 106 { 107 (void) fprintf(stderr, gettext("usage:\n")); 108 (void) fprintf(stderr, "\t%s -v\n", cmdname); 109 if (verbose) { 110 (void) fprintf(stderr, 111 gettext("\t\t Shows running microcode version.\n\n")); 112 } 113 114 (void) fprintf(stderr, "\t%s -u microcode-file\n", cmdname); 115 if (verbose) { 116 (void) fprintf(stderr, gettext("\t\t Updates microcode to the " 117 "latest matching version found in\n" 118 "\t\t microcode-file.\n\n")); 119 } 120 121 (void) fprintf(stderr, "\t%s -l microcode-file\n", cmdname); 122 if (verbose) { 123 (void) fprintf(stderr, gettext("\t\t Displays details of the " 124 "microcode file's contents.\n\n")); 125 } 126 127 (void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname); 128 if (verbose) { 129 (void) fprintf(stderr, gettext("\t\t Installs microcode to be " 130 "used for subsequent boots.\n\n")); 131 (void) fprintf(stderr, gettext("Microcode file name must start " 132 "with vendor name, such as \"intel\" or \"amd\".\n\n")); 133 } 134 } 135 136 static void 137 ucode_perror(const char *str, ucode_errno_t rc) 138 { 139 (void) fprintf(stderr, "%s: %s: %s\n", cmdname, str, 140 errno == 0 ? ucode_strerror(rc) : strerror(errno)); 141 errno = 0; 142 } 143 144 #define LINESIZE 120 /* copyright line sometimes is longer than 80 */ 145 146 /* 147 * Convert text format microcode release into binary format. 148 * Return the number of characters read. 149 * 150 * AMD microcode is already in binary format. 151 */ 152 static int 153 ucode_convert_amd(const char *infile, uint8_t *buf, size_t size) 154 { 155 int fd; 156 157 if (infile == NULL || buf == NULL || size == 0) 158 return (0); 159 160 if ((fd = open(infile, O_RDONLY)) < 0) 161 return (0); 162 163 size = read(fd, buf, size); 164 165 (void) close(fd); 166 167 return (size); 168 } 169 170 static int 171 ucode_convert_intel(const char *infile, uint8_t *buf, size_t size) 172 { 173 char linebuf[LINESIZE]; 174 FILE *infd = NULL; 175 int count = 0, firstline = 1; 176 uint32_t *intbuf = (uint32_t *)(uintptr_t)buf; 177 178 if (infile == NULL || buf == NULL || size == 0) 179 return (0); 180 181 if ((infd = fopen(infile, "r")) == NULL) 182 return (0); 183 184 while (fgets(linebuf, LINESIZE, infd)) { 185 186 /* Check to see if we are processing a binary file */ 187 if (firstline && !isprint(linebuf[0])) { 188 if (fseek(infd, 0, SEEK_SET) == 0) 189 count = fread(buf, 1, size, infd); 190 191 (void) fclose(infd); 192 return (count); 193 } 194 195 firstline = 0; 196 197 /* Skip blank lines */ 198 if (strlen(linebuf) == 1) 199 continue; 200 201 /* Skip lines with all spaces or tabs */ 202 if (strcspn(linebuf, " \t") == 0) 203 continue; 204 205 /* Text file. Skip comments. */ 206 if (linebuf[0] == '/') 207 continue; 208 209 if (sscanf(linebuf, "%x, %x, %x, %x", 210 &intbuf[count], &intbuf[count+1], 211 &intbuf[count+2], &intbuf[count+3]) != 4) 212 break; 213 214 count += 4; 215 } 216 217 (void) fclose(infd); 218 219 /* 220 * If we get here, we are processing a text format file 221 * where "count" is used to count the number of integers 222 * read. Convert it to number of characters read. 223 */ 224 return (count * sizeof (int)); 225 } 226 227 /* 228 * Returns 0 if no need to update the link; -1 otherwise 229 */ 230 static int 231 ucode_should_update_intel(char *filename, uint32_t new_rev) 232 { 233 int fd; 234 struct stat statbuf; 235 ucode_header_intel_t header; 236 237 /* 238 * If the file or link already exists, check to see if 239 * it is necessary to update it. 240 */ 241 if (stat(filename, &statbuf) == 0) { 242 if ((fd = open(filename, O_RDONLY)) == -1) 243 return (-1); 244 245 if (read(fd, &header, sizeof (header)) == -1) { 246 (void) close(fd); 247 return (-1); 248 } 249 250 (void) close(fd); 251 252 if (header.uh_rev >= new_rev) 253 return (0); 254 } 255 256 return (-1); 257 } 258 259 /* 260 * Generate microcode binary files. Must be called after ucode_validate(). 261 */ 262 static ucode_errno_t 263 ucode_gen_files_amd(uint8_t *buf, int size, char *path) 264 { 265 uint32_t *ptr = (uint32_t *)buf; 266 char common_path[PATH_MAX]; 267 int fd, count, counter = 0; 268 ucode_header_amd_t *uh; 269 int last_cpu_rev = 0; 270 271 /* write container file */ 272 (void) snprintf(common_path, PATH_MAX, "%s/%s", path, "container"); 273 274 dprintf("path = %s\n", common_path); 275 fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC, 276 S_IRUSR | S_IRGRP | S_IROTH); 277 278 if (fd == -1) { 279 ucode_perror(common_path, EM_SYS); 280 return (EM_SYS); 281 } 282 283 if (write(fd, buf, size) != size) { 284 (void) close(fd); 285 ucode_perror(common_path, EM_SYS); 286 return (EM_SYS); 287 } 288 289 (void) close(fd); 290 291 /* skip over magic number & equivalence table header */ 292 ptr += 2; size -= 8; 293 294 count = *ptr++; size -= 4; 295 296 /* equivalence table uses special name */ 297 (void) snprintf(common_path, PATH_MAX, "%s/%s", path, 298 "equivalence-table"); 299 300 for (;;) { 301 dprintf("path = %s\n", common_path); 302 fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC, 303 S_IRUSR | S_IRGRP | S_IROTH); 304 305 if (fd == -1) { 306 ucode_perror(common_path, EM_SYS); 307 return (EM_SYS); 308 } 309 310 if (write(fd, ptr, count) != count) { 311 (void) close(fd); 312 ucode_perror(common_path, EM_SYS); 313 return (EM_SYS); 314 } 315 316 (void) close(fd); 317 ptr += count >> 2; size -= count; 318 319 if (!size) 320 return (EM_OK); 321 322 ptr++; size -= 4; 323 count = *ptr++; size -= 4; 324 325 /* construct name from header information */ 326 uh = (ucode_header_amd_t *)ptr; 327 328 if (uh->uh_cpu_rev != last_cpu_rev) { 329 last_cpu_rev = uh->uh_cpu_rev; 330 counter = 0; 331 } 332 333 (void) snprintf(common_path, PATH_MAX, "%s/%04X-%02X", path, 334 uh->uh_cpu_rev, counter++); 335 } 336 } 337 338 static ucode_errno_t 339 ucode_gen_files_intel(uint8_t *buf, int size, char *path) 340 { 341 int remaining; 342 char common_path[PATH_MAX]; 343 DIR *dirp; 344 struct dirent *dp; 345 346 (void) snprintf(common_path, PATH_MAX, "%s/%s", path, 347 UCODE_INSTALL_COMMON_PATH); 348 349 if (mkdirp(common_path, 0755) == -1 && errno != EEXIST) { 350 ucode_perror(common_path, EM_SYS); 351 return (EM_SYS); 352 } 353 354 for (remaining = size; remaining > 0; ) { 355 uint32_t total_size, body_size, offset; 356 char firstname[PATH_MAX]; 357 char name[PATH_MAX]; 358 int i; 359 uint8_t *curbuf = &buf[size - remaining]; 360 ucode_header_intel_t *uhp; 361 ucode_ext_table_intel_t *extp; 362 363 uhp = (ucode_header_intel_t *)(uintptr_t)curbuf; 364 365 total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 366 body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 367 368 remaining -= total_size; 369 370 (void) snprintf(firstname, PATH_MAX, "%s/%08X-%02X", 371 common_path, uhp->uh_signature, uhp->uh_proc_flags); 372 dprintf("firstname = %s\n", firstname); 373 374 if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) { 375 int fd; 376 377 /* Remove the existing one first */ 378 (void) unlink(firstname); 379 380 if ((fd = open(firstname, O_WRONLY | O_CREAT | O_TRUNC, 381 S_IRUSR | S_IRGRP | S_IROTH)) == -1) { 382 ucode_perror(firstname, EM_SYS); 383 return (EM_SYS); 384 } 385 386 if (write(fd, curbuf, total_size) != total_size) { 387 (void) close(fd); 388 ucode_perror(firstname, EM_SYS); 389 return (EM_SYS); 390 } 391 392 (void) close(fd); 393 } 394 395 /* 396 * Only 1 byte of the proc_flags field is used, therefore 397 * we only need to match 8 potential platform ids. 398 */ 399 for (i = 0; i < 8; i++) { 400 uint32_t platid = uhp->uh_proc_flags & (1 << i); 401 402 if (platid == 0 && uhp->uh_proc_flags != 0) 403 continue; 404 405 (void) snprintf(name, PATH_MAX, 406 "%s/%08X-%02X", path, uhp->uh_signature, platid); 407 408 dprintf("proc_flags = %x, platid = %x, name = %s\n", 409 uhp->uh_proc_flags, platid, name); 410 411 if (ucode_should_update_intel(name, 412 uhp->uh_rev) != 0) { 413 /* Remove the existing one first */ 414 (void) unlink(name); 415 if (link(firstname, name) == -1) { 416 ucode_perror(name, EM_SYS); 417 return (EM_SYS); 418 } 419 } 420 421 if (uhp->uh_proc_flags == 0) 422 break; 423 } 424 425 offset = UCODE_HEADER_SIZE_INTEL + body_size; 426 427 /* Check to see if there is extended signature table */ 428 if (total_size == offset) 429 continue; 430 431 /* There is extended signature table. More processing. */ 432 extp = (ucode_ext_table_intel_t *)&curbuf[offset]; 433 434 for (i = 0; i < extp->uet_count; i++) { 435 ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i]; 436 int j; 437 438 for (j = 0; j < 8; j++) { 439 uint32_t id = uesp->ues_proc_flags & (1 << j); 440 441 if (id == 0 && uesp->ues_proc_flags) 442 continue; 443 444 (void) snprintf(name, PATH_MAX, 445 "%s/%08X-%02X", path, 446 uesp->ues_signature, id); 447 448 dprintf("extsig: proc_flags = %x, " 449 "platid = %x, name = %s\n", 450 uesp->ues_proc_flags, id, name); 451 452 if (ucode_should_update_intel(name, 453 uhp->uh_rev) != 0) { 454 /* Remove the existing one first */ 455 (void) unlink(name); 456 if (link(firstname, name) == -1) { 457 ucode_perror(name, EM_SYS); 458 return (EM_SYS); 459 } 460 } 461 462 if (uesp->ues_proc_flags == 0) 463 break; 464 } 465 } 466 467 } 468 469 /* 470 * Remove files with no links to them. These are probably 471 * obsolete microcode files. 472 */ 473 if ((dirp = opendir(common_path)) == NULL) { 474 ucode_perror(common_path, EM_SYS); 475 return (EM_SYS); 476 } 477 478 while ((dp = readdir(dirp)) != NULL) { 479 char filename[PATH_MAX]; 480 struct stat statbuf; 481 482 (void) snprintf(filename, PATH_MAX, 483 "%s/%s", common_path, dp->d_name); 484 if (stat(filename, &statbuf) == -1) 485 continue; 486 487 if ((statbuf.st_mode & S_IFMT) == S_IFREG) { 488 if (statbuf.st_nlink == 1) 489 (void) unlink(filename); 490 } 491 } 492 493 (void) closedir(dirp); 494 495 return (EM_OK); 496 } 497 498 static void 499 ucode_fms(uint32_t sig, uint8_t *family, uint8_t *model, uint8_t *stepping) 500 { 501 *family = ((sig >> 8) & 0xf) + ((sig >> 20) & 0xff); 502 *model = ((sig >> 4) & 0xf) | ((sig >> 12) & 0xf0); 503 *stepping = sig & 0xf; 504 } 505 506 static void 507 ucode_list_intel(uint8_t *buf, int size) 508 { 509 int remaining; 510 511 printf("Microcode patches:\n"); 512 for (remaining = size; remaining > 0; ) { 513 uint8_t *curbuf = &buf[size - remaining]; 514 uint8_t family, model, stepping; 515 uint32_t total_size, body_size, offset; 516 ucode_header_intel_t *uhp; 517 ucode_ext_table_intel_t *extp; 518 519 uhp = (ucode_header_intel_t *)(uintptr_t)curbuf; 520 521 total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 522 body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 523 524 remaining -= total_size; 525 526 ucode_fms(uhp->uh_signature, &family, &model, &stepping); 527 528 printf( 529 " %08lX-%02lX -> Family=%02x Model=%02x Stepping=%02x\n", 530 uhp->uh_signature, uhp->uh_proc_flags, 531 family, model, stepping); 532 printf( 533 " %14s Date=%08lX Bytes=%lu\n", "", 534 uhp->uh_date, uhp->uh_body_size); 535 536 offset = UCODE_HEADER_SIZE_INTEL + body_size; 537 538 /* Check to see if there is extended signature table */ 539 if (total_size == offset) 540 continue; 541 542 printf("Extended Signature Table:\n"); 543 544 extp = (ucode_ext_table_intel_t *)&curbuf[offset]; 545 546 for (uint32_t i = 0; i < extp->uet_count; i++) { 547 ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i]; 548 549 ucode_fms(uesp->ues_signature, 550 &family, &model, &stepping); 551 552 printf( 553 " %08lX-%02lX -> Family=%02x Model=%02x " 554 "Stepping=%02x\n", 555 uesp->ues_signature, uesp->ues_proc_flags, 556 family, model, stepping); 557 } 558 } 559 } 560 561 static void 562 ucode_list_amd(uint8_t *buf, int size) 563 { 564 ucode_eqtbl_amd_t *eq; 565 ucode_header_amd_t *uh; 566 uint32_t tsz; 567 568 /* 569 * The file has already been validated so we can skip straight to 570 * the equivalence table. 571 */ 572 tsz = *(uint32_t *)(buf + 8); 573 eq = (ucode_eqtbl_amd_t *)(buf + 12); 574 size -= 12; 575 576 printf("Equivalence table:\n"); 577 while (size >= sizeof (ucode_eqtbl_amd_t) && eq->ue_inst_cpu != 0) { 578 uint8_t family, model, stepping; 579 580 ucode_fms(eq->ue_inst_cpu, &family, &model, &stepping); 581 582 printf( 583 " %08lX Family=%02x Model=%02x Stepping=%02x -> %04X\n", 584 eq->ue_inst_cpu, family, model, stepping, eq->ue_equiv_cpu); 585 eq++; 586 size -= sizeof (*eq); 587 } 588 589 /* Move past the equivalence table terminating record */ 590 eq++; 591 size -= sizeof (*eq); 592 buf = (uint8_t *)eq; 593 594 printf("Microcode patches:\n"); 595 while (size > sizeof (ucode_header_amd_t) + 8) { 596 tsz = *(uint32_t *)(buf + 4); 597 uh = (ucode_header_amd_t *)(buf + 8); 598 599 if (uh->uh_cpu_rev == 0) 600 break; 601 602 printf(" %4X -> Patch=%08lX Date=%08lX Bytes=%lu\n", 603 uh->uh_cpu_rev, uh->uh_patch_id, uh->uh_date, tsz); 604 605 buf += (tsz + 8); 606 size -= (tsz + 8); 607 } 608 } 609 610 /* 611 * Returns 0 on success, 2 on usage error, and 3 on operation error. 612 */ 613 int 614 main(int argc, char *argv[]) 615 { 616 int c; 617 int action = 0; 618 int actcount = 0; 619 char *path = NULL; 620 char *filename = NULL; 621 int errflg = 0; 622 int dev_fd = -1; 623 int fd = -1; 624 int verbose = 0; 625 uint8_t *buf = NULL; 626 ucode_errno_t rc = EM_OK; 627 processorid_t cpuid_max; 628 struct stat filestat; 629 int ucode_size = 0; 630 631 (void) setlocale(LC_ALL, ""); 632 633 #if !defined(TEXT_DOMAIN) 634 #define TEXT_DOMAIN "SYS_TEST" 635 #endif 636 (void) textdomain(TEXT_DOMAIN); 637 638 cmdname = basename(argv[0]); 639 640 while ((c = getopt(argc, argv, "idhluvVR:")) != EOF) { 641 switch (c) { 642 643 case 'i': 644 action |= UCODE_OPT_INSTALL; 645 actcount++; 646 break; 647 648 case 'l': 649 action |= UCODE_OPT_LIST; 650 actcount++; 651 break; 652 653 case 'u': 654 action |= UCODE_OPT_UPDATE; 655 actcount++; 656 break; 657 658 case 'v': 659 action |= UCODE_OPT_VERSION; 660 actcount++; 661 break; 662 663 case 'd': 664 ucode_debug = 1; 665 break; 666 667 case 'R': 668 if (optarg[0] == '-') { 669 errflg++; 670 } else if (strlen(optarg) > UCODE_MAX_PATH_LEN) { 671 (void) fprintf(stderr, 672 gettext("Alternate path too long\n")); 673 errflg++; 674 } else if ((path = strdup(optarg)) == NULL) { 675 errflg++; 676 } 677 678 break; 679 680 case 'V': 681 verbose = 1; 682 break; 683 684 case 'h': 685 usage(1); 686 return (0); 687 688 default: 689 usage(verbose); 690 return (2); 691 } 692 } 693 694 if (actcount == 0) { 695 (void) fprintf(stderr, gettext("%s: One of -i, -l, -u or -v " 696 "must be provided.\n"), cmdname); 697 usage(verbose); 698 return (2); 699 } 700 701 if (actcount != 1) { 702 (void) fprintf(stderr, gettext("%s: options -i, -l, -u and -v " 703 "are mutually exclusive.\n"), cmdname); 704 usage(verbose); 705 return (2); 706 } 707 708 if (optind <= argc - 1) 709 filename = argv[optind]; 710 else if (action != UCODE_OPT_VERSION) 711 errflg++; 712 713 if (errflg || action == 0) { 714 usage(verbose); 715 return (2); 716 } 717 718 /* 719 * Convert from the vendor-shipped format (text for Intel, binary 720 * container for AMD) to individual microcode files. 721 */ 722 if ((action & 723 (UCODE_OPT_INSTALL | UCODE_OPT_UPDATE | UCODE_OPT_LIST))) { 724 int i; 725 UCODE_VENDORS; 726 727 for (i = 0; ucode_vendors[i].filestr != NULL; i++) { 728 dprintf("i = %d, filestr = %s, filename = %s\n", 729 i, ucode_vendors[i].filestr, filename); 730 if (strncasecmp(ucode_vendors[i].filestr, 731 basename(filename), 732 strlen(ucode_vendors[i].filestr)) == 0) { 733 ucode = &ucode_ops[i]; 734 (void) strncpy(ucode_vendor_str, 735 ucode_vendors[i].vendorstr, 736 sizeof (ucode_vendor_str)); 737 break; 738 } 739 } 740 741 if (ucode_vendors[i].filestr == NULL) { 742 rc = EM_NOVENDOR; 743 ucode_perror(basename(filename), rc); 744 goto out; 745 } 746 747 if ((stat(filename, &filestat)) < 0) { 748 rc = EM_SYS; 749 ucode_perror(filename, rc); 750 goto out; 751 } 752 753 if ((filestat.st_mode & S_IFMT) != S_IFREG && 754 (filestat.st_mode & S_IFMT) != S_IFLNK) { 755 rc = EM_FILEFORMAT; 756 ucode_perror(filename, rc); 757 goto out; 758 } 759 760 if ((buf = malloc(filestat.st_size)) == NULL) { 761 rc = EM_SYS; 762 ucode_perror(filename, rc); 763 goto out; 764 } 765 766 ucode_size = ucode->convert(filename, buf, filestat.st_size); 767 768 dprintf("ucode_size = %d\n", ucode_size); 769 770 if (ucode_size == 0) { 771 rc = EM_FILEFORMAT; 772 ucode_perror(filename, rc); 773 goto out; 774 } 775 776 if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) { 777 ucode_perror(filename, rc); 778 goto out; 779 } 780 } 781 782 if (action & UCODE_OPT_LIST) { 783 ucode->list(buf, ucode_size); 784 goto out; 785 } 786 787 /* 788 * For the install option, the microcode file must start with 789 * "intel" for Intel microcode, and "amd" for AMD microcode. 790 */ 791 if (action & UCODE_OPT_INSTALL) { 792 /* 793 * If no path is provided by the -R option, put the files in 794 * /ucode_install_path/ucode_vendor_str/. 795 */ 796 if (path == NULL) { 797 if ((path = malloc(PATH_MAX)) == NULL) { 798 rc = EM_SYS; 799 ucode_perror("malloc", rc); 800 goto out; 801 } 802 803 (void) snprintf(path, PATH_MAX, "/%s/%s", 804 ucode_install_path, ucode_vendor_str); 805 } 806 807 if (mkdirp(path, 0755) == -1 && errno != EEXIST) { 808 rc = EM_SYS; 809 ucode_perror(path, rc); 810 goto out; 811 } 812 813 rc = ucode->gen_files(buf, ucode_size, path); 814 815 goto out; 816 } 817 818 if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) { 819 rc = EM_SYS; 820 ucode_perror(ucode_dev, rc); 821 goto out; 822 } 823 824 if (action & UCODE_OPT_VERSION) { 825 int tmprc; 826 uint32_t *revp = NULL; 827 int i; 828 #if defined(_SYSCALL32_IMPL) 829 struct ucode_get_rev_struct32 inf32; 830 #else 831 struct ucode_get_rev_struct info; 832 #endif 833 834 cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX); 835 836 if ((revp = (uint32_t *) 837 malloc(cpuid_max * sizeof (uint32_t))) == NULL) { 838 rc = EM_SYS; 839 ucode_perror("malloc", rc); 840 goto out; 841 } 842 843 for (i = 0; i < cpuid_max; i++) 844 revp[i] = (uint32_t)-1; 845 846 #if defined(_SYSCALL32_IMPL) 847 info32.ugv_rev = (caddr32_t)revp; 848 info32.ugv_size = cpuid_max; 849 info32.ugv_errno = EM_OK; 850 tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info32); 851 rc = info32.ugv_errno; 852 #else 853 info.ugv_rev = revp; 854 info.ugv_size = cpuid_max; 855 info.ugv_errno = EM_OK; 856 tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info); 857 rc = info.ugv_errno; 858 #endif 859 860 if (tmprc && rc == EM_OK) { 861 rc = EM_SYS; 862 } 863 864 if (rc == EM_OK) { 865 (void) printf(gettext("CPU\tMicrocode Version\n")); 866 for (i = 0; i < cpuid_max; i++) { 867 if (info.ugv_rev[i] == (uint32_t)-1) 868 continue; 869 (void) printf("%d\t0x%x\n", i, info.ugv_rev[i]); 870 } 871 } else { 872 ucode_perror(gettext("get microcode version"), rc); 873 } 874 875 if (revp) 876 free(revp); 877 } 878 879 if (action & UCODE_OPT_UPDATE) { 880 int tmprc; 881 #if defined(_SYSCALL32_IMPL) 882 struct ucode_write_struct32 uw_struct32; 883 #else 884 struct ucode_write_struct uw_struct; 885 #endif 886 887 #if defined(_SYSCALL32_IMPL) 888 uw_struct32.uw_size = ucode_size; 889 uw_struct32.uw_ucode = (caddr32_t)buf; 890 uw_struct32.uw_errno = EM_OK; 891 tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct32); 892 rc = uw_struct32.uw_errno; 893 894 #else 895 uw_struct.uw_size = ucode_size; 896 uw_struct.uw_ucode = buf; 897 uw_struct.uw_errno = EM_OK; 898 tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct); 899 rc = uw_struct.uw_errno; 900 #endif 901 902 if (rc == EM_OK) { 903 if (tmprc) { 904 rc = EM_SYS; 905 ucode_perror(ucode_dev, rc); 906 } 907 } else if (rc == EM_NOMATCH || rc == EM_HIGHERREV) { 908 ucode_perror(filename, rc); 909 } else { 910 ucode_perror(gettext("microcode update"), rc); 911 } 912 } 913 914 out: 915 if (dev_fd != -1) 916 (void) close(dev_fd); 917 918 if (fd != -1) 919 (void) close(fd); 920 921 free(buf); 922 free(path); 923 924 if (rc != EM_OK) 925 return (3); 926 927 return (0); 928 } 929