xref: /titanic_50/usr/src/cmd/ucodeadm/ucodeadm.c (revision 08d2fdc210e92c7a249e69a795663019da6f23ca)
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 
262449e17fSsherrym #include <sys/types.h>
272449e17fSsherrym #include <sys/processor.h>
282449e17fSsherrym #include <sys/ucode.h>
292449e17fSsherrym #include <sys/ioctl.h>
302449e17fSsherrym #include <sys/stat.h>
312449e17fSsherrym #include <unistd.h>
322449e17fSsherrym #include <dirent.h>
332449e17fSsherrym #include <fcntl.h>
342449e17fSsherrym #include <errno.h>
352449e17fSsherrym #include <stdio.h>
362449e17fSsherrym #include <stdlib.h>
372449e17fSsherrym #include <stdarg.h>
382449e17fSsherrym #include <string.h>
392449e17fSsherrym #include <errno.h>
402449e17fSsherrym #include <syslog.h>
412449e17fSsherrym #include <time.h>
422449e17fSsherrym #include <ctype.h>
432449e17fSsherrym #include <assert.h>
442449e17fSsherrym #include <libgen.h>
452449e17fSsherrym #include <locale.h>
462449e17fSsherrym #include <libintl.h>
472449e17fSsherrym 
482449e17fSsherrym #define	UCODE_OPT_INSTALL	0x0001
492449e17fSsherrym #define	UCODE_OPT_UPDATE	0x0002
502449e17fSsherrym #define	UCODE_OPT_VERSION	0x0004
512449e17fSsherrym 
522449e17fSsherrym static const char ucode_dev[] = "/dev/" UCODE_DRIVER_NAME;
532449e17fSsherrym 
542449e17fSsherrym static char	*cmdname;
552449e17fSsherrym 
562449e17fSsherrym static char	ucode_vendor_str[UCODE_MAX_VENDORS_NAME_LEN];
572449e17fSsherrym static char	ucode_install_path[] = UCODE_INSTALL_PATH;
582449e17fSsherrym 
592449e17fSsherrym static int	ucode_debug = 0;
602449e17fSsherrym 
61adc586deSMark Johnson static int ucode_convert_amd(const char *, uint8_t *, size_t);
62adc586deSMark Johnson static int ucode_convert_intel(const char *, uint8_t *, size_t);
63adc586deSMark Johnson 
64adc586deSMark Johnson static ucode_errno_t ucode_gen_files_amd(uint8_t *, int, char *);
65adc586deSMark Johnson static ucode_errno_t ucode_gen_files_intel(uint8_t *, int, char *);
66adc586deSMark Johnson 
67adc586deSMark Johnson static const struct ucode_ops ucode_ops[] = {
68adc586deSMark Johnson 	{ ucode_convert_intel, ucode_gen_files_intel, ucode_validate_intel },
69adc586deSMark Johnson 	{ ucode_convert_amd, ucode_gen_files_amd, ucode_validate_amd },
70adc586deSMark Johnson };
71adc586deSMark Johnson 
72adc586deSMark Johnson const struct ucode_ops *ucode;
73adc586deSMark Johnson 
742449e17fSsherrym static void
dprintf(const char * format,...)752449e17fSsherrym dprintf(const char *format, ...)
762449e17fSsherrym {
772449e17fSsherrym 	if (ucode_debug) {
782449e17fSsherrym 		va_list alist;
792449e17fSsherrym 		va_start(alist, format);
802449e17fSsherrym 		(void) vfprintf(stderr, format, alist);
812449e17fSsherrym 		va_end(alist);
822449e17fSsherrym 	}
832449e17fSsherrym }
842449e17fSsherrym 
852449e17fSsherrym static void
usage(int verbose)862449e17fSsherrym usage(int verbose)
872449e17fSsherrym {
882449e17fSsherrym 	(void) fprintf(stderr, gettext("usage:\n"));
892449e17fSsherrym 	(void) fprintf(stderr, "\t%s -v\n", cmdname);
902449e17fSsherrym 	if (verbose) {
912449e17fSsherrym 		(void) fprintf(stderr,
922449e17fSsherrym 		    gettext("\t\t Shows running microcode version.\n\n"));
932449e17fSsherrym 	}
942449e17fSsherrym 
95adc586deSMark Johnson 	(void) fprintf(stderr, "\t%s -u microcode-file\n", cmdname);
962449e17fSsherrym 	if (verbose) {
972449e17fSsherrym 		(void) fprintf(stderr, gettext("\t\t Updates microcode to the "
982449e17fSsherrym 		    "latest matching version found in\n"
99adc586deSMark Johnson 		    "\t\t microcode-file.\n\n"));
1002449e17fSsherrym 	}
1012449e17fSsherrym 
102adc586deSMark Johnson 	(void) fprintf(stderr, "\t%s -i [-R path] microcode-file\n", cmdname);
1032449e17fSsherrym 	if (verbose) {
1042449e17fSsherrym 		(void) fprintf(stderr, gettext("\t\t Installs microcode to be "
105adc586deSMark Johnson 		    "used for subsequent boots.\n\n"));
106adc586deSMark Johnson 		(void) fprintf(stderr, gettext("Microcode file name must start "
107adc586deSMark Johnson 		    "with vendor name, such as \"intel\" or \"amd\".\n\n"));
1082449e17fSsherrym 	}
1092449e17fSsherrym }
1102449e17fSsherrym 
1112449e17fSsherrym static void
ucode_perror(const char * str,ucode_errno_t rc)1122449e17fSsherrym ucode_perror(const char *str, ucode_errno_t rc)
1132449e17fSsherrym {
1142449e17fSsherrym 	(void) fprintf(stderr, "%s: %s: %s\n", cmdname, str,
1152449e17fSsherrym 	    errno == 0 ? ucode_strerror(rc) : strerror(errno));
1162449e17fSsherrym 	errno = 0;
1172449e17fSsherrym }
1182449e17fSsherrym 
1192449e17fSsherrym #define	LINESIZE	120	/* copyright line sometimes is longer than 80 */
1202449e17fSsherrym 
1212449e17fSsherrym /*
1222449e17fSsherrym  * Convert text format microcode release into binary format.
1232449e17fSsherrym  * Return the number of characters read.
1242449e17fSsherrym  */
1252449e17fSsherrym static int
ucode_convert_amd(const char * infile,uint8_t * buf,size_t size)126adc586deSMark Johnson ucode_convert_amd(const char *infile, uint8_t *buf, size_t size)
127adc586deSMark Johnson {
128adc586deSMark Johnson 	int fd;
129adc586deSMark Johnson 
130adc586deSMark Johnson 	if (infile == NULL || buf == NULL || size == 0)
131adc586deSMark Johnson 		return (0);
132adc586deSMark Johnson 
133adc586deSMark Johnson 	if ((fd = open(infile, O_RDONLY)) < 0)
134adc586deSMark Johnson 		return (0);
135adc586deSMark Johnson 
136adc586deSMark Johnson 	size = read(fd, buf, size);
137adc586deSMark Johnson 
138adc586deSMark Johnson 	(void) close(fd);
139adc586deSMark Johnson 
140adc586deSMark Johnson 	return (size);
141adc586deSMark Johnson }
142adc586deSMark Johnson 
143adc586deSMark Johnson static int
ucode_convert_intel(const char * infile,uint8_t * buf,size_t size)144adc586deSMark Johnson ucode_convert_intel(const char *infile, uint8_t *buf, size_t size)
1452449e17fSsherrym {
1462449e17fSsherrym 	char	linebuf[LINESIZE];
1472449e17fSsherrym 	FILE	*infd = NULL;
1482449e17fSsherrym 	int	count = 0, firstline = 1;
1492449e17fSsherrym 	uint32_t *intbuf = (uint32_t *)(intptr_t)buf;
1502449e17fSsherrym 
1512449e17fSsherrym 	if (infile == NULL || buf == NULL || size == 0)
1522449e17fSsherrym 		return (0);
1532449e17fSsherrym 
1542449e17fSsherrym 	if ((infd = fopen(infile, "r")) == NULL)
1552449e17fSsherrym 		return (0);
1562449e17fSsherrym 
1572449e17fSsherrym 	while (fgets(linebuf, LINESIZE, infd)) {
1582449e17fSsherrym 
1592449e17fSsherrym 		/* Check to see if we are processing a binary file */
1602449e17fSsherrym 		if (firstline && !isprint(linebuf[0])) {
1612449e17fSsherrym 			if (fseek(infd, 0, SEEK_SET) == 0)
1622449e17fSsherrym 				count = fread(buf, 1, size, infd);
1632449e17fSsherrym 
1642449e17fSsherrym 			(void) fclose(infd);
1652449e17fSsherrym 			return (count);
1662449e17fSsherrym 		}
1672449e17fSsherrym 
1682449e17fSsherrym 		firstline = 0;
1692449e17fSsherrym 
1702449e17fSsherrym 		/* Skip blank lines */
1712449e17fSsherrym 		if (strlen(linebuf) == 1)
1722449e17fSsherrym 			continue;
1732449e17fSsherrym 
1742449e17fSsherrym 		/* Skip lines with all spaces or tabs */
1752449e17fSsherrym 		if (strcspn(linebuf, " \t") == 0)
1762449e17fSsherrym 			continue;
1772449e17fSsherrym 
1782449e17fSsherrym 		/* Text file.  Skip comments. */
1792449e17fSsherrym 		if (linebuf[0] == '/')
1802449e17fSsherrym 			continue;
1812449e17fSsherrym 
1822449e17fSsherrym 		if (sscanf(linebuf, "%x, %x, %x, %x",
1832449e17fSsherrym 		    &intbuf[count], &intbuf[count+1],
1842449e17fSsherrym 		    &intbuf[count+2], &intbuf[count+3]) != 4)
1852449e17fSsherrym 			break;
1862449e17fSsherrym 
1872449e17fSsherrym 		count += 4;
1882449e17fSsherrym 	}
1892449e17fSsherrym 
1902449e17fSsherrym 	(void) fclose(infd);
1912449e17fSsherrym 
1922449e17fSsherrym 	/*
1932449e17fSsherrym 	 * If we get here, we are processing a text format file
1942449e17fSsherrym 	 * where "count" is used to count the number of integers
1952449e17fSsherrym 	 * read.  Convert it to number of characters read.
1962449e17fSsherrym 	 */
1972449e17fSsherrym 	return (count * sizeof (int));
1982449e17fSsherrym }
1992449e17fSsherrym 
2002449e17fSsherrym /*
2012449e17fSsherrym  * Returns 0 if no need to update the link; -1 otherwise
2022449e17fSsherrym  */
2032449e17fSsherrym static int
ucode_should_update_intel(char * filename,uint32_t new_rev)204adc586deSMark Johnson ucode_should_update_intel(char *filename, uint32_t new_rev)
2052449e17fSsherrym {
2062449e17fSsherrym 	int		fd;
2072449e17fSsherrym 	struct stat	statbuf;
208adc586deSMark Johnson 	ucode_header_intel_t header;
2092449e17fSsherrym 
2102449e17fSsherrym 	/*
2112449e17fSsherrym 	 * If the file or link already exists, check to see if
2122449e17fSsherrym 	 * it is necessary to update it.
2132449e17fSsherrym 	 */
2142449e17fSsherrym 	if (stat(filename, &statbuf) == 0) {
2152449e17fSsherrym 		if ((fd = open(filename, O_RDONLY)) == -1)
2162449e17fSsherrym 			return (-1);
2172449e17fSsherrym 
2182449e17fSsherrym 		if (read(fd, &header, sizeof (header)) == -1) {
2192449e17fSsherrym 			(void) close(fd);
2202449e17fSsherrym 			return (-1);
2212449e17fSsherrym 		}
2222449e17fSsherrym 
2232449e17fSsherrym 		(void) close(fd);
2242449e17fSsherrym 
2252449e17fSsherrym 		if (header.uh_rev >= new_rev)
2262449e17fSsherrym 			return (0);
2272449e17fSsherrym 	}
2282449e17fSsherrym 
2292449e17fSsherrym 	return (-1);
2302449e17fSsherrym }
2312449e17fSsherrym 
2322449e17fSsherrym /*
2332449e17fSsherrym  * Generate microcode binary files.  Must be called after ucode_validate().
2342449e17fSsherrym  */
2352449e17fSsherrym static ucode_errno_t
ucode_gen_files_amd(uint8_t * buf,int size,char * path)236adc586deSMark Johnson ucode_gen_files_amd(uint8_t *buf, int size, char *path)
237adc586deSMark Johnson {
238adc586deSMark Johnson 	/* LINTED: pointer alignment */
239adc586deSMark Johnson 	uint32_t *ptr = (uint32_t *)buf;
240*08d2fdc2SMark Johnson 	char common_path[PATH_MAX];
241adc586deSMark Johnson 	int fd, count, counter;
242adc586deSMark Johnson 	ucode_header_amd_t *uh;
243adc586deSMark Johnson 	int last_cpu_rev = 0;
244adc586deSMark Johnson 
2450ba6f73dSMark Johnson 
246*08d2fdc2SMark Johnson 	/* write container file */
247*08d2fdc2SMark Johnson 	(void) snprintf(common_path, PATH_MAX, "%s/%s", path, "container");
248*08d2fdc2SMark Johnson 
249*08d2fdc2SMark Johnson 	dprintf("path = %s\n", common_path);
250*08d2fdc2SMark Johnson 	fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC,
2510ba6f73dSMark Johnson 	    S_IRUSR | S_IRGRP | S_IROTH);
2520ba6f73dSMark Johnson 
2530ba6f73dSMark Johnson 	if (fd == -1) {
254*08d2fdc2SMark Johnson 		ucode_perror(common_path, EM_SYS);
2550ba6f73dSMark Johnson 		return (EM_SYS);
2560ba6f73dSMark Johnson 	}
2570ba6f73dSMark Johnson 
2580ba6f73dSMark Johnson 	if (write(fd, buf, size) != size) {
2590ba6f73dSMark Johnson 		(void) close(fd);
260*08d2fdc2SMark Johnson 		ucode_perror(common_path, EM_SYS);
2610ba6f73dSMark Johnson 		return (EM_SYS);
2620ba6f73dSMark Johnson 	}
2630ba6f73dSMark Johnson 
2640ba6f73dSMark Johnson 	(void) close(fd);
2650ba6f73dSMark Johnson 
266adc586deSMark Johnson 	/* skip over magic number & equivalence table header */
267adc586deSMark Johnson 	ptr += 2; size -= 8;
268adc586deSMark Johnson 
269adc586deSMark Johnson 	count = *ptr++; size -= 4;
270adc586deSMark Johnson 
271adc586deSMark Johnson 	/* equivalence table uses special name */
272*08d2fdc2SMark Johnson 	(void) snprintf(common_path, PATH_MAX, "%s/%s", path,
273*08d2fdc2SMark Johnson 	    "equivalence-table");
274adc586deSMark Johnson 
275adc586deSMark Johnson 	for (;;) {
276*08d2fdc2SMark Johnson 		dprintf("path = %s\n", common_path);
277*08d2fdc2SMark Johnson 		fd = open(common_path, O_WRONLY | O_CREAT | O_TRUNC,
278adc586deSMark Johnson 		    S_IRUSR | S_IRGRP | S_IROTH);
279adc586deSMark Johnson 
280adc586deSMark Johnson 		if (fd == -1) {
281*08d2fdc2SMark Johnson 			ucode_perror(common_path, EM_SYS);
282adc586deSMark Johnson 			return (EM_SYS);
283adc586deSMark Johnson 		}
284adc586deSMark Johnson 
285adc586deSMark Johnson 		if (write(fd, ptr, count) != count) {
286adc586deSMark Johnson 			(void) close(fd);
287*08d2fdc2SMark Johnson 			ucode_perror(common_path, EM_SYS);
288adc586deSMark Johnson 			return (EM_SYS);
289adc586deSMark Johnson 		}
290adc586deSMark Johnson 
291adc586deSMark Johnson 		(void) close(fd);
292adc586deSMark Johnson 		ptr += count >> 2; size -= count;
293adc586deSMark Johnson 
294adc586deSMark Johnson 		if (!size)
295adc586deSMark Johnson 			return (EM_OK);
296adc586deSMark Johnson 
297adc586deSMark Johnson 		ptr++; size -= 4;
298adc586deSMark Johnson 		count = *ptr++; size -= 4;
299adc586deSMark Johnson 
300adc586deSMark Johnson 		/* construct name from header information */
301adc586deSMark Johnson 		uh = (ucode_header_amd_t *)ptr;
302adc586deSMark Johnson 
303adc586deSMark Johnson 		if (uh->uh_cpu_rev != last_cpu_rev) {
304adc586deSMark Johnson 			last_cpu_rev = uh->uh_cpu_rev;
305adc586deSMark Johnson 			counter = 0;
306adc586deSMark Johnson 		}
307adc586deSMark Johnson 
308*08d2fdc2SMark Johnson 		(void) snprintf(common_path, PATH_MAX, "%s/%04X-%02X", path,
309adc586deSMark Johnson 		    uh->uh_cpu_rev, counter++);
310adc586deSMark Johnson 	}
311adc586deSMark Johnson }
312adc586deSMark Johnson 
313adc586deSMark Johnson static ucode_errno_t
ucode_gen_files_intel(uint8_t * buf,int size,char * path)314adc586deSMark Johnson ucode_gen_files_intel(uint8_t *buf, int size, char *path)
3152449e17fSsherrym {
3162449e17fSsherrym 	int	remaining;
3172449e17fSsherrym 	char	common_path[PATH_MAX];
3182449e17fSsherrym 	DIR	*dirp;
3192449e17fSsherrym 	struct dirent *dp;
3202449e17fSsherrym 
3212449e17fSsherrym 	(void) snprintf(common_path, PATH_MAX, "%s/%s", path,
3222449e17fSsherrym 	    UCODE_INSTALL_COMMON_PATH);
3232449e17fSsherrym 
3242449e17fSsherrym 	if (mkdirp(common_path, 0755) == -1 && errno != EEXIST) {
3252449e17fSsherrym 		ucode_perror(common_path, EM_SYS);
3262449e17fSsherrym 		return (EM_SYS);
3272449e17fSsherrym 	}
3282449e17fSsherrym 
3292449e17fSsherrym 	for (remaining = size; remaining > 0; ) {
3302449e17fSsherrym 		uint32_t	total_size, body_size, offset;
3312449e17fSsherrym 		char		firstname[PATH_MAX];
3322449e17fSsherrym 		char		name[PATH_MAX];
3332449e17fSsherrym 		int		i;
3342449e17fSsherrym 		uint8_t		*curbuf = &buf[size - remaining];
335adc586deSMark Johnson 		ucode_header_intel_t	*uhp;
336adc586deSMark Johnson 		ucode_ext_table_intel_t *extp;
3372449e17fSsherrym 
338adc586deSMark Johnson 		uhp = (ucode_header_intel_t *)(intptr_t)curbuf;
339adc586deSMark Johnson 
340adc586deSMark Johnson 		total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
341adc586deSMark Johnson 		body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
3422449e17fSsherrym 
3432449e17fSsherrym 		remaining -= total_size;
3442449e17fSsherrym 
3452449e17fSsherrym 		(void) snprintf(firstname, PATH_MAX, "%s/%08X-%02X",
3462449e17fSsherrym 		    common_path, uhp->uh_signature, uhp->uh_proc_flags);
3472449e17fSsherrym 		dprintf("firstname = %s\n", firstname);
3482449e17fSsherrym 
349adc586deSMark Johnson 		if (ucode_should_update_intel(firstname, uhp->uh_rev) != 0) {
3502449e17fSsherrym 			int fd;
3512449e17fSsherrym 
3522449e17fSsherrym 			/* Remove the existing one first */
3532449e17fSsherrym 			(void) unlink(firstname);
3542449e17fSsherrym 
3552449e17fSsherrym 			if ((fd = open(firstname, O_WRONLY | O_CREAT | O_TRUNC,
3562449e17fSsherrym 			    S_IRUSR | S_IRGRP | S_IROTH)) == -1) {
3572449e17fSsherrym 				ucode_perror(firstname, EM_SYS);
3582449e17fSsherrym 				return (EM_SYS);
3592449e17fSsherrym 			}
3602449e17fSsherrym 
3612449e17fSsherrym 			if (write(fd, curbuf, total_size) != total_size) {
3622449e17fSsherrym 				(void) close(fd);
3632449e17fSsherrym 				ucode_perror(firstname, EM_SYS);
3642449e17fSsherrym 				return (EM_SYS);
3652449e17fSsherrym 			}
3662449e17fSsherrym 
3672449e17fSsherrym 			(void) close(fd);
3682449e17fSsherrym 		}
3692449e17fSsherrym 
3702449e17fSsherrym 		/*
3712449e17fSsherrym 		 * Only 1 byte of the proc_flags field is used, therefore
3722449e17fSsherrym 		 * we only need to match 8 potential platform ids.
3732449e17fSsherrym 		 */
3742449e17fSsherrym 		for (i = 0; i < 8; i++) {
3752449e17fSsherrym 			uint32_t platid = uhp->uh_proc_flags & (1 << i);
3762449e17fSsherrym 
3772449e17fSsherrym 			if (platid == 0 && uhp->uh_proc_flags != 0)
3782449e17fSsherrym 				continue;
3792449e17fSsherrym 
3802449e17fSsherrym 			(void) snprintf(name, PATH_MAX,
3812449e17fSsherrym 			    "%s/%08X-%02X", path, uhp->uh_signature, platid);
3822449e17fSsherrym 
3832449e17fSsherrym 			dprintf("proc_flags = %x, platid = %x, name = %s\n",
3842449e17fSsherrym 			    uhp->uh_proc_flags, platid, name);
3852449e17fSsherrym 
386adc586deSMark Johnson 			if (ucode_should_update_intel(name, uhp->uh_rev) != 0) {
3872449e17fSsherrym 
3882449e17fSsherrym 				/* Remove the existing one first */
3892449e17fSsherrym 				(void) unlink(name);
3902449e17fSsherrym 
3912449e17fSsherrym 				if (link(firstname, name) == -1) {
3922449e17fSsherrym 					ucode_perror(name, EM_SYS);
3932449e17fSsherrym 					return (EM_SYS);
3942449e17fSsherrym 				}
3952449e17fSsherrym 			}
3962449e17fSsherrym 
3972449e17fSsherrym 			if (uhp->uh_proc_flags == 0)
3982449e17fSsherrym 				break;
3992449e17fSsherrym 		}
4002449e17fSsherrym 
401adc586deSMark Johnson 		offset = UCODE_HEADER_SIZE_INTEL + body_size;
4022449e17fSsherrym 
4032449e17fSsherrym 		/* Check to see if there is extended signature table */
4042449e17fSsherrym 		if (total_size == offset)
4052449e17fSsherrym 			continue;
4062449e17fSsherrym 
4072449e17fSsherrym 		/* There is extended signature table.  More processing. */
408adc586deSMark Johnson 		extp = (ucode_ext_table_intel_t *)(uintptr_t)&curbuf[offset];
4092449e17fSsherrym 
4102449e17fSsherrym 		for (i = 0; i < extp->uet_count; i++) {
411adc586deSMark Johnson 			ucode_ext_sig_intel_t *uesp = &extp->uet_ext_sig[i];
4122449e17fSsherrym 			int j;
4132449e17fSsherrym 
4142449e17fSsherrym 			for (j = 0; j < 8; j++) {
4152449e17fSsherrym 				uint32_t id = uesp->ues_proc_flags & (1 << j);
4162449e17fSsherrym 
4172449e17fSsherrym 				if (id == 0 && uesp->ues_proc_flags)
4182449e17fSsherrym 					continue;
4192449e17fSsherrym 
4202449e17fSsherrym 				(void) snprintf(name, PATH_MAX,
4212449e17fSsherrym 				    "%s/%08X-%02X", path, extp->uet_ext_sig[i],
4222449e17fSsherrym 				    id);
4232449e17fSsherrym 
424adc586deSMark Johnson 				if (ucode_should_update_intel(name, uhp->uh_rev)
425adc586deSMark Johnson 				    != 0) {
4262449e17fSsherrym 
4272449e17fSsherrym 					/* Remove the existing one first */
4282449e17fSsherrym 					(void) unlink(name);
4292449e17fSsherrym 					if (link(firstname, name) == -1) {
4302449e17fSsherrym 						ucode_perror(name, EM_SYS);
4312449e17fSsherrym 						return (EM_SYS);
4322449e17fSsherrym 					}
4332449e17fSsherrym 				}
4342449e17fSsherrym 
4352449e17fSsherrym 				if (uesp->ues_proc_flags == 0)
4362449e17fSsherrym 					break;
4372449e17fSsherrym 			}
4382449e17fSsherrym 		}
4392449e17fSsherrym 
4402449e17fSsherrym 	}
4412449e17fSsherrym 
4422449e17fSsherrym 	/*
4432449e17fSsherrym 	 * Remove files with no links to them.  These are probably
4442449e17fSsherrym 	 * obsolete microcode files.
4452449e17fSsherrym 	 */
4462449e17fSsherrym 	if ((dirp = opendir(common_path)) == NULL) {
4472449e17fSsherrym 		ucode_perror(common_path, EM_SYS);
4482449e17fSsherrym 		return (EM_SYS);
4492449e17fSsherrym 	}
4502449e17fSsherrym 
4512449e17fSsherrym 	while ((dp = readdir(dirp)) != NULL) {
4522449e17fSsherrym 		char filename[PATH_MAX];
4532449e17fSsherrym 		struct stat statbuf;
4542449e17fSsherrym 
4552449e17fSsherrym 		(void) snprintf(filename, PATH_MAX,
4562449e17fSsherrym 		    "%s/%s", common_path, dp->d_name);
4572449e17fSsherrym 		if (stat(filename, &statbuf) == -1)
4582449e17fSsherrym 			continue;
4592449e17fSsherrym 
4602449e17fSsherrym 		if ((statbuf.st_mode & S_IFMT) == S_IFREG) {
4612449e17fSsherrym 			if (statbuf.st_nlink == 1)
4622449e17fSsherrym 				(void) unlink(filename);
4632449e17fSsherrym 		}
4642449e17fSsherrym 	}
4652449e17fSsherrym 
4662449e17fSsherrym 	(void) closedir(dirp);
4672449e17fSsherrym 
4682449e17fSsherrym 	return (EM_OK);
4692449e17fSsherrym }
4702449e17fSsherrym 
4712449e17fSsherrym /*
4722449e17fSsherrym  * Returns 0 on success, 2 on usage error, and 3 on operation error.
4732449e17fSsherrym  */
4742449e17fSsherrym int
main(int argc,char * argv[])4752449e17fSsherrym main(int argc, char *argv[])
4762449e17fSsherrym {
4772449e17fSsherrym 	int	c;
4782449e17fSsherrym 	int	action = 0;
4792449e17fSsherrym 	int	actcount = 0;
4802449e17fSsherrym 	char	*path = NULL;
4812449e17fSsherrym 	char	*filename = NULL;
4822449e17fSsherrym 	int	errflg = 0;
4832449e17fSsherrym 	int	dev_fd = -1;
4842449e17fSsherrym 	int	fd = -1;
4852449e17fSsherrym 	int	verbose = 0;
4862449e17fSsherrym 	uint8_t	*buf = NULL;
4872449e17fSsherrym 	ucode_errno_t	rc = EM_OK;
4882449e17fSsherrym 	processorid_t	cpuid_max;
4892449e17fSsherrym 	struct stat filestat;
4902449e17fSsherrym 	uint32_t ucode_size;
4912449e17fSsherrym 
4922449e17fSsherrym 	(void) setlocale(LC_ALL, "");
4932449e17fSsherrym 
4942449e17fSsherrym #if !defined(TEXT_DOMAIN)
4952449e17fSsherrym #define	TEXT_DOMAIN "SYS_TEST"
4962449e17fSsherrym #endif
4972449e17fSsherrym 	(void) textdomain(TEXT_DOMAIN);
4982449e17fSsherrym 
4992449e17fSsherrym 	cmdname = basename(argv[0]);
5002449e17fSsherrym 
5012449e17fSsherrym 	while ((c = getopt(argc, argv, "idhuvVR:")) != EOF) {
5022449e17fSsherrym 		switch (c) {
5032449e17fSsherrym 
5042449e17fSsherrym 		case 'i':
5052449e17fSsherrym 			action |= UCODE_OPT_INSTALL;
5062449e17fSsherrym 			actcount++;
5072449e17fSsherrym 			break;
5082449e17fSsherrym 
5092449e17fSsherrym 		case 'u':
5102449e17fSsherrym 			action |= UCODE_OPT_UPDATE;
5112449e17fSsherrym 			actcount++;
5122449e17fSsherrym 			break;
5132449e17fSsherrym 
5142449e17fSsherrym 		case 'v':
5152449e17fSsherrym 			action |= UCODE_OPT_VERSION;
5162449e17fSsherrym 			actcount++;
5172449e17fSsherrym 			break;
5182449e17fSsherrym 
5192449e17fSsherrym 		case 'd':
5202449e17fSsherrym 			ucode_debug = 1;
5212449e17fSsherrym 			break;
5222449e17fSsherrym 
5232449e17fSsherrym 		case 'R':
5242449e17fSsherrym 			if (optarg[0] == '-')
5252449e17fSsherrym 				errflg++;
5262449e17fSsherrym 			else if (strlen(optarg) > UCODE_MAX_PATH_LEN) {
5272449e17fSsherrym 				(void) fprintf(stderr,
5282449e17fSsherrym 				    gettext("Alternate path too long\n"));
5292449e17fSsherrym 				errflg++;
5302449e17fSsherrym 			} else if ((path = strdup(optarg)) == NULL) {
5312449e17fSsherrym 				errflg++;
5322449e17fSsherrym 			}
5332449e17fSsherrym 
5342449e17fSsherrym 			break;
5352449e17fSsherrym 
5362449e17fSsherrym 		case 'V':
5372449e17fSsherrym 			verbose = 1;
5382449e17fSsherrym 			break;
5392449e17fSsherrym 
5402449e17fSsherrym 		case 'h':
5412449e17fSsherrym 			usage(1);
5422449e17fSsherrym 			return (0);
5432449e17fSsherrym 
5442449e17fSsherrym 		default:
5452449e17fSsherrym 			usage(verbose);
5462449e17fSsherrym 			return (2);
5472449e17fSsherrym 		}
5482449e17fSsherrym 	}
5492449e17fSsherrym 
5502449e17fSsherrym 	if (actcount != 1) {
5512449e17fSsherrym 		(void) fprintf(stderr, gettext("%s: options -v, -i and -u "
5522449e17fSsherrym 		    "are mutually exclusive.\n"), cmdname);
5532449e17fSsherrym 		usage(verbose);
5542449e17fSsherrym 		return (2);
5552449e17fSsherrym 	}
5562449e17fSsherrym 
5572449e17fSsherrym 	if (optind <= argc - 1)
5582449e17fSsherrym 		filename = argv[optind];
5592449e17fSsherrym 	else if (!(action & UCODE_OPT_VERSION))
5602449e17fSsherrym 		errflg++;
5612449e17fSsherrym 
5622449e17fSsherrym 	if (errflg || action == 0) {
5632449e17fSsherrym 		usage(verbose);
5642449e17fSsherrym 		return (2);
5652449e17fSsherrym 	}
5662449e17fSsherrym 
5672449e17fSsherrym 	/*
5682449e17fSsherrym 	 * Convert from text format to binary format
5692449e17fSsherrym 	 */
5702449e17fSsherrym 	if ((action & UCODE_OPT_INSTALL) || (action & UCODE_OPT_UPDATE)) {
571adc586deSMark Johnson 		int i;
572adc586deSMark Johnson 		UCODE_VENDORS;
573adc586deSMark Johnson 
574adc586deSMark Johnson 		for (i = 0; ucode_vendors[i].filestr != NULL; i++) {
575adc586deSMark Johnson 			dprintf("i = %d, filestr = %s, filename = %s\n",
576adc586deSMark Johnson 			    i, ucode_vendors[i].filestr, filename);
577adc586deSMark Johnson 			if (strncasecmp(ucode_vendors[i].filestr,
578adc586deSMark Johnson 			    basename(filename),
579adc586deSMark Johnson 			    strlen(ucode_vendors[i].filestr)) == 0) {
580adc586deSMark Johnson 				ucode = &ucode_ops[i];
581adc586deSMark Johnson 				(void) strncpy(ucode_vendor_str,
582adc586deSMark Johnson 				    ucode_vendors[i].vendorstr,
583adc586deSMark Johnson 				    sizeof (ucode_vendor_str));
584adc586deSMark Johnson 				break;
585adc586deSMark Johnson 			}
586adc586deSMark Johnson 		}
587adc586deSMark Johnson 
588adc586deSMark Johnson 		if (ucode_vendors[i].filestr == NULL) {
589adc586deSMark Johnson 			rc = EM_NOVENDOR;
590adc586deSMark Johnson 			ucode_perror(basename(filename), rc);
591adc586deSMark Johnson 			goto err_out;
592adc586deSMark Johnson 		}
593adc586deSMark Johnson 
5942449e17fSsherrym 		if ((stat(filename, &filestat)) < 0) {
5952449e17fSsherrym 			rc = EM_SYS;
5962449e17fSsherrym 			ucode_perror(filename, rc);
5972449e17fSsherrym 			goto err_out;
5982449e17fSsherrym 		}
5992449e17fSsherrym 
6002449e17fSsherrym 		if ((filestat.st_mode & S_IFMT) != S_IFREG &&
6012449e17fSsherrym 		    (filestat.st_mode & S_IFMT) != S_IFLNK) {
6022449e17fSsherrym 			rc = EM_FILEFORMAT;
6032449e17fSsherrym 			ucode_perror(filename, rc);
6042449e17fSsherrym 			goto err_out;
6052449e17fSsherrym 		}
6062449e17fSsherrym 
6072449e17fSsherrym 		if ((buf = malloc(filestat.st_size)) == NULL) {
6082449e17fSsherrym 			rc = EM_SYS;
6092449e17fSsherrym 			ucode_perror(filename, rc);
6102449e17fSsherrym 			goto err_out;
6112449e17fSsherrym 		}
6122449e17fSsherrym 
613adc586deSMark Johnson 		ucode_size = ucode->convert(filename, buf, filestat.st_size);
6142449e17fSsherrym 
6152449e17fSsherrym 		dprintf("ucode_size = %d\n", ucode_size);
6162449e17fSsherrym 
6172449e17fSsherrym 		if (ucode_size == 0) {
6182449e17fSsherrym 			rc = EM_FILEFORMAT;
6192449e17fSsherrym 			ucode_perror(filename, rc);
6202449e17fSsherrym 			goto err_out;
6212449e17fSsherrym 		}
6222449e17fSsherrym 
623adc586deSMark Johnson 		if ((rc = ucode->validate(buf, ucode_size)) != EM_OK) {
6242449e17fSsherrym 			ucode_perror(filename, rc);
6252449e17fSsherrym 			goto err_out;
6262449e17fSsherrym 		}
6272449e17fSsherrym 	}
6282449e17fSsherrym 
6292449e17fSsherrym 	/*
6302449e17fSsherrym 	 * For the install option, the microcode file must start with
6312449e17fSsherrym 	 * "intel" for Intel microcode, and "amd" for AMD microcode.
6322449e17fSsherrym 	 */
6332449e17fSsherrym 	if (action & UCODE_OPT_INSTALL) {
6342449e17fSsherrym 		/*
6352449e17fSsherrym 		 * If no path is provided by the -R option, put the files in
6362449e17fSsherrym 		 * /ucode_install_path/ucode_vendor_str/.
6372449e17fSsherrym 		 */
6382449e17fSsherrym 		if (path == NULL) {
6392449e17fSsherrym 			if ((path = malloc(PATH_MAX)) == NULL) {
6402449e17fSsherrym 				rc = EM_SYS;
6412449e17fSsherrym 				ucode_perror("malloc", rc);
6422449e17fSsherrym 				goto err_out;
6432449e17fSsherrym 			}
6442449e17fSsherrym 
6452449e17fSsherrym 			(void) snprintf(path, PATH_MAX, "/%s/%s",
6462449e17fSsherrym 			    ucode_install_path, ucode_vendor_str);
6472449e17fSsherrym 		}
6482449e17fSsherrym 
6492449e17fSsherrym 		if (mkdirp(path, 0755) == -1 && errno != EEXIST) {
6502449e17fSsherrym 			rc = EM_SYS;
6512449e17fSsherrym 			ucode_perror(path, rc);
6522449e17fSsherrym 			goto err_out;
6532449e17fSsherrym 		}
6542449e17fSsherrym 
655adc586deSMark Johnson 		rc = ucode->gen_files(buf, ucode_size, path);
6562449e17fSsherrym 
6572449e17fSsherrym 		goto err_out;
6582449e17fSsherrym 	}
6592449e17fSsherrym 
6602449e17fSsherrym 	if ((dev_fd = open(ucode_dev, O_RDONLY)) == -1) {
6612449e17fSsherrym 		rc = EM_SYS;
6622449e17fSsherrym 		ucode_perror(ucode_dev, rc);
6632449e17fSsherrym 		goto err_out;
6642449e17fSsherrym 	}
6652449e17fSsherrym 
6662449e17fSsherrym 	if (action & UCODE_OPT_VERSION) {
6672449e17fSsherrym 		int tmprc;
6682449e17fSsherrym 		uint32_t *revp = NULL;
6692449e17fSsherrym 		int i;
6702449e17fSsherrym #if defined(_SYSCALL32_IMPL)
6712449e17fSsherrym 	struct ucode_get_rev_struct32 inf32;
6722449e17fSsherrym #else
6732449e17fSsherrym 	struct ucode_get_rev_struct info;
6742449e17fSsherrym #endif
6752449e17fSsherrym 
6762449e17fSsherrym 		cpuid_max = (processorid_t)sysconf(_SC_CPUID_MAX);
6772449e17fSsherrym 
6782449e17fSsherrym 		if ((revp = (uint32_t *)
6792449e17fSsherrym 		    malloc(cpuid_max * sizeof (uint32_t))) == NULL) {
6802449e17fSsherrym 			rc = EM_SYS;
6812449e17fSsherrym 			ucode_perror("malloc", rc);
6822449e17fSsherrym 			goto err_out;
6832449e17fSsherrym 		}
6842449e17fSsherrym 
6852449e17fSsherrym 		for (i = 0; i < cpuid_max; i++)
6862449e17fSsherrym 			revp[i] = (uint32_t)-1;
6872449e17fSsherrym 
6882449e17fSsherrym #if defined(_SYSCALL32_IMPL)
6892449e17fSsherrym 		info32.ugv_rev = (caddr32_t)revp;
6902449e17fSsherrym 		info32.ugv_size = cpuid_max;
6912449e17fSsherrym 		info32.ugv_errno = EM_OK;
6922449e17fSsherrym 		tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info32);
6932449e17fSsherrym 		rc = info32.ugv_errno;
6942449e17fSsherrym #else
6952449e17fSsherrym 		info.ugv_rev = revp;
6962449e17fSsherrym 		info.ugv_size = cpuid_max;
6972449e17fSsherrym 		info.ugv_errno = EM_OK;
6982449e17fSsherrym 		tmprc = ioctl(dev_fd, UCODE_GET_VERSION, &info);
6992449e17fSsherrym 		rc = info.ugv_errno;
7002449e17fSsherrym #endif
7012449e17fSsherrym 
7022449e17fSsherrym 		if (tmprc && rc == EM_OK) {
7032449e17fSsherrym 			rc = EM_SYS;
7042449e17fSsherrym 		}
7052449e17fSsherrym 
7062449e17fSsherrym 		if (rc == EM_OK) {
7072449e17fSsherrym 			(void) printf(gettext("CPU\tMicrocode Version\n"));
7082449e17fSsherrym 			for (i = 0; i < cpuid_max; i++) {
7092449e17fSsherrym 				if (info.ugv_rev[i] == (uint32_t)-1)
7102449e17fSsherrym 					continue;
7112449e17fSsherrym 				(void) printf("%d\t0x%x\n", i, info.ugv_rev[i]);
7122449e17fSsherrym 			}
7132449e17fSsherrym 		} else {
7142449e17fSsherrym 			ucode_perror(gettext("get microcode version"), rc);
7152449e17fSsherrym 		}
7162449e17fSsherrym 
7172449e17fSsherrym 		if (revp)
7182449e17fSsherrym 			free(revp);
7192449e17fSsherrym 	}
7202449e17fSsherrym 
7212449e17fSsherrym 	if (action & UCODE_OPT_UPDATE) {
7222449e17fSsherrym 		int tmprc;
7232449e17fSsherrym #if defined(_SYSCALL32_IMPL)
7242449e17fSsherrym 	struct ucode_write_struct32 uw_struct32;
7252449e17fSsherrym #else
7262449e17fSsherrym 	struct ucode_write_struct uw_struct;
7272449e17fSsherrym #endif
7282449e17fSsherrym 
7292449e17fSsherrym #if defined(_SYSCALL32_IMPL)
7302449e17fSsherrym 		uw_struct32.uw_size = ucode_size;
7312449e17fSsherrym 		uw_struct32.uw_ucode = (caddr32_t)buf;
7322449e17fSsherrym 		uw_struct32.uw_errno = EM_OK;
7332449e17fSsherrym 		tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct32);
7342449e17fSsherrym 		rc = uw_struct32.uw_errno;
7352449e17fSsherrym 
7362449e17fSsherrym #else
7372449e17fSsherrym 		uw_struct.uw_size = ucode_size;
7382449e17fSsherrym 		uw_struct.uw_ucode = buf;
7392449e17fSsherrym 		uw_struct.uw_errno = EM_OK;
7402449e17fSsherrym 		tmprc = ioctl(dev_fd, UCODE_UPDATE, &uw_struct);
7412449e17fSsherrym 		rc = uw_struct.uw_errno;
7422449e17fSsherrym #endif
7432449e17fSsherrym 
7442449e17fSsherrym 		if (rc == EM_OK) {
7452449e17fSsherrym 			if (tmprc) {
7462449e17fSsherrym 				rc = EM_SYS;
7472449e17fSsherrym 				ucode_perror(ucode_dev, rc);
7482449e17fSsherrym 			}
7492449e17fSsherrym 		} else if (rc == EM_NOMATCH || rc == EM_HIGHERREV) {
7502449e17fSsherrym 			ucode_perror(filename, rc);
7512449e17fSsherrym 		} else {
7522449e17fSsherrym 			ucode_perror(gettext("microcode update"), rc);
7532449e17fSsherrym 		}
7542449e17fSsherrym 	}
7552449e17fSsherrym 
7562449e17fSsherrym err_out:
7572449e17fSsherrym 	if (dev_fd != -1)
7582449e17fSsherrym 		(void) close(dev_fd);
7592449e17fSsherrym 
7602449e17fSsherrym 	if (fd != -1)
7612449e17fSsherrym 		(void) close(fd);
7622449e17fSsherrym 
7632449e17fSsherrym 	free(buf);
7642449e17fSsherrym 	free(path);
7652449e17fSsherrym 
7662449e17fSsherrym 	if (rc != EM_OK)
7672449e17fSsherrym 		return (3);
7682449e17fSsherrym 
7692449e17fSsherrym 	return (0);
7702449e17fSsherrym }
771