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