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