Hello community,
here is the log from the commit of package iucode-tool for openSUSE:Factory checked in at 2018-02-02 22:23:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/iucode-tool (Old)
and /work/SRC/openSUSE:Factory/.iucode-tool.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "iucode-tool"
Fri Feb 2 22:23:17 2018 rev:6 rq:572024 version:2.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/iucode-tool/iucode-tool.changes 2017-10-27 14:00:22.314960804 +0200
+++ /work/SRC/openSUSE:Factory/.iucode-tool.new/iucode-tool.changes 2018-02-02 22:23:33.810286659 +0100
@@ -1,0 +2,19 @@
+Fri Feb 2 13:30:19 UTC 2018 - mpluskal@suse.com
+
+- Update to version 2.3:
+ * Ready for release: v2.3
+ * update copyright dates to 2018
+ * iucode_tool(8): document changes to ucode filtering
+ * iucode_tool: support selecting by ucode revision
+ * iucode_tool: add function to parse signed 32-bit integers
+ * iucode_tool: optimize detection of base10 numeric names
+ * iucode_tool: better handle offline/non-continuous topology
+ * iucode_tool(8): document changes to --scan-system
+ * iucode_tool: select scan-system strategy change at runtime
+ * gitignore: rearrange, and ignore backup and vim swap files
+ * iucode_tool: move scan_system_processor() one layer down
+ * iucode_tool: do not scan-system while parsing
+ * iucode_tool: add two command-line parser helpers
+ * intel_microcode.h: document intel_ucode_status_t sources
+
+-------------------------------------------------------------------
Old:
----
iucode-tool-2.2.tar.xz
New:
----
iucode-tool-2.3.tar.xz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ iucode-tool.spec ++++++
--- /var/tmp/diff_new_pack.fTM8KJ/_old 2018-02-02 22:23:34.802240354 +0100
+++ /var/tmp/diff_new_pack.fTM8KJ/_new 2018-02-02 22:23:34.806240168 +0100
@@ -1,7 +1,7 @@
#
# spec file for package iucode-tool
#
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -17,12 +17,12 @@
Name: iucode-tool
-Version: 2.2
+Version: 2.3
Release: 0
Summary: A program to manipulate Intel microcode update collections
License: GPL-2.0
Group: System/Boot
-Url: https://gitlab.com/iucode-tool/iucode-tool
+URL: https://gitlab.com/iucode-tool/iucode-tool
Source: %{name}-%{version}.tar.xz
BuildRequires: autoconf
BuildRequires: automake
++++++ _service ++++++
--- /var/tmp/diff_new_pack.fTM8KJ/_old 2018-02-02 22:23:34.834238861 +0100
+++ /var/tmp/diff_new_pack.fTM8KJ/_new 2018-02-02 22:23:34.834238861 +0100
@@ -4,8 +4,8 @@
<param name="scm">git</param>
<param name="changesgenerate">enable</param>
<param name="filename">iucode-tool</param>
- <param name="revision">refs/tags/v2.2</param>
- <param name="version">2.2</param>
+ <param name="revision">refs/tags/v2.3</param>
+ <param name="version">2.3</param>
</service>
<service mode="disabled" name="recompress">
<param name="file">*.tar</param>
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.fTM8KJ/_old 2018-02-02 22:23:34.854237928 +0100
+++ /var/tmp/diff_new_pack.fTM8KJ/_new 2018-02-02 22:23:34.854237928 +0100
@@ -1,4 +1,4 @@
<servicedata>
<service name="tar_scm">
<param name="url">https://gitlab.com/iucode-tool/iucode-tool.git</param>
- <param name="changesrevision">3d05f5b913703893795fe04338285444b8e7ebe1</param></service></servicedata>
\ No newline at end of file
+ <param name="changesrevision">327f21f412183ef8f29e8b0c3c8c44d841c63fc9</param></service></servicedata>
\ No newline at end of file
++++++ iucode-tool-2.2.tar.xz -> iucode-tool-2.3.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/ChangeLog new/iucode-tool-2.3/ChangeLog
--- old/iucode-tool-2.2/ChangeLog 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/ChangeLog 2018-01-28 16:00:44.000000000 +0100
@@ -1,3 +1,45 @@
+2018-01-28, iucode_tool v2.3
+
+ * iucode_tool(8): document changes to ucode filtering
+ * iucode_tool: support selecting by ucode revision
+ Add a third (and optional) parameter to microcode selection filters, to
+ select microcodes by revision. The revision can be prefixed by the
+ operators eq: (equal to), lt: (less than), or gt: (greater than).
+ The revision numbering is signed, but in order to be more user friendly,
+ since we display revisions as unsigned values in hex, we accept the
+ range -INT32_MAX to +UINT32_MAX, and convert it to int32_t.
+ * iucode_tool: add function to parse signed 32-bit integers
+ Add parse_s32e(), based on parse_u32(). It will be used to parse
+ microcode revisions in the command line, so it has an extension
+ that accepts something like 0xfffffffe as an alias for -2.
+ * iucode_tool: optimize detection of base10 numeric names
+ * iucode_tool: better handle offline/non-continuous topology
+ * iucode_tool(8): document changes to --scan-system
+ * iucode_tool: select scan-system strategy change at runtime
+ Instead of selecting the scan-system strategy at compile time, enhance the
+ long-version of the --scan-system option to take an optional argument, and
+ select the strategy. Available strategies are: 0 (auto), 1 (fast), and 2
+ (exact). Fast uses just the cpuid instruction and activates all steppings.
+ Exact will query all processors using the kernel cpuid driver. Auto (the
+ default) is currently the same as fast. The short option -S is equivalent
+ to --scan-system=auto. This way, we don't break backwards command line
+ behavior, and something like "iucode_tool -Sl" will still work. In
+ --scan-system=exact mode, when a /dev/cpu/#/cpuid scan fails, it will use
+ the result from the cpuid instruction and also add every other stepping for
+ any signatures found before the failure.
+ * gitignore: rearrange, and ignore backup and vim swap files
+ * iucode_tool: move scan_system_processor() one layer down
+ * iucode_tool: do not scan-system while parsing
+ Instead of processing -s and -S/--scan-system while parsing, queue all
+ filters so that we can call scan_system_processors() later. This was the
+ only complex operation that was being carried out while parsing the command
+ line. This change ensures that global options such as -q and -v, that are
+ not supposed to be sensitive to their position in the command line, will
+ work as expected.
+ * iucode_tool: add two command-line parser helpers
+ * intel_microcode.h: document intel_ucode_status_t sources
+ * update copyright dates to 2018
+
2017-08-28, iucode_tool v2.2
* README: update for mixed dat and bin Intel releases
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/NEWS new/iucode-tool-2.3/NEWS
--- old/iucode-tool-2.2/NEWS 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/NEWS 2018-01-28 16:00:44.000000000 +0100
@@ -1,3 +1,12 @@
+v2.3:
+ * Processor signature scan strategies can now be selected at
+ runtime, using a new optional argument of the --scan-system
+ option. It is possible to disable the "exact" scan strategy
+ (which uses the kernel cpuid device) at build time to reduce the
+ impact on executable size.
+ * Microcode updates for a specific signature can now be optionally
+ selected based on their revision, not just processor flags mask.
+
v2.2:
* build infrastructure changes: autoconf 2.69 or later, and
automake 1.13 or later are now required. The configure script
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/README new/iucode-tool-2.3/README
--- old/iucode-tool-2.2/README 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/README 2018-01-28 16:00:44.000000000 +0100
@@ -2,8 +2,8 @@
iucode_tool - Intel® 64 and IA-32 processor microcode tool
- Version 2.2
- August 28th, 2017
+ Version 2.3
+ January 28th, 2018
https://gitlab.com/iucode-tool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/configure.ac new/iucode-tool-2.3/configure.ac
--- old/iucode-tool-2.2/configure.ac 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/configure.ac 2018-01-28 16:00:44.000000000 +0100
@@ -1,6 +1,6 @@
dnl Process this file with autoconf 2.69+ to produce a configure script.
dnl
-dnl Copyright (c) 2010-2017 Henrique de Moraes Holschuh
+dnl Copyright (c) 2010-2018 Henrique de Moraes Holschuh
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
@@ -17,11 +17,11 @@
dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
AC_PREREQ([2.69])
-AC_INIT([iucode_tool], [2.2],
+AC_INIT([iucode_tool], [2.3],
[https://gitlab.com/iucode-tool/iucode-tool/issues],
[iucode-tool],
[https://gitlab.com/iucode-tool/iucode-tool/wikis/home])
-AC_COPYRIGHT([Copyright (c) 2010-2017 Henrique de Moraes Holschuh])
+AC_COPYRIGHT([Copyright (c) 2010-2018 Henrique de Moraes Holschuh])
AC_CONFIG_SRCDIR([iucode_tool.c])
AC_CANONICAL_HOST
@@ -128,23 +128,32 @@
[Path to the kernel microcode firmware directory])
AC_SUBST(MICROCODE_DIR_DEFAULT)
+AC_ARG_WITH([cpuid-device-parent],
+ [AS_HELP_STRING([--with-cpuid-device-parent=PATH],
+ [per-cpu devices parent directory (/dev/cpu)])],
+ [AS_IF([test "x$withval" = "x" || test "x$withval" = "xno"],
+ [AC_ERROR([use --disable-cpuid-device instead of --without-cpuid-device-parent])],
+ [CPUID_DEVICE_PARENT="$withval"])],
+ [CPUID_DEVICE_PARENT="/dev/cpu"])
+AC_DEFINE_UNQUOTED(CPUID_DEVICE_PARENT, "$CPUID_DEVICE_PARENT",
+ [path to the per-cpu tree of cpuid devices])
+AC_SUBST(CPUID_DEVICE_PARENT)
AC_ARG_WITH([cpuid-device-base],
[AS_HELP_STRING([--with-cpuid-device-base=PATH_FORMAT],
- [per-cpu cpuid device path (/dev/cpu/%u/cpuid)])],
+ [per-cpu cpuid device format string, relative to CPUID_DEVICE_PARENT (%s/cpuid)])],
[AS_IF([test "x$withval" = "x" || test "x$withval" = "xno"],
[AC_ERROR([use --disable-cpuid-device instead of --without-cpuid-device-base])],
[CPUID_DEVICE_BASE="$withval"])],
- [CPUID_DEVICE_BASE="/dev/cpu/%u/cpuid"])
+ [CPUID_DEVICE_BASE="%s/cpuid"])
AC_DEFINE_UNQUOTED(CPUID_DEVICE_BASE, "$CPUID_DEVICE_BASE",
- [fprintf base string to the per-cpu cpuid device])
+ [snprintf format string for the per-cpu cpuid device path, relative to CPUID_DEVICE_NAME])
AC_SUBST(CPUID_DEVICE_BASE)
AC_ARG_ENABLE([cpuid-device],
- [AS_HELP_STRING([--enable-cpuid-device],
- [use Linux cpuid device and check all cores])],
- [AS_IF([test "x$enableval" != "xno"],
- [AC_DEFINE(USE_CPUID_DEVICE, [], [Scan every core using Linux cpuid device])])
- ])
+ [AS_HELP_STRING([--disable-cpuid-device],
+ [disable support for the Linux cpuid device (cripples --scan-system=exact)])])
+AS_IF([test "x${enable_cpuid_device}" != "xno"],
+ [AC_DEFINE(USE_CPUID_DEVICE, [], [Support scanning every core using Linux cpuid device])])
AC_ARG_ENABLE([valgrind-build],
[AS_HELP_STRING([--enable-valgrind-build],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/intel_microcode.c new/iucode-tool-2.3/intel_microcode.c
--- old/iucode-tool-2.2/intel_microcode.c 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/intel_microcode.c 2018-01-28 16:00:44.000000000 +0100
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006 Tigran Aivazian
* 2006 Shaohua Li
- * 2010-2017 Henrique de Moraes Holschuh
+ * 2010-2018 Henrique de Moraes Holschuh
*
* Based on Linux kernel Intel Microcode driver v2.6.36-rc3 (1.14)
* Based on Linux microcode.ctl version 1.17
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/intel_microcode.h new/iucode-tool-2.3/intel_microcode.h
--- old/iucode-tool-2.2/intel_microcode.h 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/intel_microcode.h 2018-01-28 16:00:44.000000000 +0100
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2006 Tigran Aivazian
* 2006 Shaohua Li
- * 2010-2017 Henrique de Moraes Holschuh
+ * 2010-2018 Henrique de Moraes Holschuh
*
* Based on Linux kernel Intel Microcode driver v2.6.36-rc3 (1.14)
* Based on Linux microcode.ctl version 1.17
@@ -35,12 +35,14 @@
INTEL_UCODE_BAD_PARAMETERS,
INTEL_UCODE_INVALID_DATA,
INTEL_UCODE_UNKNOWN_FORMAT,
- INTEL_UCODE_COUNTEROVERFLOW,
+ /* only returned by intel_ucode_check_microcode() */
INTEL_UCODE_BAD_EXTENDED_TABLE,
INTEL_UCODE_BAD_EXTENDED_TABLE_CHECKSUM,
INTEL_UCODE_BAD_EXTENDED_SIG_CHECKSUM,
INTEL_UCODE_BAD_CHECKSUM,
+ /* only returned by the foreach functions */
INTEL_UCODE_CALLBACK_ERROR,
+ INTEL_UCODE_COUNTEROVERFLOW,
} intel_ucode_status_t;
struct intel_ucode_metadata {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/iucode_tool.8.in new/iucode-tool-2.3/iucode_tool.8.in
--- old/iucode-tool-2.2/iucode_tool.8.in 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/iucode_tool.8.in 2018-01-28 16:00:44.000000000 +0100
@@ -1,5 +1,5 @@
.\" hey, Emacs: -*- nroff -*-
-.\" Copyright (c) 2010-2017 Henrique de Moraes Holschuh
+.\" Copyright (c) 2010-2018 Henrique de Moraes Holschuh
.\"
.\" iucode_tool is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
.\" along with this program; see the file COPYING. If not, write to
.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
.\"
-.TH IUCODE_TOOL 8 "2016-11-10" "IUCODE_TOOL @VERSION@" "iucode_tool manual"
+.TH IUCODE_TOOL 8 "2018-01-28" "IUCODE_TOOL @VERSION@" "iucode_tool manual"
.\" Please update the above date whenever this man page is modified.
.\"
.\" Some roff macros, for reference:
@@ -179,11 +179,20 @@
.TP
-.BI "\-s ! | [!]" signature "[," pf_mask "]"
-Select microcodes by the specified \fIsignature\fP and \fIprocessor flags
-mask\fP (\fIpf_mask\fP). If the \fIprocessor flags mask\fP is specified, it will
-select only microcodes that are suitable for at least one of the processor flag
-combinations present in the mask.
+.BI "\-s ! | [!]" signature "[,[" pf_mask "][,[" lt: "|" eq: "|" gt: "]" revision "]]"
+Select microcodes by the specified \fIsignature\fP, \fIprocessor flags mask\fP
+(\fIpf_mask\fP), and \fIrevision\fP.
+
+If the \fIprocessor flags mask\fP is specified, it will select only microcodes
+that are suitable for at least one of the processor flag combinations present
+in the mask.
+
+If the \fIrevision\fP is specified, optionally prefixed by one of the
+\(lq\fIeq:\fP\(rq, \(lq\fIlt:\fP\(rq or \(lq\fIgt:\fP\(rq operators, it will
+select only microcodes that have that same \fIrevision\fP (if no operator, or
+if the \(lq\fIeq:\fP\(rq operator is used), or microcodes that have a
+\fIrevision\fP that is less than (\(lq\fIlt:\fP\(rq operator), or greater than
+(\(lq\fIgt:\fP\(rq operator), the one specified.
Specify more than once to select more microcodes. This option can be combined
with the \fI\-\-scan\-system\fP option to select more microcodes. If
@@ -201,7 +210,7 @@
the non\-negated form of \fI\-s\fP, or using \fI\-\-scan\-system\fP).
.TP
-.BR "\-S" ", " "\-\-scan\-system"
+.BR "\-S" ", " "\-\-scan\-system" "[=\fImode\fP]"
Select microcodes by scanning online processors on this system for their
signatures.
@@ -210,10 +219,26 @@
\fI\-\-scan\-system\fP can also be deselected by a later \fI\-s\ !signature\fP
option.
-Should the signature scan fail, the program will print a warning to the user
-and continue as if \fI\-\-scan\-system\fP had not been specified. This is a
-fail-safe condition when \fBiucode_tool\fP is used to install microcode updates
-for the next boot.
+The optional \fImode\fP argument (accepted only by the long version of the
+option) selects the strategy used to scan processors:
+.RS
+.IP "\fB0\fP or \fBauto\fP"
+Currently the same as \fBfast\fP, but this might change in future versions if
+Intel ever deploys multi-signature systems that go beyond mixed-stepping. This
+is the default mode of operation, for backwards compatibility
+with previous versions of \fBiucode_tool\fP.
+.IP "\fB1\fP or \fBfast\fP"
+Uses the cpuid instruction to detect the signature of the processor
+\fBiucode_tool\fP is running on, and selects all steppings for that processor's
+type, family and model. Supports mixed-stepping systems.
+.IP "\fB2\fP or \fBexact\fP"
+Uses kernel drivers to scan the signature of every online processor directly.
+This mode supports multi-signature systems. This scan mode will be slow on
+large systems with many processors, and likely requires special permissions
+(such as running as the root user). Should the scan fail for any reason, as
+a fail-safe measure, it will issue an warning and consider all possible
+steppings for every signature it did manage to scan successfully.
+.RE
.TP
\fB\-\-date\-before\fR=\fIYYYY\-MM\-DD\fR and \fB\-\-date\-after\fR=\fIYYYY\-MM\-DD\fR
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iucode-tool-2.2/iucode_tool.c new/iucode-tool-2.3/iucode_tool.c
--- old/iucode-tool-2.2/iucode_tool.c 2017-08-28 16:40:04.000000000 +0200
+++ new/iucode-tool-2.3/iucode_tool.c 2018-01-28 16:00:44.000000000 +0100
@@ -1,7 +1,7 @@
/*
* iucode_tool - Manipulates Intel(R) IA32/x86_64 processor microcode bundles
*
- * Copyright (c) 2010-2017 Henrique de Moraes Holschuh
+ * Copyright (c) 2010-2018 Henrique de Moraes Holschuh
* 2000 Simon Trimmer, Tigran Aivazian
*
* Some code copied from microcode.ctl v1.17.
@@ -177,12 +177,33 @@
static struct microcode_iterator_data microcode_iterator_data;
/* Filter masks */
+#define IUCODE_FILTERMASK_SCANCPUS 0xffffffffU
+
+enum iuc_rev_match_mode {
+ IUCODE_REVFLT_ANY = 0, /* Ignore revision on match */
+ IUCODE_REVFLT_EQ, /* Revision must be = filter's rev */
+ IUCODE_REVFLT_LT, /* Revision must be < filter's rev */
+ IUCODE_REVFLT_GT, /* Revision must be > filter's rev */
+
+ IUCODE_REVFLT_SIZE /* EOL */
+};
+static const char * const iuc_rev_match_mode_s[IUCODE_REVFLT_SIZE] = {
+ [IUCODE_REVFLT_ANY] = NULL,
+ [IUCODE_REVFLT_EQ] = "eq:",
+ [IUCODE_REVFLT_LT] = "lt:",
+ [IUCODE_REVFLT_GT] = "gt:",
+}; /* keep this in sync with enum iuc_rev_match_mode !! */
+
struct microcode_filter_entry {
struct microcode_filter_entry *next;
uint32_t cpuid; /* exact match */
uint32_t pfm; /* common bits set match */
- int invert;
+ int32_t rev;
+ enum iuc_rev_match_mode rev_match;
+ int invert;
};
+static struct microcode_filter_entry *uc_filter_queue = NULL;
+static struct microcode_filter_entry *uc_filter_queue_tail = NULL;
static struct microcode_filter_entry *uc_filter_list = NULL;
static int filter_list_allow = 1;
@@ -247,6 +268,31 @@
return 0;
}
+static int parse_s32e(const char *nptr, char **endptr, int base,
+ int32_t * const res)
+{
+ long int l;
+
+ assert(nptr);
+ assert(endptr);
+ assert(res);
+
+ errno = 0;
+ l = strtol(nptr, endptr, base);
+ if (errno || nptr == *endptr)
+ return errno ? errno : EINVAL;
+ if (l > UINT32_MAX || l < INT32_MIN)
+ return ERANGE;
+
+ /*
+ * Accept UINT32_MAX >= x > INT32_MAX, as if it were
+ * the binary representation of int32_t read as uint32_t
+ */
+ *res = (int32_t)(l & UINT32_MAX);
+
+ return 0;
+}
+
static int is_valid_fd(const int fd)
{
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
@@ -1898,7 +1944,6 @@
return !!((d > datefilter_min) && (d < datefilter_max));
}
-static void free_filter_list(struct microcode_filter_entry *f) __attribute__((unused));
static void free_filter_list(struct microcode_filter_entry *f)
{
static struct microcode_filter_entry *p;
@@ -1910,9 +1955,15 @@
}
}
-static void xx_merge_filter(struct microcode_filter_entry * const f,
- const uint32_t pf_mask, const int invert)
-{
+static int xx_merge_filter(struct microcode_filter_entry * const f,
+ const uint32_t pf_mask, const int32_t rev,
+ const enum iuc_rev_match_mode rev_match,
+ const int invert)
+{
+ /* FIXME: we could do better, sometimes it is possible to merge */
+ if (f->rev_match != rev_match || f->rev != rev)
+ return 0; /* can't merge */
+
if (f->invert == invert) {
f->pfm |= pf_mask;
} else if (!(f->invert)) {
@@ -1921,15 +1972,21 @@
f->invert = 0;
f->pfm = pf_mask;
}
+
+ return 1; /* merged */
}
-static int add_filter_to_list(uint32_t cpuid, uint32_t pf_mask, int invert,
- struct microcode_filter_entry ** const base)
+static int add_filter_to_list(uint32_t cpuid, uint32_t pf_mask, int32_t rev,
+ enum iuc_rev_match_mode rev_match, int invert,
+ struct microcode_filter_entry ** const base)
{
struct microcode_filter_entry **pnext, *n;
assert(base);
+ if (!cpuid || cpuid == IUCODE_FILTERMASK_SCANCPUS)
+ return EINVAL;
+
if (!pf_mask)
pf_mask = PFMASK_MATCH_ANY;
@@ -1940,13 +1997,16 @@
if (*pnext && (*pnext)->cpuid == cpuid) {
if (((pf_mask & (*pnext)->pfm) == pf_mask) &&
- ((*pnext)->invert == invert)) {
+ (*pnext)->rev_match == rev_match &&
+ (*pnext)->rev == rev &&
+ (*pnext)->invert == invert) {
/* found equivalent, report it */
return EEXIST;
}
- xx_merge_filter(*pnext, pf_mask, invert);
- return 0;
+ /* merge when possible */
+ if (xx_merge_filter(*pnext, pf_mask, rev, rev_match, invert))
+ return 0;
}
/* insert before */
@@ -1955,6 +2015,8 @@
return ENOMEM;
n->cpuid = cpuid;
n->pfm = pf_mask;
+ n->rev = rev;
+ n->rev_match = rev_match;
n->invert = invert;
n->next = *pnext;
*pnext = n;
@@ -1982,34 +2044,51 @@
while (*pp && (*pp)->cpuid < e->cpuid)
pp = &((*pp)->next);
- if (*pp && (*pp)->cpuid == e->cpuid) {
- xx_merge_filter(*pp, e->pfm, e->invert);
- } else {
+ if (!*pp || (*pp)->cpuid != e->cpuid ||
+ !xx_merge_filter(*pp, e->pfm, e->rev, e->rev_match, e->invert)) {
/* insert before */
e->next = *pp;
*pp = e;
e = NULL;
}
- if (e)
- free(e);
+ free(e);
+ }
+}
+
+static int xx_compare_rev(const int32_t rev,
+ const struct microcode_filter_entry *f)
+{
+ const enum iuc_rev_match_mode op = f->rev_match;
+
+ if ((op == IUCODE_REVFLT_ANY) ||
+ (op == IUCODE_REVFLT_EQ && rev == f->rev) ||
+ (op == IUCODE_REVFLT_LT && rev < f->rev) ||
+ (op == IUCODE_REVFLT_GT && rev > f->rev)) {
+ return !(f->invert);
}
+
+ return -1;
}
/* returns non-zero if selected */
static int is_selected(const uint32_t cpuid,
const uint32_t pf_mask,
+ const int32_t rev,
const struct microcode_filter_entry *f)
{
+ int state = -1;
+
while (f && f->cpuid < cpuid)
f = f->next;
- while (f && f->cpuid == cpuid) {
+ while (f && f->cpuid == cpuid && state < 0) {
if ((pf_mask & f->pfm) != 0 ||
- f->pfm == PFMASK_MATCH_ANY)
- return !(f->invert);
+ f->pfm == PFMASK_MATCH_ANY) {
+ state = xx_compare_rev(rev, f);
+ }
f = f->next;
}
- return filter_list_allow;
+ return (state >= 0)? state : filter_list_allow;
}
/* Microcode extended signature deduplication */
@@ -2230,7 +2309,7 @@
INTEL_UCLE_HASXST;
extsig_tables_in_use = 1;
}
- if (is_selected(cpuid, pf_mask, uc_filter_list))
+ if (is_selected(cpuid, pf_mask, m.revision, uc_filter_list))
uce_flags |= (is_in_date_range(&m)) ?
INTEL_UCLE_SELECT : INTEL_UCLE_SELID;
@@ -2640,7 +2719,7 @@
* Get main processor signature from cpuid(1) EAX
* and add it as a filter.
*/
- switch (add_filter_to_list(sig, 0, 0, ucfp)) {
+ switch (add_filter_to_list(sig, 0, 0, IUCODE_REVFLT_ANY, 0, ucfp)) {
case ENOMEM:
print_err("out of memory");
return ENOMEM;
@@ -2656,8 +2735,22 @@
}
#ifdef USE_CPUID_DEVICE
-static int check_cpuid_devs(__attribute__((unused)) const uint32_t sig,
- struct microcode_filter_entry ** const ucfp)
+static int is_base10_number(const char *s)
+{
+ if (!s || !*s)
+ return 0;
+
+ while(*s) {
+ if (*s < '0' || *s > '9')
+ return 0;
+ s++;
+ }
+
+ return 1;
+}
+
+/* requires a kernel driver, and *really* hurts on very large systems */
+static int xx_check_cpuid_devs(struct microcode_filter_entry ** const ucfp)
{
uint32_t cpuid_buf[8]; /* two cpuid levels */
char cpuid_device[PATH_MAX];
@@ -2665,27 +2758,57 @@
int rc = 0;
unsigned int i = 0;
unsigned int ncpu = 0;
+ struct dirent *d;
+
+ DIR *cpudir = opendir(CPUID_DEVICE_PARENT);
+ if (!cpudir) {
+ int en = errno;
+ print_err("%s: could not open directory: %s", CPUID_DEVICE_PARENT, strerror(en));
+ return -1;
+ }
while (1) {
+ errno = 0;
+ d = readdir(cpudir);
+ if (!d) {
+ int err = errno;
+ if (unlikely(err)) {
+ print_err("%s: cannot walk directory: %s",
+ CPUID_DEVICE_PARENT, strerror(err));
+ rc = -1; /* note that we skipped processors due to unexpected errors */
+ }
+ break; /* finish/abort walk */
+ }
+
+ /* Linux procfs supports d_type */
+ if (d->d_type != DT_DIR)
+ continue; /* next dentry */
+
+ /* must be [0-9]+, no trailling weirdness */
+ if (!is_base10_number(d->d_name))
+ continue; /* next dentry */
+
snprintf(cpuid_device, sizeof(cpuid_device),
- CPUID_DEVICE_BASE, i);
- cpuid_fd = open(cpuid_device, O_RDONLY);
+ CPUID_DEVICE_BASE, d->d_name);
+
+ errno = EINTR;
+ cpuid_fd = -1;
+ while (cpuid_fd == -1 && errno == EINTR)
+ cpuid_fd = openat(dirfd(cpudir), cpuid_device, O_RDONLY | O_CLOEXEC);
if (cpuid_fd == -1) {
int en = errno;
- print_msg(4, "%s: returned error status on open(): %s",
- cpuid_device, strerror(en));
+ print_msg(4, "%s/%s: returned error status on open(): %s",
+ CPUID_DEVICE_PARENT, cpuid_device, strerror(en));
- if (en == EINTR)
- continue; /* try again */
if (en == ENOENT)
break; /* cpuid device inode not found */
if (en == ENXIO || en == EIO) {
/* Linux cpuid driver: ENXIO: offline; EIO: no cpuid support */
print_msg(2, "processor %u is offline or has no cpuid support", i);
} else {
- print_msg(2, "%s: cannot open cpuid device node: %s",
- cpuid_device, strerror(en));
+ print_msg(2, "%s/%s: cannot open cpuid device node: %s",
+ CPUID_DEVICE_PARENT, cpuid_device, strerror(en));
rc = -1; /* note that we skipped processors due to unexpected errors */
}
@@ -2694,13 +2817,14 @@
continue;
}
- print_msg(3, "trying to get CPUID information from %s",
- cpuid_device);
+ print_msg(3, "trying to get CPUID information from %s/%s",
+ CPUID_DEVICE_PARENT, cpuid_device);
if (read(cpuid_fd, &cpuid_buf, sizeof(cpuid_buf)) == -1) {
- print_err("%s: access to CPUID(0) and CPUID(1) failed: %s",
- cpuid_device, strerror(errno));
+ print_err("%s/%s: access to CPUID(0) and CPUID(1) failed: %s",
+ CPUID_DEVICE_PARENT, cpuid_device, strerror(errno));
/* this is in the should not happen list, so abort */
close(cpuid_fd);
+ closedir(cpudir);
return 1;
}
@@ -2716,6 +2840,8 @@
i++;
};
+ closedir(cpudir);
+
if (i == 0 && ncpu == 0) {
print_err("cpuid kernel driver unavailable");
return -1;
@@ -2732,16 +2858,22 @@
return rc;
}
#else
+static int xx_check_cpuid_devs(__attribute__((unused)) struct microcode_filter_entry ** const ucfp)
+{
+ print_msg(1, "support for exact system scan disabled at compile time");
+ return -1;
+}
+#endif /* USE_CPUID_DEVICE */
-/* this hurts a lot less on very big systems... */
-static int check_cpuid_devs(uint32_t sig, struct microcode_filter_entry ** const ucfp)
+
+/* xx_add_all_steppings(cpuid) hurts a lot less on very big systems... */
+static int xx_add_all_steppings(uint32_t sig, struct microcode_filter_entry ** const ucfp)
{
unsigned int i;
- print_msg(2, "assuming all processors have the same type, family and model");
sig |= 0xf;
for (i = 0; i < 0x10; i++) {
- if (add_filter_to_list(sig, 0, 0, ucfp) == ENOMEM) {
+ if (add_filter_to_list(sig, 0, 0, IUCODE_REVFLT_ANY, 0, ucfp) == ENOMEM) {
print_err("out of memory");
return ENOMEM;
}
@@ -2749,14 +2881,46 @@
}
return 0;
}
-#endif
-static int scan_system_processors(void)
+/* Handle mixed-signature systems, even if Intel still hasn't admited that
+ * they will exist in the SDM, the writing is already out in the wall */
+static int xx_add_all_steppings_for_every_sig(uint32_t sig, struct microcode_filter_entry ** const ucfp)
+{
+ struct microcode_filter_entry *fl = NULL;
+ struct microcode_filter_entry *p;
+ int rc;
+
+ /* failsafe of the failsafe: add running processor sig */
+ rc = xx_add_all_steppings(sig, &fl);
+
+ /* creating a new list is just plain safer in the long run */
+ p = *ucfp;
+ while (p && !rc) {
+ /* handle mixed sig systems, unlikely as that might be */
+ if (p->cpuid != sig)
+ rc = xx_add_all_steppings(p->cpuid, &fl);
+ p = p->next;
+ }
+
+ if (!rc) {
+ free_filter_list(*ucfp);
+ *ucfp = fl;
+ } else {
+ free_filter_list(fl);
+ }
+
+ return rc;
+}
+
+static int scan_system_processors(unsigned int strategy,
+ struct microcode_filter_entry ** const filter_list)
{
uint32_t id0, id1, id2, id3, sig, idx;
struct microcode_filter_entry *uc_cpu = NULL;
int rc = 0;
+ assert(filter_list);
+
print_msg(3, "trying to get CPUID information directly");
if (!(__get_cpuid(0, &id0, &id1, &id2, &id3) &&
__get_cpuid(1, &sig, &idx, &idx, &idx))) {
@@ -2775,7 +2939,15 @@
switch (xx_scan_handle_sig(id1, id2, id3, sig, &uc_cpu)) {
case 0:
- rc = check_cpuid_devs(sig, &uc_cpu);
+ if (strategy == 2) {
+ if (xx_check_cpuid_devs(&uc_cpu)) {
+ print_warn("exact cpuid signature scan failed, switching to failsafe strategy");
+ rc = xx_add_all_steppings_for_every_sig(sig, &uc_cpu);
+ }
+ } else {
+ print_msg(2, "assuming all processors have the same type, family and model");
+ rc = xx_add_all_steppings(sig, &uc_cpu);
+ }
break;
case ENXIO:
print_msg(1, "running on a non-Intel processor");
@@ -2792,18 +2964,81 @@
if (uc_cpu) {
/* tie linked lists */
- add_filter_list_to_list(&uc_filter_list, uc_cpu);
+ add_filter_list_to_list(filter_list, uc_cpu);
uc_cpu = NULL;
}
return (rc > 0) ? rc : 0;
}
+static int cmdline_queue_ucode_filter(uint32_t cpuid, uint32_t pf_mask,
+ int32_t rev, enum iuc_rev_match_mode rev_match,
+ int invert)
+{
+ struct microcode_filter_entry *n;
+
+ n = malloc(sizeof(struct microcode_filter_entry));
+ if (!n)
+ return ENOMEM;
+ n->cpuid = cpuid;
+ n->pfm = pf_mask;
+ n->rev = rev;
+ n->rev_match = rev_match;
+ n->invert = invert;
+ n->next = NULL;
+
+ if (uc_filter_queue_tail) {
+ uc_filter_queue_tail->next = n;
+ } else {
+ uc_filter_queue = n;
+ }
+
+ uc_filter_queue_tail = n;
+
+ return 0;
+}
+
+static int process_ucode_filter_queue(void)
+{
+ struct microcode_filter_entry *p = uc_filter_queue;
+ int rc = 0;
+
+ while(p && !rc) {
+ if (p->cpuid != IUCODE_FILTERMASK_SCANCPUS) {
+ rc = add_filter_to_list(p->cpuid, p->pfm, p->rev, p->rev_match, p->invert, &uc_filter_list);
+ if (rc == EEXIST)
+ rc = 0;
+ } else {
+ rc = scan_system_processors(p->pfm, &uc_filter_list);
+ }
+
+ p = p->next;
+ }
+
+ uc_filter_queue_tail = NULL;
+ free_filter_list(uc_filter_queue);
+ uc_filter_queue = NULL;
+
+ switch(rc) {
+ case 0:
+ return 0;
+
+ case ENOMEM:
+ print_err("Cannot add filter entry: out of memory");
+ break;
+ case EINVAL:
+ print_err("Internal error while processing filter list");
+ break;
+ }
+
+ return 1;
+}
+
/* Command line processing */
static const char program_version[] =
PROGNAME " " VERSION "\n"
- "Copyright (c) 2010-2017 by Henrique de Moraes Holschuh\n\n"
+ "Copyright (c) 2010-2018 by Henrique de Moraes Holschuh\n\n"
"Based on code from the Linux microcode_intel driver and from\n"
"the microcode.ctl package, copyright (c) 2000 by Simon Trimmer\n"
@@ -2851,6 +3086,7 @@
IUCODE_ARGP_DATEAFTER,
IUCODE_ARGP_DATEFSTRICT,
IUCODE_ARGP_DATEFLOOSE,
+ IUCODE_ARGP_SCANSYSTEMOPT,
IUCODE_ARGP_EIRFS,
IUCODE_ARGP_MINSIZE_EIRFS,
IUCODE_ARGP_DFLSIZE_EIRFS,
@@ -2870,19 +3106,29 @@
"selected by filename suffix)",
10 },
- { NULL, 's', "! | [!]signature[,pf_mask]", 0,
- "Select microcodes by the specified signature and processor "
- "flags mask (pf_mask). Specify more than once to select/unselect "
- "more microcodes. Prefix with ! to unselect microcodes. "
+ { NULL, 's', "! | [!]signature[,[pf_mask][,[lt:|eq:|gt:]revision]]", 0,
+ "Select microcodes by the specified signature, processor "
+ "flags mask (pf_mask), and revision. Optionally, prefix revision "
+ "with eq: (equal -- implied there is no prefix), lt: (less than) "
+ "or gt: (greater than). "
+ "Specify more than once to select/unselect more microcodes. "
+ "Prefix with ! to unselect microcodes. "
"Use -s ! to disable the default behavior of selecting all "
"microcodes when no -s or -S filter is specified",
20 },
- { "scan-system", 'S', NULL, 0,
+ { NULL, 'S', NULL, 0,
+ "Same as --scan-system=auto",
+ 21 },
+ { "scan-system", IUCODE_ARGP_SCANSYSTEMOPT, "mode", OPTION_ARG_OPTIONAL,
"Select microcodes based on the running system processor(s). "
"Can be combined with the -s option, and can be used only once. "
"Microcodes selected by --scan-system can be unselected by a "
- "later -s !<signature> option",
- 20 },
+ "later -s !<signature> option. The optional mode argument "
+ "selects the strategy: 0 or auto (default); 1 or fast (good for "
+ "most systems, including mixed-stepping); and 2 or exact (slow, "
+ "supports multi-signature systems, requires the cpuid kernel "
+ "driver and might require root access)",
+ 22 },
{ "downgrade", IUCODE_ARGP_DOWNGRADE, NULL, 0,
"Instead of discarding microcodes based on revision level, "
@@ -2976,6 +3222,8 @@
};
static const char cmdline_nonarg_doc[] = "[[-t<type>] filename] ...";
+static const char * const cmdline_scan_system_tbl[] = { "auto", "fast", "exact", NULL };
+
static int new_filename(const char * const fn,
const intel_ucode_file_type_t ftype)
{
@@ -3022,15 +3270,17 @@
input_files = NULL;
}
-/* -s ! | [!]cpuid[,pf_mask] */
-static int add_ucode_filter(const char *arg)
+/* -s ! | [!]cpuid[,[pf_mask][,[]rev]] */
+static int cmdline_parse_ucode_filter(const char *arg)
{
char *p;
uint32_t acpuid, amask;
- int invert;
+ int32_t arev;
+ int invert, arev_match;
amask = 0;
invert = 0;
+ arev = 0;
while (isspace(*arg))
arg++;
@@ -3051,28 +3301,65 @@
}
}
+ /* cpuid, mandatory */
if (!*arg || parse_u32(arg, &p, 0, &acpuid))
return EINVAL;
while (isspace(*p))
p++;
+ /* pf_mask, optional */
if (*p == ',') {
p++;
+ if (*p != ',') {
+ arg = p;
+ if (!*arg || parse_u32(arg, &p, 0, &amask))
+ return EINVAL;
+ } /* else amask = MATCH_ANY */
+ while (isspace(*p))
+ p++;
+ } else if (*p) {
+ return EINVAL;
+ }
+
+ /* rev, optional */
+ if (*p == ',') {
+ p++;
+ while (isspace(*p))
+ p++;
+ if (!*p)
+ return EINVAL;
+
+ /* revison match operator, optional */
+ int i = 0;
+ while (i < IUCODE_REVFLT_SIZE &&
+ (!iuc_rev_match_mode_s[i] ||
+ strncasecmp(p, iuc_rev_match_mode_s[i],
+ strlen(iuc_rev_match_mode_s[i]))))
+ i++;
+ if (i < IUCODE_REVFLT_SIZE) {
+ arev_match = i;
+ p += strlen(iuc_rev_match_mode_s[i]);
+ } else {
+ arev_match = IUCODE_REVFLT_EQ;
+ }
+
+ /* revision */
arg = p;
- if (!*arg || parse_u32(arg, &p, 0, &amask))
+ if (!*arg || parse_s32e(arg, &p, 0, &arev))
return EINVAL;
while (isspace(*p))
p++;
- if (*p)
- return EINVAL;
- } else if (*p) {
+ } else {
+ arev_match = IUCODE_REVFLT_ANY;
+ }
+ if (*p) {
return EINVAL;
}
if (!invert)
filter_list_allow = 0;
- return add_filter_to_list(acpuid, amask, invert, &uc_filter_list);
+ return cmdline_queue_ucode_filter(acpuid, amask, arev, arev_match, invert);
}
/* YYYY-MM-DD */
@@ -3114,6 +3401,55 @@
return 0;
}
+static int cmdline_get_int(const char *arg, int pmin, int pmax, int *d)
+{
+ char *p;
+ long int l;
+
+ if (!arg)
+ return 0;
+
+ errno = 0;
+ l = strtol(arg, &p, 10);
+ if (errno || p == arg)
+ return errno ? errno : EINVAL;
+ if (l > INT32_MAX || l < INT32_MIN)
+ return ERANGE;
+ if (l < pmin || l > pmax)
+ return EINVAL;
+
+ while (isspace(*p))
+ p++;
+ if (*p)
+ return EINVAL;
+
+ if (d)
+ *d = (int) l;
+
+ return 0;
+}
+
+/* note: does not tolerate trailing blanks */
+static int cmdline_get_enumstr(const char *arg, const char * const table[],
+ int *d)
+{
+ int r = 0;
+
+ if (!arg || !table)
+ return 0;
+
+ while (table[r]) {
+ if (!strcasecmp(arg, table[r])) {
+ if (d)
+ *d = r;
+ return 0;
+ }
+ r++;
+ }
+
+ return ENOENT;
+}
+
static error_t cmdline_do_parse_arg(int key, char *arg,
struct argp_state *state)
{
@@ -3237,29 +3573,61 @@
break;
case 's':
- rc = add_ucode_filter(arg);
+ rc = cmdline_parse_ucode_filter(arg);
switch (rc) {
case 0:
- case EEXIST:
break; /* success */
case EINVAL:
argp_error(state, "invalid filter: '%s'", arg);
break; /* not reached */
default:
argp_failure(state, EXIT_SWFAILURE, rc,
- "could not add filter '%s'", arg);
+ "could not queue filter '%s'", arg);
}
command_line_actions |= IUCODE_F_UCSELECT;
break;
+
case 'S':
+ /*
+ * -S and --scan-system cannot be handled the same way
+ * because -S cannot be made OPTION_ARG_OPTIONAL: it would
+ * break command-line backwards compatibility when people
+ * specify several short options together and -S is not the
+ * last option in the chain
+ */
+ if (command_line_actions & IUCODE_DO_SELPROC)
+ argp_error(state,
+ "--scan-system option can be specified only once");
+ /*
+ * note: the pfm field of the queue filter item is used to
+ * encode the scan-system strategy.
+ */
+ rc = cmdline_queue_ucode_filter(IUCODE_FILTERMASK_SCANCPUS, 0, 0, 0, 0);
+ if (rc)
+ argp_failure(state, EXIT_SWFAILURE, rc,
+ "could not queue --scan-system action");
+ command_line_actions |= IUCODE_DO_SELPROC | IUCODE_F_UCSELECT;
+ break;
+ case IUCODE_ARGP_SCANSYSTEMOPT:
if (command_line_actions & IUCODE_DO_SELPROC)
argp_error(state,
"--scan-system option can be specified only once");
- if (scan_system_processors()) {
- argp_failure(state, EXIT_SWFAILURE, 0,
- "fatal failure while scanning for system processors");
- }
+ int scan_system_strategy = 0;
+ if (cmdline_get_int(arg, 0, 2, &scan_system_strategy) &&
+ cmdline_get_enumstr(arg, cmdline_scan_system_tbl, &scan_system_strategy))
+ argp_error(state, "invalid --scan-system mode: '%s'", arg);
+
+ /*
+ * note: the pfm field of the queue filter item is used to
+ * encode the scan-system strategy.
+ */
+ rc = cmdline_queue_ucode_filter(IUCODE_FILTERMASK_SCANCPUS,
+ (uint32_t)scan_system_strategy,
+ 0, 0, 0);
+ if (rc)
+ argp_failure(state, EXIT_SWFAILURE, rc,
+ "could not queue --scan-system action");
command_line_actions |= IUCODE_DO_SELPROC | IUCODE_F_UCSELECT;
break;
@@ -3335,6 +3703,11 @@
goto do_nothing;
}
+ if (process_ucode_filter_queue()) {
+ rc = EXIT_SWFAILURE;
+ goto err_exit;
+ }
+
if (command_line_actions & IUCODE_DO_LOADFILE) {
struct filename_list *fn = input_files;
while (fn && next_bundle_id) {