2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER START
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * The contents of this file are subject to the terms of the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Common Development and Distribution License (the "License").
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * You may not use this file except in compliance with the License.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * or http://www.opensolaris.org/os/licensing.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * See the License for the specific language governing permissions
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * and limitations under the License.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * When distributing Covered Code, include this CDDL HEADER in each
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If applicable, add the following below this CDDL HEADER, with the
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * fields enclosed by brackets "[]" replaced with your own identifying
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * information: Portions Copyright [yyyy] [name of copyright owner]
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym *
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * CDDL HEADER END
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Use is subject to license terms.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/types.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/processor.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/ucode.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/ioctl.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <sys/stat.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <unistd.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <dirent.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <fcntl.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <errno.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <stdio.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <stdlib.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <stdarg.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <string.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <errno.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <syslog.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <time.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <ctype.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <assert.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <libgen.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <locale.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#include <libintl.h>
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#define UCODE_OPT_INSTALL 0x0001
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#define UCODE_OPT_UPDATE 0x0002
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#define UCODE_OPT_VERSION 0x0004
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic char *cmdname;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic char ucode_vendor_str[UCODE_MAX_VENDORS_NAME_LEN];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic char ucode_install_path[] = UCODE_INSTALL_PATH;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic int ucode_debug = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic int ucode_convert_amd(const char *, uint8_t *, size_t);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic int ucode_convert_intel(const char *, uint8_t *, size_t);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic const struct ucode_ops ucode_ops[] = {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson { ucode_convert_intel, ucode_gen_files_intel, ucode_validate_intel },
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson { ucode_convert_amd, ucode_gen_files_amd, ucode_validate_amd },
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson};
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonconst struct ucode_ops *ucode;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymdprintf(const char *format, ...)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucode_debug) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym va_list alist;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym va_start(alist, format);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) vfprintf(stderr, format, alist);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym va_end(alist);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymusage(int verbose)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr, gettext("usage:\n"));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr, "\t%s -v\n", cmdname);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (verbose) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym gettext("\t\t Shows running microcode version.\n\n"));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) fprintf(stderr, "\t%s -u microcode-file\n", cmdname);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (verbose) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr, gettext("\t\t Updates microcode to the "
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym "latest matching version found in\n"
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson "\t\t microcode-file.\n\n"));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (verbose) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr, gettext("\t\t Installs microcode to be "
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson "used for subsequent boots.\n\n"));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) fprintf(stderr, gettext("Microcode file name must start "
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson "with vendor name, such as \"intel\" or \"amd\".\n\n"));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic void
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymucode_perror(const char *str, ucode_errno_t rc)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr, "%s: %s: %s\n", cmdname, str,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errno == 0 ? ucode_strerror(rc) : strerror(errno));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errno = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#define LINESIZE 120 /* copyright line sometimes is longer than 80 */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Convert text format microcode release into binary format.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Return the number of characters read.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic int
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_convert_amd(const char *infile, uint8_t *buf, size_t size)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int fd;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (infile == NULL || buf == NULL || size == 0)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (0);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((fd = open(infile, O_RDONLY)) < 0)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (0);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson size = read(fd, buf, size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) close(fd);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic int
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_convert_intel(const char *infile, uint8_t *buf, size_t size)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char linebuf[LINESIZE];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym FILE *infd = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int count = 0, firstline = 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t *intbuf = (uint32_t *)(intptr_t)buf;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (infile == NULL || buf == NULL || size == 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((infd = fopen(infile, "r")) == NULL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym while (fgets(linebuf, LINESIZE, infd)) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Check to see if we are processing a binary file */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (firstline && !isprint(linebuf[0])) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (fseek(infd, 0, SEEK_SET) == 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym count = fread(buf, 1, size, infd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fclose(infd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (count);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym firstline = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Skip blank lines */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (strlen(linebuf) == 1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Skip lines with all spaces or tabs */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (strcspn(linebuf, " \t") == 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Text file. Skip comments. */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (linebuf[0] == '/')
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (sscanf(linebuf, "%x, %x, %x, %x",
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym &intbuf[count], &intbuf[count+1],
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym &intbuf[count+2], &intbuf[count+3]) != 4)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym count += 4;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fclose(infd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If we get here, we are processing a text format file
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * where "count" is used to count the number of integers
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * read. Convert it to number of characters read.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (count * sizeof (int));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns 0 if no need to update the link; -1 otherwise
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic int
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_should_update_intel(char *filename, uint32_t new_rev)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int fd;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct stat statbuf;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_intel_t header;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If the file or link already exists, check to see if
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * it is necessary to update it.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (stat(filename, &statbuf) == 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((fd = open(filename, O_RDONLY)) == -1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (-1);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (read(fd, &header, sizeof (header)) == -1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) close(fd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (-1);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) close(fd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (header.uh_rev >= new_rev)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (-1);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Generate microcode binary files. Must be called after ucode_validate().
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymstatic ucode_errno_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_gen_files_amd(uint8_t *buf, int size, char *path)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson{
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* LINTED: pointer alignment */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uint32_t *ptr = (uint32_t *)buf;
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson char common_path[PATH_MAX];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int fd, count, counter;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_amd_t *uh;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int last_cpu_rev = 0;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson /* write container file */
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson (void) snprintf(common_path, PATH_MAX, "%s/%s", path, "container");
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson dprintf("path = %s\n", common_path);
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC,
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson S_IRUSR | S_IRGRP | S_IROTH);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (fd == -1) {
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson ucode_perror(common_path, EM_SYS);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (EM_SYS);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson }
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson if (write(fd, buf, size) != size) {
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson (void) close(fd);
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson ucode_perror(common_path, EM_SYS);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson return (EM_SYS);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson }
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson (void) close(fd);
0ba6f73dcd1c9160a44b2872ed0e0d81b51d168fMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* skip over magic number & equivalence table header */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ptr += 2; size -= 8;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = *ptr++; size -= 4;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* equivalence table uses special name */
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson (void) snprintf(common_path, PATH_MAX, "%s/%s", path,
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson "equivalence-table");
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson for (;;) {
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson dprintf("path = %s\n", common_path);
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson S_IRUSR | S_IRGRP | S_IROTH);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (fd == -1) {
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson ucode_perror(common_path, EM_SYS);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_SYS);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (write(fd, ptr, count) != count) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) close(fd);
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson ucode_perror(common_path, EM_SYS);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_SYS);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) close(fd);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ptr += count >> 2; size -= count;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (!size)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson return (EM_OK);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ptr++; size -= 4;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson count = *ptr++; size -= 4;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson /* construct name from header information */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uh = (ucode_header_amd_t *)ptr;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (uh->uh_cpu_rev != last_cpu_rev) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson last_cpu_rev = uh->uh_cpu_rev;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson counter = 0;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
08d2fdc210e92c7a249e69a795663019da6f23caMark Johnson (void) snprintf(common_path, PATH_MAX, "%s/%04X-%02X", path,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uh->uh_cpu_rev, counter++);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson}
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonstatic ucode_errno_t
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnsonucode_gen_files_intel(uint8_t *buf, int size, char *path)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int remaining;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char common_path[PATH_MAX];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym DIR *dirp;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct dirent *dp;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(common_path, PATH_MAX, "%s/%s", path,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym UCODE_INSTALL_COMMON_PATH);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (mkdirp(common_path, 0755) == -1 && errno != EEXIST) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(common_path, EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (remaining = size; remaining > 0; ) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t total_size, body_size, offset;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char firstname[PATH_MAX];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char name[PATH_MAX];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int i;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint8_t *curbuf = &buf[size - remaining];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_header_intel_t *uhp;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_ext_table_intel_t *extp;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson uhp = (ucode_header_intel_t *)(intptr_t)curbuf;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym remaining -= total_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(firstname, PATH_MAX, "%s/%08X-%02X",
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym common_path, uhp->uh_signature, uhp->uh_proc_flags);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym dprintf("firstname = %s\n", firstname);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int fd;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Remove the existing one first */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) unlink(firstname);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((fd = open(firstname, O_WRONLY | O_CREAT | O_TRUNC,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym S_IRUSR | S_IRGRP | S_IROTH)) == -1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(firstname, EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (write(fd, curbuf, total_size) != total_size) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) close(fd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(firstname, EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) close(fd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Only 1 byte of the proc_flags field is used, therefore
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * we only need to match 8 potential platform ids.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < 8; i++) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t platid = uhp->uh_proc_flags & (1 << i);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (platid == 0 && uhp->uh_proc_flags != 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(name, PATH_MAX,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym "%s/%08X-%02X", path, uhp->uh_signature, platid);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym dprintf("proc_flags = %x, platid = %x, name = %s\n",
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uhp->uh_proc_flags, platid, name);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_should_update_intel(name, uhp->uh_rev) != 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Remove the existing one first */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) unlink(name);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (link(firstname, name) == -1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(name, EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uhp->uh_proc_flags == 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson offset = UCODE_HEADER_SIZE_INTEL + body_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Check to see if there is extended signature table */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (total_size == offset)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* There is extended signature table. More processing. */
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson extp = (ucode_ext_table_intel_t *)(uintptr_t)&curbuf[offset];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < extp->uet_count; i++) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int j;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (j = 0; j < 8; j++) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t id = uesp->ues_proc_flags & (1 << j);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (id == 0 && uesp->ues_proc_flags)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(name, PATH_MAX,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym "%s/%08X-%02X", path, extp->uet_ext_sig[i],
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym id);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_should_update_intel(name, uhp->uh_rev)
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson != 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /* Remove the existing one first */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) unlink(name);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (link(firstname, name) == -1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(name, EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (uesp->ues_proc_flags == 0)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Remove files with no links to them. These are probably
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * obsolete microcode files.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((dirp = opendir(common_path)) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(common_path, EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_SYS);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym while ((dp = readdir(dirp)) != NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char filename[PATH_MAX];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct stat statbuf;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(filename, PATH_MAX,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym "%s/%s", common_path, dp->d_name);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (stat(filename, &statbuf) == -1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((statbuf.st_mode & S_IFMT) == S_IFREG) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (statbuf.st_nlink == 1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) unlink(filename);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) closedir(dirp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (EM_OK);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym/*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Returns 0 on success, 2 on usage error, and 3 on operation error.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymint
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymmain(int argc, char *argv[])
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym{
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int c;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int action = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int actcount = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char *path = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym char *filename = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int errflg = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int dev_fd = -1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int fd = -1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int verbose = 0;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint8_t *buf = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_errno_t rc = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym processorid_t cpuid_max;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct stat filestat;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t ucode_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) setlocale(LC_ALL, "");
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#if !defined(TEXT_DOMAIN)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#define TEXT_DOMAIN "SYS_TEST"
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) textdomain(TEXT_DOMAIN);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cmdname = basename(argv[0]);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym while ((c = getopt(argc, argv, "idhuvVR:")) != EOF) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym switch (c) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case 'i':
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym action |= UCODE_OPT_INSTALL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym actcount++;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case 'u':
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym action |= UCODE_OPT_UPDATE;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym actcount++;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case 'v':
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym action |= UCODE_OPT_VERSION;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym actcount++;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case 'd':
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_debug = 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case 'R':
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (optarg[0] == '-')
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errflg++;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym else if (strlen(optarg) > UCODE_MAX_PATH_LEN) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr,
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym gettext("Alternate path too long\n"));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errflg++;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else if ((path = strdup(optarg)) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errflg++;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case 'V':
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym verbose = 1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym break;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym case 'h':
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym usage(1);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym default:
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym usage(verbose);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (2);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (actcount != 1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) fprintf(stderr, gettext("%s: options -v, -i and -u "
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym "are mutually exclusive.\n"), cmdname);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym usage(verbose);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (2);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (optind <= argc - 1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym filename = argv[optind];
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym else if (!(action & UCODE_OPT_VERSION))
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym errflg++;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (errflg || action == 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym usage(verbose);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (2);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * Convert from text format to binary format
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson int i;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson UCODE_VENDORS;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson for (i = 0; ucode_vendors[i].filestr != NULL; i++) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson dprintf("i = %d, filestr = %s, filename = %s\n",
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson i, ucode_vendors[i].filestr, filename);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (strncasecmp(ucode_vendors[i].filestr,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson basename(filename),
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson strlen(ucode_vendors[i].filestr)) == 0) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode = &ucode_ops[i];
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson (void) strncpy(ucode_vendor_str,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_vendors[i].vendorstr,
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson sizeof (ucode_vendor_str));
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson break;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if (ucode_vendors[i].filestr == NULL) {
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson rc = EM_NOVENDOR;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_perror(basename(filename), rc);
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson goto err_out;
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson }
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((stat(filename, &filestat)) < 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(filename, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((filestat.st_mode & S_IFMT) != S_IFREG &&
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (filestat.st_mode & S_IFMT) != S_IFLNK) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_FILEFORMAT;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(filename, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((buf = malloc(filestat.st_size)) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(filename, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson ucode_size = ucode->convert(filename, buf, filestat.st_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym dprintf("ucode_size = %d\n", ucode_size);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (ucode_size == 0) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_FILEFORMAT;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(filename, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(filename, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * For the install option, the microcode file must start with
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * "intel" for Intel microcode, and "amd" for AMD microcode.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (action & UCODE_OPT_INSTALL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym /*
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * If no path is provided by the -R option, put the files in
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym * /ucode_install_path/ucode_vendor_str/.
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym */
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (path == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((path = malloc(PATH_MAX)) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror("malloc", rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) snprintf(path, PATH_MAX, "/%s/%s",
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_install_path, ucode_vendor_str);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (mkdirp(path, 0755) == -1 && errno != EEXIST) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(path, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
adc586debf12d2592024c0b8b9e44ffa104f858cMark Johnson rc = ucode->gen_files(buf, ucode_size, path);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(ucode_dev, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (action & UCODE_OPT_VERSION) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int tmprc;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uint32_t *revp = NULL;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int i;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#if defined(_SYSCALL32_IMPL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_get_rev_struct32 inf32;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#else
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_get_rev_struct info;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if ((revp = (uint32_t *)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym malloc(cpuid_max * sizeof (uint32_t))) == NULL) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror("malloc", rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym goto err_out;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < cpuid_max; i++)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym revp[i] = (uint32_t)-1;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#if defined(_SYSCALL32_IMPL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym info32.ugv_rev = (caddr32_t)revp;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym info32.ugv_size = cpuid_max;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym info32.ugv_errno = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info32);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = info32.ugv_errno;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#else
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym info.ugv_rev = revp;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym info.ugv_size = cpuid_max;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym info.ugv_errno = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = info.ugv_errno;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (tmprc && rc == EM_OK) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (rc == EM_OK) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) printf(gettext("CPU\tMicrocode Version\n"));
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym for (i = 0; i < cpuid_max; i++) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (info.ugv_rev[i] == (uint32_t)-1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym continue;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) printf("%d\t0x%x\n", i, info.ugv_rev[i]);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(gettext("get microcode version"), rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (revp)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym free(revp);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (action & UCODE_OPT_UPDATE) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym int tmprc;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#if defined(_SYSCALL32_IMPL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_write_struct32 uw_struct32;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#else
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym struct ucode_write_struct uw_struct;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#if defined(_SYSCALL32_IMPL)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uw_struct32.uw_size = ucode_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uw_struct32.uw_ucode = (caddr32_t)buf;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uw_struct32.uw_errno = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct32);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = uw_struct32.uw_errno;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#else
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uw_struct.uw_size = ucode_size;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uw_struct.uw_ucode = buf;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym uw_struct.uw_errno = EM_OK;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = uw_struct.uw_errno;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym#endif
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (rc == EM_OK) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (tmprc) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym rc = EM_SYS;
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(ucode_dev, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else if (rc == EM_NOMATCH || rc == EM_HIGHERREV) {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(filename, rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym } else {
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym ucode_perror(gettext("microcode update"), rc);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym }
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrymerr_out:
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (dev_fd != -1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) close(dev_fd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (fd != -1)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym (void) close(fd);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym free(buf);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym free(path);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym if (rc != EM_OK)
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (3);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym return (0);
2449e17f82f6097fd2c665b64723e31ceecbeca6sherrym}