12449e17fSsherrym /*
22449e17fSsherrym * CDDL HEADER START
32449e17fSsherrym *
42449e17fSsherrym * The contents of this file are subject to the terms of the
52449e17fSsherrym * Common Development and Distribution License (the "License").
62449e17fSsherrym * You may not use this file except in compliance with the License.
72449e17fSsherrym *
82449e17fSsherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92449e17fSsherrym * or http://www.opensolaris.org/os/licensing.
102449e17fSsherrym * See the License for the specific language governing permissions
112449e17fSsherrym * and limitations under the License.
122449e17fSsherrym *
132449e17fSsherrym * When distributing Covered Code, include this CDDL HEADER in each
142449e17fSsherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152449e17fSsherrym * If applicable, add the following below this CDDL HEADER, with the
162449e17fSsherrym * fields enclosed by brackets "[]" replaced with your own identifying
172449e17fSsherrym * information: Portions Copyright [yyyy] [name of copyright owner]
182449e17fSsherrym *
192449e17fSsherrym * CDDL HEADER END
202449e17fSsherrym */
212449e17fSsherrym /*
220ba6f73dSMark Johnson * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
232449e17fSsherrym * Use is subject to license terms.
242449e17fSsherrym */
252449e17fSsherrym
26bc54f855SJohn Levon /*
27bc54f855SJohn Levon * Copyright (c) 2018, Joyent, Inc.
28be672c8eSAndy Fiddaman * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
29*d32f26eeSAndy Fiddaman * Copyright 2023 Oxide Computer Company
30bc54f855SJohn Levon */
31bc54f855SJohn Levon
322449e17fSsherrym #include <sys/types.h>
332449e17fSsherrym #include <sys/processor.h>
34*d32f26eeSAndy Fiddaman #include <sys/sysmacros.h>
352449e17fSsherrym #include <sys/ucode.h>
36*d32f26eeSAndy Fiddaman #include <sys/ucode_intel.h>
37*d32f26eeSAndy Fiddaman #include <sys/ucode_amd.h>
38*d32f26eeSAndy Fiddaman #include <sys/utsname.h>
392449e17fSsherrym #include <sys/ioctl.h>
402449e17fSsherrym #include <sys/stat.h>
412449e17fSsherrym #include <unistd.h>
422449e17fSsherrym #include <dirent.h>
432449e17fSsherrym #include <fcntl.h>
442449e17fSsherrym #include <errno.h>
45*d32f26eeSAndy Fiddaman #include <stdbool.h>
462449e17fSsherrym #include <stdio.h>
472449e17fSsherrym #include <stdlib.h>
482449e17fSsherrym #include <stdarg.h>
492449e17fSsherrym #include <string.h>
502449e17fSsherrym #include <errno.h>
512449e17fSsherrym #include <syslog.h>
522449e17fSsherrym #include <time.h>
532449e17fSsherrym #include <ctype.h>
542449e17fSsherrym #include <assert.h>
552449e17fSsherrym #include <libgen.h>
56*d32f26eeSAndy Fiddaman #include <limits.h>
572449e17fSsherrym #include <locale.h>
582449e17fSsherrym #include <libintl.h>
59*d32f26eeSAndy Fiddaman #include <ucode/ucode_errno.h>
60*d32f26eeSAndy Fiddaman #include <ucode/ucode_utils_intel.h>
61*d32f26eeSAndy Fiddaman #include <ucode/ucode_utils_amd.h>
622449e17fSsherrym
632449e17fSsherrym #define UCODE_OPT_INSTALL 0x0001
642449e17fSsherrym #define UCODE_OPT_UPDATE 0x0002
652449e17fSsherrym #define UCODE_OPT_VERSION 0x0004
66be672c8eSAndy Fiddaman #define UCODE_OPT_LIST 0x0008
672449e17fSsherrym
682449e17fSsherrym static const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME;
692449e17fSsherrym
702449e17fSsherrym static char *cmdname;
712449e17fSsherrym
72*d32f26eeSAndy Fiddaman #define UCODE_INSTALL_COMMON_PATH ".f"
732449e17fSsherrym
74*d32f26eeSAndy Fiddaman /*
75*d32f26eeSAndy Fiddaman * The maximum directory path length that can be provided via -R has
76*d32f26eeSAndy Fiddaman * to allow for appending the files within the microcode bundles.
77*d32f26eeSAndy Fiddaman */
78*d32f26eeSAndy Fiddaman #define UCODE_MAX_PATH_LEN (PATH_MAX - \
79*d32f26eeSAndy Fiddaman MAX(UCODE_MAX_NAME_LEN_INTEL, UCODE_MAX_NAME_LEN_AMD) - 1)
80*d32f26eeSAndy Fiddaman
81*d32f26eeSAndy Fiddaman static bool ucode_debug = false;
822449e17fSsherrym
83adc586deSMark Johnson static int ucode_convert_amd(const char *, uint8_t *, size_t);
84adc586deSMark Johnson static int ucode_convert_intel(const char *, uint8_t *, size_t);
85adc586deSMark Johnson
86adc586deSMark Johnson static ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *);
87adc586deSMark Johnson static ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *);
88adc586deSMark Johnson
89be672c8eSAndy Fiddaman static void ucode_list_amd(uint8_t *, int);
90be672c8eSAndy Fiddaman static void ucode_list_intel(uint8_t *, int);
91be672c8eSAndy Fiddaman
92*d32f26eeSAndy Fiddaman typedef struct ucode_source {
93*d32f26eeSAndy Fiddaman const char *us_prefix;
94*d32f26eeSAndy Fiddaman const char *us_vendor;
95*d32f26eeSAndy Fiddaman int (*us_convert)(const char *, uint8_t *, size_t);
96*d32f26eeSAndy Fiddaman ucode_errno_t (*us_gen_files)(uint8_t *, int, char *);
97*d32f26eeSAndy Fiddaman ucode_errno_t (*us_validate)(uint8_t *, int);
98*d32f26eeSAndy Fiddaman void (*us_list)(uint8_t *, int);
99*d32f26eeSAndy Fiddaman } ucode_source_t;
100*d32f26eeSAndy Fiddaman
101*d32f26eeSAndy Fiddaman static const ucode_source_t ucode_sources[] = {
102be672c8eSAndy Fiddaman {
103*d32f26eeSAndy Fiddaman .us_prefix = "intel",
104*d32f26eeSAndy Fiddaman .us_vendor = "GenuineIntel",
105*d32f26eeSAndy Fiddaman .us_convert = ucode_convert_intel,
106*d32f26eeSAndy Fiddaman .us_gen_files = ucode_gen_files_intel,
107*d32f26eeSAndy Fiddaman .us_validate = ucode_validate_intel,
108*d32f26eeSAndy Fiddaman .us_list = ucode_list_intel,
109be672c8eSAndy Fiddaman },
110be672c8eSAndy Fiddaman {
111*d32f26eeSAndy Fiddaman .us_prefix = "amd",
112*d32f26eeSAndy Fiddaman .us_vendor = "AuthenticAMD",
113*d32f26eeSAndy Fiddaman .us_convert = ucode_convert_amd,
114*d32f26eeSAndy Fiddaman .us_gen_files = ucode_gen_files_amd,
115*d32f26eeSAndy Fiddaman .us_validate = ucode_validate_amd,
116*d32f26eeSAndy Fiddaman .us_list = ucode_list_amd,
117be672c8eSAndy Fiddaman },
118adc586deSMark Johnson };
119adc586deSMark Johnson
120*d32f26eeSAndy Fiddaman const ucode_source_t *ucode;
121adc586deSMark Johnson
1222449e17fSsherrym static void
dprintf(const char * format,...)1232449e17fSsherrym dprintf(const char *format, ...)
1242449e17fSsherrym {
1252449e17fSsherrym if (ucode_debug) {
1262449e17fSsherrym va_list alist;
1272449e17fSsherrym va_start(alist, format);
1282449e17fSsherrym (void) vfprintf(stderr, format, alist);
1292449e17fSsherrym va_end(alist);
1302449e17fSsherrym }
1312449e17fSsherrym }
1322449e17fSsherrym
1332449e17fSsherrym static void
usage(bool verbose)134*d32f26eeSAndy Fiddaman usage(bool verbose)
1352449e17fSsherrym {
1362449e17fSsherrym (void) fprintf(stderr, gettext("usage:\n"));
1372449e17fSsherrym (void) fprintf(stderr, "\t%s -v\n", cmdname);
1382449e17fSsherrym if (verbose) {
1392449e17fSsherrym (void) fprintf(stderr,
1402449e17fSsherrym gettext("\t\t Shows running microcode version.\n\n"));
1412449e17fSsherrym }
1422449e17fSsherrym
143*d32f26eeSAndy Fiddaman (void) fprintf(stderr, "\t%s -u [-t type] microcode-file\n", cmdname);
1442449e17fSsherrym if (verbose) {
1452449e17fSsherrym (void) fprintf(stderr, gettext("\t\t Updates microcode to the "
1462449e17fSsherrym "latest matching version found in\n"
147adc586deSMark Johnson "\t\t microcode-file.\n\n"));
1482449e17fSsherrym }
1492449e17fSsherrym
150*d32f26eeSAndy Fiddaman (void) fprintf(stderr, "\t%s -l [-t type] microcode-file\n", cmdname);
151be672c8eSAndy Fiddaman if (verbose) {
152be672c8eSAndy Fiddaman (void) fprintf(stderr, gettext("\t\t Displays details of the "
153be672c8eSAndy Fiddaman "microcode file's contents.\n\n"));
154be672c8eSAndy Fiddaman }
155be672c8eSAndy Fiddaman
156*d32f26eeSAndy Fiddaman (void) fprintf(stderr,
157*d32f26eeSAndy Fiddaman "\t%s -i [-t type] [-R path] microcode-file\n", cmdname);
1582449e17fSsherrym if (verbose) {
1592449e17fSsherrym (void) fprintf(stderr, gettext("\t\t Installs microcode to be "
160*d32f26eeSAndy Fiddaman "used for subsequent boots.\n"));
1612449e17fSsherrym }
162*d32f26eeSAndy Fiddaman (void) fprintf(stderr, gettext(
163*d32f26eeSAndy Fiddaman "\nThe type of the microcode file must either be specified with "
164*d32f26eeSAndy Fiddaman "the -t option\nor microcode-file must start with the vendor name "
165*d32f26eeSAndy Fiddaman "prefix, either \"intel\"\nor \"amd\", so that the type can be "
166*d32f26eeSAndy Fiddaman "inferred from it.\n\n"));
1672449e17fSsherrym }
1682449e17fSsherrym
1692449e17fSsherrym static void
ucode_perror(const char * str,ucode_errno_t rc)1702449e17fSsherrym ucode_perror(const char *str, ucode_errno_t rc)
1712449e17fSsherrym {
1722449e17fSsherrym (void) fprintf(stderr, "%s: %s: %s\n", cmdname, str,
1732449e17fSsherrym errno == 0 ? ucode_strerror(rc) : strerror(errno));
1742449e17fSsherrym errno = 0;
1752449e17fSsherrym }
1762449e17fSsherrym
1772449e17fSsherrym #define LINESIZE 120 /* copyright line sometimes is longer than 80 */
1782449e17fSsherrym
1792449e17fSsherrym /*
1802449e17fSsherrym * Convert text format microcode release into binary format.
1812449e17fSsherrym * Return the number of characters read.
182be672c8eSAndy Fiddaman *
183be672c8eSAndy Fiddaman * AMD microcode is already in binary format.
1842449e17fSsherrym */
1852449e17fSsherrym static int
ucode_convert_amd(const char * infile,uint8_t * buf,size_t size)186adc586deSMark Johnson ucode_convert_amd(const char *infile, uint8_t *buf, size_t size)
187adc586deSMark Johnson {
188adc586deSMark Johnson int fd;
189adc586deSMark Johnson
190adc586deSMark Johnson if (infile == NULL || buf == NULL || size == 0)
191adc586deSMark Johnson return (0);
192adc586deSMark Johnson
193adc586deSMark Johnson if ((fd = open(infile, O_RDONLY)) < 0)
194adc586deSMark Johnson return (0);
195adc586deSMark Johnson
196adc586deSMark Johnson size = read(fd, buf, size);
197adc586deSMark Johnson
198adc586deSMark Johnson (void) close(fd);
199adc586deSMark Johnson
200adc586deSMark Johnson return (size);
201adc586deSMark Johnson }
202adc586deSMark Johnson
203adc586deSMark Johnson static int
ucode_convert_intel(const char * infile,uint8_t * buf,size_t size)204adc586deSMark Johnson ucode_convert_intel(const char *infile, uint8_t *buf, size_t size)
2052449e17fSsherrym {
2062449e17fSsherrym char linebuf[LINESIZE];
2072449e17fSsherrym FILE *infd = NULL;
2082449e17fSsherrym int count = 0, firstline = 1;
209be672c8eSAndy Fiddaman uint32_t *intbuf = (uint32_t *)(uintptr_t)buf;
2102449e17fSsherrym
2112449e17fSsherrym if (infile == NULL || buf == NULL || size == 0)
2122449e17fSsherrym return (0);
2132449e17fSsherrym
2142449e17fSsherrym if ((infd = fopen(infile, "r")) == NULL)
2152449e17fSsherrym return (0);
2162449e17fSsherrym
2172449e17fSsherrym while (fgets(linebuf, LINESIZE, infd)) {
2182449e17fSsherrym
2192449e17fSsherrym /* Check to see if we are processing a binary file */
2202449e17fSsherrym if (firstline && !isprint(linebuf[0])) {
2212449e17fSsherrym if (fseek(infd, 0, SEEK_SET) == 0)
2222449e17fSsherrym count = fread(buf, 1, size, infd);
2232449e17fSsherrym
2242449e17fSsherrym (void) fclose(infd);
2252449e17fSsherrym return (count);
2262449e17fSsherrym }
2272449e17fSsherrym
2282449e17fSsherrym firstline = 0;
2292449e17fSsherrym
2302449e17fSsherrym /* Skip blank lines */
2312449e17fSsherrym if (strlen(linebuf) == 1)
2322449e17fSsherrym continue;
2332449e17fSsherrym
2342449e17fSsherrym /* Skip lines with all spaces or tabs */
2352449e17fSsherrym if (strcspn(linebuf, " \t") == 0)
2362449e17fSsherrym continue;
2372449e17fSsherrym
2382449e17fSsherrym /* Text file. Skip comments. */
2392449e17fSsherrym if (linebuf[0] == '/')
2402449e17fSsherrym continue;
2412449e17fSsherrym
2422449e17fSsherrym if (sscanf(linebuf, "%x, %x, %x, %x",
2432449e17fSsherrym &intbuf[count], &intbuf[count+1],
2442449e17fSsherrym &intbuf[count+2], &intbuf[count+3]) != 4)
2452449e17fSsherrym break;
2462449e17fSsherrym
2472449e17fSsherrym count += 4;
2482449e17fSsherrym }
2492449e17fSsherrym
2502449e17fSsherrym (void) fclose(infd);
2512449e17fSsherrym
2522449e17fSsherrym /*
2532449e17fSsherrym * If we get here, we are processing a text format file
2542449e17fSsherrym * where "count" is used to count the number of integers
2552449e17fSsherrym * read. Convert it to number of characters read.
2562449e17fSsherrym */
2572449e17fSsherrym return (count * sizeof (int));
2582449e17fSsherrym }
2592449e17fSsherrym
2602449e17fSsherrym /*
2612449e17fSsherrym * Returns 0 if no need to update the link; -1 otherwise
2622449e17fSsherrym */
2632449e17fSsherrym static int
ucode_should_update_intel(char * filename,uint32_t new_rev)264adc586deSMark Johnson ucode_should_update_intel(char *filename, uint32_t new_rev)
2652449e17fSsherrym {
2662449e17fSsherrym int fd;
2672449e17fSsherrym struct stat statbuf;
268adc586deSMark Johnson ucode_header_intel_t header;
2692449e17fSsherrym
2702449e17fSsherrym /*
2712449e17fSsherrym * If the file or link already exists, check to see if
2722449e17fSsherrym * it is necessary to update it.
2732449e17fSsherrym */
2742449e17fSsherrym if (stat(filename, &statbuf) == 0) {
2752449e17fSsherrym if ((fd = open(filename, O_RDONLY)) == -1)
2762449e17fSsherrym return (-1);
2772449e17fSsherrym
2782449e17fSsherrym if (read(fd, &header, sizeof (header)) == -1) {
2792449e17fSsherrym (void) close(fd);
2802449e17fSsherrym return (-1);
2812449e17fSsherrym }
2822449e17fSsherrym
2832449e17fSsherrym (void) close(fd);
2842449e17fSsherrym
2852449e17fSsherrym if (header.uh_rev >= new_rev)
2862449e17fSsherrym return (0);
2872449e17fSsherrym }
2882449e17fSsherrym
2892449e17fSsherrym return (-1);
2902449e17fSsherrym }
2912449e17fSsherrym
2922449e17fSsherrym /*
2932449e17fSsherrym * Generate microcode binary files. Must be called after ucode_validate().
2942449e17fSsherrym */
2952449e17fSsherrym static ucode_errno_t
ucode_gen_files_amd(uint8_t * buf,int size,char * path)296adc586deSMark Johnson ucode_gen_files_amd(uint8_t *buf, int size, char *path)
297adc586deSMark Johnson {
298adc586deSMark Johnson uint32_t *ptr = (uint32_t *)buf;
29908d2fdc2SMark Johnson char common_path[PATH_MAX];
300be672c8eSAndy Fiddaman int fd, count, counter = 0;
301adc586deSMark Johnson ucode_header_amd_t *uh;
302adc586deSMark Johnson int last_cpu_rev = 0;
303adc586deSMark Johnson
30408d2fdc2SMark Johnson /* write container file */
30508d2fdc2SMark Johnson (void) snprintf(common_path, PATH_MAX, "%s/%s", path, "container");
30608d2fdc2SMark Johnson
30708d2fdc2SMark Johnson dprintf("path = %s\n", common_path);
30808d2fdc2SMark Johnson fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC,
3090ba6f73dSMark Johnson S_IRUSR | S_IRGRP | S_IROTH);
3100ba6f73dSMark Johnson
3110ba6f73dSMark Johnson if (fd == -1) {
31208d2fdc2SMark Johnson ucode_perror(common_path, EM_SYS);
3130ba6f73dSMark Johnson return (EM_SYS);
3140ba6f73dSMark Johnson }
3150ba6f73dSMark Johnson
3160ba6f73dSMark Johnson if (write(fd, buf, size) != size) {
3170ba6f73dSMark Johnson (void) close(fd);
31808d2fdc2SMark Johnson ucode_perror(common_path, EM_SYS);
3190ba6f73dSMark Johnson return (EM_SYS);
3200ba6f73dSMark Johnson }
3210ba6f73dSMark Johnson
3220ba6f73dSMark Johnson (void) close(fd);
3230ba6f73dSMark Johnson
324adc586deSMark Johnson /* skip over magic number & equivalence table header */
325adc586deSMark Johnson ptr += 2; size -= 8;
326adc586deSMark Johnson
327adc586deSMark Johnson count = *ptr++; size -= 4;
328adc586deSMark Johnson
329adc586deSMark Johnson /* equivalence table uses special name */
33008d2fdc2SMark Johnson (void) snprintf(common_path, PATH_MAX, "%s/%s", path,
331*d32f26eeSAndy Fiddaman UCODE_AMD_EQUIVALENCE_TABLE_NAME);
332adc586deSMark Johnson
333adc586deSMark Johnson for (;;) {
33408d2fdc2SMark Johnson dprintf("path = %s\n", common_path);
33508d2fdc2SMark Johnson fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC,
336adc586deSMark Johnson S_IRUSR | S_IRGRP | S_IROTH);
337adc586deSMark Johnson
338adc586deSMark Johnson if (fd == -1) {
33908d2fdc2SMark Johnson ucode_perror(common_path, EM_SYS);
340adc586deSMark Johnson return (EM_SYS);
341adc586deSMark Johnson }
342adc586deSMark Johnson
343adc586deSMark Johnson if (write(fd, ptr, count) != count) {
344adc586deSMark Johnson (void) close(fd);
34508d2fdc2SMark Johnson ucode_perror(common_path, EM_SYS);
346adc586deSMark Johnson return (EM_SYS);
347adc586deSMark Johnson }
348adc586deSMark Johnson
349adc586deSMark Johnson (void) close(fd);
350adc586deSMark Johnson ptr += count >> 2; size -= count;
351adc586deSMark Johnson
352adc586deSMark Johnson if (!size)
353adc586deSMark Johnson return (EM_OK);
354adc586deSMark Johnson
355adc586deSMark Johnson ptr++; size -= 4;
356adc586deSMark Johnson count = *ptr++; size -= 4;
357adc586deSMark Johnson
358adc586deSMark Johnson /* construct name from header information */
359adc586deSMark Johnson uh = (ucode_header_amd_t *)ptr;
360adc586deSMark Johnson
361adc586deSMark Johnson if (uh->uh_cpu_rev != last_cpu_rev) {
362adc586deSMark Johnson last_cpu_rev = uh->uh_cpu_rev;
363adc586deSMark Johnson counter = 0;
364adc586deSMark Johnson }
365adc586deSMark Johnson
36608d2fdc2SMark Johnson (void) snprintf(common_path, PATH_MAX, "%s/%04X-%02X", path,
367adc586deSMark Johnson uh->uh_cpu_rev, counter++);
368adc586deSMark Johnson }
369adc586deSMark Johnson }
370adc586deSMark Johnson
371adc586deSMark Johnson static ucode_errno_t
ucode_gen_files_intel(uint8_t * buf,int size,char * path)372adc586deSMark Johnson ucode_gen_files_intel(uint8_t *buf, int size, char *path)
3732449e17fSsherrym {
3742449e17fSsherrym int remaining;
3752449e17fSsherrym char common_path[PATH_MAX];
3762449e17fSsherrym DIR *dirp;
3772449e17fSsherrym struct dirent *dp;
3782449e17fSsherrym
3792449e17fSsherrym (void) snprintf(common_path, PATH_MAX, "%s/%s", path,
3802449e17fSsherrym UCODE_INSTALL_COMMON_PATH);
3812449e17fSsherrym
3822449e17fSsherrym if (mkdirp(common_path, 0755) == -1 && errno != EEXIST) {
3832449e17fSsherrym ucode_perror(common_path, EM_SYS);
3842449e17fSsherrym return (EM_SYS);
3852449e17fSsherrym }
3862449e17fSsherrym
3872449e17fSsherrym for (remaining = size; remaining > 0; ) {
3882449e17fSsherrym uint32_t total_size, body_size, offset;
3892449e17fSsherrym char firstname[PATH_MAX];
3902449e17fSsherrym char name[PATH_MAX];
3912449e17fSsherrym int i;
3922449e17fSsherrym uint8_t *curbuf = &buf[size - remaining];
393adc586deSMark Johnson ucode_header_intel_t *uhp;
394adc586deSMark Johnson ucode_ext_table_intel_t *extp;
3952449e17fSsherrym
396be672c8eSAndy Fiddaman uhp = (ucode_header_intel_t *)(uintptr_t)curbuf;
397adc586deSMark Johnson
398adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
399adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
4002449e17fSsherrym
4012449e17fSsherrym remaining -= total_size;
4022449e17fSsherrym
4032449e17fSsherrym (void) snprintf(firstname, PATH_MAX, "%s/%08X-%02X",
4042449e17fSsherrym common_path, uhp->uh_signature, uhp->uh_proc_flags);
4052449e17fSsherrym dprintf("firstname = %s\n", firstname);
4062449e17fSsherrym
407adc586deSMark Johnson if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) {
4082449e17fSsherrym int fd;
4092449e17fSsherrym
4102449e17fSsherrym /* Remove the existing one first */
4112449e17fSsherrym (void) unlink(firstname);
4122449e17fSsherrym
4132449e17fSsherrym if ((fd = open(firstname, O_WRONLY | O_CREAT | O_TRUNC,
4142449e17fSsherrym S_IRUSR | S_IRGRP | S_IROTH)) == -1) {
4152449e17fSsherrym ucode_perror(firstname, EM_SYS);
4162449e17fSsherrym return (EM_SYS);
4172449e17fSsherrym }
4182449e17fSsherrym
4192449e17fSsherrym if (write(fd, curbuf, total_size) != total_size) {
4202449e17fSsherrym (void) close(fd);
4212449e17fSsherrym ucode_perror(firstname, EM_SYS);
4222449e17fSsherrym return (EM_SYS);
4232449e17fSsherrym }
4242449e17fSsherrym
4252449e17fSsherrym (void) close(fd);
4262449e17fSsherrym }
4272449e17fSsherrym
4282449e17fSsherrym /*
4292449e17fSsherrym * Only 1 byte of the proc_flags field is used, therefore
4302449e17fSsherrym * we only need to match 8 potential platform ids.
4312449e17fSsherrym */
4322449e17fSsherrym for (i = 0; i < 8; i++) {
4332449e17fSsherrym uint32_t platid = uhp->uh_proc_flags & (1 << i);
4342449e17fSsherrym
4352449e17fSsherrym if (platid == 0 && uhp->uh_proc_flags != 0)
4362449e17fSsherrym continue;
4372449e17fSsherrym
4382449e17fSsherrym (void) snprintf(name, PATH_MAX,
4392449e17fSsherrym "%s/%08X-%02X", path, uhp->uh_signature, platid);
4402449e17fSsherrym
4412449e17fSsherrym dprintf("proc_flags = %x, platid = %x, name = %s\n",
4422449e17fSsherrym uhp->uh_proc_flags, platid, name);
4432449e17fSsherrym
444afcdc73aSAndy Fiddaman if (ucode_should_update_intel(name,
445afcdc73aSAndy Fiddaman uhp->uh_rev) != 0) {
4462449e17fSsherrym /* Remove the existing one first */
4472449e17fSsherrym (void) unlink(name);
4482449e17fSsherrym if (link(firstname, name) == -1) {
4492449e17fSsherrym ucode_perror(name, EM_SYS);
4502449e17fSsherrym return (EM_SYS);
4512449e17fSsherrym }
4522449e17fSsherrym }
4532449e17fSsherrym
4542449e17fSsherrym if (uhp->uh_proc_flags == 0)
4552449e17fSsherrym break;
4562449e17fSsherrym }
4572449e17fSsherrym
458adc586deSMark Johnson offset = UCODE_HEADER_SIZE_INTEL + body_size;
4592449e17fSsherrym
4602449e17fSsherrym /* Check to see if there is extended signature table */
4612449e17fSsherrym if (total_size == offset)
4622449e17fSsherrym continue;
4632449e17fSsherrym
4642449e17fSsherrym /* There is extended signature table. More processing. */
465be672c8eSAndy Fiddaman extp = (ucode_ext_table_intel_t *)&curbuf[offset];
4662449e17fSsherrym
4672449e17fSsherrym for (i = 0; i < extp->uet_count; i++) {
468adc586deSMark Johnson ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i];
4692449e17fSsherrym int j;
4702449e17fSsherrym
4712449e17fSsherrym for (j = 0; j < 8; j++) {
4722449e17fSsherrym uint32_t id = uesp->ues_proc_flags & (1 << j);
4732449e17fSsherrym
4742449e17fSsherrym if (id == 0 && uesp->ues_proc_flags)
4752449e17fSsherrym continue;
4762449e17fSsherrym
4772449e17fSsherrym (void) snprintf(name, PATH_MAX,
478afcdc73aSAndy Fiddaman "%s/%08X-%02X", path,
479afcdc73aSAndy Fiddaman uesp->ues_signature, id);
4802449e17fSsherrym
481afcdc73aSAndy Fiddaman dprintf("extsig: proc_flags = %x, "
482afcdc73aSAndy Fiddaman "platid = %x, name = %s\n",
483afcdc73aSAndy Fiddaman uesp->ues_proc_flags, id, name);
4842449e17fSsherrym
485afcdc73aSAndy Fiddaman if (ucode_should_update_intel(name,
486afcdc73aSAndy Fiddaman uhp->uh_rev) != 0) {
4872449e17fSsherrym /* Remove the existing one first */
4882449e17fSsherrym (void) unlink(name);
4892449e17fSsherrym if (link(firstname, name) == -1) {
4902449e17fSsherrym ucode_perror(name, EM_SYS);
4912449e17fSsherrym return (EM_SYS);
4922449e17fSsherrym }
4932449e17fSsherrym }
4942449e17fSsherrym
4952449e17fSsherrym if (uesp->ues_proc_flags == 0)
4962449e17fSsherrym break;
4972449e17fSsherrym }
4982449e17fSsherrym }
4992449e17fSsherrym
5002449e17fSsherrym }
5012449e17fSsherrym
5022449e17fSsherrym /*
5032449e17fSsherrym * Remove files with no links to them. These are probably
5042449e17fSsherrym * obsolete microcode files.
5052449e17fSsherrym */
5062449e17fSsherrym if ((dirp = opendir(common_path)) == NULL) {
5072449e17fSsherrym ucode_perror(common_path, EM_SYS);
5082449e17fSsherrym return (EM_SYS);
5092449e17fSsherrym }
5102449e17fSsherrym
5112449e17fSsherrym while ((dp = readdir(dirp)) != NULL) {
5122449e17fSsherrym char filename[PATH_MAX];
5132449e17fSsherrym struct stat statbuf;
5142449e17fSsherrym
5152449e17fSsherrym (void) snprintf(filename, PATH_MAX,
5162449e17fSsherrym "%s/%s", common_path, dp->d_name);
5172449e17fSsherrym if (stat(filename, &statbuf) == -1)
5182449e17fSsherrym continue;
5192449e17fSsherrym
5202449e17fSsherrym if ((statbuf.st_mode & S_IFMT) == S_IFREG) {
5212449e17fSsherrym if (statbuf.st_nlink == 1)
5222449e17fSsherrym (void) unlink(filename);
5232449e17fSsherrym }
5242449e17fSsherrym }
5252449e17fSsherrym
5262449e17fSsherrym (void) closedir(dirp);
5272449e17fSsherrym
5282449e17fSsherrym return (EM_OK);
5292449e17fSsherrym }
5302449e17fSsherrym
531be672c8eSAndy Fiddaman static void
ucode_fms(uint32_t sig,uint8_t * family,uint8_t * model,uint8_t * stepping)532be672c8eSAndy Fiddaman ucode_fms(uint32_t sig, uint8_t *family, uint8_t *model, uint8_t *stepping)
533be672c8eSAndy Fiddaman {
534be672c8eSAndy Fiddaman *family = ((sig >> 8) & 0xf) + ((sig >> 20) & 0xff);
535be672c8eSAndy Fiddaman *model = ((sig >> 4) & 0xf) | ((sig >> 12) & 0xf0);
536be672c8eSAndy Fiddaman *stepping = sig & 0xf;
537be672c8eSAndy Fiddaman }
538be672c8eSAndy Fiddaman
539be672c8eSAndy Fiddaman static void
ucode_list_intel(uint8_t * buf,int size)540be672c8eSAndy Fiddaman ucode_list_intel(uint8_t *buf, int size)
541be672c8eSAndy Fiddaman {
542be672c8eSAndy Fiddaman int remaining;
543be672c8eSAndy Fiddaman
544be672c8eSAndy Fiddaman printf("Microcode patches:\n");
545be672c8eSAndy Fiddaman for (remaining = size; remaining > 0; ) {
546be672c8eSAndy Fiddaman uint8_t *curbuf = &buf[size - remaining];
547be672c8eSAndy Fiddaman uint8_t family, model, stepping;
548be672c8eSAndy Fiddaman uint32_t total_size, body_size, offset;
549be672c8eSAndy Fiddaman ucode_header_intel_t *uhp;
550be672c8eSAndy Fiddaman ucode_ext_table_intel_t *extp;
551be672c8eSAndy Fiddaman
552be672c8eSAndy Fiddaman uhp = (ucode_header_intel_t *)(uintptr_t)curbuf;
553be672c8eSAndy Fiddaman
554be672c8eSAndy Fiddaman total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
555be672c8eSAndy Fiddaman body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
556be672c8eSAndy Fiddaman
557be672c8eSAndy Fiddaman remaining -= total_size;
558be672c8eSAndy Fiddaman
559be672c8eSAndy Fiddaman ucode_fms(uhp->uh_signature, &family, &model, &stepping);
560be672c8eSAndy Fiddaman
561be672c8eSAndy Fiddaman printf(
562be672c8eSAndy Fiddaman " %08lX-%02lX -> Family=%02x Model=%02x Stepping=%02x\n",
563be672c8eSAndy Fiddaman uhp->uh_signature, uhp->uh_proc_flags,
564be672c8eSAndy Fiddaman family, model, stepping);
565be672c8eSAndy Fiddaman printf(
566be672c8eSAndy Fiddaman " %14s Date=%08lX Bytes=%lu\n", "",
567be672c8eSAndy Fiddaman uhp->uh_date, uhp->uh_body_size);
568be672c8eSAndy Fiddaman
569be672c8eSAndy Fiddaman offset = UCODE_HEADER_SIZE_INTEL + body_size;
570be672c8eSAndy Fiddaman
571be672c8eSAndy Fiddaman /* Check to see if there is extended signature table */
572be672c8eSAndy Fiddaman if (total_size == offset)
573be672c8eSAndy Fiddaman continue;
574be672c8eSAndy Fiddaman
575be672c8eSAndy Fiddaman printf("Extended Signature Table:\n");
576be672c8eSAndy Fiddaman
577be672c8eSAndy Fiddaman extp = (ucode_ext_table_intel_t *)&curbuf[offset];
578be672c8eSAndy Fiddaman
579be672c8eSAndy Fiddaman for (uint32_t i = 0; i < extp->uet_count; i++) {
580be672c8eSAndy Fiddaman ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i];
581be672c8eSAndy Fiddaman
582be672c8eSAndy Fiddaman ucode_fms(uesp->ues_signature,
583be672c8eSAndy Fiddaman &family, &model, &stepping);
584be672c8eSAndy Fiddaman
585be672c8eSAndy Fiddaman printf(
586be672c8eSAndy Fiddaman " %08lX-%02lX -> Family=%02x Model=%02x "
587be672c8eSAndy Fiddaman "Stepping=%02x\n",
588be672c8eSAndy Fiddaman uesp->ues_signature, uesp->ues_proc_flags,
589be672c8eSAndy Fiddaman family, model, stepping);
590be672c8eSAndy Fiddaman }
591be672c8eSAndy Fiddaman }
592be672c8eSAndy Fiddaman }
593be672c8eSAndy Fiddaman
594be672c8eSAndy Fiddaman static void
ucode_list_amd(uint8_t * buf,int size)595be672c8eSAndy Fiddaman ucode_list_amd(uint8_t *buf, int size)
596be672c8eSAndy Fiddaman {
597be672c8eSAndy Fiddaman ucode_eqtbl_amd_t *eq;
598be672c8eSAndy Fiddaman ucode_header_amd_t *uh;
599be672c8eSAndy Fiddaman uint32_t tsz;
600be672c8eSAndy Fiddaman
601be672c8eSAndy Fiddaman /*
602be672c8eSAndy Fiddaman * The file has already been validated so we can skip straight to
603be672c8eSAndy Fiddaman * the equivalence table.
604be672c8eSAndy Fiddaman */
605be672c8eSAndy Fiddaman tsz = *(uint32_t *)(buf + 8);
606be672c8eSAndy Fiddaman eq = (ucode_eqtbl_amd_t *)(buf + 12);
607be672c8eSAndy Fiddaman size -= 12;
608be672c8eSAndy Fiddaman
609be672c8eSAndy Fiddaman printf("Equivalence table:\n");
610be672c8eSAndy Fiddaman while (size >= sizeof (ucode_eqtbl_amd_t) && eq->ue_inst_cpu != 0) {
611be672c8eSAndy Fiddaman uint8_t family, model, stepping;
612be672c8eSAndy Fiddaman
613be672c8eSAndy Fiddaman ucode_fms(eq->ue_inst_cpu, &family, &model, &stepping);
614be672c8eSAndy Fiddaman
615be672c8eSAndy Fiddaman printf(
616be672c8eSAndy Fiddaman " %08lX Family=%02x Model=%02x Stepping=%02x -> %04X\n",
617be672c8eSAndy Fiddaman eq->ue_inst_cpu, family, model, stepping, eq->ue_equiv_cpu);
618be672c8eSAndy Fiddaman eq++;
619be672c8eSAndy Fiddaman size -= sizeof (*eq);
620be672c8eSAndy Fiddaman }
621be672c8eSAndy Fiddaman
622be672c8eSAndy Fiddaman /* Move past the equivalence table terminating record */
623be672c8eSAndy Fiddaman eq++;
624be672c8eSAndy Fiddaman size -= sizeof (*eq);
625be672c8eSAndy Fiddaman buf = (uint8_t *)eq;
626be672c8eSAndy Fiddaman
627be672c8eSAndy Fiddaman printf("Microcode patches:\n");
628be672c8eSAndy Fiddaman while (size > sizeof (ucode_header_amd_t) + 8) {
629be672c8eSAndy Fiddaman tsz = *(uint32_t *)(buf + 4);
630be672c8eSAndy Fiddaman uh = (ucode_header_amd_t *)(buf + 8);
631be672c8eSAndy Fiddaman
632be672c8eSAndy Fiddaman if (uh->uh_cpu_rev == 0)
633be672c8eSAndy Fiddaman break;
634be672c8eSAndy Fiddaman
635be672c8eSAndy Fiddaman printf(" %4X -> Patch=%08lX Date=%08lX Bytes=%lu\n",
636be672c8eSAndy Fiddaman uh->uh_cpu_rev, uh->uh_patch_id, uh->uh_date, tsz);
637be672c8eSAndy Fiddaman
638be672c8eSAndy Fiddaman buf += (tsz + 8);
639be672c8eSAndy Fiddaman size -= (tsz + 8);
640be672c8eSAndy Fiddaman }
641be672c8eSAndy Fiddaman }
642be672c8eSAndy Fiddaman
6432449e17fSsherrym /*
6442449e17fSsherrym * Returns 0 on success, 2 on usage error, and 3 on operation error.
6452449e17fSsherrym */
6462449e17fSsherrym int
main(int argc,char * argv[])6472449e17fSsherrym main(int argc, char *argv[])
6482449e17fSsherrym {
6492449e17fSsherrym int c;
6502449e17fSsherrym int action = 0;
6512449e17fSsherrym int actcount = 0;
652*d32f26eeSAndy Fiddaman int typeindex = -1;
6532449e17fSsherrym char *path = NULL;
6542449e17fSsherrym char *filename = NULL;
6552449e17fSsherrym int errflg = 0;
6562449e17fSsherrym int dev_fd = -1;
6572449e17fSsherrym int fd = -1;
658*d32f26eeSAndy Fiddaman bool verbose = false;
659*d32f26eeSAndy Fiddaman bool needfile = false;
6602449e17fSsherrym uint8_t *buf = NULL;
6612449e17fSsherrym ucode_errno_t rc = EM_OK;
6622449e17fSsherrym processorid_t cpuid_max;
6632449e17fSsherrym struct stat filestat;
664be672c8eSAndy Fiddaman int ucode_size = 0;
6652449e17fSsherrym
6662449e17fSsherrym (void) setlocale(LC_ALL, "");
6672449e17fSsherrym
6682449e17fSsherrym #if !defined(TEXT_DOMAIN)
6692449e17fSsherrym #define TEXT_DOMAIN "SYS_TEST"
6702449e17fSsherrym #endif
6712449e17fSsherrym (void) textdomain(TEXT_DOMAIN);
6722449e17fSsherrym
6732449e17fSsherrym cmdname = basename(argv[0]);
6742449e17fSsherrym
675*d32f26eeSAndy Fiddaman while ((c = getopt(argc, argv, "idhluvVR:t:")) != EOF) {
6762449e17fSsherrym switch (c) {
6772449e17fSsherrym
678*d32f26eeSAndy Fiddaman case 'd':
679*d32f26eeSAndy Fiddaman ucode_debug = true;
680*d32f26eeSAndy Fiddaman break;
681*d32f26eeSAndy Fiddaman
6822449e17fSsherrym case 'i':
6832449e17fSsherrym action |= UCODE_OPT_INSTALL;
6842449e17fSsherrym actcount++;
685*d32f26eeSAndy Fiddaman needfile = true;
6862449e17fSsherrym break;
6872449e17fSsherrym
688be672c8eSAndy Fiddaman case 'l':
689be672c8eSAndy Fiddaman action |= UCODE_OPT_LIST;
690be672c8eSAndy Fiddaman actcount++;
691*d32f26eeSAndy Fiddaman needfile = true;
692*d32f26eeSAndy Fiddaman break;
693*d32f26eeSAndy Fiddaman
694*d32f26eeSAndy Fiddaman case 't':
695*d32f26eeSAndy Fiddaman if (typeindex != -1) {
696*d32f26eeSAndy Fiddaman (void) fprintf(stderr, gettext(
697*d32f26eeSAndy Fiddaman "-t can only be specified once\n"));
698*d32f26eeSAndy Fiddaman errflg++;
699*d32f26eeSAndy Fiddaman break;
700*d32f26eeSAndy Fiddaman }
701*d32f26eeSAndy Fiddaman for (uint_t i = 0; i < ARRAY_SIZE(ucode_sources); i++) {
702*d32f26eeSAndy Fiddaman if (strcmp(optarg,
703*d32f26eeSAndy Fiddaman ucode_sources[i].us_prefix) == 0) {
704*d32f26eeSAndy Fiddaman typeindex = i;
705*d32f26eeSAndy Fiddaman break;
706*d32f26eeSAndy Fiddaman }
707*d32f26eeSAndy Fiddaman }
708*d32f26eeSAndy Fiddaman if (typeindex == -1) {
709*d32f26eeSAndy Fiddaman (void) fprintf(stderr,
710*d32f26eeSAndy Fiddaman gettext("Unknown microcode type, %s\n"),
711*d32f26eeSAndy Fiddaman optarg);
712*d32f26eeSAndy Fiddaman errflg++;
713*d32f26eeSAndy Fiddaman }
714be672c8eSAndy Fiddaman break;
715be672c8eSAndy Fiddaman
7162449e17fSsherrym case 'u':
7172449e17fSsherrym action |= UCODE_OPT_UPDATE;
7182449e17fSsherrym actcount++;
719*d32f26eeSAndy Fiddaman needfile = true;
7202449e17fSsherrym break;
7212449e17fSsherrym
7222449e17fSsherrym case 'v':
7232449e17fSsherrym action |= UCODE_OPT_VERSION;
7242449e17fSsherrym actcount++;
7252449e17fSsherrym break;
7262449e17fSsherrym
7272449e17fSsherrym case 'R':
728be672c8eSAndy Fiddaman if (optarg[0] == '-') {
7292449e17fSsherrym errflg++;
730be672c8eSAndy Fiddaman } else if (strlen(optarg) > UCODE_MAX_PATH_LEN) {
7312449e17fSsherrym (void) fprintf(stderr,
7322449e17fSsherrym gettext("Alternate path too long\n"));
7332449e17fSsherrym errflg++;
7342449e17fSsherrym } else if ((path = strdup(optarg)) == NULL) {
7352449e17fSsherrym errflg++;
7362449e17fSsherrym }
7372449e17fSsherrym
7382449e17fSsherrym break;
7392449e17fSsherrym
7402449e17fSsherrym case 'V':
741*d32f26eeSAndy Fiddaman verbose = true;
7422449e17fSsherrym break;
7432449e17fSsherrym
7442449e17fSsherrym case 'h':
745*d32f26eeSAndy Fiddaman usage(true);
7462449e17fSsherrym return (0);
7472449e17fSsherrym
7482449e17fSsherrym default:
7492449e17fSsherrym usage(verbose);
7502449e17fSsherrym return (2);
7512449e17fSsherrym }
7522449e17fSsherrym }
7532449e17fSsherrym
754be672c8eSAndy Fiddaman if (actcount == 0) {
755be672c8eSAndy Fiddaman (void) fprintf(stderr, gettext("%s: One of -i, -l, -u or -v "
756be672c8eSAndy Fiddaman "must be provided.\n"), cmdname);
757be672c8eSAndy Fiddaman usage(verbose);
758be672c8eSAndy Fiddaman return (2);
759be672c8eSAndy Fiddaman }
760be672c8eSAndy Fiddaman
7612449e17fSsherrym if (actcount != 1) {
762be672c8eSAndy Fiddaman (void) fprintf(stderr, gettext("%s: options -i, -l, -u and -v "
7632449e17fSsherrym "are mutually exclusive.\n"), cmdname);
7642449e17fSsherrym usage(verbose);
7652449e17fSsherrym return (2);
7662449e17fSsherrym }
7672449e17fSsherrym
768*d32f26eeSAndy Fiddaman if (typeindex != -1 && !needfile) {
769*d32f26eeSAndy Fiddaman (void) fprintf(stderr, gettext("%s: option -t requires one of "
770*d32f26eeSAndy Fiddaman "-i, -l or -u\n"), cmdname);
771*d32f26eeSAndy Fiddaman usage(verbose);
772*d32f26eeSAndy Fiddaman return (2);
773*d32f26eeSAndy Fiddaman }
774*d32f26eeSAndy Fiddaman
7752449e17fSsherrym if (optind <= argc - 1)
7762449e17fSsherrym filename = argv[optind];
777*d32f26eeSAndy Fiddaman else if (needfile)
7782449e17fSsherrym errflg++;
7792449e17fSsherrym
7802449e17fSsherrym if (errflg || action == 0) {
7812449e17fSsherrym usage(verbose);
7822449e17fSsherrym return (2);
7832449e17fSsherrym }
7842449e17fSsherrym
7852449e17fSsherrym /*
786*d32f26eeSAndy Fiddaman * Convert from the vendor-shipped format to individual microcode files.
7872449e17fSsherrym */
788*d32f26eeSAndy Fiddaman if (needfile) {
789*d32f26eeSAndy Fiddaman if (typeindex != -1) {
790*d32f26eeSAndy Fiddaman ucode = &ucode_sources[typeindex];
791*d32f26eeSAndy Fiddaman } else {
792*d32f26eeSAndy Fiddaman for (uint_t i = 0; i < ARRAY_SIZE(ucode_sources); i++) {
793*d32f26eeSAndy Fiddaman const ucode_source_t *src = &ucode_sources[i];
794adc586deSMark Johnson
795adc586deSMark Johnson dprintf("i = %d, filestr = %s, filename = %s\n",
796*d32f26eeSAndy Fiddaman i, src->us_prefix, filename);
797*d32f26eeSAndy Fiddaman if (strncasecmp(src->us_prefix,
798adc586deSMark Johnson basename(filename),
799*d32f26eeSAndy Fiddaman strlen(src->us_prefix)) == 0) {
800*d32f26eeSAndy Fiddaman ucode = src;
801adc586deSMark Johnson break;
802adc586deSMark Johnson }
803adc586deSMark Johnson }
804*d32f26eeSAndy Fiddaman }
805adc586deSMark Johnson
806*d32f26eeSAndy Fiddaman if (ucode == NULL) {
807adc586deSMark Johnson rc = EM_NOVENDOR;
808*d32f26eeSAndy Fiddaman (void) fprintf(stderr, "%s: %s.\n\n"
809*d32f26eeSAndy Fiddaman "Either specify the type with the -t option, "
810*d32f26eeSAndy Fiddaman "or rename the file such that\nits name begins "
811*d32f26eeSAndy Fiddaman "with a vendor string.\n",
812*d32f26eeSAndy Fiddaman cmdname, ucode_strerror(rc));
813be672c8eSAndy Fiddaman goto out;
814adc586deSMark Johnson }
815adc586deSMark Johnson
816*d32f26eeSAndy Fiddaman dprintf("Selected microcode type %s (%s)\n",
817*d32f26eeSAndy Fiddaman ucode->us_prefix, ucode->us_vendor);
818*d32f26eeSAndy Fiddaman
8192449e17fSsherrym if ((stat(filename, &filestat)) < 0) {
8202449e17fSsherrym rc = EM_SYS;
8212449e17fSsherrym ucode_perror(filename, rc);
822be672c8eSAndy Fiddaman goto out;
8232449e17fSsherrym }
8242449e17fSsherrym
8252449e17fSsherrym if ((filestat.st_mode & S_IFMT) != S_IFREG &&
8262449e17fSsherrym (filestat.st_mode & S_IFMT) != S_IFLNK) {
8272449e17fSsherrym rc = EM_FILEFORMAT;
8282449e17fSsherrym ucode_perror(filename, rc);
829be672c8eSAndy Fiddaman goto out;
8302449e17fSsherrym }
8312449e17fSsherrym
8322449e17fSsherrym if ((buf = malloc(filestat.st_size)) == NULL) {
8332449e17fSsherrym rc = EM_SYS;
8342449e17fSsherrym ucode_perror(filename, rc);
835be672c8eSAndy Fiddaman goto out;
8362449e17fSsherrym }
8372449e17fSsherrym
838*d32f26eeSAndy Fiddaman ucode_size = ucode->us_convert(filename, buf, filestat.st_size);
8392449e17fSsherrym
8402449e17fSsherrym dprintf("ucode_size = %d\n", ucode_size);
8412449e17fSsherrym
8422449e17fSsherrym if (ucode_size == 0) {
8432449e17fSsherrym rc = EM_FILEFORMAT;
8442449e17fSsherrym ucode_perror(filename, rc);
845be672c8eSAndy Fiddaman goto out;
8462449e17fSsherrym }
8472449e17fSsherrym
848*d32f26eeSAndy Fiddaman if ((rc = ucode->us_validate(buf, ucode_size)) != EM_OK) {
8492449e17fSsherrym ucode_perror(filename, rc);
850be672c8eSAndy Fiddaman goto out;
8512449e17fSsherrym }
8522449e17fSsherrym }
8532449e17fSsherrym
854be672c8eSAndy Fiddaman if (action & UCODE_OPT_LIST) {
855*d32f26eeSAndy Fiddaman ucode->us_list(buf, ucode_size);
856be672c8eSAndy Fiddaman goto out;
857be672c8eSAndy Fiddaman }
858be672c8eSAndy Fiddaman
8592449e17fSsherrym if (action & UCODE_OPT_INSTALL) {
8602449e17fSsherrym /*
8612449e17fSsherrym * If no path is provided by the -R option, put the files in
862*d32f26eeSAndy Fiddaman * /platform/<arch>/ucode/<ucode_vendor_str>/.
8632449e17fSsherrym */
8642449e17fSsherrym if (path == NULL) {
865*d32f26eeSAndy Fiddaman struct utsname uts;
866*d32f26eeSAndy Fiddaman
867*d32f26eeSAndy Fiddaman if (uname(&uts) == -1) {
868*d32f26eeSAndy Fiddaman perror("Unable to retrieve system uname");
869*d32f26eeSAndy Fiddaman goto out;
870*d32f26eeSAndy Fiddaman }
871*d32f26eeSAndy Fiddaman
8722449e17fSsherrym if ((path = malloc(PATH_MAX)) == NULL) {
8732449e17fSsherrym rc = EM_SYS;
8742449e17fSsherrym ucode_perror("malloc", rc);
875be672c8eSAndy Fiddaman goto out;
8762449e17fSsherrym }
8772449e17fSsherrym
878*d32f26eeSAndy Fiddaman (void) snprintf(path, PATH_MAX, "/platform/%s/ucode/%s",
879*d32f26eeSAndy Fiddaman uts.machine, ucode->us_vendor);
8802449e17fSsherrym }
8812449e17fSsherrym
8822449e17fSsherrym if (mkdirp(path, 0755) == -1 && errno != EEXIST) {
8832449e17fSsherrym rc = EM_SYS;
8842449e17fSsherrym ucode_perror(path, rc);
885be672c8eSAndy Fiddaman goto out;
8862449e17fSsherrym }
8872449e17fSsherrym
888*d32f26eeSAndy Fiddaman rc = ucode->us_gen_files(buf, ucode_size, path);
8892449e17fSsherrym
890be672c8eSAndy Fiddaman goto out;
8912449e17fSsherrym }
8922449e17fSsherrym
8932449e17fSsherrym if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) {
8942449e17fSsherrym rc = EM_SYS;
8952449e17fSsherrym ucode_perror(ucode_dev, rc);
896be672c8eSAndy Fiddaman goto out;
8972449e17fSsherrym }
8982449e17fSsherrym
8992449e17fSsherrym if (action & UCODE_OPT_VERSION) {
9002449e17fSsherrym int tmprc;
9012449e17fSsherrym uint32_t *revp = NULL;
9022449e17fSsherrym int i;
9032449e17fSsherrym struct ucode_get_rev_struct info;
9042449e17fSsherrym
9052449e17fSsherrym cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX);
9062449e17fSsherrym
9072449e17fSsherrym if ((revp = (uint32_t *)
9082449e17fSsherrym malloc(cpuid_max * sizeof (uint32_t))) == NULL) {
9092449e17fSsherrym rc = EM_SYS;
9102449e17fSsherrym ucode_perror("malloc", rc);
911be672c8eSAndy Fiddaman goto out;
9122449e17fSsherrym }
9132449e17fSsherrym
9142449e17fSsherrym for (i = 0; i < cpuid_max; i++)
9152449e17fSsherrym revp[i] = (uint32_t)-1;
9162449e17fSsherrym
9172449e17fSsherrym info.ugv_rev = revp;
9182449e17fSsherrym info.ugv_size = cpuid_max;
9192449e17fSsherrym info.ugv_errno = EM_OK;
9202449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info);
9212449e17fSsherrym rc = info.ugv_errno;
9222449e17fSsherrym
9232449e17fSsherrym if (tmprc && rc == EM_OK) {
9242449e17fSsherrym rc = EM_SYS;
9252449e17fSsherrym }
9262449e17fSsherrym
9272449e17fSsherrym if (rc == EM_OK) {
9282449e17fSsherrym (void) printf(gettext("CPU\tMicrocode Version\n"));
9292449e17fSsherrym for (i = 0; i < cpuid_max; i++) {
9302449e17fSsherrym if (info.ugv_rev[i] == (uint32_t)-1)
9312449e17fSsherrym continue;
9322449e17fSsherrym (void) printf("%d\t0x%x\n", i, info.ugv_rev[i]);
9332449e17fSsherrym }
9342449e17fSsherrym } else {
9352449e17fSsherrym ucode_perror(gettext("get microcode version"), rc);
9362449e17fSsherrym }
9372449e17fSsherrym
9382449e17fSsherrym if (revp)
9392449e17fSsherrym free(revp);
9402449e17fSsherrym }
9412449e17fSsherrym
9422449e17fSsherrym if (action & UCODE_OPT_UPDATE) {
9432449e17fSsherrym int tmprc;
9442449e17fSsherrym struct ucode_write_struct uw_struct;
9452449e17fSsherrym
9462449e17fSsherrym uw_struct.uw_size = ucode_size;
9472449e17fSsherrym uw_struct.uw_ucode = buf;
9482449e17fSsherrym uw_struct.uw_errno = EM_OK;
9492449e17fSsherrym tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct);
9502449e17fSsherrym rc = uw_struct.uw_errno;
9512449e17fSsherrym
9522449e17fSsherrym if (rc == EM_OK) {
9532449e17fSsherrym if (tmprc) {
9542449e17fSsherrym rc = EM_SYS;
9552449e17fSsherrym ucode_perror(ucode_dev, rc);
9562449e17fSsherrym }
9572449e17fSsherrym } else if (rc == EM_NOMATCH || rc == EM_HIGHERREV) {
9582449e17fSsherrym ucode_perror(filename, rc);
9592449e17fSsherrym } else {
9602449e17fSsherrym ucode_perror(gettext("microcode update"), rc);
9612449e17fSsherrym }
9622449e17fSsherrym }
9632449e17fSsherrym
964be672c8eSAndy Fiddaman out:
9652449e17fSsherrym if (dev_fd != -1)
9662449e17fSsherrym (void) close(dev_fd);
9672449e17fSsherrym
9682449e17fSsherrym if (fd != -1)
9692449e17fSsherrym (void) close(fd);
9702449e17fSsherrym
9712449e17fSsherrym free(buf);
9722449e17fSsherrym free(path);
9732449e17fSsherrym
9742449e17fSsherrym if (rc != EM_OK)
9752449e17fSsherrym return (3);
9762449e17fSsherrym
9772449e17fSsherrym return (0);
9782449e17fSsherrym }
979