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.  This goes well
beyond the required, since it actually means iucode_tool supports
multi-signature systems in --scan-system=exact mode...
parent f626ff7a
......@@ -140,11 +140,10 @@ AC_DEFINE_UNQUOTED(CPUID_DEVICE_BASE, "$CPUID_DEVICE_BASE",
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],
......
......@@ -2661,8 +2661,8 @@ static int xx_scan_handle_sig(const uint32_t id1, const uint32_t id2,
}
#ifdef USE_CPUID_DEVICE
static int check_cpuid_devs(__attribute__((unused)) const uint32_t sig,
struct microcode_filter_entry ** const ucfp)
/* 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];
......@@ -2737,13 +2737,19 @@ static int check_cpuid_devs(__attribute__((unused)) const uint32_t sig,
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) {
......@@ -2754,9 +2760,39 @@ static int check_cpuid_devs(uint32_t sig, struct microcode_filter_entry ** const
}
return 0;
}
#endif
static int scan_system_processors(struct microcode_filter_entry ** const filter_list)
/* 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;
......@@ -2782,7 +2818,15 @@ static int scan_system_processors(struct microcode_filter_entry ** const filter_
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");
......@@ -2840,7 +2884,7 @@ static int process_ucode_filter_queue(void)
if (rc == EEXIST)
rc = 0;
} else {
rc = scan_system_processors(&uc_filter_list);
rc = scan_system_processors(p->pfm, &uc_filter_list);
}
p = p->next;
......@@ -2917,6 +2961,7 @@ enum {
IUCODE_ARGP_DATEAFTER,
IUCODE_ARGP_DATEFSTRICT,
IUCODE_ARGP_DATEFLOOSE,
IUCODE_ARGP_SCANSYSTEMOPT,
IUCODE_ARGP_EIRFS,
IUCODE_ARGP_MINSIZE_EIRFS,
IUCODE_ARGP_DFLSIZE_EIRFS,
......@@ -2943,12 +2988,19 @@ static const struct argp_option cmdline_options[] = {
"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, "
......@@ -3042,6 +3094,8 @@ static const struct argp_option cmdline_options[] = {
};
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)
{
......@@ -3365,16 +3419,49 @@ static error_t cmdline_do_parse_arg(int key, char *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);
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");
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);
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_DATEBEFORE:
case IUCODE_ARGP_DATEAFTER:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment