xref: /freebsd/usr.sbin/cpucontrol/cpucontrol.c (revision 96ff3b75d4f8574bb210c6035cd9f6f08ef81ea7)
1e085f869SStanislav Sedov /*-
2f264409aSStanislav Sedov  * Copyright (c) 2008-2011 Stanislav Sedov <stas@FreeBSD.org>.
3e085f869SStanislav Sedov  * All rights reserved.
4e085f869SStanislav Sedov  *
5e085f869SStanislav Sedov  * Redistribution and use in source and binary forms, with or without
6e085f869SStanislav Sedov  * modification, are permitted provided that the following conditions
7e085f869SStanislav Sedov  * are met:
8e085f869SStanislav Sedov  * 1. Redistributions of source code must retain the above copyright
9e085f869SStanislav Sedov  *    notice, this list of conditions and the following disclaimer.
10e085f869SStanislav Sedov  * 2. Redistributions in binary form must reproduce the above copyright
11e085f869SStanislav Sedov  *    notice, this list of conditions and the following disclaimer in the
12e085f869SStanislav Sedov  *    documentation and/or other materials provided with the distribution.
13e085f869SStanislav Sedov  *
14e085f869SStanislav Sedov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15e085f869SStanislav Sedov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16e085f869SStanislav Sedov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17e085f869SStanislav Sedov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18e085f869SStanislav Sedov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19e085f869SStanislav Sedov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20e085f869SStanislav Sedov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21e085f869SStanislav Sedov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22e085f869SStanislav Sedov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23e085f869SStanislav Sedov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24e085f869SStanislav Sedov  */
25e085f869SStanislav Sedov 
26e085f869SStanislav Sedov /*
27e085f869SStanislav Sedov  * This utility provides userland access to the cpuctl(4) pseudo-device
28e085f869SStanislav Sedov  * features.
29e085f869SStanislav Sedov  */
30e085f869SStanislav Sedov 
31e085f869SStanislav Sedov #include <sys/cdefs.h>
32e085f869SStanislav Sedov __FBSDID("$FreeBSD$");
33e085f869SStanislav Sedov 
34e085f869SStanislav Sedov #include <assert.h>
35e085f869SStanislav Sedov #include <stdio.h>
36e085f869SStanislav Sedov #include <stdlib.h>
37e085f869SStanislav Sedov #include <string.h>
38e085f869SStanislav Sedov #include <unistd.h>
39e085f869SStanislav Sedov #include <fcntl.h>
40e085f869SStanislav Sedov #include <err.h>
41e085f869SStanislav Sedov #include <sysexits.h>
42e085f869SStanislav Sedov #include <dirent.h>
43e085f869SStanislav Sedov 
44e085f869SStanislav Sedov #include <sys/queue.h>
45e085f869SStanislav Sedov #include <sys/param.h>
46e085f869SStanislav Sedov #include <sys/types.h>
47e085f869SStanislav Sedov #include <sys/stat.h>
48e085f869SStanislav Sedov #include <sys/ioctl.h>
49e085f869SStanislav Sedov #include <sys/cpuctl.h>
50e085f869SStanislav Sedov 
51e085f869SStanislav Sedov #include "cpucontrol.h"
52e085f869SStanislav Sedov #include "amd.h"
53e085f869SStanislav Sedov #include "intel.h"
54*96ff3b75SFabien Thomas #include "via.h"
55e085f869SStanislav Sedov 
56e085f869SStanislav Sedov int	verbosity_level = 0;
57e085f869SStanislav Sedov 
58e085f869SStanislav Sedov #define	DEFAULT_DATADIR	"/usr/local/share/cpucontrol"
59e085f869SStanislav Sedov 
60e085f869SStanislav Sedov #define	FLAG_I	0x01
61e085f869SStanislav Sedov #define	FLAG_M	0x02
62e085f869SStanislav Sedov #define	FLAG_U	0x04
63e085f869SStanislav Sedov 
64b2d75854SStanislav Sedov #define	OP_INVAL	0x00
65b2d75854SStanislav Sedov #define	OP_READ		0x01
66b2d75854SStanislav Sedov #define	OP_WRITE	0x02
67b2d75854SStanislav Sedov #define	OP_OR		0x04
68b2d75854SStanislav Sedov #define	OP_AND		0x08
69b2d75854SStanislav Sedov 
70e085f869SStanislav Sedov #define	HIGH(val)	(uint32_t)(((val) >> 32) & 0xffffffff)
71e085f869SStanislav Sedov #define	LOW(val)	(uint32_t)((val) & 0xffffffff)
72e085f869SStanislav Sedov 
73e085f869SStanislav Sedov /*
74e085f869SStanislav Sedov  * Macros for freeing SLISTs, probably must be in /sys/queue.h
75e085f869SStanislav Sedov  */
76e085f869SStanislav Sedov #define	SLIST_FREE(head, field, freef) do {				\
77e085f869SStanislav Sedov 		typeof(SLIST_FIRST(head)) __elm0;			\
78e085f869SStanislav Sedov 		typeof(SLIST_FIRST(head)) __elm;			\
79e085f869SStanislav Sedov 		SLIST_FOREACH_SAFE(__elm, (head), field, __elm0)	\
80e085f869SStanislav Sedov 			(void)(freef)(__elm);				\
81e085f869SStanislav Sedov } while(0);
82e085f869SStanislav Sedov 
83e085f869SStanislav Sedov struct datadir {
84e085f869SStanislav Sedov 	const char		*path;
85e085f869SStanislav Sedov 	SLIST_ENTRY(datadir)	next;
86e085f869SStanislav Sedov };
8713e403fdSAntoine Brodin static SLIST_HEAD(, datadir) datadirs = SLIST_HEAD_INITIALIZER(datadirs);
88e085f869SStanislav Sedov 
89e085f869SStanislav Sedov struct ucode_handler {
90e085f869SStanislav Sedov 	ucode_probe_t *probe;
91e085f869SStanislav Sedov 	ucode_update_t *update;
92e085f869SStanislav Sedov } handlers[] = {
93e085f869SStanislav Sedov 	{ intel_probe, intel_update },
94e085f869SStanislav Sedov 	{ amd_probe, amd_update },
95*96ff3b75SFabien Thomas 	{ via_probe, via_update },
96e085f869SStanislav Sedov };
97e085f869SStanislav Sedov #define NHANDLERS (sizeof(handlers) / sizeof(*handlers))
98e085f869SStanislav Sedov 
99e085f869SStanislav Sedov static void	usage(void);
100e085f869SStanislav Sedov static int	isdir(const char *path);
101e085f869SStanislav Sedov static int	do_cpuid(const char *cmdarg, const char *dev);
102e085f869SStanislav Sedov static int	do_msr(const char *cmdarg, const char *dev);
103e085f869SStanislav Sedov static int	do_update(const char *dev);
104e085f869SStanislav Sedov static void	datadir_add(const char *path);
105e085f869SStanislav Sedov 
106e085f869SStanislav Sedov static void __dead2
10710bc3a7fSEd Schouten usage(void)
108e085f869SStanislav Sedov {
109e085f869SStanislav Sedov 	const char *name;
110e085f869SStanislav Sedov 
111e085f869SStanislav Sedov 	name = getprogname();
112e085f869SStanislav Sedov 	if (name == NULL)
113e085f869SStanislav Sedov 		name = "cpuctl";
114e085f869SStanislav Sedov 	fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | "
115e085f869SStanislav Sedov 	    "-i level | -u] device\n", name);
116e085f869SStanislav Sedov 	exit(EX_USAGE);
117e085f869SStanislav Sedov }
118e085f869SStanislav Sedov 
119e085f869SStanislav Sedov static int
120e085f869SStanislav Sedov isdir(const char *path)
121e085f869SStanislav Sedov {
122e085f869SStanislav Sedov 	int error;
123e085f869SStanislav Sedov 	struct stat st;
124e085f869SStanislav Sedov 
125e085f869SStanislav Sedov 	error = stat(path, &st);
126e085f869SStanislav Sedov 	if (error < 0) {
127e085f869SStanislav Sedov 		WARN(0, "stat(%s)", path);
128e085f869SStanislav Sedov 		return (error);
129e085f869SStanislav Sedov 	}
130e085f869SStanislav Sedov 	return (st.st_mode & S_IFDIR);
131e085f869SStanislav Sedov }
132e085f869SStanislav Sedov 
133e085f869SStanislav Sedov static int
134e085f869SStanislav Sedov do_cpuid(const char *cmdarg, const char *dev)
135e085f869SStanislav Sedov {
136e085f869SStanislav Sedov 	unsigned int level;
137e085f869SStanislav Sedov 	cpuctl_cpuid_args_t args;
138e085f869SStanislav Sedov 	int fd, error;
139e085f869SStanislav Sedov 	char *endptr;
140e085f869SStanislav Sedov 
141e085f869SStanislav Sedov 	assert(cmdarg != NULL);
142e085f869SStanislav Sedov 	assert(dev != NULL);
143e085f869SStanislav Sedov 
144e085f869SStanislav Sedov 	level = strtoul(cmdarg, &endptr, 16);
145e085f869SStanislav Sedov 	if (*cmdarg == '\0' || *endptr != '\0') {
146e085f869SStanislav Sedov 		WARNX(0, "incorrect operand: %s", cmdarg);
147e085f869SStanislav Sedov 		usage();
148e085f869SStanislav Sedov 		/* NOTREACHED */
149e085f869SStanislav Sedov 	}
150e085f869SStanislav Sedov 
151e085f869SStanislav Sedov 	/*
152e085f869SStanislav Sedov 	 * Fill ioctl argument structure.
153e085f869SStanislav Sedov 	 */
154e085f869SStanislav Sedov 	args.level = level;
155e085f869SStanislav Sedov 	fd = open(dev, O_RDONLY);
156e085f869SStanislav Sedov 	if (fd < 0) {
157cbcc5579SStanislav Sedov 		WARN(0, "error opening %s for reading", dev);
158e085f869SStanislav Sedov 		return (1);
159e085f869SStanislav Sedov 	}
160e085f869SStanislav Sedov 	error = ioctl(fd, CPUCTL_CPUID, &args);
161e085f869SStanislav Sedov 	if (error < 0) {
162cbcc5579SStanislav Sedov 		WARN(0, "ioctl(%s, CPUCTL_CPUID)", dev);
163e085f869SStanislav Sedov 		close(fd);
164e085f869SStanislav Sedov 		return (error);
165e085f869SStanislav Sedov 	}
166e085f869SStanislav Sedov 	fprintf(stdout, "cpuid level 0x%x: 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
167e085f869SStanislav Sedov 	    level, args.data[0], args.data[1], args.data[2], args.data[3]);
168e085f869SStanislav Sedov 	close(fd);
169e085f869SStanislav Sedov 	return (0);
170e085f869SStanislav Sedov }
171e085f869SStanislav Sedov 
172e085f869SStanislav Sedov static int
173e085f869SStanislav Sedov do_msr(const char *cmdarg, const char *dev)
174e085f869SStanislav Sedov {
175e085f869SStanislav Sedov 	unsigned int msr;
176e085f869SStanislav Sedov 	cpuctl_msr_args_t args;
177b2d75854SStanislav Sedov 	size_t len;
178b2d75854SStanislav Sedov 	uint64_t data = 0;
179b2d75854SStanislav Sedov 	unsigned long command;
180b2d75854SStanislav Sedov 	int do_invert = 0, op;
181e085f869SStanislav Sedov 	int fd, error;
182f264409aSStanislav Sedov 	const char *command_name;
183e085f869SStanislav Sedov 	char *endptr;
184b2d75854SStanislav Sedov 	char *p;
185e085f869SStanislav Sedov 
186e085f869SStanislav Sedov 	assert(cmdarg != NULL);
187e085f869SStanislav Sedov 	assert(dev != NULL);
188b2d75854SStanislav Sedov 	len = strlen(cmdarg);
189b2d75854SStanislav Sedov 	if (len == 0) {
190b2d75854SStanislav Sedov 		WARNX(0, "MSR register expected");
191b2d75854SStanislav Sedov 		usage();
192b2d75854SStanislav Sedov 		/* NOTREACHED */
193b2d75854SStanislav Sedov 	}
194e085f869SStanislav Sedov 
195b2d75854SStanislav Sedov 	/*
196b2d75854SStanislav Sedov 	 * Parse command string.
197b2d75854SStanislav Sedov 	 */
198b2d75854SStanislav Sedov 	msr = strtoul(cmdarg, &endptr, 16);
199b2d75854SStanislav Sedov 	switch (*endptr) {
200b2d75854SStanislav Sedov 	case '\0':
201b2d75854SStanislav Sedov 		op = OP_READ;
202b2d75854SStanislav Sedov 		break;
203b2d75854SStanislav Sedov 	case '=':
204b2d75854SStanislav Sedov 		op = OP_WRITE;
205b2d75854SStanislav Sedov 		break;
206b2d75854SStanislav Sedov 	case '&':
207b2d75854SStanislav Sedov 		op = OP_AND;
208b2d75854SStanislav Sedov 		endptr++;
209b2d75854SStanislav Sedov 		break;
210b2d75854SStanislav Sedov 	case '|':
211b2d75854SStanislav Sedov 		op = OP_OR;
212b2d75854SStanislav Sedov 		endptr++;
213b2d75854SStanislav Sedov 		break;
214b2d75854SStanislav Sedov 	default:
215b2d75854SStanislav Sedov 		op = OP_INVAL;
216b2d75854SStanislav Sedov 	}
217b2d75854SStanislav Sedov 	if (op != OP_READ) {	/* Complex operation. */
218b2d75854SStanislav Sedov 		if (*endptr != '=')
219b2d75854SStanislav Sedov 			op = OP_INVAL;
220b2d75854SStanislav Sedov 		else {
221b2d75854SStanislav Sedov 			p = ++endptr;
222b2d75854SStanislav Sedov 			if (*p == '~') {
223b2d75854SStanislav Sedov 				do_invert = 1;
224b2d75854SStanislav Sedov 				p++;
225b2d75854SStanislav Sedov 			}
226b2d75854SStanislav Sedov 			data = strtoull(p, &endptr, 16);
227e085f869SStanislav Sedov 			if (*p == '\0' || *endptr != '\0') {
228b2d75854SStanislav Sedov 				WARNX(0, "argument required: %s", cmdarg);
229e085f869SStanislav Sedov 				usage();
230e085f869SStanislav Sedov 				/* NOTREACHED */
231e085f869SStanislav Sedov 			}
232e085f869SStanislav Sedov 		}
233b2d75854SStanislav Sedov 	}
234b2d75854SStanislav Sedov 	if (op == OP_INVAL) {
235b2d75854SStanislav Sedov 		WARNX(0, "invalid operator: %s", cmdarg);
236e085f869SStanislav Sedov 		usage();
237e085f869SStanislav Sedov 		/* NOTREACHED */
238e085f869SStanislav Sedov 	}
239e085f869SStanislav Sedov 
240e085f869SStanislav Sedov 	/*
241e085f869SStanislav Sedov 	 * Fill ioctl argument structure.
242e085f869SStanislav Sedov 	 */
243e085f869SStanislav Sedov 	args.msr = msr;
244b2d75854SStanislav Sedov 	if ((do_invert != 0) ^ (op == OP_AND))
245b2d75854SStanislav Sedov 		args.data = ~data;
246b2d75854SStanislav Sedov 	else
247b2d75854SStanislav Sedov 		args.data = data;
248b2d75854SStanislav Sedov 	switch (op) {
249b2d75854SStanislav Sedov 	case OP_READ:
250b2d75854SStanislav Sedov 		command = CPUCTL_RDMSR;
2513b232eb6SStanislav Sedov 		command_name = "RDMSR";
252b2d75854SStanislav Sedov 		break;
253b2d75854SStanislav Sedov 	case OP_WRITE:
254b2d75854SStanislav Sedov 		command = CPUCTL_WRMSR;
2553b232eb6SStanislav Sedov 		command_name = "WRMSR";
256b2d75854SStanislav Sedov 		break;
257b2d75854SStanislav Sedov 	case OP_OR:
258b2d75854SStanislav Sedov 		command = CPUCTL_MSRSBIT;
2593b232eb6SStanislav Sedov 		command_name = "MSRSBIT";
260b2d75854SStanislav Sedov 		break;
261b2d75854SStanislav Sedov 	case OP_AND:
262b2d75854SStanislav Sedov 		command = CPUCTL_MSRCBIT;
2633b232eb6SStanislav Sedov 		command_name = "MSRCBIT";
264b2d75854SStanislav Sedov 		break;
265b2d75854SStanislav Sedov 	default:
266b2d75854SStanislav Sedov 		abort();
267b2d75854SStanislav Sedov 	}
268b2d75854SStanislav Sedov 	fd = open(dev, op == OP_READ ? O_RDONLY : O_WRONLY);
269e085f869SStanislav Sedov 	if (fd < 0) {
270cbcc5579SStanislav Sedov 		WARN(0, "error opening %s for %s", dev,
271b2d75854SStanislav Sedov 		    op == OP_READ ? "reading" : "writing");
272e085f869SStanislav Sedov 		return (1);
273e085f869SStanislav Sedov 	}
274b2d75854SStanislav Sedov 	error = ioctl(fd, command, &args);
275e085f869SStanislav Sedov 	if (error < 0) {
2763b232eb6SStanislav Sedov 		WARN(0, "ioctl(%s, CPUCTL_%s (%lu))", dev, command_name, command);
277e085f869SStanislav Sedov 		close(fd);
278e085f869SStanislav Sedov 		return (1);
279e085f869SStanislav Sedov 	}
280b2d75854SStanislav Sedov 	if (op == OP_READ)
281e085f869SStanislav Sedov 		fprintf(stdout, "MSR 0x%x: 0x%.8x 0x%.8x\n", msr,
282e085f869SStanislav Sedov 		    HIGH(args.data), LOW(args.data));
283e085f869SStanislav Sedov 	close(fd);
284e085f869SStanislav Sedov 	return (0);
285e085f869SStanislav Sedov }
286e085f869SStanislav Sedov 
287e085f869SStanislav Sedov static int
288e085f869SStanislav Sedov do_update(const char *dev)
289e085f869SStanislav Sedov {
290e085f869SStanislav Sedov 	int fd;
291e085f869SStanislav Sedov 	unsigned int i;
292e085f869SStanislav Sedov 	int error;
293e085f869SStanislav Sedov 	struct ucode_handler *handler;
294e085f869SStanislav Sedov 	struct datadir *dir;
295e085f869SStanislav Sedov 	DIR *dirfd;
296e085f869SStanislav Sedov 	struct dirent *direntry;
297e085f869SStanislav Sedov 	char buf[MAXPATHLEN];
298e085f869SStanislav Sedov 
299e085f869SStanislav Sedov 	fd = open(dev, O_RDONLY);
300e085f869SStanislav Sedov 	if (fd < 0) {
301cbcc5579SStanislav Sedov 		WARN(0, "error opening %s for reading", dev);
302e085f869SStanislav Sedov 		return (1);
303e085f869SStanislav Sedov 	}
304e085f869SStanislav Sedov 
305e085f869SStanislav Sedov 	/*
306e085f869SStanislav Sedov 	 * Find the appropriate handler for device.
307e085f869SStanislav Sedov 	 */
308e085f869SStanislav Sedov 	for (i = 0; i < NHANDLERS; i++)
309e085f869SStanislav Sedov 		if (handlers[i].probe(fd) == 0)
310e085f869SStanislav Sedov 			break;
311e085f869SStanislav Sedov 	if (i < NHANDLERS)
312e085f869SStanislav Sedov 		handler = &handlers[i];
313e085f869SStanislav Sedov 	else {
314e085f869SStanislav Sedov 		WARNX(0, "cannot find the appropriate handler for device");
315e085f869SStanislav Sedov 		close(fd);
316e085f869SStanislav Sedov 		return (1);
317e085f869SStanislav Sedov 	}
318e085f869SStanislav Sedov 	close(fd);
319e085f869SStanislav Sedov 
320e085f869SStanislav Sedov 	/*
321e085f869SStanislav Sedov 	 * Process every image in specified data directories.
322e085f869SStanislav Sedov 	 */
323e085f869SStanislav Sedov 	SLIST_FOREACH(dir, &datadirs, next) {
324e085f869SStanislav Sedov 		dirfd  = opendir(dir->path);
325e085f869SStanislav Sedov 		if (dirfd == NULL) {
326e085f869SStanislav Sedov 			WARNX(1, "skipping directory %s: not accessible", dir->path);
327e085f869SStanislav Sedov 			continue;
328e085f869SStanislav Sedov 		}
329e085f869SStanislav Sedov 		while ((direntry = readdir(dirfd)) != NULL) {
330e085f869SStanislav Sedov 			if (direntry->d_namlen == 0)
331e085f869SStanislav Sedov 				continue;
332e085f869SStanislav Sedov 			error = snprintf(buf, sizeof(buf), "%s/%s", dir->path,
333e085f869SStanislav Sedov 			    direntry->d_name);
334e085f869SStanislav Sedov 			if ((unsigned)error >= sizeof(buf))
335e085f869SStanislav Sedov 				WARNX(0, "skipping %s, buffer too short",
336e085f869SStanislav Sedov 				    direntry->d_name);
337e085f869SStanislav Sedov 			if (isdir(buf) != 0) {
338e085f869SStanislav Sedov 				WARNX(2, "skipping %s: is a directory", buf);
339e085f869SStanislav Sedov 				continue;
340e085f869SStanislav Sedov 			}
341e085f869SStanislav Sedov 			handler->update(dev, buf);
342e085f869SStanislav Sedov 		}
343e085f869SStanislav Sedov 		error = closedir(dirfd);
344e085f869SStanislav Sedov 		if (error != 0)
345e085f869SStanislav Sedov 			WARN(0, "closedir(%s)", dir->path);
346e085f869SStanislav Sedov 	}
347e085f869SStanislav Sedov 	return (0);
348e085f869SStanislav Sedov }
349e085f869SStanislav Sedov 
350e085f869SStanislav Sedov /*
351e085f869SStanislav Sedov  * Add new data directory to the search list.
352e085f869SStanislav Sedov  */
353e085f869SStanislav Sedov static void
354e085f869SStanislav Sedov datadir_add(const char *path)
355e085f869SStanislav Sedov {
356e085f869SStanislav Sedov 	struct datadir *newdir;
357e085f869SStanislav Sedov 
358e085f869SStanislav Sedov 	newdir = (struct datadir *)malloc(sizeof(*newdir));
359e085f869SStanislav Sedov 	if (newdir == NULL)
360e085f869SStanislav Sedov 		err(EX_OSERR, "cannot allocate memory");
361e085f869SStanislav Sedov 	newdir->path = path;
362e085f869SStanislav Sedov 	SLIST_INSERT_HEAD(&datadirs, newdir, next);
363e085f869SStanislav Sedov }
364e085f869SStanislav Sedov 
365e085f869SStanislav Sedov int
366e085f869SStanislav Sedov main(int argc, char *argv[])
367e085f869SStanislav Sedov {
368e085f869SStanislav Sedov 	int c, flags;
369e085f869SStanislav Sedov 	const char *cmdarg;
370e085f869SStanislav Sedov 	const char *dev;
371e085f869SStanislav Sedov 	int error;
372e085f869SStanislav Sedov 
373e085f869SStanislav Sedov 	flags = 0;
374e085f869SStanislav Sedov 	error = 0;
375e085f869SStanislav Sedov 	cmdarg = "";	/* To keep gcc3 happy. */
376e085f869SStanislav Sedov 
377e085f869SStanislav Sedov 	/*
378e085f869SStanislav Sedov 	 * Add all default data dirs to the list first.
379e085f869SStanislav Sedov 	 */
380e085f869SStanislav Sedov 	datadir_add(DEFAULT_DATADIR);
381e085f869SStanislav Sedov 	while ((c = getopt(argc, argv, "d:hi:m:uv")) != -1) {
382e085f869SStanislav Sedov 		switch (c) {
383e085f869SStanislav Sedov 		case 'd':
384e085f869SStanislav Sedov 			datadir_add(optarg);
385e085f869SStanislav Sedov 			break;
386e085f869SStanislav Sedov 		case 'i':
387e085f869SStanislav Sedov 			flags |= FLAG_I;
388e085f869SStanislav Sedov 			cmdarg = optarg;
389e085f869SStanislav Sedov 			break;
390e085f869SStanislav Sedov 		case 'm':
391e085f869SStanislav Sedov 			flags |= FLAG_M;
392e085f869SStanislav Sedov 			cmdarg = optarg;
393e085f869SStanislav Sedov 			break;
394e085f869SStanislav Sedov 		case 'u':
395e085f869SStanislav Sedov 			flags |= FLAG_U;
396e085f869SStanislav Sedov 			break;
397e085f869SStanislav Sedov 		case 'v':
398e085f869SStanislav Sedov 			verbosity_level++;
399e085f869SStanislav Sedov 			break;
400e085f869SStanislav Sedov 		case 'h':
401e085f869SStanislav Sedov 			/* FALLTHROUGH */
402e085f869SStanislav Sedov 		default:
403e085f869SStanislav Sedov 			usage();
404e085f869SStanislav Sedov 			/* NOTREACHED */
405e085f869SStanislav Sedov 		}
406e085f869SStanislav Sedov 	}
407e085f869SStanislav Sedov 	argc -= optind;
408e085f869SStanislav Sedov 	argv += optind;
409e085f869SStanislav Sedov 	if (argc < 1) {
410e085f869SStanislav Sedov 		usage();
411e085f869SStanislav Sedov 		/* NOTREACHED */
412e085f869SStanislav Sedov 	}
413e085f869SStanislav Sedov 	dev = argv[0];
414e085f869SStanislav Sedov 	c = flags & (FLAG_I | FLAG_M | FLAG_U);
415e085f869SStanislav Sedov 	switch (c) {
416e085f869SStanislav Sedov 		case FLAG_I:
417e085f869SStanislav Sedov 			error = do_cpuid(cmdarg, dev);
418e085f869SStanislav Sedov 			break;
419e085f869SStanislav Sedov 		case FLAG_M:
420e085f869SStanislav Sedov 			error = do_msr(cmdarg, dev);
421e085f869SStanislav Sedov 			break;
422e085f869SStanislav Sedov 		case FLAG_U:
423e085f869SStanislav Sedov 			error = do_update(dev);
424e085f869SStanislav Sedov 			break;
425e085f869SStanislav Sedov 		default:
426e085f869SStanislav Sedov 			usage();	/* Only one command can be selected. */
427e085f869SStanislav Sedov 	}
428e085f869SStanislav Sedov 	SLIST_FREE(&datadirs, next, free);
429e085f869SStanislav Sedov 	return (error);
430e085f869SStanislav Sedov }
431