xref: /freebsd/usr.sbin/cpucontrol/cpucontrol.c (revision 3b232eb663e815d942b91ced33eae58cd3740fd0)
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"
54e085f869SStanislav Sedov 
55e085f869SStanislav Sedov int	verbosity_level = 0;
56e085f869SStanislav Sedov 
57e085f869SStanislav Sedov #define	DEFAULT_DATADIR	"/usr/local/share/cpucontrol"
58e085f869SStanislav Sedov 
59e085f869SStanislav Sedov #define	FLAG_I	0x01
60e085f869SStanislav Sedov #define	FLAG_M	0x02
61e085f869SStanislav Sedov #define	FLAG_U	0x04
62e085f869SStanislav Sedov 
63b2d75854SStanislav Sedov #define	OP_INVAL	0x00
64b2d75854SStanislav Sedov #define	OP_READ		0x01
65b2d75854SStanislav Sedov #define	OP_WRITE	0x02
66b2d75854SStanislav Sedov #define	OP_OR		0x04
67b2d75854SStanislav Sedov #define	OP_AND		0x08
68b2d75854SStanislav Sedov 
69e085f869SStanislav Sedov #define	HIGH(val)	(uint32_t)(((val) >> 32) & 0xffffffff)
70e085f869SStanislav Sedov #define	LOW(val)	(uint32_t)((val) & 0xffffffff)
71e085f869SStanislav Sedov 
72e085f869SStanislav Sedov /*
73e085f869SStanislav Sedov  * Macros for freeing SLISTs, probably must be in /sys/queue.h
74e085f869SStanislav Sedov  */
75e085f869SStanislav Sedov #define	SLIST_FREE(head, field, freef) do {				\
76e085f869SStanislav Sedov 		typeof(SLIST_FIRST(head)) __elm0;			\
77e085f869SStanislav Sedov 		typeof(SLIST_FIRST(head)) __elm;			\
78e085f869SStanislav Sedov 		SLIST_FOREACH_SAFE(__elm, (head), field, __elm0)	\
79e085f869SStanislav Sedov 			(void)(freef)(__elm);				\
80e085f869SStanislav Sedov } while(0);
81e085f869SStanislav Sedov 
82e085f869SStanislav Sedov struct datadir {
83e085f869SStanislav Sedov 	const char		*path;
84e085f869SStanislav Sedov 	SLIST_ENTRY(datadir)	next;
85e085f869SStanislav Sedov };
8613e403fdSAntoine Brodin static SLIST_HEAD(, datadir) datadirs = SLIST_HEAD_INITIALIZER(datadirs);
87e085f869SStanislav Sedov 
88e085f869SStanislav Sedov struct ucode_handler {
89e085f869SStanislav Sedov 	ucode_probe_t *probe;
90e085f869SStanislav Sedov 	ucode_update_t *update;
91e085f869SStanislav Sedov } handlers[] = {
92e085f869SStanislav Sedov 	{ intel_probe, intel_update },
93e085f869SStanislav Sedov 	{ amd_probe, amd_update },
94e085f869SStanislav Sedov };
95e085f869SStanislav Sedov #define NHANDLERS (sizeof(handlers) / sizeof(*handlers))
96e085f869SStanislav Sedov 
97e085f869SStanislav Sedov static void	usage(void);
98e085f869SStanislav Sedov static int	isdir(const char *path);
99e085f869SStanislav Sedov static int	do_cpuid(const char *cmdarg, const char *dev);
100e085f869SStanislav Sedov static int	do_msr(const char *cmdarg, const char *dev);
101e085f869SStanislav Sedov static int	do_update(const char *dev);
102e085f869SStanislav Sedov static void	datadir_add(const char *path);
103e085f869SStanislav Sedov 
104e085f869SStanislav Sedov static void __dead2
10510bc3a7fSEd Schouten usage(void)
106e085f869SStanislav Sedov {
107e085f869SStanislav Sedov 	const char *name;
108e085f869SStanislav Sedov 
109e085f869SStanislav Sedov 	name = getprogname();
110e085f869SStanislav Sedov 	if (name == NULL)
111e085f869SStanislav Sedov 		name = "cpuctl";
112e085f869SStanislav Sedov 	fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | "
113e085f869SStanislav Sedov 	    "-i level | -u] device\n", name);
114e085f869SStanislav Sedov 	exit(EX_USAGE);
115e085f869SStanislav Sedov }
116e085f869SStanislav Sedov 
117e085f869SStanislav Sedov static int
118e085f869SStanislav Sedov isdir(const char *path)
119e085f869SStanislav Sedov {
120e085f869SStanislav Sedov 	int error;
121e085f869SStanislav Sedov 	struct stat st;
122e085f869SStanislav Sedov 
123e085f869SStanislav Sedov 	error = stat(path, &st);
124e085f869SStanislav Sedov 	if (error < 0) {
125e085f869SStanislav Sedov 		WARN(0, "stat(%s)", path);
126e085f869SStanislav Sedov 		return (error);
127e085f869SStanislav Sedov 	}
128e085f869SStanislav Sedov 	return (st.st_mode & S_IFDIR);
129e085f869SStanislav Sedov }
130e085f869SStanislav Sedov 
131e085f869SStanislav Sedov static int
132e085f869SStanislav Sedov do_cpuid(const char *cmdarg, const char *dev)
133e085f869SStanislav Sedov {
134e085f869SStanislav Sedov 	unsigned int level;
135e085f869SStanislav Sedov 	cpuctl_cpuid_args_t args;
136e085f869SStanislav Sedov 	int fd, error;
137e085f869SStanislav Sedov 	char *endptr;
138e085f869SStanislav Sedov 
139e085f869SStanislav Sedov 	assert(cmdarg != NULL);
140e085f869SStanislav Sedov 	assert(dev != NULL);
141e085f869SStanislav Sedov 
142e085f869SStanislav Sedov 	level = strtoul(cmdarg, &endptr, 16);
143e085f869SStanislav Sedov 	if (*cmdarg == '\0' || *endptr != '\0') {
144e085f869SStanislav Sedov 		WARNX(0, "incorrect operand: %s", cmdarg);
145e085f869SStanislav Sedov 		usage();
146e085f869SStanislav Sedov 		/* NOTREACHED */
147e085f869SStanislav Sedov 	}
148e085f869SStanislav Sedov 
149e085f869SStanislav Sedov 	/*
150e085f869SStanislav Sedov 	 * Fill ioctl argument structure.
151e085f869SStanislav Sedov 	 */
152e085f869SStanislav Sedov 	args.level = level;
153e085f869SStanislav Sedov 	fd = open(dev, O_RDONLY);
154e085f869SStanislav Sedov 	if (fd < 0) {
155cbcc5579SStanislav Sedov 		WARN(0, "error opening %s for reading", dev);
156e085f869SStanislav Sedov 		return (1);
157e085f869SStanislav Sedov 	}
158e085f869SStanislav Sedov 	error = ioctl(fd, CPUCTL_CPUID, &args);
159e085f869SStanislav Sedov 	if (error < 0) {
160cbcc5579SStanislav Sedov 		WARN(0, "ioctl(%s, CPUCTL_CPUID)", dev);
161e085f869SStanislav Sedov 		close(fd);
162e085f869SStanislav Sedov 		return (error);
163e085f869SStanislav Sedov 	}
164e085f869SStanislav Sedov 	fprintf(stdout, "cpuid level 0x%x: 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
165e085f869SStanislav Sedov 	    level, args.data[0], args.data[1], args.data[2], args.data[3]);
166e085f869SStanislav Sedov 	close(fd);
167e085f869SStanislav Sedov 	return (0);
168e085f869SStanislav Sedov }
169e085f869SStanislav Sedov 
170e085f869SStanislav Sedov static int
171e085f869SStanislav Sedov do_msr(const char *cmdarg, const char *dev)
172e085f869SStanislav Sedov {
173e085f869SStanislav Sedov 	unsigned int msr;
174e085f869SStanislav Sedov 	cpuctl_msr_args_t args;
175b2d75854SStanislav Sedov 	size_t len;
176b2d75854SStanislav Sedov 	uint64_t data = 0;
177b2d75854SStanislav Sedov 	unsigned long command;
178b2d75854SStanislav Sedov 	int do_invert = 0, op;
179e085f869SStanislav Sedov 	int fd, error;
180f264409aSStanislav Sedov 	const char *command_name;
181e085f869SStanislav Sedov 	char *endptr;
182b2d75854SStanislav Sedov 	char *p;
183e085f869SStanislav Sedov 
184e085f869SStanislav Sedov 	assert(cmdarg != NULL);
185e085f869SStanislav Sedov 	assert(dev != NULL);
186b2d75854SStanislav Sedov 	len = strlen(cmdarg);
187b2d75854SStanislav Sedov 	if (len == 0) {
188b2d75854SStanislav Sedov 		WARNX(0, "MSR register expected");
189b2d75854SStanislav Sedov 		usage();
190b2d75854SStanislav Sedov 		/* NOTREACHED */
191b2d75854SStanislav Sedov 	}
192e085f869SStanislav Sedov 
193b2d75854SStanislav Sedov 	/*
194b2d75854SStanislav Sedov 	 * Parse command string.
195b2d75854SStanislav Sedov 	 */
196b2d75854SStanislav Sedov 	msr = strtoul(cmdarg, &endptr, 16);
197b2d75854SStanislav Sedov 	switch (*endptr) {
198b2d75854SStanislav Sedov 	case '\0':
199b2d75854SStanislav Sedov 		op = OP_READ;
200b2d75854SStanislav Sedov 		break;
201b2d75854SStanislav Sedov 	case '=':
202b2d75854SStanislav Sedov 		op = OP_WRITE;
203b2d75854SStanislav Sedov 		break;
204b2d75854SStanislav Sedov 	case '&':
205b2d75854SStanislav Sedov 		op = OP_AND;
206b2d75854SStanislav Sedov 		endptr++;
207b2d75854SStanislav Sedov 		break;
208b2d75854SStanislav Sedov 	case '|':
209b2d75854SStanislav Sedov 		op = OP_OR;
210b2d75854SStanislav Sedov 		endptr++;
211b2d75854SStanislav Sedov 		break;
212b2d75854SStanislav Sedov 	default:
213b2d75854SStanislav Sedov 		op = OP_INVAL;
214b2d75854SStanislav Sedov 	}
215b2d75854SStanislav Sedov 	if (op != OP_READ) {	/* Complex operation. */
216b2d75854SStanislav Sedov 		if (*endptr != '=')
217b2d75854SStanislav Sedov 			op = OP_INVAL;
218b2d75854SStanislav Sedov 		else {
219b2d75854SStanislav Sedov 			p = ++endptr;
220b2d75854SStanislav Sedov 			if (*p == '~') {
221b2d75854SStanislav Sedov 				do_invert = 1;
222b2d75854SStanislav Sedov 				p++;
223b2d75854SStanislav Sedov 			}
224b2d75854SStanislav Sedov 			data = strtoull(p, &endptr, 16);
225e085f869SStanislav Sedov 			if (*p == '\0' || *endptr != '\0') {
226b2d75854SStanislav Sedov 				WARNX(0, "argument required: %s", cmdarg);
227e085f869SStanislav Sedov 				usage();
228e085f869SStanislav Sedov 				/* NOTREACHED */
229e085f869SStanislav Sedov 			}
230e085f869SStanislav Sedov 		}
231b2d75854SStanislav Sedov 	}
232b2d75854SStanislav Sedov 	if (op == OP_INVAL) {
233b2d75854SStanislav Sedov 		WARNX(0, "invalid operator: %s", cmdarg);
234e085f869SStanislav Sedov 		usage();
235e085f869SStanislav Sedov 		/* NOTREACHED */
236e085f869SStanislav Sedov 	}
237e085f869SStanislav Sedov 
238e085f869SStanislav Sedov 	/*
239e085f869SStanislav Sedov 	 * Fill ioctl argument structure.
240e085f869SStanislav Sedov 	 */
241e085f869SStanislav Sedov 	args.msr = msr;
242b2d75854SStanislav Sedov 	if ((do_invert != 0) ^ (op == OP_AND))
243b2d75854SStanislav Sedov 		args.data = ~data;
244b2d75854SStanislav Sedov 	else
245b2d75854SStanislav Sedov 		args.data = data;
246b2d75854SStanislav Sedov 	switch (op) {
247b2d75854SStanislav Sedov 	case OP_READ:
248b2d75854SStanislav Sedov 		command = CPUCTL_RDMSR;
249*3b232eb6SStanislav Sedov 		command_name = "RDMSR";
250b2d75854SStanislav Sedov 		break;
251b2d75854SStanislav Sedov 	case OP_WRITE:
252b2d75854SStanislav Sedov 		command = CPUCTL_WRMSR;
253*3b232eb6SStanislav Sedov 		command_name = "WRMSR";
254b2d75854SStanislav Sedov 		break;
255b2d75854SStanislav Sedov 	case OP_OR:
256b2d75854SStanislav Sedov 		command = CPUCTL_MSRSBIT;
257*3b232eb6SStanislav Sedov 		command_name = "MSRSBIT";
258b2d75854SStanislav Sedov 		break;
259b2d75854SStanislav Sedov 	case OP_AND:
260b2d75854SStanislav Sedov 		command = CPUCTL_MSRCBIT;
261*3b232eb6SStanislav Sedov 		command_name = "MSRCBIT";
262b2d75854SStanislav Sedov 		break;
263b2d75854SStanislav Sedov 	default:
264b2d75854SStanislav Sedov 		abort();
265b2d75854SStanislav Sedov 	}
266b2d75854SStanislav Sedov 	fd = open(dev, op == OP_READ ? O_RDONLY : O_WRONLY);
267e085f869SStanislav Sedov 	if (fd < 0) {
268cbcc5579SStanislav Sedov 		WARN(0, "error opening %s for %s", dev,
269b2d75854SStanislav Sedov 		    op == OP_READ ? "reading" : "writing");
270e085f869SStanislav Sedov 		return (1);
271e085f869SStanislav Sedov 	}
272b2d75854SStanislav Sedov 	error = ioctl(fd, command, &args);
273e085f869SStanislav Sedov 	if (error < 0) {
274*3b232eb6SStanislav Sedov 		WARN(0, "ioctl(%s, CPUCTL_%s (%lu))", dev, command_name, command);
275e085f869SStanislav Sedov 		close(fd);
276e085f869SStanislav Sedov 		return (1);
277e085f869SStanislav Sedov 	}
278b2d75854SStanislav Sedov 	if (op == OP_READ)
279e085f869SStanislav Sedov 		fprintf(stdout, "MSR 0x%x: 0x%.8x 0x%.8x\n", msr,
280e085f869SStanislav Sedov 		    HIGH(args.data), LOW(args.data));
281e085f869SStanislav Sedov 	close(fd);
282e085f869SStanislav Sedov 	return (0);
283e085f869SStanislav Sedov }
284e085f869SStanislav Sedov 
285e085f869SStanislav Sedov static int
286e085f869SStanislav Sedov do_update(const char *dev)
287e085f869SStanislav Sedov {
288e085f869SStanislav Sedov 	int fd;
289e085f869SStanislav Sedov 	unsigned int i;
290e085f869SStanislav Sedov 	int error;
291e085f869SStanislav Sedov 	struct ucode_handler *handler;
292e085f869SStanislav Sedov 	struct datadir *dir;
293e085f869SStanislav Sedov 	DIR *dirfd;
294e085f869SStanislav Sedov 	struct dirent *direntry;
295e085f869SStanislav Sedov 	char buf[MAXPATHLEN];
296e085f869SStanislav Sedov 
297e085f869SStanislav Sedov 	fd = open(dev, O_RDONLY);
298e085f869SStanislav Sedov 	if (fd < 0) {
299cbcc5579SStanislav Sedov 		WARN(0, "error opening %s for reading", dev);
300e085f869SStanislav Sedov 		return (1);
301e085f869SStanislav Sedov 	}
302e085f869SStanislav Sedov 
303e085f869SStanislav Sedov 	/*
304e085f869SStanislav Sedov 	 * Find the appropriate handler for device.
305e085f869SStanislav Sedov 	 */
306e085f869SStanislav Sedov 	for (i = 0; i < NHANDLERS; i++)
307e085f869SStanislav Sedov 		if (handlers[i].probe(fd) == 0)
308e085f869SStanislav Sedov 			break;
309e085f869SStanislav Sedov 	if (i < NHANDLERS)
310e085f869SStanislav Sedov 		handler = &handlers[i];
311e085f869SStanislav Sedov 	else {
312e085f869SStanislav Sedov 		WARNX(0, "cannot find the appropriate handler for device");
313e085f869SStanislav Sedov 		close(fd);
314e085f869SStanislav Sedov 		return (1);
315e085f869SStanislav Sedov 	}
316e085f869SStanislav Sedov 	close(fd);
317e085f869SStanislav Sedov 
318e085f869SStanislav Sedov 	/*
319e085f869SStanislav Sedov 	 * Process every image in specified data directories.
320e085f869SStanislav Sedov 	 */
321e085f869SStanislav Sedov 	SLIST_FOREACH(dir, &datadirs, next) {
322e085f869SStanislav Sedov 		dirfd  = opendir(dir->path);
323e085f869SStanislav Sedov 		if (dirfd == NULL) {
324e085f869SStanislav Sedov 			WARNX(1, "skipping directory %s: not accessible", dir->path);
325e085f869SStanislav Sedov 			continue;
326e085f869SStanislav Sedov 		}
327e085f869SStanislav Sedov 		while ((direntry = readdir(dirfd)) != NULL) {
328e085f869SStanislav Sedov 			if (direntry->d_namlen == 0)
329e085f869SStanislav Sedov 				continue;
330e085f869SStanislav Sedov 			error = snprintf(buf, sizeof(buf), "%s/%s", dir->path,
331e085f869SStanislav Sedov 			    direntry->d_name);
332e085f869SStanislav Sedov 			if ((unsigned)error >= sizeof(buf))
333e085f869SStanislav Sedov 				WARNX(0, "skipping %s, buffer too short",
334e085f869SStanislav Sedov 				    direntry->d_name);
335e085f869SStanislav Sedov 			if (isdir(buf) != 0) {
336e085f869SStanislav Sedov 				WARNX(2, "skipping %s: is a directory", buf);
337e085f869SStanislav Sedov 				continue;
338e085f869SStanislav Sedov 			}
339e085f869SStanislav Sedov 			handler->update(dev, buf);
340e085f869SStanislav Sedov 		}
341e085f869SStanislav Sedov 		error = closedir(dirfd);
342e085f869SStanislav Sedov 		if (error != 0)
343e085f869SStanislav Sedov 			WARN(0, "closedir(%s)", dir->path);
344e085f869SStanislav Sedov 	}
345e085f869SStanislav Sedov 	return (0);
346e085f869SStanislav Sedov }
347e085f869SStanislav Sedov 
348e085f869SStanislav Sedov /*
349e085f869SStanislav Sedov  * Add new data directory to the search list.
350e085f869SStanislav Sedov  */
351e085f869SStanislav Sedov static void
352e085f869SStanislav Sedov datadir_add(const char *path)
353e085f869SStanislav Sedov {
354e085f869SStanislav Sedov 	struct datadir *newdir;
355e085f869SStanislav Sedov 
356e085f869SStanislav Sedov 	newdir = (struct datadir *)malloc(sizeof(*newdir));
357e085f869SStanislav Sedov 	if (newdir == NULL)
358e085f869SStanislav Sedov 		err(EX_OSERR, "cannot allocate memory");
359e085f869SStanislav Sedov 	newdir->path = path;
360e085f869SStanislav Sedov 	SLIST_INSERT_HEAD(&datadirs, newdir, next);
361e085f869SStanislav Sedov }
362e085f869SStanislav Sedov 
363e085f869SStanislav Sedov int
364e085f869SStanislav Sedov main(int argc, char *argv[])
365e085f869SStanislav Sedov {
366e085f869SStanislav Sedov 	int c, flags;
367e085f869SStanislav Sedov 	const char *cmdarg;
368e085f869SStanislav Sedov 	const char *dev;
369e085f869SStanislav Sedov 	int error;
370e085f869SStanislav Sedov 
371e085f869SStanislav Sedov 	flags = 0;
372e085f869SStanislav Sedov 	error = 0;
373e085f869SStanislav Sedov 	cmdarg = "";	/* To keep gcc3 happy. */
374e085f869SStanislav Sedov 
375e085f869SStanislav Sedov 	/*
376e085f869SStanislav Sedov 	 * Add all default data dirs to the list first.
377e085f869SStanislav Sedov 	 */
378e085f869SStanislav Sedov 	datadir_add(DEFAULT_DATADIR);
379e085f869SStanislav Sedov 	while ((c = getopt(argc, argv, "d:hi:m:uv")) != -1) {
380e085f869SStanislav Sedov 		switch (c) {
381e085f869SStanislav Sedov 		case 'd':
382e085f869SStanislav Sedov 			datadir_add(optarg);
383e085f869SStanislav Sedov 			break;
384e085f869SStanislav Sedov 		case 'i':
385e085f869SStanislav Sedov 			flags |= FLAG_I;
386e085f869SStanislav Sedov 			cmdarg = optarg;
387e085f869SStanislav Sedov 			break;
388e085f869SStanislav Sedov 		case 'm':
389e085f869SStanislav Sedov 			flags |= FLAG_M;
390e085f869SStanislav Sedov 			cmdarg = optarg;
391e085f869SStanislav Sedov 			break;
392e085f869SStanislav Sedov 		case 'u':
393e085f869SStanislav Sedov 			flags |= FLAG_U;
394e085f869SStanislav Sedov 			break;
395e085f869SStanislav Sedov 		case 'v':
396e085f869SStanislav Sedov 			verbosity_level++;
397e085f869SStanislav Sedov 			break;
398e085f869SStanislav Sedov 		case 'h':
399e085f869SStanislav Sedov 			/* FALLTHROUGH */
400e085f869SStanislav Sedov 		default:
401e085f869SStanislav Sedov 			usage();
402e085f869SStanislav Sedov 			/* NOTREACHED */
403e085f869SStanislav Sedov 		}
404e085f869SStanislav Sedov 	}
405e085f869SStanislav Sedov 	argc -= optind;
406e085f869SStanislav Sedov 	argv += optind;
407e085f869SStanislav Sedov 	if (argc < 1) {
408e085f869SStanislav Sedov 		usage();
409e085f869SStanislav Sedov 		/* NOTREACHED */
410e085f869SStanislav Sedov 	}
411e085f869SStanislav Sedov 	dev = argv[0];
412e085f869SStanislav Sedov 	c = flags & (FLAG_I | FLAG_M | FLAG_U);
413e085f869SStanislav Sedov 	switch (c) {
414e085f869SStanislav Sedov 		case FLAG_I:
415e085f869SStanislav Sedov 			error = do_cpuid(cmdarg, dev);
416e085f869SStanislav Sedov 			break;
417e085f869SStanislav Sedov 		case FLAG_M:
418e085f869SStanislav Sedov 			error = do_msr(cmdarg, dev);
419e085f869SStanislav Sedov 			break;
420e085f869SStanislav Sedov 		case FLAG_U:
421e085f869SStanislav Sedov 			error = do_update(dev);
422e085f869SStanislav Sedov 			break;
423e085f869SStanislav Sedov 		default:
424e085f869SStanislav Sedov 			usage();	/* Only one command can be selected. */
425e085f869SStanislav Sedov 	}
426e085f869SStanislav Sedov 	SLIST_FREE(&datadirs, next, free);
427e085f869SStanislav Sedov 	return (error);
428e085f869SStanislav Sedov }
429