cpucontrol - Add amd10h support
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 16 Jan 2018 00:28:21 +0000 (16:28 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 16 Jan 2018 00:28:21 +0000 (16:28 -0800)
* Add support for ryzen and later microcodes.

* Adds general support for AMD microcodes in their
  packed format.  No need to unpack AMD microcode any
  more, cpucontrol will parse the distribution file
  from AMD.

Taken-from: FreeBSD

usr.sbin/cpucontrol/Makefile
usr.sbin/cpucontrol/amd.c
usr.sbin/cpucontrol/amd.h
usr.sbin/cpucontrol/amd10h.c [new file with mode: 0644]
usr.sbin/cpucontrol/cpucontrol.8
usr.sbin/cpucontrol/cpucontrol.c
usr.sbin/cpucontrol/cpucontrol.h
usr.sbin/cpucontrol/intel.c
usr.sbin/cpucontrol/intel.h
usr.sbin/cpucontrol/via.c
usr.sbin/cpucontrol/via.h

index 62231e9..df84f70 100644 (file)
@@ -1,9 +1,9 @@
-# $FreeBSD: release/10.0.0/usr.sbin/cpucontrol/Makefile 242159 2012-10-26 20:25:05Z eadler $
+# $FreeBSD$
 
 PROG=  cpucontrol
 MAN=   cpucontrol.8
-SRCS=  cpucontrol.c intel.c amd.c via.c
+SRCS=  cpucontrol.c intel.c amd.c amd10h.c via.c
 
-NO_STRICT_ALIASING=
+NO_WCAST_ALIGN=
 
 .include <bsd.prog.mk>
index f8cbfd7..a875afd 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2006, 2008 Stanislav Sedov <stas@FreeBSD.org>.
  * All rights reserved.
  *
@@ -24,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: release/10.0.0/usr.sbin/cpucontrol/amd.c 236504 2012-06-03 08:30:00Z avg $");
+__FBSDID("$FreeBSD$");
 
 #include <assert.h>
 #include <stdio.h>
@@ -38,6 +40,7 @@ __FBSDID("$FreeBSD: release/10.0.0/usr.sbin/cpucontrol/amd.c 236504 2012-06-03 0
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/ioctl.h>
+#include <sys/ioccom.h>
 #include <sys/cpuctl.h>
 
 #include <machine/cpufunc.h>
index 3187eb8..dd83687 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2006, 2008 Stanislav Sedov <stas@FreeBSD.org>.
  * All rights reserved.
  *
@@ -22,7 +24,7 @@
  * (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: release/10.0.0/usr.sbin/cpucontrol/amd.h 181430 2008-08-08 16:26:53Z stas $
+ * $FreeBSD$
  */
 
 #ifndef AMD_H
@@ -33,6 +35,8 @@
  */
 ucode_probe_t  amd_probe;
 ucode_update_t amd_update;
+ucode_probe_t  amd10h_probe;
+ucode_update_t amd10h_update;
 
 typedef struct amd_fw_header {
        uint32_t        date;           /* Update creation date. */
@@ -46,4 +50,45 @@ typedef struct amd_fw_header {
 
 #define        AMD_MAGIC       0xaaaaaa
 
+/*
+ * AMD family 10h and later.
+ */
+typedef struct amd_10h_fw_header {
+       uint32_t        data_code;
+       uint32_t        patch_id;
+       uint16_t        mc_patch_data_id;
+       uint8_t         mc_patch_data_len;
+       uint8_t         init_flag;
+       uint32_t        mc_patch_data_checksum;
+       uint32_t        nb_dev_id;
+       uint32_t        sb_dev_id;
+       uint16_t        processor_rev_id;
+       uint8_t         nb_rev_id;
+       uint8_t         sb_rev_id;
+       uint8_t         bios_api_rev;
+       uint8_t         reserved1[3];
+       uint32_t        match_reg[8];
+} amd_10h_fw_header_t;
+
+typedef struct equiv_cpu_entry {
+       uint32_t        installed_cpu;
+       uint32_t        fixed_errata_mask;
+       uint32_t        fixed_errata_compare;
+       uint16_t        equiv_cpu;
+       uint16_t        res;
+} equiv_cpu_entry_t;
+
+typedef struct section_header {
+       uint32_t        type;
+       uint32_t        size;
+} section_header_t;
+
+typedef struct container_header {
+       uint32_t        magic;
+} container_header_t;
+
+#define        AMD_10H_MAGIC                   0x414d44
+#define AMD_10H_EQUIV_TABLE_TYPE       0
+#define AMD_10H_uCODE_TYPE             1
+
 #endif /* !AMD_H */
diff --git a/usr.sbin/cpucontrol/amd10h.c b/usr.sbin/cpucontrol/amd10h.c
new file mode 100644 (file)
index 0000000..fe7deff
--- /dev/null
@@ -0,0 +1,308 @@
+/*-
+ * Copyright (c) 2012 Andriy Gapon <avg@FreeBSD.org>.
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/ioccom.h>
+#include <sys/cpuctl.h>
+
+#include <machine/cpufunc.h>
+#include <machine/specialreg.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+
+#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)
+{
+       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;
+       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;
+       unsigned int i;
+       int error;
+
+       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 = 0x0000008b;
+       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 >> 4) & 0x0f,
+           (signature >> 0) & 0x0f, (signature >> 20) & 0xff,
+           (signature >> 16) & 0x0f);
+       WARNX(1, "microcode revision %#x", revision);
+
+       /*
+        * Open the firmware file.
+        */
+       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 <
+           (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++) {
+               printf("TEST %s %08x %08x\n", path, signature, equiv_cpu_table[i].installed_cpu);
+               if (signature == equiv_cpu_table[i].installed_cpu) {
+                       equiv_id = equiv_cpu_table[i].equiv_cpu;
+                       WARNX(3, "equiv_id: %x", equiv_id);
+                       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)
+                       continue; /* different cpu */
+               if (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 = 0x0000008b;
+       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 25e3132..4e54bb5 100644 (file)
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/usr.sbin/cpucontrol/cpucontrol.8 267668 2014-06-20 09:57:27Z bapt $
+.\" $FreeBSD$
 .\"
-.Dd April 12, 2016
+.Dd January 5, 2018
 .Dt CPUCONTROL 8
 .Os
 .Sh NAME
 device
 .Sh SYNOPSIS
 .Nm
-.Op Fl vh
-.Fl m Ar msr
 .Bk
+.Op Fl v
+.Fl m Ar msr
 .Ar device
 .Ek
+.Bk
 .Nm
-.Op Fl vh
+.Op Fl v
 .Fl m Ar msr Ns = Ns Ar value
-.Bk
 .Ar device
 .Ek
+.Bk
 .Nm
-.Op Fl vh
+.Op Fl v
 .Fl m Ar msr Ns &= Ns Ar mask
-.Bk
 .Ar device
 .Ek
+.Bk
 .Nm
-.Op Fl vh
+.Op Fl v
 .Fl m Ar msr Ns |= Ns Ar mask
-.Bk
 .Ar device
 .Ek
+.Bk
 .Nm
-.Op Fl vh
+.Op Fl v
 .Fl i Ar level
-.Bk
 .Ar device
 .Ek
+.Bk
 .Nm
-.Op Fl vh
+.Op Fl v
 .Fl i Ar level,level_type
-.Bk
 .Ar device
 .Ek
+.Bk
 .Nm
-.Op Fl vh
+.Op Fl vn
 .Op Fl d Ar datadir
 .Fl u
+.Ar device
+.Ek
 .Bk
+.Nm
+.Fl e
 .Ar device
 .Ek
 .Sh DESCRIPTION
@@ -88,11 +93,18 @@ It can also be used to apply CPU firmware updates.
 The following options are available:
 .Bl -tag -width indent
 .It Fl d Ar datadir
-Where to look for microcode images.
+Directory paths where to look for microcode images.
 The option can be specified multiple times.
-.It Fl m Ar msr Ns Op = Ns Ar value
+The paths are added in order of the options appearance on the command
+line, default directories are appended after the user-supplied paths.
+.It Fl n
+Do not look for the microcode images in the standard directories.
+Currently standard directory to look for the microcode update files is
+.Pa /usr/local/share/cpucontrol .
+.It Fl m Ar msr
 Show value of the specified MSR.
 MSR register number should be given as a hexadecimal number.
+The high word is printed first, then the low word is printed second.
 .It Fl m Ar msr Ns = Ns Ar value
 Store the
 .Ar value
@@ -129,6 +141,20 @@ The
 .Nm
 utility will walk through the configured data directories
 and apply all firmware updates available for this CPU.
+.It Fl e
+Re-evaluate the kernel flags indicating the present CPU features.
+This command is typically executed after a firmware update was applied
+which changes information reported by the
+.Dv CPUID
+instruction.
+.Pp
+.Bf -symbolic
+Only execute the
+.Fl e
+command after the microcode update was applied to all CPUs in the system.
+The kernel does not operate correctly if the features of processors are
+not identical.
+.Ef
 .It Fl v
 Increase the verbosity level.
 .It Fl h
@@ -162,10 +188,10 @@ The command
 will retrieve the CPUID level 0x1 from CPU 1.
 .Pp
 To perform firmware updates on CPU 0 from images located at
-.Pa /usr/local/share/cpuctl/
+.Pa /usr/local/share/cpuctl
 use the following command:
 .Pp
-.Dq Li "cpucontrol -d /usr/local/share/cpuctl/ -u /dev/cpuctl0"
+.Dq Li "cpucontrol -nd /usr/local/share/cpuctl -u /dev/cpuctl0"
 .Sh SEE ALSO
 .Xr cpuctl 4
 .Sh HISTORY
@@ -178,5 +204,3 @@ The
 .Nm
 utility and this manual page was written by
 .An Stanislav Sedov Aq Mt stas@FreeBSD.org .
-.Sh BUGS
-Yes, probably, report if any.
index d3cb13e..121cb10 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2008-2011 Stanislav Sedov <stas@FreeBSD.org>.
  * All rights reserved.
  *
@@ -29,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/usr.sbin/cpucontrol/cpucontrol.c 267673 2014-06-20 13:13:38Z kib $");
+__FBSDID("$FreeBSD$");
 
 #include <assert.h>
 #include <stdio.h>
@@ -60,6 +62,8 @@ int   verbosity_level = 0;
 #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
@@ -73,13 +77,6 @@ int  verbosity_level = 0;
 /*
  * 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_MUTABLE(__elm, (head), field, __elm0)     \
-                       (void)(freef)(__elm);                           \
-} while(0);
-
 struct datadir {
        const char              *path;
        SLIST_ENTRY(datadir)    next;
@@ -91,6 +88,7 @@ static struct ucode_handler {
        ucode_update_t *update;
 } handlers[] = {
        { intel_probe, intel_update },
+       { amd10h_probe, amd10h_update },
        { amd_probe, amd_update },
        { via_probe, via_update },
 };
@@ -113,7 +111,7 @@ usage(void)
        if (name == NULL)
                name = "cpuctl";
        fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | "
-           "-i level | -i level,level_type | -u] device\n", name);
+           "-i level | -i level,level_type | -e | -u] device\n", name);
        exit(EX_USAGE);
 }
 
@@ -336,6 +334,27 @@ do_msr(const char *cmdarg, const char *dev)
        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);
+       }
+#if 0
+       error = ioctl(fd, CPUCTL_EVAL_CPU_FEATURES, NULL);
+       if (error < 0)
+               WARN(0, "ioctl(%s, CPUCTL_EVAL_CPU_FEATURES)", dev);
+#endif
+       close(fd);
+       return (error);
+}
+
 static int
 do_update(const char *dev)
 {
@@ -426,15 +445,14 @@ main(int argc, char *argv[])
        error = 0;
        cmdarg = "";    /* To keep gcc3 happy. */
 
-       /*
-        * Add all default data dirs to the list first.
-        */
-       datadir_add(DEFAULT_DATADIR);
-       while ((c = getopt(argc, argv, "d:hi:m:uv")) != -1) {
+       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;
@@ -443,6 +461,9 @@ main(int argc, char *argv[])
                        flags |= FLAG_M;
                        cmdarg = optarg;
                        break;
+               case 'n':
+                       flags |= FLAG_N;
+                       break;
                case 'u':
                        flags |= FLAG_U;
                        break;
@@ -462,24 +483,28 @@ main(int argc, char *argv[])
                usage();
                /* NOTREACHED */
        }
+       if ((flags & FLAG_N) == 0)
+               datadir_add(DEFAULT_DATADIR);
        dev = argv[0];
-       c = flags & (FLAG_I | FLAG_M | FLAG_U);
+       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;
-               default:
-                       usage();        /* Only one command can be selected. */
+       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);
-       return (error);
+       return (error == 0 ? 0 : 1);
 }
index 2a4f848..555e931 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2008 Stanislav Sedov <stas@FreeBSD.org>.
  * All rights reserved.
  *
@@ -22,7 +24,7 @@
  * (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: release/10.0.0/usr.sbin/cpucontrol/cpucontrol.h 181430 2008-08-08 16:26:53Z stas $
+ * $FreeBSD$
  */
 
 #ifndef CPUCONTROL_H
index 9efab30..7eca224 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2006, 2008 Stanislav Sedov <stas@FreeBSD.org>.
  * All rights reserved.
  *
@@ -24,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: release/10.0.0/usr.sbin/cpucontrol/intel.c 245491 2013-01-16 05:00:51Z eadler $");
+__FBSDID("$FreeBSD$");
 
 #include <assert.h>
 #include <stdio.h>
@@ -39,6 +41,7 @@ __FBSDID("$FreeBSD: release/10.0.0/usr.sbin/cpucontrol/intel.c 245491 2013-01-16
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/ioctl.h>
+#include <sys/ioccom.h>
 #include <sys/cpuctl.h>
 
 #include <machine/cpufunc.h>
@@ -85,7 +88,7 @@ intel_update(const char *dev, const char *path)
        intel_fw_header_t *fw_header;
        intel_cpu_signature_t *ext_table;
        intel_ext_header_t *ext_header;
-       uint32_t signature, flags;
+       uint32_t sig, signature, flags;
        int32_t revision;
        ssize_t ext_size;
        size_t ext_table_size;
@@ -144,7 +147,7 @@ intel_update(const char *dev, const char *path)
        fd = open(path, O_RDONLY, 0);
        if (fd < 0) {
                WARN(0, "open(%s)", path);
-               return;
+               goto fail;
        }
        error = fstat(fd, &st);
        if (error != 0) {
@@ -228,7 +231,8 @@ intel_update(const char *dev, const char *path)
                for (i = 0; i < (ext_table_size / sizeof(uint32_t)); i++)
                        sum += *((uint32_t *)ext_header + i);
                if (sum != 0) {
-                       WARNX(2, "%s: extended signature table checksum invalid",
+                       WARNX(2,
+                           "%s: extended signature table checksum invalid",
                            path);
                        goto no_table;
                }
@@ -243,10 +247,10 @@ no_table:
         */
        if (signature == fw_header->cpu_signature &&
            (flags & fw_header->cpu_flags) != 0)
-                       goto matched;
+               goto matched;
        else if (have_ext_table != 0) {
                for (i = 0; i < ext_header->sig_count; i++) {
-                       uint32_t sig = ext_table[i].cpu_signature;
+                       sig = ext_table[i].cpu_signature;
                        if (signature == sig &&
                            (flags & ext_table[i].cpu_flags) != 0)
                                goto matched;
@@ -258,17 +262,17 @@ matched:
        if (revision >= fw_header->revision) {
                WARNX(1, "skipping %s of rev %#x: up to date",
                    path, fw_header->revision);
-               return;
+               goto fail;
        }
        fprintf(stderr, "%s: updating cpu %s from rev %#x to rev %#x... ",
-                       path, dev, revision, fw_header->revision);
+           path, dev, revision, fw_header->revision);
        args.data = fw_data;
        args.size = data_size;
        error = ioctl(devfd, CPUCTL_UPDATE, &args);
        if (error < 0) {
-               error = errno;
+               error = errno;
                fprintf(stderr, "failed.\n");
-               errno = error;
+               errno = error;
                WARN(0, "ioctl()");
                goto fail;
        }
@@ -282,5 +286,4 @@ fail:
                close(devfd);
        if (fd >= 0)
                close(fd);
-       return;
 }
index c7215be..a30fc50 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2006, 2008 Stanislav Sedov <stas@FreeBSD.org>.
  * All rights reserved.
  *
@@ -22,7 +24,7 @@
  * (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: release/10.0.0/usr.sbin/cpucontrol/intel.h 181430 2008-08-08 16:26:53Z stas $
+ * $FreeBSD$
  */
 
 #ifndef INTEL_H
index e3f9007..354817e 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2011 Fabien Thomas <fabient@FreeBSD.org>.
  * All rights reserved.
  *
@@ -24,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: release/10.0.0/usr.sbin/cpucontrol/via.c 245491 2013-01-16 05:00:51Z eadler $");
+__FBSDID("$FreeBSD$");
 
 #include <assert.h>
 #include <stdio.h>
@@ -39,6 +41,7 @@ __FBSDID("$FreeBSD: release/10.0.0/usr.sbin/cpucontrol/via.c 245491 2013-01-16 0
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/ioctl.h>
+#include <sys/ioccom.h>
 #include <sys/cpuctl.h>
 
 #include <machine/cpufunc.h>
@@ -137,7 +140,7 @@ via_update(const char *dev, const char *path)
        fd = open(path, O_RDONLY, 0);
        if (fd < 0) {
                WARN(0, "open(%s)", path);
-               return;
+               goto fail;
        }
        error = fstat(fd, &st);
        if (error != 0) {
index c8ca740..4427ff3 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
  * Copyright (c) 2011 Fabien Thomas <fabient@FreeBSD.org>.
  * All rights reserved.
  *
@@ -22,7 +24,7 @@
  * (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: release/10.0.0/usr.sbin/cpucontrol/via.h 228436 2011-12-12 12:30:44Z fabient $
+ * $FreeBSD$
  */
 
 #ifndef VIA_H