1/* $NetBSD: cpuctl.c,v 1.19 2011/09/27 11:24:21 jruoho 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.19 2011/09/27 11:24:21 jruoho 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 57static u_int getcpuid(char **); 58__dead static void usage(void); 59 60static void cpu_identify(char **); 61static void cpu_list(char **); 62static void cpu_offline(char **); 63static void cpu_online(char **); 64static void cpu_intr(char **); 65static void cpu_nointr(char **); 66static void cpu_ucode(char **); 67 68static 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 84static int fd; 85 86int 87main(int argc, char **argv) 88{ 89 const struct cmdtab *ct; 90 91 if (argc < 2) 92 usage(); 93 94 if ((fd = open(_PATH_CPUCTL, O_RDWR)) < 0) 95 err(EXIT_FAILURE, _PATH_CPUCTL); 96 97 for (ct = cpu_cmdtab; ct->label != NULL; ct++) { 98 if (strcmp(argv[1], ct->label) == 0) { 99 if (!ct->argsoptional && 100 ((ct->takesargs == 0) ^ (argv[2] == NULL))) 101 { 102 usage(); 103 } 104 (*ct->func)(argv + 2); 105 break; 106 } 107 } 108 109 if (ct->label == NULL) 110 errx(EXIT_FAILURE, "unknown command ``%s''", argv[optind]); 111 112 close(fd); 113 exit(EXIT_SUCCESS); 114 /* NOTREACHED */ 115} 116 117static void 118usage(void) 119{ 120 const char *progname = getprogname(); 121 122 fprintf(stderr, "usage: %s identify cpuno\n", progname); 123 fprintf(stderr, " %s list\n", progname); 124 fprintf(stderr, " %s offline cpuno\n", progname); 125 fprintf(stderr, " %s online cpuno\n", progname); 126 fprintf(stderr, " %s intr cpuno\n", progname); 127 fprintf(stderr, " %s nointr cpuno\n", progname); 128 fprintf(stderr, " %s ucode [file]\n", progname); 129 exit(EXIT_FAILURE); 130 /* NOTREACHED */ 131} 132 133static void 134cpu_online(char **argv) 135{ 136 cpustate_t cs; 137 138 cs.cs_id = getcpuid(argv); 139 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 140 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 141 cs.cs_online = true; 142 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) 143 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 144} 145 146static void 147cpu_offline(char **argv) 148{ 149 cpustate_t cs; 150 151 cs.cs_id = getcpuid(argv); 152 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 153 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 154 cs.cs_online = false; 155 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) 156 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 157} 158 159static void 160cpu_intr(char **argv) 161{ 162 cpustate_t cs; 163 164 cs.cs_id = getcpuid(argv); 165 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 166 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 167 cs.cs_intr = true; 168 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) 169 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 170} 171 172static void 173cpu_nointr(char **argv) 174{ 175 cpustate_t cs; 176 177 cs.cs_id = getcpuid(argv); 178 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 179 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 180 cs.cs_intr = false; 181 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) { 182 if (errno == EOPNOTSUPP) { 183 warnx("interrupt control not supported on " 184 "this platform"); 185 } else 186 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 187 } 188} 189 190static void 191cpu_ucode(char **argv) 192{ 193 int error; 194 struct cpu_ucode uc; 195 196 if (argv[0] != NULL) 197 strlcpy(uc.fwname, argv[0], sizeof(uc.fwname)); 198 else 199 memset(uc.fwname, '\0', sizeof(uc.fwname)); 200 201 error = ioctl(fd, IOC_CPU_UCODE_APPLY, &uc); 202 if (error < 0) { 203 if (uc.fwname[0]) 204 err(EXIT_FAILURE, "%s", uc.fwname); 205 else 206 err(EXIT_FAILURE, "IOC_CPU_UCODE_APPLY"); 207 } 208} 209 210 211static void 212cpu_identify(char **argv) 213{ 214 char name[32]; 215 unsigned int id, np; 216 cpuset_t *cpuset; 217 struct cpu_ucode ucode; 218 char ucbuf[16]; 219 220 np = sysconf(_SC_NPROCESSORS_CONF); 221 id = getcpuid(argv); 222 snprintf(name, sizeof(name), "cpu%u", id); 223 224 if (np != 0) { 225 cpuset = cpuset_create(); 226 if (cpuset == NULL) 227 err(EXIT_FAILURE, "cpuset_create"); 228 cpuset_zero(cpuset); 229 cpuset_set(id, cpuset); 230 if (_sched_setaffinity(0, 0, cpuset_size(cpuset), cpuset) < 0) { 231 if (errno == EPERM) { 232 printf("Cannot bind to target CPU. Output " 233 "may not accurately describe the target.\n" 234 "Run as root to allow binding.\n\n"); 235 } else { 236 err(EXIT_FAILURE, "_sched_setaffinity"); 237 } 238 } 239 cpuset_destroy(cpuset); 240 } 241 identifycpu(name); 242 243 if (ioctl(fd, IOC_CPU_UCODE_GET_VERSION, &ucode) < 0) 244 ucode.version = (uint64_t)-1; 245 if (ucode.version == (uint64_t)-1) 246 strcpy(ucbuf, "?"); 247 else 248 snprintf(ucbuf, sizeof(ucbuf), "0x%"PRIx64, 249 ucode.version); 250 251 printf("%s: UCode version: %s\n", name, ucbuf); 252} 253 254static u_int 255getcpuid(char **argv) 256{ 257 char *argp; 258 u_int id; 259 long np; 260 261 id = (u_int)strtoul(argv[0], &argp, 0); 262 if (*argp != '\0') 263 usage(); 264 265 np = sysconf(_SC_NPROCESSORS_CONF); 266 if (id >= (u_long)np) 267 errx(EXIT_FAILURE, "Invalid CPU number"); 268 269 return id; 270} 271 272static void 273cpu_list(char **argv) 274{ 275 const char *state, *intr; 276 cpustate_t cs; 277 u_int cnt, i; 278 time_t lastmod; 279 char ibuf[16], *ts; 280 281 if (ioctl(fd, IOC_CPU_GETCOUNT, &cnt) < 0) 282 err(EXIT_FAILURE, "IOC_CPU_GETCOUNT"); 283 284 printf( 285"Num HwId Unbound LWPs Interrupts Last change #Intr\n" 286"---- ---- ------------ ---------- ------------------------ -----\n"); 287 288 for (i = 0; i < cnt; i++) { 289 cs.cs_id = i; 290 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 291 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 292 if (ioctl(fd, IOC_CPU_MAPID, &cs.cs_id) < 0) 293 err(EXIT_FAILURE, "IOC_CPU_MAPID"); 294 if (cs.cs_online) 295 state = "online"; 296 else 297 state = "offline"; 298 if (cs.cs_intr) 299 intr = "intr"; 300 else 301 intr = "nointr"; 302 if (cs.cs_intrcnt == 0) 303 strcpy(ibuf, "?"); 304 else 305 snprintf(ibuf, sizeof(ibuf), "%d", cs.cs_intrcnt - 1); 306 307 lastmod = (time_t)cs.cs_lastmod | 308 ((time_t)cs.cs_lastmodhi << 32); 309 ts = asctime(localtime(&lastmod)); 310 ts[strlen(ts) - 1] = '\0'; 311 printf("%-4d %-4x %-12s %-10s %s %-5s\n", 312 i, cs.cs_hwid, state, 313 intr, ts, ibuf); 314 } 315} 316 317int 318aprint_normal(const char *fmt, ...) 319{ 320 va_list ap; 321 int rv; 322 323 va_start(ap, fmt); 324 rv = vfprintf(stdout, fmt, ap); 325 va_end(ap); 326 327 return rv; 328} 329__strong_alias(aprint_verbose,aprint_normal) 330__strong_alias(aprint_error,aprint_normal) 331 332int 333aprint_normal_dev(const char *dev, const char *fmt, ...) 334{ 335 va_list ap; 336 int rv; 337 338 printf("%s: ", dev); 339 va_start(ap, fmt); 340 rv = vfprintf(stdout, fmt, ap); 341 va_end(ap); 342 343 return rv; 344} 345__strong_alias(aprint_verbose_dev,aprint_normal_dev) 346__strong_alias(aprint_error_dev,aprint_normal_dev) 347