iucode_tool: better handle offline/non-continuous topology

Iterate the /dev/cpu directory, instead of assuming anything about the
cpu id (other than the fact that they're decimal numbers).

We require the /dev/cpu/<cpu number> entries to be directories, all
numeric.
parent 99a0a85d
......@@ -128,15 +128,25 @@ AC_DEFINE_UNQUOTED(MICROCODE_DIR_DEFAULT, "$MICROCODE_DIR_DEFAULT",
[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],
......
......@@ -2670,27 +2670,60 @@ static int xx_check_cpuid_devs(struct microcode_filter_entry ** const ucfp)
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) {
unsigned int cpu_number;
char *ep;
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 (parse_u32(d->d_name, &ep, 10, &cpu_number) || !ep || *ep)
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 */
}
......@@ -2699,13 +2732,14 @@ static int xx_check_cpuid_devs(struct microcode_filter_entry ** const ucfp)
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;
}
......@@ -2721,6 +2755,8 @@ static int xx_check_cpuid_devs(struct microcode_filter_entry ** const ucfp)
i++;
};
closedir(cpudir);
if (i == 0 && ncpu == 0) {
print_err("cpuid kernel driver unavailable");
return -1;
......
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