1e085f869SStanislav Sedov /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 4f264409aSStanislav Sedov * Copyright (c) 2008-2011 Stanislav Sedov <stas@FreeBSD.org>. 5e085f869SStanislav Sedov * All rights reserved. 6e085f869SStanislav Sedov * 7e085f869SStanislav Sedov * Redistribution and use in source and binary forms, with or without 8e085f869SStanislav Sedov * modification, are permitted provided that the following conditions 9e085f869SStanislav Sedov * are met: 10e085f869SStanislav Sedov * 1. Redistributions of source code must retain the above copyright 11e085f869SStanislav Sedov * notice, this list of conditions and the following disclaimer. 12e085f869SStanislav Sedov * 2. Redistributions in binary form must reproduce the above copyright 13e085f869SStanislav Sedov * notice, this list of conditions and the following disclaimer in the 14e085f869SStanislav Sedov * documentation and/or other materials provided with the distribution. 15e085f869SStanislav Sedov * 16e085f869SStanislav Sedov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17e085f869SStanislav Sedov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18e085f869SStanislav Sedov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19e085f869SStanislav Sedov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20e085f869SStanislav Sedov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21e085f869SStanislav Sedov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22e085f869SStanislav Sedov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23e085f869SStanislav Sedov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24e085f869SStanislav Sedov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25e085f869SStanislav Sedov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26e085f869SStanislav Sedov */ 27e085f869SStanislav Sedov 28e085f869SStanislav Sedov /* 29e085f869SStanislav Sedov * This utility provides userland access to the cpuctl(4) pseudo-device 30e085f869SStanislav Sedov * features. 31e085f869SStanislav Sedov */ 32e085f869SStanislav Sedov 33e085f869SStanislav Sedov #include <sys/cdefs.h> 34e085f869SStanislav Sedov __FBSDID("$FreeBSD$"); 35e085f869SStanislav Sedov 36e085f869SStanislav Sedov #include <assert.h> 37*dee401e8SConrad Meyer #include <err.h> 38*dee401e8SConrad Meyer #include <errno.h> 39*dee401e8SConrad Meyer #include <dirent.h> 40*dee401e8SConrad Meyer #include <fcntl.h> 41e085f869SStanislav Sedov #include <stdio.h> 42e085f869SStanislav Sedov #include <stdlib.h> 43e085f869SStanislav Sedov #include <string.h> 44e085f869SStanislav Sedov #include <unistd.h> 45e085f869SStanislav Sedov #include <sysexits.h> 46e085f869SStanislav Sedov 47e085f869SStanislav Sedov #include <sys/queue.h> 48e085f869SStanislav Sedov #include <sys/param.h> 49e085f869SStanislav Sedov #include <sys/types.h> 50*dee401e8SConrad Meyer #include <sys/mman.h> 51e085f869SStanislav Sedov #include <sys/stat.h> 52e085f869SStanislav Sedov #include <sys/ioctl.h> 53e085f869SStanislav Sedov #include <sys/cpuctl.h> 54e085f869SStanislav Sedov 55e085f869SStanislav Sedov #include "cpucontrol.h" 56e085f869SStanislav Sedov #include "amd.h" 57e085f869SStanislav Sedov #include "intel.h" 5896ff3b75SFabien Thomas #include "via.h" 59e085f869SStanislav Sedov 60e085f869SStanislav Sedov int verbosity_level = 0; 61e085f869SStanislav Sedov 62e085f869SStanislav Sedov #define DEFAULT_DATADIR "/usr/local/share/cpucontrol" 63e085f869SStanislav Sedov 64e085f869SStanislav Sedov #define FLAG_I 0x01 65e085f869SStanislav Sedov #define FLAG_M 0x02 66e085f869SStanislav Sedov #define FLAG_U 0x04 670539c173SKonstantin Belousov #define FLAG_N 0x08 680530a936SKonstantin Belousov #define FLAG_E 0x10 69e085f869SStanislav Sedov 70b2d75854SStanislav Sedov #define OP_INVAL 0x00 71b2d75854SStanislav Sedov #define OP_READ 0x01 72b2d75854SStanislav Sedov #define OP_WRITE 0x02 73b2d75854SStanislav Sedov #define OP_OR 0x04 74b2d75854SStanislav Sedov #define OP_AND 0x08 75b2d75854SStanislav Sedov 76e085f869SStanislav Sedov #define HIGH(val) (uint32_t)(((val) >> 32) & 0xffffffff) 77e085f869SStanislav Sedov #define LOW(val) (uint32_t)((val) & 0xffffffff) 78e085f869SStanislav Sedov 79e085f869SStanislav Sedov struct datadir { 80e085f869SStanislav Sedov const char *path; 81e085f869SStanislav Sedov SLIST_ENTRY(datadir) next; 82e085f869SStanislav Sedov }; 8313e403fdSAntoine Brodin static SLIST_HEAD(, datadir) datadirs = SLIST_HEAD_INITIALIZER(datadirs); 84e085f869SStanislav Sedov 85bf70beceSEd Schouten static struct ucode_handler { 86e085f869SStanislav Sedov ucode_probe_t *probe; 87e085f869SStanislav Sedov ucode_update_t *update; 88e085f869SStanislav Sedov } handlers[] = { 89e085f869SStanislav Sedov { intel_probe, intel_update }, 900112b52bSAndriy Gapon { amd10h_probe, amd10h_update }, 91e085f869SStanislav Sedov { amd_probe, amd_update }, 9296ff3b75SFabien Thomas { via_probe, via_update }, 93e085f869SStanislav Sedov }; 94e085f869SStanislav Sedov #define NHANDLERS (sizeof(handlers) / sizeof(*handlers)) 95e085f869SStanislav Sedov 96e085f869SStanislav Sedov static void usage(void); 97e085f869SStanislav Sedov static int do_cpuid(const char *cmdarg, const char *dev); 98aa1cb750SAttilio Rao static int do_cpuid_count(const char *cmdarg, const char *dev); 99e085f869SStanislav Sedov static int do_msr(const char *cmdarg, const char *dev); 100e085f869SStanislav Sedov static int do_update(const char *dev); 101e085f869SStanislav Sedov static void datadir_add(const char *path); 102e085f869SStanislav Sedov 103e085f869SStanislav Sedov static void __dead2 10410bc3a7fSEd Schouten usage(void) 105e085f869SStanislav Sedov { 106e085f869SStanislav Sedov const char *name; 107e085f869SStanislav Sedov 108e085f869SStanislav Sedov name = getprogname(); 109e085f869SStanislav Sedov if (name == NULL) 110e085f869SStanislav Sedov name = "cpuctl"; 111e085f869SStanislav Sedov fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | " 1120530a936SKonstantin Belousov "-i level | -i level,level_type | -e | -u] device\n", name); 113e085f869SStanislav Sedov exit(EX_USAGE); 114e085f869SStanislav Sedov } 115e085f869SStanislav Sedov 116e085f869SStanislav Sedov static int 117e085f869SStanislav Sedov do_cpuid(const char *cmdarg, const char *dev) 118e085f869SStanislav Sedov { 119e085f869SStanislav Sedov unsigned int level; 120e085f869SStanislav Sedov cpuctl_cpuid_args_t args; 121e085f869SStanislav Sedov int fd, error; 122e085f869SStanislav Sedov char *endptr; 123e085f869SStanislav Sedov 124e085f869SStanislav Sedov assert(cmdarg != NULL); 125e085f869SStanislav Sedov assert(dev != NULL); 126e085f869SStanislav Sedov 127e085f869SStanislav Sedov level = strtoul(cmdarg, &endptr, 16); 128e085f869SStanislav Sedov if (*cmdarg == '\0' || *endptr != '\0') { 129e085f869SStanislav Sedov WARNX(0, "incorrect operand: %s", cmdarg); 130e085f869SStanislav Sedov usage(); 131e085f869SStanislav Sedov /* NOTREACHED */ 132e085f869SStanislav Sedov } 133e085f869SStanislav Sedov 134e085f869SStanislav Sedov /* 135e085f869SStanislav Sedov * Fill ioctl argument structure. 136e085f869SStanislav Sedov */ 137e085f869SStanislav Sedov args.level = level; 138e085f869SStanislav Sedov fd = open(dev, O_RDONLY); 139e085f869SStanislav Sedov if (fd < 0) { 140cbcc5579SStanislav Sedov WARN(0, "error opening %s for reading", dev); 141e085f869SStanislav Sedov return (1); 142e085f869SStanislav Sedov } 143e085f869SStanislav Sedov error = ioctl(fd, CPUCTL_CPUID, &args); 144e085f869SStanislav Sedov if (error < 0) { 145cbcc5579SStanislav Sedov WARN(0, "ioctl(%s, CPUCTL_CPUID)", dev); 146e085f869SStanislav Sedov close(fd); 147e085f869SStanislav Sedov return (error); 148e085f869SStanislav Sedov } 149e085f869SStanislav Sedov fprintf(stdout, "cpuid level 0x%x: 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", 150e085f869SStanislav Sedov level, args.data[0], args.data[1], args.data[2], args.data[3]); 151e085f869SStanislav Sedov close(fd); 152e085f869SStanislav Sedov return (0); 153e085f869SStanislav Sedov } 154e085f869SStanislav Sedov 155e085f869SStanislav Sedov static int 156aa1cb750SAttilio Rao do_cpuid_count(const char *cmdarg, const char *dev) 157aa1cb750SAttilio Rao { 158aa1cb750SAttilio Rao char *cmdarg1, *endptr, *endptr1; 159aa1cb750SAttilio Rao unsigned int level, level_type; 160cef789cdSKonstantin Belousov cpuctl_cpuid_count_args_t args; 161aa1cb750SAttilio Rao int fd, error; 162aa1cb750SAttilio Rao 163aa1cb750SAttilio Rao assert(cmdarg != NULL); 164aa1cb750SAttilio Rao assert(dev != NULL); 165aa1cb750SAttilio Rao 166aa1cb750SAttilio Rao level = strtoul(cmdarg, &endptr, 16); 167aa1cb750SAttilio Rao if (*cmdarg == '\0' || *endptr == '\0') { 168aa1cb750SAttilio Rao WARNX(0, "incorrect or missing operand: %s", cmdarg); 169aa1cb750SAttilio Rao usage(); 170aa1cb750SAttilio Rao /* NOTREACHED */ 171aa1cb750SAttilio Rao } 172aa1cb750SAttilio Rao /* Locate the comma... */ 173aa1cb750SAttilio Rao cmdarg1 = strstr(endptr, ","); 174aa1cb750SAttilio Rao /* ... and skip past it */ 175aa1cb750SAttilio Rao cmdarg1 += 1; 176aa1cb750SAttilio Rao level_type = strtoul(cmdarg1, &endptr1, 16); 177aa1cb750SAttilio Rao if (*cmdarg1 == '\0' || *endptr1 != '\0') { 178aa1cb750SAttilio Rao WARNX(0, "incorrect or missing operand: %s", cmdarg); 179aa1cb750SAttilio Rao usage(); 180aa1cb750SAttilio Rao /* NOTREACHED */ 181aa1cb750SAttilio Rao } 182aa1cb750SAttilio Rao 183aa1cb750SAttilio Rao /* 184aa1cb750SAttilio Rao * Fill ioctl argument structure. 185aa1cb750SAttilio Rao */ 186aa1cb750SAttilio Rao args.level = level; 187aa1cb750SAttilio Rao args.level_type = level_type; 188aa1cb750SAttilio Rao fd = open(dev, O_RDONLY); 189aa1cb750SAttilio Rao if (fd < 0) { 190aa1cb750SAttilio Rao WARN(0, "error opening %s for reading", dev); 191aa1cb750SAttilio Rao return (1); 192aa1cb750SAttilio Rao } 193aa1cb750SAttilio Rao error = ioctl(fd, CPUCTL_CPUID_COUNT, &args); 194aa1cb750SAttilio Rao if (error < 0) { 195aa1cb750SAttilio Rao WARN(0, "ioctl(%s, CPUCTL_CPUID_COUNT)", dev); 196aa1cb750SAttilio Rao close(fd); 197aa1cb750SAttilio Rao return (error); 198aa1cb750SAttilio Rao } 199aa1cb750SAttilio Rao fprintf(stdout, "cpuid level 0x%x, level_type 0x%x: 0x%.8x 0x%.8x " 200aa1cb750SAttilio Rao "0x%.8x 0x%.8x\n", level, level_type, args.data[0], args.data[1], 201aa1cb750SAttilio Rao args.data[2], args.data[3]); 202aa1cb750SAttilio Rao close(fd); 203aa1cb750SAttilio Rao return (0); 204aa1cb750SAttilio Rao } 205aa1cb750SAttilio Rao 206aa1cb750SAttilio Rao static int 207e085f869SStanislav Sedov do_msr(const char *cmdarg, const char *dev) 208e085f869SStanislav Sedov { 209e085f869SStanislav Sedov unsigned int msr; 210e085f869SStanislav Sedov cpuctl_msr_args_t args; 211b2d75854SStanislav Sedov size_t len; 212b2d75854SStanislav Sedov uint64_t data = 0; 213b2d75854SStanislav Sedov unsigned long command; 214b2d75854SStanislav Sedov int do_invert = 0, op; 215e085f869SStanislav Sedov int fd, error; 216f264409aSStanislav Sedov const char *command_name; 217e085f869SStanislav Sedov char *endptr; 218b2d75854SStanislav Sedov char *p; 219e085f869SStanislav Sedov 220e085f869SStanislav Sedov assert(cmdarg != NULL); 221e085f869SStanislav Sedov assert(dev != NULL); 222b2d75854SStanislav Sedov len = strlen(cmdarg); 223b2d75854SStanislav Sedov if (len == 0) { 224b2d75854SStanislav Sedov WARNX(0, "MSR register expected"); 225b2d75854SStanislav Sedov usage(); 226b2d75854SStanislav Sedov /* NOTREACHED */ 227b2d75854SStanislav Sedov } 228e085f869SStanislav Sedov 229b2d75854SStanislav Sedov /* 230b2d75854SStanislav Sedov * Parse command string. 231b2d75854SStanislav Sedov */ 232b2d75854SStanislav Sedov msr = strtoul(cmdarg, &endptr, 16); 233b2d75854SStanislav Sedov switch (*endptr) { 234b2d75854SStanislav Sedov case '\0': 235b2d75854SStanislav Sedov op = OP_READ; 236b2d75854SStanislav Sedov break; 237b2d75854SStanislav Sedov case '=': 238b2d75854SStanislav Sedov op = OP_WRITE; 239b2d75854SStanislav Sedov break; 240b2d75854SStanislav Sedov case '&': 241b2d75854SStanislav Sedov op = OP_AND; 242b2d75854SStanislav Sedov endptr++; 243b2d75854SStanislav Sedov break; 244b2d75854SStanislav Sedov case '|': 245b2d75854SStanislav Sedov op = OP_OR; 246b2d75854SStanislav Sedov endptr++; 247b2d75854SStanislav Sedov break; 248b2d75854SStanislav Sedov default: 249b2d75854SStanislav Sedov op = OP_INVAL; 250b2d75854SStanislav Sedov } 251b2d75854SStanislav Sedov if (op != OP_READ) { /* Complex operation. */ 252b2d75854SStanislav Sedov if (*endptr != '=') 253b2d75854SStanislav Sedov op = OP_INVAL; 254b2d75854SStanislav Sedov else { 255b2d75854SStanislav Sedov p = ++endptr; 256b2d75854SStanislav Sedov if (*p == '~') { 257b2d75854SStanislav Sedov do_invert = 1; 258b2d75854SStanislav Sedov p++; 259b2d75854SStanislav Sedov } 260b2d75854SStanislav Sedov data = strtoull(p, &endptr, 16); 261e085f869SStanislav Sedov if (*p == '\0' || *endptr != '\0') { 262b2d75854SStanislav Sedov WARNX(0, "argument required: %s", cmdarg); 263e085f869SStanislav Sedov usage(); 264e085f869SStanislav Sedov /* NOTREACHED */ 265e085f869SStanislav Sedov } 266e085f869SStanislav Sedov } 267b2d75854SStanislav Sedov } 268b2d75854SStanislav Sedov if (op == OP_INVAL) { 269b2d75854SStanislav Sedov WARNX(0, "invalid operator: %s", cmdarg); 270e085f869SStanislav Sedov usage(); 271e085f869SStanislav Sedov /* NOTREACHED */ 272e085f869SStanislav Sedov } 273e085f869SStanislav Sedov 274e085f869SStanislav Sedov /* 275e085f869SStanislav Sedov * Fill ioctl argument structure. 276e085f869SStanislav Sedov */ 277e085f869SStanislav Sedov args.msr = msr; 278b2d75854SStanislav Sedov if ((do_invert != 0) ^ (op == OP_AND)) 279b2d75854SStanislav Sedov args.data = ~data; 280b2d75854SStanislav Sedov else 281b2d75854SStanislav Sedov args.data = data; 282b2d75854SStanislav Sedov switch (op) { 283b2d75854SStanislav Sedov case OP_READ: 284b2d75854SStanislav Sedov command = CPUCTL_RDMSR; 2853b232eb6SStanislav Sedov command_name = "RDMSR"; 286b2d75854SStanislav Sedov break; 287b2d75854SStanislav Sedov case OP_WRITE: 288b2d75854SStanislav Sedov command = CPUCTL_WRMSR; 2893b232eb6SStanislav Sedov command_name = "WRMSR"; 290b2d75854SStanislav Sedov break; 291b2d75854SStanislav Sedov case OP_OR: 292b2d75854SStanislav Sedov command = CPUCTL_MSRSBIT; 2933b232eb6SStanislav Sedov command_name = "MSRSBIT"; 294b2d75854SStanislav Sedov break; 295b2d75854SStanislav Sedov case OP_AND: 296b2d75854SStanislav Sedov command = CPUCTL_MSRCBIT; 2973b232eb6SStanislav Sedov command_name = "MSRCBIT"; 298b2d75854SStanislav Sedov break; 299b2d75854SStanislav Sedov default: 300b2d75854SStanislav Sedov abort(); 301b2d75854SStanislav Sedov } 302b2d75854SStanislav Sedov fd = open(dev, op == OP_READ ? O_RDONLY : O_WRONLY); 303e085f869SStanislav Sedov if (fd < 0) { 304cbcc5579SStanislav Sedov WARN(0, "error opening %s for %s", dev, 305b2d75854SStanislav Sedov op == OP_READ ? "reading" : "writing"); 306e085f869SStanislav Sedov return (1); 307e085f869SStanislav Sedov } 308b2d75854SStanislav Sedov error = ioctl(fd, command, &args); 309e085f869SStanislav Sedov if (error < 0) { 3103b232eb6SStanislav Sedov WARN(0, "ioctl(%s, CPUCTL_%s (%lu))", dev, command_name, command); 311e085f869SStanislav Sedov close(fd); 312e085f869SStanislav Sedov return (1); 313e085f869SStanislav Sedov } 314b2d75854SStanislav Sedov if (op == OP_READ) 315e085f869SStanislav Sedov fprintf(stdout, "MSR 0x%x: 0x%.8x 0x%.8x\n", msr, 316e085f869SStanislav Sedov HIGH(args.data), LOW(args.data)); 317e085f869SStanislav Sedov close(fd); 318e085f869SStanislav Sedov return (0); 319e085f869SStanislav Sedov } 320e085f869SStanislav Sedov 321e085f869SStanislav Sedov static int 3220530a936SKonstantin Belousov do_eval_cpu_features(const char *dev) 3230530a936SKonstantin Belousov { 3240530a936SKonstantin Belousov int fd, error; 3250530a936SKonstantin Belousov 3260530a936SKonstantin Belousov assert(dev != NULL); 3270530a936SKonstantin Belousov 3280530a936SKonstantin Belousov fd = open(dev, O_RDWR); 3290530a936SKonstantin Belousov if (fd < 0) { 3300530a936SKonstantin Belousov WARN(0, "error opening %s for writing", dev); 3310530a936SKonstantin Belousov return (1); 3320530a936SKonstantin Belousov } 3330530a936SKonstantin Belousov error = ioctl(fd, CPUCTL_EVAL_CPU_FEATURES, NULL); 3340530a936SKonstantin Belousov if (error < 0) 3350530a936SKonstantin Belousov WARN(0, "ioctl(%s, CPUCTL_EVAL_CPU_FEATURES)", dev); 3360530a936SKonstantin Belousov close(fd); 3370530a936SKonstantin Belousov return (error); 3380530a936SKonstantin Belousov } 3390530a936SKonstantin Belousov 3400530a936SKonstantin Belousov static int 341*dee401e8SConrad Meyer try_a_fw_image(const char *dev_path, int devfd, int fwdfd, const char *dpath, 342*dee401e8SConrad Meyer const char *fname, struct ucode_handler *handler) 343*dee401e8SConrad Meyer { 344*dee401e8SConrad Meyer struct ucode_update_params parm; 345*dee401e8SConrad Meyer struct stat st; 346*dee401e8SConrad Meyer char *fw_path; 347*dee401e8SConrad Meyer void *fw_map; 348*dee401e8SConrad Meyer int fwfd, rc; 349*dee401e8SConrad Meyer 350*dee401e8SConrad Meyer rc = 0; 351*dee401e8SConrad Meyer fw_path = NULL; 352*dee401e8SConrad Meyer fw_map = MAP_FAILED; 353*dee401e8SConrad Meyer fwfd = openat(fwdfd, fname, O_RDONLY); 354*dee401e8SConrad Meyer if (fwfd < 0) { 355*dee401e8SConrad Meyer WARN(0, "openat(%s, %s)", dpath, fname); 356*dee401e8SConrad Meyer goto out; 357*dee401e8SConrad Meyer } 358*dee401e8SConrad Meyer 359*dee401e8SConrad Meyer rc = asprintf(&fw_path, "%s/%s", dpath, fname); 360*dee401e8SConrad Meyer if (rc == -1) { 361*dee401e8SConrad Meyer WARNX(0, "out of memory"); 362*dee401e8SConrad Meyer rc = ENOMEM; 363*dee401e8SConrad Meyer goto out; 364*dee401e8SConrad Meyer } 365*dee401e8SConrad Meyer 366*dee401e8SConrad Meyer rc = fstat(fwfd, &st); 367*dee401e8SConrad Meyer if (rc != 0) { 368*dee401e8SConrad Meyer WARN(0, "fstat(%s)", fw_path); 369*dee401e8SConrad Meyer rc = 0; 370*dee401e8SConrad Meyer goto out; 371*dee401e8SConrad Meyer } 372*dee401e8SConrad Meyer if (st.st_size <= 0) { 373*dee401e8SConrad Meyer WARN(0, "%s: empty", fw_path); 374*dee401e8SConrad Meyer goto out; 375*dee401e8SConrad Meyer } 376*dee401e8SConrad Meyer 377*dee401e8SConrad Meyer fw_map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fwfd, 0); 378*dee401e8SConrad Meyer if (fw_map == MAP_FAILED) { 379*dee401e8SConrad Meyer WARN(0, "mmap(%s)", fw_path); 380*dee401e8SConrad Meyer goto out; 381*dee401e8SConrad Meyer } 382*dee401e8SConrad Meyer 383*dee401e8SConrad Meyer 384*dee401e8SConrad Meyer memset(&parm, 0, sizeof(parm)); 385*dee401e8SConrad Meyer parm.devfd = devfd; 386*dee401e8SConrad Meyer parm.fwimage = fw_map; 387*dee401e8SConrad Meyer parm.fwsize = st.st_size; 388*dee401e8SConrad Meyer parm.dev_path = dev_path; 389*dee401e8SConrad Meyer parm.fw_path = fw_path; 390*dee401e8SConrad Meyer 391*dee401e8SConrad Meyer handler->update(&parm); 392*dee401e8SConrad Meyer 393*dee401e8SConrad Meyer out: 394*dee401e8SConrad Meyer if (fw_map != MAP_FAILED) 395*dee401e8SConrad Meyer munmap(fw_map, st.st_size); 396*dee401e8SConrad Meyer free(fw_path); 397*dee401e8SConrad Meyer if (fwfd >= 0) 398*dee401e8SConrad Meyer close(fwfd); 399*dee401e8SConrad Meyer return (rc); 400*dee401e8SConrad Meyer } 401*dee401e8SConrad Meyer 402*dee401e8SConrad Meyer static int 403e085f869SStanislav Sedov do_update(const char *dev) 404e085f869SStanislav Sedov { 405*dee401e8SConrad Meyer int fd, fwdfd; 406e085f869SStanislav Sedov unsigned int i; 407e085f869SStanislav Sedov int error; 408e085f869SStanislav Sedov struct ucode_handler *handler; 409e085f869SStanislav Sedov struct datadir *dir; 4100bb2aabfSGleb Kurtsou DIR *dirp; 411e085f869SStanislav Sedov struct dirent *direntry; 412e085f869SStanislav Sedov 413e085f869SStanislav Sedov fd = open(dev, O_RDONLY); 414e085f869SStanislav Sedov if (fd < 0) { 415cbcc5579SStanislav Sedov WARN(0, "error opening %s for reading", dev); 416e085f869SStanislav Sedov return (1); 417e085f869SStanislav Sedov } 418e085f869SStanislav Sedov 419e085f869SStanislav Sedov /* 420*dee401e8SConrad Meyer * Find the appropriate handler for CPU. 421e085f869SStanislav Sedov */ 422e085f869SStanislav Sedov for (i = 0; i < NHANDLERS; i++) 423e085f869SStanislav Sedov if (handlers[i].probe(fd) == 0) 424e085f869SStanislav Sedov break; 425e085f869SStanislav Sedov if (i < NHANDLERS) 426e085f869SStanislav Sedov handler = &handlers[i]; 427e085f869SStanislav Sedov else { 428*dee401e8SConrad Meyer WARNX(0, "cannot find the appropriate handler for %s", dev); 429e085f869SStanislav Sedov close(fd); 430e085f869SStanislav Sedov return (1); 431e085f869SStanislav Sedov } 432e085f869SStanislav Sedov close(fd); 433e085f869SStanislav Sedov 434*dee401e8SConrad Meyer fd = open(dev, O_RDWR); 435*dee401e8SConrad Meyer if (fd < 0) { 436*dee401e8SConrad Meyer WARN(0, "error opening %s for writing", dev); 437*dee401e8SConrad Meyer return (1); 438*dee401e8SConrad Meyer } 439*dee401e8SConrad Meyer 440e085f869SStanislav Sedov /* 441e085f869SStanislav Sedov * Process every image in specified data directories. 442e085f869SStanislav Sedov */ 443e085f869SStanislav Sedov SLIST_FOREACH(dir, &datadirs, next) { 444*dee401e8SConrad Meyer fwdfd = open(dir->path, O_RDONLY); 445*dee401e8SConrad Meyer if (fwdfd < 0) { 446*dee401e8SConrad Meyer WARN(1, "skipping directory %s: not accessible", dir->path); 447e085f869SStanislav Sedov continue; 448e085f869SStanislav Sedov } 449*dee401e8SConrad Meyer dirp = fdopendir(fwdfd); 450*dee401e8SConrad Meyer if (dirp == NULL) { 451*dee401e8SConrad Meyer WARNX(0, "out of memory"); 452*dee401e8SConrad Meyer close(fwdfd); 453*dee401e8SConrad Meyer close(fd); 454*dee401e8SConrad Meyer return (1); 455*dee401e8SConrad Meyer } 456*dee401e8SConrad Meyer 4570bb2aabfSGleb Kurtsou while ((direntry = readdir(dirp)) != NULL) { 458e085f869SStanislav Sedov if (direntry->d_namlen == 0) 459e085f869SStanislav Sedov continue; 460*dee401e8SConrad Meyer if (direntry->d_type == DT_DIR) 461e085f869SStanislav Sedov continue; 462*dee401e8SConrad Meyer 463*dee401e8SConrad Meyer error = try_a_fw_image(dev, fd, fwdfd, dir->path, 464*dee401e8SConrad Meyer direntry->d_name, handler); 465*dee401e8SConrad Meyer if (error != 0) { 466*dee401e8SConrad Meyer closedir(dirp); 467*dee401e8SConrad Meyer close(fd); 468*dee401e8SConrad Meyer return (1); 469e085f869SStanislav Sedov } 470e085f869SStanislav Sedov } 4710bb2aabfSGleb Kurtsou error = closedir(dirp); 472e085f869SStanislav Sedov if (error != 0) 473e085f869SStanislav Sedov WARN(0, "closedir(%s)", dir->path); 474e085f869SStanislav Sedov } 475*dee401e8SConrad Meyer close(fd); 476e085f869SStanislav Sedov return (0); 477e085f869SStanislav Sedov } 478e085f869SStanislav Sedov 479e085f869SStanislav Sedov /* 480e085f869SStanislav Sedov * Add new data directory to the search list. 481e085f869SStanislav Sedov */ 482e085f869SStanislav Sedov static void 483e085f869SStanislav Sedov datadir_add(const char *path) 484e085f869SStanislav Sedov { 485e085f869SStanislav Sedov struct datadir *newdir; 486e085f869SStanislav Sedov 487e085f869SStanislav Sedov newdir = (struct datadir *)malloc(sizeof(*newdir)); 488e085f869SStanislav Sedov if (newdir == NULL) 489e085f869SStanislav Sedov err(EX_OSERR, "cannot allocate memory"); 490e085f869SStanislav Sedov newdir->path = path; 491e085f869SStanislav Sedov SLIST_INSERT_HEAD(&datadirs, newdir, next); 492e085f869SStanislav Sedov } 493e085f869SStanislav Sedov 494e085f869SStanislav Sedov int 495e085f869SStanislav Sedov main(int argc, char *argv[]) 496e085f869SStanislav Sedov { 497*dee401e8SConrad Meyer struct datadir *elm; 498e085f869SStanislav Sedov int c, flags; 499e085f869SStanislav Sedov const char *cmdarg; 500e085f869SStanislav Sedov const char *dev; 501e085f869SStanislav Sedov int error; 502e085f869SStanislav Sedov 503e085f869SStanislav Sedov flags = 0; 504e085f869SStanislav Sedov error = 0; 505e085f869SStanislav Sedov cmdarg = ""; /* To keep gcc3 happy. */ 506e085f869SStanislav Sedov 5070530a936SKonstantin Belousov while ((c = getopt(argc, argv, "d:ehi:m:nuv")) != -1) { 508e085f869SStanislav Sedov switch (c) { 509e085f869SStanislav Sedov case 'd': 510e085f869SStanislav Sedov datadir_add(optarg); 511e085f869SStanislav Sedov break; 5120530a936SKonstantin Belousov case 'e': 5130530a936SKonstantin Belousov flags |= FLAG_E; 5140530a936SKonstantin Belousov break; 515e085f869SStanislav Sedov case 'i': 516e085f869SStanislav Sedov flags |= FLAG_I; 517e085f869SStanislav Sedov cmdarg = optarg; 518e085f869SStanislav Sedov break; 519e085f869SStanislav Sedov case 'm': 520e085f869SStanislav Sedov flags |= FLAG_M; 521e085f869SStanislav Sedov cmdarg = optarg; 522e085f869SStanislav Sedov break; 5230539c173SKonstantin Belousov case 'n': 5240539c173SKonstantin Belousov flags |= FLAG_N; 5250539c173SKonstantin Belousov break; 526e085f869SStanislav Sedov case 'u': 527e085f869SStanislav Sedov flags |= FLAG_U; 528e085f869SStanislav Sedov break; 529e085f869SStanislav Sedov case 'v': 530e085f869SStanislav Sedov verbosity_level++; 531e085f869SStanislav Sedov break; 532e085f869SStanislav Sedov case 'h': 533e085f869SStanislav Sedov /* FALLTHROUGH */ 534e085f869SStanislav Sedov default: 535e085f869SStanislav Sedov usage(); 536e085f869SStanislav Sedov /* NOTREACHED */ 537e085f869SStanislav Sedov } 538e085f869SStanislav Sedov } 539e085f869SStanislav Sedov argc -= optind; 540e085f869SStanislav Sedov argv += optind; 541e085f869SStanislav Sedov if (argc < 1) { 542e085f869SStanislav Sedov usage(); 543e085f869SStanislav Sedov /* NOTREACHED */ 544e085f869SStanislav Sedov } 5450539c173SKonstantin Belousov if ((flags & FLAG_N) == 0) 5460539c173SKonstantin Belousov datadir_add(DEFAULT_DATADIR); 547e085f869SStanislav Sedov dev = argv[0]; 5480530a936SKonstantin Belousov c = flags & (FLAG_E | FLAG_I | FLAG_M | FLAG_U); 549e085f869SStanislav Sedov switch (c) { 550e085f869SStanislav Sedov case FLAG_I: 551aa1cb750SAttilio Rao if (strstr(cmdarg, ",") != NULL) 552aa1cb750SAttilio Rao error = do_cpuid_count(cmdarg, dev); 553aa1cb750SAttilio Rao else 554e085f869SStanislav Sedov error = do_cpuid(cmdarg, dev); 555e085f869SStanislav Sedov break; 556e085f869SStanislav Sedov case FLAG_M: 557e085f869SStanislav Sedov error = do_msr(cmdarg, dev); 558e085f869SStanislav Sedov break; 559e085f869SStanislav Sedov case FLAG_U: 560e085f869SStanislav Sedov error = do_update(dev); 561e085f869SStanislav Sedov break; 5620530a936SKonstantin Belousov case FLAG_E: 5630530a936SKonstantin Belousov error = do_eval_cpu_features(dev); 5640530a936SKonstantin Belousov break; 565e085f869SStanislav Sedov default: 566e085f869SStanislav Sedov usage(); /* Only one command can be selected. */ 567e085f869SStanislav Sedov } 568*dee401e8SConrad Meyer while ((elm = SLIST_FIRST(&datadirs)) != NULL) { 569*dee401e8SConrad Meyer SLIST_REMOVE_HEAD(&datadirs, next); 570*dee401e8SConrad Meyer free(elm); 571*dee401e8SConrad Meyer } 57278a6a430SKonstantin Belousov return (error == 0 ? 0 : 1); 573e085f869SStanislav Sedov } 574