Index: head/usr.sbin/cpucontrol/amd.c =================================================================== --- head/usr.sbin/cpucontrol/amd.c (revision 340420) +++ head/usr.sbin/cpucontrol/amd.c (revision 340421) @@ -1,183 +1,155 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006, 2008 Stanislav Sedov . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpucontrol.h" #include "amd.h" int amd_probe(int fd) { char vendor[13]; int error; cpuctl_cpuid_args_t idargs = { .level = 0, }; error = ioctl(fd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); return (1); } ((uint32_t *)vendor)[0] = idargs.data[1]; ((uint32_t *)vendor)[1] = idargs.data[3]; ((uint32_t *)vendor)[2] = idargs.data[2]; vendor[12] = '\0'; if (strncmp(vendor, AMD_VENDOR_ID, sizeof(AMD_VENDOR_ID)) != 0) return (1); return (0); } void -amd_update(const char *dev, const char *path) +amd_update(const struct ucode_update_params *params) { - int fd, devfd; + int devfd; unsigned int i; - struct stat st; - uint32_t *fw_image; - amd_fw_header_t *fw_header; + const char *dev, *path; + const uint32_t *fw_image; + const amd_fw_header_t *fw_header; uint32_t sum; uint32_t signature; - uint32_t *fw_data; + const uint32_t *fw_data; size_t fw_size; cpuctl_cpuid_args_t idargs = { .level = 1, /* Request signature. */ }; cpuctl_update_args_t args; int error; + dev = params->dev_path; + path = params->fw_path; + devfd = params->devfd; + fw_image = params->fwimage; + assert(path); assert(dev); - fd = -1; - fw_image = MAP_FAILED; - devfd = open(dev, O_RDWR); - if (devfd < 0) { - WARN(0, "could not open %s for writing", dev); - return; - } error = ioctl(devfd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); goto fail; } signature = idargs.data[0]; WARNX(2, "found cpu family %#x model %#x " "stepping %#x extfamily %#x extmodel %#x.", (signature >> 8) & 0x0f, (signature >> 4) & 0x0f, (signature >> 0) & 0x0f, (signature >> 20) & 0xff, (signature >> 16) & 0x0f); /* * Open the firmware file. */ - fd = open(path, O_RDONLY, 0); - if (fd < 0) { - WARN(0, "open(%s)", path); - goto fail; - } - error = fstat(fd, &st); - if (error != 0) { - WARN(0, "fstat(%s)", path); - goto fail; - } - if (st.st_size < 0 || (unsigned)st.st_size < sizeof(*fw_header)) { + if (params->fwsize < sizeof(*fw_header)) { WARNX(2, "file too short: %s", path); goto fail; } - /* - * mmap the whole image. - */ - fw_image = (uint32_t *)mmap(NULL, st.st_size, PROT_READ, - MAP_PRIVATE, fd, 0); - if (fw_image == MAP_FAILED) { - WARN(0, "mmap(%s)", path); - goto fail; - } - fw_header = (amd_fw_header_t *)fw_image; + fw_header = (const amd_fw_header_t *)fw_image; if ((fw_header->magic >> 8) != AMD_MAGIC) { WARNX(2, "%s is not a valid amd firmware: version mismatch", path); goto fail; } - fw_data = (uint32_t *)(fw_header + 1); - fw_size = (st.st_size - sizeof(*fw_header)) / sizeof(uint32_t); + fw_data = (const uint32_t *)(fw_header + 1); + fw_size = (params->fwsize - sizeof(*fw_header)) / sizeof(uint32_t); /* * Check the primary checksum. */ sum = 0; for (i = 0; i < fw_size; i++) sum += fw_data[i]; if (sum != fw_header->checksum) { WARNX(2, "%s: update data checksum invalid", path); goto fail; } if (signature == fw_header->signature) { fprintf(stderr, "%s: updating cpu %s... ", path, dev); - args.data = fw_image; - args.size = st.st_size; + args.data = __DECONST(void *, fw_image); + args.size = params->fwsize; error = ioctl(devfd, CPUCTL_UPDATE, &args); if (error < 0) { fprintf(stderr, "failed.\n"); warn("ioctl()"); goto fail; } fprintf(stderr, "done.\n"); } fail: - if (fd >= 0) - close(fd); - if (devfd >= 0) - close(devfd); - if (fw_image != MAP_FAILED) - if(munmap(fw_image, st.st_size) != 0) - warn("munmap(%s)", path); return; } Index: head/usr.sbin/cpucontrol/amd10h.c =================================================================== --- head/usr.sbin/cpucontrol/amd10h.c (revision 340420) +++ head/usr.sbin/cpucontrol/amd10h.c (revision 340421) @@ -1,317 +1,291 @@ /*- * Copyright (c) 2012 Andriy Gapon . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpucontrol.h" #include "amd.h" int amd10h_probe(int fd) { char vendor[13]; cpuctl_cpuid_args_t idargs; uint32_t family; uint32_t signature; int error; idargs.level = 0; error = ioctl(fd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); return (1); } ((uint32_t *)vendor)[0] = idargs.data[1]; ((uint32_t *)vendor)[1] = idargs.data[3]; ((uint32_t *)vendor)[2] = idargs.data[2]; vendor[12] = '\0'; if (strncmp(vendor, AMD_VENDOR_ID, sizeof(AMD_VENDOR_ID)) != 0) return (1); idargs.level = 1; error = ioctl(fd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); return (1); } signature = idargs.data[0]; family = ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff); if (family < 0x10) return (1); return (0); } /* * NB: the format of microcode update files is not documented by AMD. * It has been reverse engineered from studying Coreboot, illumos and Linux * source code. */ void -amd10h_update(const char *dev, const char *path) +amd10h_update(const struct ucode_update_params *params) { - struct stat st; cpuctl_cpuid_args_t idargs; cpuctl_msr_args_t msrargs; cpuctl_update_args_t args; const amd_10h_fw_header_t *fw_header; const amd_10h_fw_header_t *selected_fw; const equiv_cpu_entry_t *equiv_cpu_table; const section_header_t *section_header; const container_header_t *container_header; const uint8_t *fw_data; - uint8_t *fw_image; + const uint8_t *fw_image; + const char *dev, *path; size_t fw_size; size_t selected_size; uint32_t revision; uint32_t new_rev; uint32_t signature; uint16_t equiv_id; - int fd, devfd; + int devfd; unsigned int i; int error; + dev = params->dev_path; + path = params->fw_path; + devfd = params->devfd; + fw_image = params->fwimage; + fw_size = params->fwsize; + assert(path); assert(dev); - fd = -1; - fw_image = MAP_FAILED; - devfd = open(dev, O_RDWR); - if (devfd < 0) { - WARN(0, "could not open %s for writing", dev); - return; - } idargs.level = 1; error = ioctl(devfd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); goto done; } signature = idargs.data[0]; msrargs.msr = MSR_BIOS_SIGN; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto done; } revision = (uint32_t)msrargs.data; WARNX(1, "found cpu family %#x model %#x " "stepping %#x extfamily %#x extmodel %#x.", ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff), (signature >> 4) & 0x0f, (signature >> 0) & 0x0f, (signature >> 20) & 0xff, (signature >> 16) & 0x0f); WARNX(1, "microcode revision %#x", revision); /* * Open the firmware file. */ WARNX(1, "checking %s for update.", path); - fd = open(path, O_RDONLY, 0); - if (fd < 0) { - WARN(0, "open(%s)", path); - goto done; - } - error = fstat(fd, &st); - if (error != 0) { - WARN(0, "fstat(%s)", path); - goto done; - } - if (st.st_size < 0 || (size_t)st.st_size < + if (fw_size < (sizeof(*container_header) + sizeof(*section_header))) { WARNX(2, "file too short: %s", path); goto done; } - fw_size = st.st_size; /* * mmap the whole image. */ - fw_image = (uint8_t *)mmap(NULL, st.st_size, PROT_READ, - MAP_PRIVATE, fd, 0); - if (fw_image == MAP_FAILED) { - WARN(0, "mmap(%s)", path); - goto done; - } - fw_data = fw_image; container_header = (const container_header_t *)fw_data; if (container_header->magic != AMD_10H_MAGIC) { WARNX(2, "%s is not a valid amd firmware: bad magic", path); goto done; } fw_data += sizeof(*container_header); fw_size -= sizeof(*container_header); section_header = (const section_header_t *)fw_data; if (section_header->type != AMD_10H_EQUIV_TABLE_TYPE) { WARNX(2, "%s is not a valid amd firmware: " "first section is not CPU equivalence table", path); goto done; } if (section_header->size == 0) { WARNX(2, "%s is not a valid amd firmware: " "first section is empty", path); goto done; } fw_data += sizeof(*section_header); fw_size -= sizeof(*section_header); if (section_header->size > fw_size) { WARNX(2, "%s is not a valid amd firmware: " "file is truncated", path); goto done; } if (section_header->size < sizeof(*equiv_cpu_table)) { WARNX(2, "%s is not a valid amd firmware: " "first section is too short", path); goto done; } equiv_cpu_table = (const equiv_cpu_entry_t *)fw_data; fw_data += section_header->size; fw_size -= section_header->size; equiv_id = 0; for (i = 0; equiv_cpu_table[i].installed_cpu != 0; i++) { if (signature == equiv_cpu_table[i].installed_cpu) { equiv_id = equiv_cpu_table[i].equiv_cpu; WARNX(3, "equiv_id: %x, signature %8x," " equiv_cpu_table[%d] %8x", equiv_id, signature, i, equiv_cpu_table[i].installed_cpu); break; } } if (equiv_id == 0) { WARNX(2, "CPU is not found in the equivalence table"); goto done; } selected_fw = NULL; selected_size = 0; while (fw_size >= sizeof(*section_header)) { section_header = (const section_header_t *)fw_data; fw_data += sizeof(*section_header); fw_size -= sizeof(*section_header); if (section_header->type != AMD_10H_uCODE_TYPE) { WARNX(2, "%s is not a valid amd firmware: " "section has incorret type", path); goto done; } if (section_header->size > fw_size) { WARNX(2, "%s is not a valid amd firmware: " "file is truncated", path); goto done; } if (section_header->size < sizeof(*fw_header)) { WARNX(2, "%s is not a valid amd firmware: " "section is too short", path); goto done; } fw_header = (const amd_10h_fw_header_t *)fw_data; fw_data += section_header->size; fw_size -= section_header->size; if (fw_header->processor_rev_id != equiv_id) { WARNX(1, "firmware processor_rev_id %x, equiv_id %x", fw_header->processor_rev_id, equiv_id); continue; /* different cpu */ } if (fw_header->patch_id <= revision) { WARNX(1, "patch_id %x, revision %x", fw_header->patch_id, revision); continue; /* not newer revision */ } if (fw_header->nb_dev_id != 0 || fw_header->sb_dev_id != 0) { WARNX(2, "Chipset-specific microcode is not supported"); } WARNX(3, "selecting revision: %x", fw_header->patch_id); revision = fw_header->patch_id; selected_fw = fw_header; selected_size = section_header->size; } if (fw_size != 0) { WARNX(2, "%s is not a valid amd firmware: " "file is truncated", path); goto done; } if (selected_fw != NULL) { WARNX(1, "selected ucode size is %zu", selected_size); fprintf(stderr, "%s: updating cpu %s to revision %#x... ", path, dev, revision); args.data = __DECONST(void *, selected_fw); args.size = selected_size; error = ioctl(devfd, CPUCTL_UPDATE, &args); if (error < 0) { fprintf(stderr, "failed.\n"); warn("ioctl()"); goto done; } fprintf(stderr, "done.\n"); } msrargs.msr = MSR_BIOS_SIGN; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto done; } new_rev = (uint32_t)msrargs.data; if (new_rev != revision) WARNX(0, "revision after update %#x", new_rev); done: - if (fd >= 0) - close(fd); - if (devfd >= 0) - close(devfd); - if (fw_image != MAP_FAILED) - if (munmap(fw_image, st.st_size) != 0) - warn("munmap(%s)", path); return; } Index: head/usr.sbin/cpucontrol/cpucontrol.c =================================================================== --- head/usr.sbin/cpucontrol/cpucontrol.c (revision 340420) +++ head/usr.sbin/cpucontrol/cpucontrol.c (revision 340421) @@ -1,516 +1,573 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008-2011 Stanislav Sedov . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * This utility provides userland access to the cpuctl(4) pseudo-device * features. */ #include __FBSDID("$FreeBSD$"); #include +#include +#include +#include +#include #include #include #include #include -#include -#include #include -#include #include #include #include +#include #include #include #include #include "cpucontrol.h" #include "amd.h" #include "intel.h" #include "via.h" int verbosity_level = 0; #define DEFAULT_DATADIR "/usr/local/share/cpucontrol" #define FLAG_I 0x01 #define FLAG_M 0x02 #define FLAG_U 0x04 #define FLAG_N 0x08 #define FLAG_E 0x10 #define OP_INVAL 0x00 #define OP_READ 0x01 #define OP_WRITE 0x02 #define OP_OR 0x04 #define OP_AND 0x08 #define HIGH(val) (uint32_t)(((val) >> 32) & 0xffffffff) #define LOW(val) (uint32_t)((val) & 0xffffffff) -/* - * Macros for freeing SLISTs, probably must be in /sys/queue.h - */ -#define SLIST_FREE(head, field, freef) do { \ - typeof(SLIST_FIRST(head)) __elm0; \ - typeof(SLIST_FIRST(head)) __elm; \ - SLIST_FOREACH_SAFE(__elm, (head), field, __elm0) \ - (void)(freef)(__elm); \ -} while(0); - struct datadir { const char *path; SLIST_ENTRY(datadir) next; }; static SLIST_HEAD(, datadir) datadirs = SLIST_HEAD_INITIALIZER(datadirs); static struct ucode_handler { ucode_probe_t *probe; ucode_update_t *update; } handlers[] = { { intel_probe, intel_update }, { amd10h_probe, amd10h_update }, { amd_probe, amd_update }, { via_probe, via_update }, }; #define NHANDLERS (sizeof(handlers) / sizeof(*handlers)) static void usage(void); -static int isdir(const char *path); static int do_cpuid(const char *cmdarg, const char *dev); static int do_cpuid_count(const char *cmdarg, const char *dev); static int do_msr(const char *cmdarg, const char *dev); static int do_update(const char *dev); static void datadir_add(const char *path); static void __dead2 usage(void) { const char *name; name = getprogname(); if (name == NULL) name = "cpuctl"; fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | " "-i level | -i level,level_type | -e | -u] device\n", name); exit(EX_USAGE); } static int -isdir(const char *path) -{ - int error; - struct stat st; - - error = stat(path, &st); - if (error < 0) { - WARN(0, "stat(%s)", path); - return (error); - } - return (st.st_mode & S_IFDIR); -} - -static int do_cpuid(const char *cmdarg, const char *dev) { unsigned int level; cpuctl_cpuid_args_t args; int fd, error; char *endptr; assert(cmdarg != NULL); assert(dev != NULL); level = strtoul(cmdarg, &endptr, 16); if (*cmdarg == '\0' || *endptr != '\0') { WARNX(0, "incorrect operand: %s", cmdarg); usage(); /* NOTREACHED */ } /* * Fill ioctl argument structure. */ args.level = level; fd = open(dev, O_RDONLY); if (fd < 0) { WARN(0, "error opening %s for reading", dev); return (1); } error = ioctl(fd, CPUCTL_CPUID, &args); if (error < 0) { WARN(0, "ioctl(%s, CPUCTL_CPUID)", dev); close(fd); return (error); } fprintf(stdout, "cpuid level 0x%x: 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", level, args.data[0], args.data[1], args.data[2], args.data[3]); close(fd); return (0); } static int do_cpuid_count(const char *cmdarg, const char *dev) { char *cmdarg1, *endptr, *endptr1; unsigned int level, level_type; cpuctl_cpuid_count_args_t args; int fd, error; assert(cmdarg != NULL); assert(dev != NULL); level = strtoul(cmdarg, &endptr, 16); if (*cmdarg == '\0' || *endptr == '\0') { WARNX(0, "incorrect or missing operand: %s", cmdarg); usage(); /* NOTREACHED */ } /* Locate the comma... */ cmdarg1 = strstr(endptr, ","); /* ... and skip past it */ cmdarg1 += 1; level_type = strtoul(cmdarg1, &endptr1, 16); if (*cmdarg1 == '\0' || *endptr1 != '\0') { WARNX(0, "incorrect or missing operand: %s", cmdarg); usage(); /* NOTREACHED */ } /* * Fill ioctl argument structure. */ args.level = level; args.level_type = level_type; fd = open(dev, O_RDONLY); if (fd < 0) { WARN(0, "error opening %s for reading", dev); return (1); } error = ioctl(fd, CPUCTL_CPUID_COUNT, &args); if (error < 0) { WARN(0, "ioctl(%s, CPUCTL_CPUID_COUNT)", dev); close(fd); return (error); } fprintf(stdout, "cpuid level 0x%x, level_type 0x%x: 0x%.8x 0x%.8x " "0x%.8x 0x%.8x\n", level, level_type, args.data[0], args.data[1], args.data[2], args.data[3]); close(fd); return (0); } static int do_msr(const char *cmdarg, const char *dev) { unsigned int msr; cpuctl_msr_args_t args; size_t len; uint64_t data = 0; unsigned long command; int do_invert = 0, op; int fd, error; const char *command_name; char *endptr; char *p; assert(cmdarg != NULL); assert(dev != NULL); len = strlen(cmdarg); if (len == 0) { WARNX(0, "MSR register expected"); usage(); /* NOTREACHED */ } /* * Parse command string. */ msr = strtoul(cmdarg, &endptr, 16); switch (*endptr) { case '\0': op = OP_READ; break; case '=': op = OP_WRITE; break; case '&': op = OP_AND; endptr++; break; case '|': op = OP_OR; endptr++; break; default: op = OP_INVAL; } if (op != OP_READ) { /* Complex operation. */ if (*endptr != '=') op = OP_INVAL; else { p = ++endptr; if (*p == '~') { do_invert = 1; p++; } data = strtoull(p, &endptr, 16); if (*p == '\0' || *endptr != '\0') { WARNX(0, "argument required: %s", cmdarg); usage(); /* NOTREACHED */ } } } if (op == OP_INVAL) { WARNX(0, "invalid operator: %s", cmdarg); usage(); /* NOTREACHED */ } /* * Fill ioctl argument structure. */ args.msr = msr; if ((do_invert != 0) ^ (op == OP_AND)) args.data = ~data; else args.data = data; switch (op) { case OP_READ: command = CPUCTL_RDMSR; command_name = "RDMSR"; break; case OP_WRITE: command = CPUCTL_WRMSR; command_name = "WRMSR"; break; case OP_OR: command = CPUCTL_MSRSBIT; command_name = "MSRSBIT"; break; case OP_AND: command = CPUCTL_MSRCBIT; command_name = "MSRCBIT"; break; default: abort(); } fd = open(dev, op == OP_READ ? O_RDONLY : O_WRONLY); if (fd < 0) { WARN(0, "error opening %s for %s", dev, op == OP_READ ? "reading" : "writing"); return (1); } error = ioctl(fd, command, &args); if (error < 0) { WARN(0, "ioctl(%s, CPUCTL_%s (%lu))", dev, command_name, command); close(fd); return (1); } if (op == OP_READ) fprintf(stdout, "MSR 0x%x: 0x%.8x 0x%.8x\n", msr, HIGH(args.data), LOW(args.data)); close(fd); return (0); } static int do_eval_cpu_features(const char *dev) { int fd, error; assert(dev != NULL); fd = open(dev, O_RDWR); if (fd < 0) { WARN(0, "error opening %s for writing", dev); return (1); } error = ioctl(fd, CPUCTL_EVAL_CPU_FEATURES, NULL); if (error < 0) WARN(0, "ioctl(%s, CPUCTL_EVAL_CPU_FEATURES)", dev); close(fd); return (error); } static int +try_a_fw_image(const char *dev_path, int devfd, int fwdfd, const char *dpath, + const char *fname, struct ucode_handler *handler) +{ + struct ucode_update_params parm; + struct stat st; + char *fw_path; + void *fw_map; + int fwfd, rc; + + rc = 0; + fw_path = NULL; + fw_map = MAP_FAILED; + fwfd = openat(fwdfd, fname, O_RDONLY); + if (fwfd < 0) { + WARN(0, "openat(%s, %s)", dpath, fname); + goto out; + } + + rc = asprintf(&fw_path, "%s/%s", dpath, fname); + if (rc == -1) { + WARNX(0, "out of memory"); + rc = ENOMEM; + goto out; + } + + rc = fstat(fwfd, &st); + if (rc != 0) { + WARN(0, "fstat(%s)", fw_path); + rc = 0; + goto out; + } + if (st.st_size <= 0) { + WARN(0, "%s: empty", fw_path); + goto out; + } + + fw_map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fwfd, 0); + if (fw_map == MAP_FAILED) { + WARN(0, "mmap(%s)", fw_path); + goto out; + } + + + memset(&parm, 0, sizeof(parm)); + parm.devfd = devfd; + parm.fwimage = fw_map; + parm.fwsize = st.st_size; + parm.dev_path = dev_path; + parm.fw_path = fw_path; + + handler->update(&parm); + +out: + if (fw_map != MAP_FAILED) + munmap(fw_map, st.st_size); + free(fw_path); + if (fwfd >= 0) + close(fwfd); + return (rc); +} + +static int do_update(const char *dev) { - int fd; + int fd, fwdfd; unsigned int i; int error; struct ucode_handler *handler; struct datadir *dir; DIR *dirp; struct dirent *direntry; - char buf[MAXPATHLEN]; fd = open(dev, O_RDONLY); if (fd < 0) { WARN(0, "error opening %s for reading", dev); return (1); } /* - * Find the appropriate handler for device. + * Find the appropriate handler for CPU. */ for (i = 0; i < NHANDLERS; i++) if (handlers[i].probe(fd) == 0) break; if (i < NHANDLERS) handler = &handlers[i]; else { - WARNX(0, "cannot find the appropriate handler for device"); + WARNX(0, "cannot find the appropriate handler for %s", dev); close(fd); return (1); } close(fd); + fd = open(dev, O_RDWR); + if (fd < 0) { + WARN(0, "error opening %s for writing", dev); + return (1); + } + /* * Process every image in specified data directories. */ SLIST_FOREACH(dir, &datadirs, next) { - dirp = opendir(dir->path); - if (dirp == NULL) { - WARNX(1, "skipping directory %s: not accessible", dir->path); + fwdfd = open(dir->path, O_RDONLY); + if (fwdfd < 0) { + WARN(1, "skipping directory %s: not accessible", dir->path); continue; } + dirp = fdopendir(fwdfd); + if (dirp == NULL) { + WARNX(0, "out of memory"); + close(fwdfd); + close(fd); + return (1); + } + while ((direntry = readdir(dirp)) != NULL) { if (direntry->d_namlen == 0) continue; - error = snprintf(buf, sizeof(buf), "%s/%s", dir->path, - direntry->d_name); - if ((unsigned)error >= sizeof(buf)) - WARNX(0, "skipping %s, buffer too short", - direntry->d_name); - if (isdir(buf) != 0) { - WARNX(2, "skipping %s: is a directory", buf); + if (direntry->d_type == DT_DIR) continue; + + error = try_a_fw_image(dev, fd, fwdfd, dir->path, + direntry->d_name, handler); + if (error != 0) { + closedir(dirp); + close(fd); + return (1); } - handler->update(dev, buf); } error = closedir(dirp); if (error != 0) WARN(0, "closedir(%s)", dir->path); } + close(fd); return (0); } /* * Add new data directory to the search list. */ static void datadir_add(const char *path) { struct datadir *newdir; newdir = (struct datadir *)malloc(sizeof(*newdir)); if (newdir == NULL) err(EX_OSERR, "cannot allocate memory"); newdir->path = path; SLIST_INSERT_HEAD(&datadirs, newdir, next); } int main(int argc, char *argv[]) { + struct datadir *elm; int c, flags; const char *cmdarg; const char *dev; int error; flags = 0; error = 0; cmdarg = ""; /* To keep gcc3 happy. */ while ((c = getopt(argc, argv, "d:ehi:m:nuv")) != -1) { switch (c) { case 'd': datadir_add(optarg); break; case 'e': flags |= FLAG_E; break; case 'i': flags |= FLAG_I; cmdarg = optarg; break; case 'm': flags |= FLAG_M; cmdarg = optarg; break; case 'n': flags |= FLAG_N; break; case 'u': flags |= FLAG_U; break; case 'v': verbosity_level++; break; case 'h': /* FALLTHROUGH */ default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc < 1) { usage(); /* NOTREACHED */ } if ((flags & FLAG_N) == 0) datadir_add(DEFAULT_DATADIR); dev = argv[0]; c = flags & (FLAG_E | FLAG_I | FLAG_M | FLAG_U); switch (c) { case FLAG_I: if (strstr(cmdarg, ",") != NULL) error = do_cpuid_count(cmdarg, dev); else error = do_cpuid(cmdarg, dev); break; case FLAG_M: error = do_msr(cmdarg, dev); break; case FLAG_U: error = do_update(dev); break; case FLAG_E: error = do_eval_cpu_features(dev); break; default: usage(); /* Only one command can be selected. */ } - SLIST_FREE(&datadirs, next, free); + while ((elm = SLIST_FIRST(&datadirs)) != NULL) { + SLIST_REMOVE_HEAD(&datadirs, next); + free(elm); + } return (error == 0 ? 0 : 1); } Index: head/usr.sbin/cpucontrol/cpucontrol.h =================================================================== --- head/usr.sbin/cpucontrol/cpucontrol.h (revision 340420) +++ head/usr.sbin/cpucontrol/cpucontrol.h (revision 340421) @@ -1,58 +1,67 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2008 Stanislav Sedov . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef CPUCONTROL_H #define CPUCONTROL_H +#include + typedef int ucode_probe_t(int fd); -typedef void ucode_update_t(const char *dev, const char *image); +struct ucode_update_params { + int devfd; /* RDWR handle to cpucontrol device */ + const void *fwimage; /* READ mapping of firmware image */ + size_t fwsize; /* Non-zero size of firmware image */ + const char *dev_path; /* cpucontrol device path, for logging */ + const char *fw_path; /* firmware image path, for logging */ +}; +typedef void ucode_update_t(const struct ucode_update_params *params); extern int verbosity_level; #ifdef DEBUG # define WARNX(level, ...) \ if ((level) <= verbosity_level) { \ fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ warnx(__VA_ARGS__); \ } # define WARN(level, ...) \ if ((level) <= verbosity_level) { \ fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ warn(__VA_ARGS__); \ } #else # define WARNX(level, ...) \ if ((level) <= verbosity_level) \ warnx(__VA_ARGS__); # define WARN(level, ...) \ if ((level) <= verbosity_level) \ warn(__VA_ARGS__); #endif #endif /* !CPUCONTROL_H */ Index: head/usr.sbin/cpucontrol/intel.c =================================================================== --- head/usr.sbin/cpucontrol/intel.c (revision 340420) +++ head/usr.sbin/cpucontrol/intel.c (revision 340421) @@ -1,296 +1,270 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006, 2008 Stanislav Sedov . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpucontrol.h" #include "intel.h" #define DEFAULT_UCODE_SIZE 2000 /* Size of update data if not specified. */ int intel_probe(int fd) { char vendor[13]; int error; cpuctl_cpuid_args_t idargs = { .level = 0, }; error = ioctl(fd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); return (1); } ((uint32_t *)vendor)[0] = idargs.data[1]; ((uint32_t *)vendor)[1] = idargs.data[3]; ((uint32_t *)vendor)[2] = idargs.data[2]; vendor[12] = '\0'; if (strncmp(vendor, INTEL_VENDOR_ID, sizeof(INTEL_VENDOR_ID)) != 0) return (1); return (0); } void -intel_update(const char *dev, const char *path) +intel_update(const struct ucode_update_params *params) { - int fd, devfd; - struct stat st; - uint32_t *fw_image; + int devfd; + const char *dev, *path; + const uint32_t *fw_image; int have_ext_table; uint32_t sum; unsigned int i; size_t payload_size; - intel_fw_header_t *fw_header; - intel_cpu_signature_t *ext_table; - intel_ext_header_t *ext_header; + const intel_fw_header_t *fw_header; + const intel_cpu_signature_t *ext_table; + const intel_ext_header_t *ext_header; uint32_t sig, signature, flags; int32_t revision; ssize_t ext_size; size_t ext_table_size; - void *fw_data; + const void *fw_data; size_t data_size, total_size; cpuctl_msr_args_t msrargs = { .msr = MSR_BIOS_SIGN, .data = 0, }; cpuctl_cpuid_args_t idargs = { .level = 1, /* Signature. */ }; cpuctl_update_args_t args; int error; + dev = params->dev_path; + path = params->fw_path; + devfd = params->devfd; + fw_image = params->fwimage; + assert(path); assert(dev); - fd = -1; - fw_image = MAP_FAILED; ext_table = NULL; ext_header = NULL; - devfd = open(dev, O_RDWR); - if (devfd < 0) { - WARN(0, "could not open %s for writing", dev); - return; - } + error = ioctl(devfd, CPUCTL_WRMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto fail; } error = ioctl(devfd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto fail; } signature = idargs.data[0]; msrargs.msr = MSR_IA32_PLATFORM_ID; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto fail; } /* * MSR_IA32_PLATFORM_ID contains flag in BCD in bits 52-50. */ flags = 1 << ((msrargs.data >> 50) & 7); msrargs.msr = MSR_BIOS_SIGN; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto fail; } revision = msrargs.data >> 32; /* Revision in the high dword. */ WARNX(2, "found cpu type %#x family %#x model %#x stepping %#x.", (signature >> 12) & 0x03, (signature >> 8) & 0x0f, (signature >> 4) & 0x0f, (signature >> 0) & 0x0f); /* * Open firmware image. */ - fd = open(path, O_RDONLY, 0); - if (fd < 0) { - WARN(0, "open(%s)", path); - goto fail; - } - error = fstat(fd, &st); - if (error != 0) { - WARN(0, "fstat(%s)", path); - goto fail; - } - if (st.st_size < 0 || (unsigned)st.st_size < sizeof(*fw_header)) { + if (params->fwsize < sizeof(*fw_header)) { WARNX(2, "file too short: %s", path); goto fail; } - /* - * mmap the whole image. - */ - fw_image = (uint32_t *)mmap(NULL, st.st_size, PROT_READ, - MAP_PRIVATE, fd, 0); - if (fw_image == MAP_FAILED) { - WARN(0, "mmap(%s)", path); - goto fail; - } - fw_header = (intel_fw_header_t *)fw_image; + fw_header = (const intel_fw_header_t *)fw_image; if (fw_header->header_version != INTEL_HEADER_VERSION || fw_header->loader_revision != INTEL_LOADER_REVISION) { WARNX(2, "%s is not a valid intel firmware: version mismatch", path); goto fail; } /* * According to spec, if data_size == 0, then size of ucode = 2000. */ if (fw_header->data_size == 0) data_size = DEFAULT_UCODE_SIZE; else data_size = fw_header->data_size; if (fw_header->total_size == 0) total_size = data_size + sizeof(*fw_header); else total_size = fw_header->total_size; - if (total_size > (unsigned)st.st_size || st.st_size < 0) { + if (total_size > params->fwsize) { WARNX(2, "file too short: %s", path); goto fail; } payload_size = data_size + sizeof(*fw_header); /* * Check the primary checksum. */ sum = 0; for (i = 0; i < (payload_size / sizeof(uint32_t)); i++) - sum += *((uint32_t *)fw_image + i); + sum += *((const uint32_t *)fw_image + i); if (sum != 0) { WARNX(2, "%s: update data checksum invalid", path); goto fail; } /* * Check if there is an extended signature table. */ ext_size = total_size - payload_size; have_ext_table = 0; if (ext_size > (signed)sizeof(*ext_header)) { - ext_header = - (intel_ext_header_t *)((char *)fw_image + payload_size); - ext_table = (intel_cpu_signature_t *)(ext_header + 1); + ext_header = (const intel_ext_header_t *) + ((const char *)fw_image + payload_size); + ext_table = (const intel_cpu_signature_t *)(ext_header + 1); /* * Check the extended table size. */ ext_table_size = sizeof(*ext_header) + ext_header->sig_count * sizeof(*ext_table); if (ext_table_size + payload_size > total_size) { WARNX(2, "%s: broken extended signature table", path); goto no_table; } /* * Check the extended table signature. */ sum = 0; for (i = 0; i < (ext_table_size / sizeof(uint32_t)); i++) - sum += *((uint32_t *)ext_header + i); + sum += *((const uint32_t *)ext_header + i); if (sum != 0) { WARNX(2, "%s: extended signature table checksum invalid", path); goto no_table; } have_ext_table = 1; } no_table: fw_data = fw_header + 1; /* Pointer to the update data. */ /* * Check if the given image is ok for this cpu. */ if (signature == fw_header->cpu_signature && (flags & fw_header->cpu_flags) != 0) goto matched; else if (have_ext_table != 0) { for (i = 0; i < ext_header->sig_count; i++) { sig = ext_table[i].cpu_signature; if (signature == sig && (flags & ext_table[i].cpu_flags) != 0) goto matched; } } else goto fail; matched: if (revision >= fw_header->revision) { WARNX(1, "skipping %s of rev %#x: up to date", path, fw_header->revision); goto fail; } fprintf(stderr, "%s: updating cpu %s from rev %#x to rev %#x... ", path, dev, revision, fw_header->revision); - args.data = fw_data; + args.data = __DECONST(void *, fw_data); args.size = data_size; error = ioctl(devfd, CPUCTL_UPDATE, &args); if (error < 0) { error = errno; fprintf(stderr, "failed.\n"); errno = error; WARN(0, "ioctl()"); goto fail; } fprintf(stderr, "done.\n"); fail: - if (fw_image != MAP_FAILED) - if (munmap(fw_image, st.st_size) != 0) - warn("munmap(%s)", path); - if (devfd >= 0) - close(devfd); - if (fd >= 0) - close(fd); + return; } Index: head/usr.sbin/cpucontrol/via.c =================================================================== --- head/usr.sbin/cpucontrol/via.c (revision 340420) +++ head/usr.sbin/cpucontrol/via.c (revision 340421) @@ -1,226 +1,195 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2011 Fabien Thomas . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cpucontrol.h" #include "via.h" int via_probe(int fd) { char vendor[13]; int error; cpuctl_cpuid_args_t idargs = { .level = 0, }; error = ioctl(fd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl()"); return (1); } ((uint32_t *)vendor)[0] = idargs.data[1]; ((uint32_t *)vendor)[1] = idargs.data[3]; ((uint32_t *)vendor)[2] = idargs.data[2]; vendor[12] = '\0'; if (strncmp(vendor, CENTAUR_VENDOR_ID, sizeof(CENTAUR_VENDOR_ID)) != 0) return (1); /* TODO: detect Nano CPU. */ return (0); } void -via_update(const char *dev, const char *path) +via_update(const struct ucode_update_params *params) { - int fd, devfd; - struct stat st; - uint32_t *fw_image; + int devfd; + const char *dev, *path; + const uint32_t *fw_image; uint32_t sum; unsigned int i; size_t payload_size; - via_fw_header_t *fw_header; + const via_fw_header_t *fw_header; uint32_t signature; int32_t revision; - void *fw_data; + const void *fw_data; size_t data_size, total_size; cpuctl_msr_args_t msrargs = { .msr = MSR_IA32_PLATFORM_ID, }; cpuctl_cpuid_args_t idargs = { .level = 1, /* Signature. */ }; cpuctl_update_args_t args; int error; + dev = params->dev_path; + path = params->fw_path; + devfd = params->devfd; + fw_image = params->fwimage; + assert(path); assert(dev); - fd = -1; - devfd = -1; - fw_image = MAP_FAILED; - devfd = open(dev, O_RDWR); - if (devfd < 0) { - WARN(0, "could not open %s for writing", dev); - return; - } error = ioctl(devfd, CPUCTL_CPUID, &idargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto fail; } signature = idargs.data[0]; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto fail; } /* * MSR_IA32_PLATFORM_ID contains flag in BCD in bits 52-50. */ msrargs.msr = MSR_BIOS_SIGN; error = ioctl(devfd, CPUCTL_RDMSR, &msrargs); if (error < 0) { WARN(0, "ioctl(%s)", dev); goto fail; } revision = msrargs.data >> 32; /* Revision in the high dword. */ WARNX(2, "found cpu type %#x family %#x model %#x stepping %#x.", (signature >> 12) & 0x03, (signature >> 8) & 0x0f, (signature >> 4) & 0x0f, (signature >> 0) & 0x0f); - /* - * Open firmware image. - */ - fd = open(path, O_RDONLY, 0); - if (fd < 0) { - WARN(0, "open(%s)", path); - goto fail; - } - error = fstat(fd, &st); - if (error != 0) { - WARN(0, "fstat(%s)", path); - goto fail; - } - if (st.st_size < 0 || (unsigned)st.st_size < sizeof(*fw_header)) { + + if (params->fwsize < sizeof(*fw_header)) { WARNX(2, "file too short: %s", path); goto fail; } - /* - * mmap the whole image. - */ - fw_image = (uint32_t *)mmap(NULL, st.st_size, PROT_READ, - MAP_PRIVATE, fd, 0); - if (fw_image == MAP_FAILED) { - WARN(0, "mmap(%s)", path); - goto fail; - } - fw_header = (via_fw_header_t *)fw_image; + fw_header = (const via_fw_header_t *)fw_image; if (fw_header->signature != VIA_HEADER_SIGNATURE || fw_header->loader_revision != VIA_LOADER_REVISION) { WARNX(2, "%s is not a valid via firmware: version mismatch", path); goto fail; } data_size = fw_header->data_size; total_size = fw_header->total_size; - if (total_size > (unsigned)st.st_size || st.st_size < 0) { + if (total_size > params->fwsize) { WARNX(2, "file too short: %s", path); goto fail; } payload_size = data_size + sizeof(*fw_header); /* * Check the primary checksum. */ sum = 0; for (i = 0; i < (payload_size / sizeof(uint32_t)); i++) - sum += *((uint32_t *)fw_image + i); + sum += *((const uint32_t *)fw_image + i); if (sum != 0) { WARNX(2, "%s: update data checksum invalid", path); goto fail; } fw_data = fw_header + 1; /* Pointer to the update data. */ /* * Check if the given image is ok for this cpu. */ if (signature != fw_header->cpu_signature) goto fail; if (fw_header->revision != 0 && revision >= fw_header->revision) { WARNX(1, "skipping %s of rev %#x: up to date", path, fw_header->revision); goto fail; } fprintf(stderr, "%s: updating cpu %s from rev %#x to rev %#x... ", path, dev, revision, fw_header->revision); - args.data = fw_data; + args.data = __DECONST(void *, fw_data); args.size = data_size; error = ioctl(devfd, CPUCTL_UPDATE, &args); if (error < 0) { error = errno; - fprintf(stderr, "failed.\n"); + fprintf(stderr, "failed.\n"); errno = error; - WARN(0, "ioctl()"); - goto fail; + WARN(0, "ioctl()"); + goto fail; } fprintf(stderr, "done.\n"); fail: - if (fw_image != MAP_FAILED) - if (munmap(fw_image, st.st_size) != 0) - warn("munmap(%s)", path); - if (devfd >= 0) - close(devfd); - if (fd >= 0) - close(fd); return; }