xref: /netbsd-src/usr.sbin/cpuctl/cpuctl.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: cpuctl.c,v 1.23 2013/12/23 12:35:33 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 2007, 2008, 2009, 2012 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: cpuctl.c,v 1.23 2013/12/23 12:35:33 msaitoh Exp $");
35 #endif /* not lint */
36 
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/uio.h>
40 #include <sys/cpuio.h>
41 
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <paths.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <stdarg.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <util.h>
52 #include <time.h>
53 #include <sched.h>
54 
55 #include "cpuctl.h"
56 
57 static u_int	getcpuid(char **);
58 __dead static void	usage(void);
59 
60 static void	cpu_identify(char **);
61 static void	cpu_list(char **);
62 static void	cpu_offline(char **);
63 static void	cpu_online(char **);
64 static void	cpu_intr(char **);
65 static void	cpu_nointr(char **);
66 static void	cpu_ucode(char **);
67 
68 static struct cmdtab {
69 	const char	*label;
70 	int	takesargs;
71 	int	argsoptional;
72 	void	(*func)(char **);
73 } const cpu_cmdtab[] = {
74 	{ "identify", 1, 0, cpu_identify },
75 	{ "list", 0, 0, cpu_list },
76 	{ "offline", 1, 0, cpu_offline },
77 	{ "online", 1, 0, cpu_online },
78 	{ "intr", 1, 0, cpu_intr },
79 	{ "nointr", 1, 0, cpu_nointr },
80 	{ "ucode", 1, 1, cpu_ucode },
81 	{ NULL, 0, 0, NULL },
82 };
83 
84 static int	fd;
85 int		verbose;
86 
87 int
88 main(int argc, char **argv)
89 {
90 	const struct cmdtab *ct;
91 	int ch;
92 
93 	while ((ch = getopt(argc, argv, "v")) != -1)
94 		switch (ch) {
95 		case 'v':
96 			verbose = 1;
97 			break;
98 		default:
99 			usage();
100 		}
101 	argc -= optind;
102 	argv += optind;
103 	if (argc < 1)
104 		usage();
105 
106 	if ((fd = open(_PATH_CPUCTL, O_RDWR)) < 0)
107 		err(EXIT_FAILURE, _PATH_CPUCTL);
108 
109 	for (ct = cpu_cmdtab; ct->label != NULL; ct++) {
110 		if (strcmp(argv[0], ct->label) == 0) {
111 			if (!ct->argsoptional &&
112 			    ((ct->takesargs == 0) ^ (argv[1] == NULL)))
113 			{
114 				usage();
115 			}
116 			(*ct->func)(argv + 1);
117 			break;
118 		}
119 	}
120 
121 	if (ct->label == NULL)
122 		errx(EXIT_FAILURE, "unknown command ``%s''", argv[optind]);
123 
124 	close(fd);
125 	exit(EXIT_SUCCESS);
126 	/* NOTREACHED */
127 }
128 
129 static void
130 usage(void)
131 {
132 	const char *progname = getprogname();
133 
134 	fprintf(stderr, "usage: %s identify cpuno\n", progname);
135 	fprintf(stderr, "       %s list\n", progname);
136 	fprintf(stderr, "       %s offline cpuno\n", progname);
137 	fprintf(stderr, "       %s online cpuno\n", progname);
138 	fprintf(stderr, "       %s intr cpuno\n", progname);
139 	fprintf(stderr, "       %s nointr cpuno\n", progname);
140 	fprintf(stderr, "       %s ucode [file]\n", progname);
141 	exit(EXIT_FAILURE);
142 	/* NOTREACHED */
143 }
144 
145 static void
146 cpu_online(char **argv)
147 {
148 	cpustate_t cs;
149 
150 	cs.cs_id = getcpuid(argv);
151 	if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0)
152 		err(EXIT_FAILURE, "IOC_CPU_GETSTATE");
153 	cs.cs_online = true;
154 	if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0)
155 		err(EXIT_FAILURE, "IOC_CPU_SETSTATE");
156 }
157 
158 static void
159 cpu_offline(char **argv)
160 {
161 	cpustate_t cs;
162 
163 	cs.cs_id = getcpuid(argv);
164 	if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0)
165 		err(EXIT_FAILURE, "IOC_CPU_GETSTATE");
166 	cs.cs_online = false;
167 	if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0)
168 		err(EXIT_FAILURE, "IOC_CPU_SETSTATE");
169 }
170 
171 static void
172 cpu_intr(char **argv)
173 {
174 	cpustate_t cs;
175 
176 	cs.cs_id = getcpuid(argv);
177 	if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0)
178 		err(EXIT_FAILURE, "IOC_CPU_GETSTATE");
179 	cs.cs_intr = true;
180 	if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0)
181 		err(EXIT_FAILURE, "IOC_CPU_SETSTATE");
182 }
183 
184 static void
185 cpu_nointr(char **argv)
186 {
187 	cpustate_t cs;
188 
189 	cs.cs_id = getcpuid(argv);
190 	if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0)
191 		err(EXIT_FAILURE, "IOC_CPU_GETSTATE");
192 	cs.cs_intr = false;
193 	if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) {
194 		if (errno == EOPNOTSUPP) {
195 			warnx("interrupt control not supported on "
196 			    "this platform");
197 		} else
198 			err(EXIT_FAILURE, "IOC_CPU_SETSTATE");
199 	}
200 }
201 
202 static void
203 cpu_ucode(char **argv)
204 {
205 	int error;
206 	struct cpu_ucode uc;
207 	unsigned long id = 0; /* gcc */
208 	char *ep;
209 	cpuset_t *cpuset;
210 
211 	uc.cpu_nr = -1;
212 	if (argv[0] != NULL) {
213 		id = strtoul(argv[0], &ep, 0);
214 		if (id != ULONG_MAX && *ep == '\0') {
215 			uc.cpu_nr = id;
216 			argv++;
217 		}
218 	}
219 	if (argv[0] != NULL)
220 		strlcpy(uc.fwname, argv[0], sizeof(uc.fwname));
221 	else
222 		memset(uc.fwname, '\0', sizeof(uc.fwname));
223 
224 	error = ucodeupdate_check(fd, &uc);
225 	if (error)
226 		errx(EXIT_FAILURE, "unsupported");
227 
228 	if (uc.cpu_nr == CPU_UCODE_CURRENT_CPU) {
229 		cpuset = cpuset_create();
230 		if (cpuset == NULL)
231 			err(EXIT_FAILURE, "cpuset_create");
232 		cpuset_zero(cpuset);
233 		cpuset_set(id, cpuset);
234 		if (_sched_setaffinity(0, 0, cpuset_size(cpuset), cpuset) < 0) {
235 			err(EXIT_FAILURE, "_sched_setaffinity");
236 		}
237 		cpuset_destroy(cpuset);
238 	}
239 	error = ioctl(fd, IOC_CPU_UCODE_APPLY, &uc);
240 	if (error < 0) {
241 		if (uc.fwname[0])
242 			err(EXIT_FAILURE, "%s", uc.fwname);
243 		else
244 			err(EXIT_FAILURE, "IOC_CPU_UCODE_APPLY");
245 	}
246 }
247 
248 
249 static void
250 cpu_identify(char **argv)
251 {
252 	char name[32];
253 	unsigned int id, np;
254 	cpuset_t *cpuset;
255 
256 	np = sysconf(_SC_NPROCESSORS_CONF);
257 	id = getcpuid(argv);
258 	snprintf(name, sizeof(name), "cpu%u", id);
259 
260 	if (np != 1) {
261 		cpuset = cpuset_create();
262 		if (cpuset == NULL)
263 			err(EXIT_FAILURE, "cpuset_create");
264 		cpuset_zero(cpuset);
265 		cpuset_set(id, cpuset);
266 		if (_sched_setaffinity(0, 0, cpuset_size(cpuset), cpuset) < 0) {
267 			if (errno == EPERM) {
268 				printf("Cannot bind to target CPU.  Output "
269 				    "may not accurately describe the target.\n"
270 				    "Run as root to allow binding.\n\n");
271 			} else {
272 				err(EXIT_FAILURE, "_sched_setaffinity");
273 			}
274 		}
275 		cpuset_destroy(cpuset);
276 	}
277 	identifycpu(fd, name);
278 }
279 
280 static u_int
281 getcpuid(char **argv)
282 {
283 	char *argp;
284 	u_int id;
285 	long np;
286 
287 	id = (u_int)strtoul(argv[0], &argp, 0);
288 	if (*argp != '\0')
289 		usage();
290 
291 	np = sysconf(_SC_NPROCESSORS_CONF);
292 	if (id >= (u_long)np)
293 		errx(EXIT_FAILURE, "Invalid CPU number");
294 
295 	return id;
296 }
297 
298 static void
299 cpu_list(char **argv)
300 {
301 	const char *state, *intr;
302 	cpustate_t cs;
303 	u_int cnt, i;
304 	time_t lastmod;
305 	char ibuf[16], *ts;
306 
307 	if (ioctl(fd, IOC_CPU_GETCOUNT, &cnt) < 0)
308 		err(EXIT_FAILURE, "IOC_CPU_GETCOUNT");
309 
310 	printf(
311 "Num  HwId Unbound LWPs Interrupts Last change              #Intr\n"
312 "---- ---- ------------ ---------- ------------------------ -----\n");
313 
314 	for (i = 0; i < cnt; i++) {
315 		cs.cs_id = i;
316 		if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0)
317 			err(EXIT_FAILURE, "IOC_CPU_GETSTATE");
318 		if (ioctl(fd, IOC_CPU_MAPID, &cs.cs_id) < 0)
319 			err(EXIT_FAILURE, "IOC_CPU_MAPID");
320 		if (cs.cs_online)
321 			state = "online";
322 		else
323 			state = "offline";
324 		if (cs.cs_intr)
325 			intr = "intr";
326 		else
327 			intr = "nointr";
328 		if (cs.cs_intrcnt == 0)
329 			strcpy(ibuf, "?");
330 		else
331 			snprintf(ibuf, sizeof(ibuf), "%d", cs.cs_intrcnt - 1);
332 
333 		lastmod = (time_t)cs.cs_lastmod |
334 		    ((time_t)cs.cs_lastmodhi << 32);
335 		ts = asctime(localtime(&lastmod));
336 		ts[strlen(ts) - 1] = '\0';
337 		printf("%-4d %-4x %-12s %-10s %s %-5s\n",
338 		   i, cs.cs_hwid, state,
339 		   intr, ts, ibuf);
340 	}
341 }
342 
343 int
344 aprint_normal(const char *fmt, ...)
345 {
346 	va_list ap;
347 	int rv;
348 
349 	va_start(ap, fmt);
350 	rv = vfprintf(stdout, fmt, ap);
351 	va_end(ap);
352 
353 	return rv;
354 }
355 __strong_alias(aprint_verbose,aprint_normal)
356 __strong_alias(aprint_error,aprint_normal)
357 
358 int
359 aprint_normal_dev(const char *dev, const char *fmt, ...)
360 {
361 	va_list ap;
362 	int rv;
363 
364 	printf("%s: ", dev);
365 	va_start(ap, fmt);
366 	rv = vfprintf(stdout, fmt, ap);
367 	va_end(ap);
368 
369 	return rv;
370 }
371 __strong_alias(aprint_verbose_dev,aprint_normal_dev)
372 __strong_alias(aprint_error_dev,aprint_normal_dev)
373