Commit 29c73dac authored by Henrique de Moraes Holschuh's avatar Henrique de Moraes Holschuh

Merge branches 'topic/misc' and 'topic/standalone-argp'

......@@ -41,9 +41,11 @@ for all Intel i686 and X86_64 processor models.
Updating the system processor microcode:
The Intel-distributed microcode bundle contains microcode update data for
several processor models. It uses a text format which is unsuitable to be
used directly by the Linux kernel: it must be converted by an utility like
iucode_tool before Linux can use it.
several processor models. Older microcode releases used a text format
which is unsuitable to be used directly by the Linux kernel: it must be
converted by an utility like iucode_tool before Linux can use it. Newer
releases have the same microcode update content both in the legacy text
format, and in binary format.
Updating the processor microcode is a process that can be done at any time
(even with the system at full load), and as many times as required. It is
......@@ -227,17 +229,30 @@ can be listed by iucode_tool:
iucode_tool -L /usr/share/misc/intel-microcode.dat
microcode bundle 1: /usr/share/misc/intel-microcode.dat
01/001: sig 0x00000683, pf_mask 0x01, 2001-02-06, rev 0x0013, size 2048
01/002: sig 0x00000f4a, pf_mask 0x5c, 2005-12-14, rev 0x0004, size 2048
01/003: sig 0x00000653, pf_mask 0x04, 1999-05-20, rev 0x000b, size 2048
001/001: sig 0x00000683, pf_mask 0x01, 2001-02-06, rev 0x0013, size 2048
001/002: sig 0x00000f4a, pf_mask 0x5c, 2005-12-14, rev 0x0004, size 2048
001/003: sig 0x00000653, pf_mask 0x04, 1999-05-20, rev 0x000b, size 2048
...
The first and third microcode updates are for very specific processor
models (a single combination of processor flags, each, as they only have
one bit set in the pf_mask field). The second microcode update applies
to several processors that share the same family, model and stepping, but
have different processor flags (more than one bit set in the pf_mask
field). The processor flags and pf_mask field are explained below.
one bit set in the pf_mask field). The second microcode update applies to
several processors that share the same family, model and stepping, but have
different processor flags (more than one bit set in the pf_mask field). The
processor flags and pf_mask field are explained below.
iucode_tool -L s000406A8_m00000001_r0000081F.fw
microcode bundle 1: s000406A8_m00000001_r0000081F.fw
001/001: sig 0x000406a8, pf_mask 0x01, 2014-08-12, rev 0x081f, size 38912
sig 0x000406a8, pf_mask 0x01, 2014-08-12, rev 0x081f
sig 0x000406a9, pf_mask 0x01, 2014-08-12, rev 0x081f
This is a microcode update with multiple signatures. At least one of the
signatures will typically be a duplicate. iucode_tool will act on each
signature (list, select, etc) as if they were independent, but when writing
out the microcode, all of its signatures will be included. It will not
output more than a single copy of the microcode to the same output file.
Microcode revisions:
......
......@@ -56,6 +56,10 @@ AC_FUNC_REALLOC
AC_FUNC_STAT
AC_CHECK_FUNCS([memset strcasecmp strdup strerror strrchr strtoul timegm])
# Allow GNU Argp as a standalone lib, as an alternative to glibc
AC_SEARCH_LIBS([argp_parse], [argp], [],
[AC_ERROR([An implementation of GNU Argp was not found, please install libargp])])
dnl important system extensions
AC_SYS_LARGEFILE
AC_CHECK_FUNCS([flockfile fgets_unlocked])
......@@ -67,7 +71,9 @@ dnl -----------------
AC_ARG_WITH([default-kernel-device],
[AS_HELP_STRING([--with-default-kernel-device=PATH],
[default microcode device (/dev/cpu/microcode)])],
[MICROCODE_DEVICE_DEFAULT="$withval"],
[AS_IF([test "x$withval" = "x" || test "x$withval" = "xno"],
[AC_ERROR([--without-kernel-device build unsupported])],
[MICROCODE_DEVICE_DEFAULT="$withval"])],
[MICROCODE_DEVICE_DEFAULT="/dev/cpu/microcode"])
AC_DEFINE_UNQUOTED(MICROCODE_DEVICE_DEFAULT, "$MICROCODE_DEVICE_DEFAULT",[Path to kernel microcode device])
AC_SUBST(MICROCODE_DEVICE_DEFAULT)
......@@ -75,7 +81,9 @@ AC_SUBST(MICROCODE_DEVICE_DEFAULT)
AC_ARG_WITH([default-firmware-dir],
[AS_HELP_STRING([--with-default-firmware-dir=PATH],
[default firmware loader directory (/lib/firmware/intel-ucode)])],
[MICROCODE_DIR_DEFAULT="$withval"],
[AS_IF([test "x$withval" = "x" || test "x$withval" = "xno"],
[AC_ERROR([--without-default-firmware-dir build unsupported])],
[MICROCODE_DIR_DEFAULT="$withval"])],
[MICROCODE_DIR_DEFAULT="/lib/firmware/intel-ucode"])
AC_DEFINE_UNQUOTED(MICROCODE_DIR_DEFAULT, "$MICROCODE_DIR_DEFAULT",[Path to the kernel microcode firmware directory])
AC_SUBST(MICROCODE_DIR_DEFAULT)
......@@ -83,7 +91,9 @@ AC_SUBST(MICROCODE_DIR_DEFAULT)
AC_ARG_WITH([cpuid-device-base],
[AS_HELP_STRING([--with-cpuid-device-base=PATH_FORMAT],
[per-cpu cpuid device path (/dev/cpu/%u/cpuid)])],
[CPUID_DEVICE_BASE="$withval"],
[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"])
AC_DEFINE_UNQUOTED(CPUID_DEVICE_BASE, "$CPUID_DEVICE_BASE",[fprintf base string to the per-cpu cpuid device])
AC_SUBST(CPUID_DEVICE_BASE)
......@@ -91,12 +101,16 @@ AC_SUBST(CPUID_DEVICE_BASE)
AC_ARG_ENABLE([cpuid-device],
[AS_HELP_STRING([--enable-cpuid-device],
[use Linux cpuid device and check all cores])],
[AC_DEFINE(USE_CPUID_DEVICE, [], [Scan every core using Linux cpuid device])])
[AS_IF([test "x$enableval" != "xno"],
[AC_DEFINE(USE_CPUID_DEVICE, [], [Scan every core using Linux cpuid device])])
])
AC_ARG_ENABLE([valgrind-build],
[AS_HELP_STRING([--enable-valgrind-build],
[build for valgrind testing])],
[AC_DEFINE(VALGRIND_BUILD, [], [Valgrind-friendly build])])
[AS_IF([test "x$enableval" != "xno"],
[AC_DEFINE(VALGRIND_BUILD, [], [Valgrind-friendly build])])
])
dnl --------------------------
dnl autoconf output generation
......
......@@ -244,6 +244,9 @@ int intel_ucode_compare(const void * const uc1, const void * const uc2)
if (unlikely((hdr1->hdrver != 1) || (hdr2->hdrver != 1)))
return -EINVAL;
if (unlikely(uc1 == uc2))
return 2;
ts1 = intel_ucode_v1_get_totalsize(hdr1);
ts2 = intel_ucode_v1_get_totalsize(hdr2);
if (ts1 != ts2)
......@@ -285,6 +288,7 @@ int intel_ucode_compare(const void * const uc1, const void * const uc2)
*/
const char * intel_ucode_errstr(const intel_ucode_status_t status)
{
/* warning: this is an __attribute__((const)) function! */
switch (status) {
case INTEL_UCODE_INVALID_DATA:
return "invalid microcode data";
......@@ -311,7 +315,7 @@ const char * intel_ucode_errstr(const intel_ucode_status_t status)
}
}
static inline int is_zero_checksum(const uint8_t *data, uint32_t dwords)
static int is_zero_checksum(const uint8_t *data, uint32_t dwords)
{
uint32_t s = 0;
......
......@@ -73,7 +73,7 @@ uint32_t intel_ucode_getdate_bcd(const void * const uc);
#define intel_ucode_sigmatch(s1, s2, p1, p2) \
(((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
const char * intel_ucode_errstr(const intel_ucode_status_t status);
const char * intel_ucode_errstr(const intel_ucode_status_t status) __attribute__((const));
intel_ucode_status_t intel_ucode_check_microcode(const void * const uc,
const size_t maxlen,
......
......@@ -1405,7 +1405,7 @@ static void log_microcode_action(const char * const action,
print_msg_u("%s: %s microcode " UCODE_ID_FMT_UU
" (sig 0x%08x, pf_mask 0x%02x, rev 0x%04x)",
devname, action, uce->gid, uce->id,
uce->cpuid, uce->pfm, uce->uc_rev);
uce->cpuid, uce->pfm, (uint32_t) uce->uc_rev);
}
/**
......@@ -1550,9 +1550,9 @@ static int xx_write_cpio_hdrentry(int fd, const char * const name,
"%08X%08X%08X%08X%08X%08X%08zX%08X%08X%08X%08X%08zX%08X%s",
ino, /* inode */
size ? LINUX_CPIO_FILE_MODE : LINUX_CPIO_DIR_MODE, /* mode */
0, 0, /* uid, gid */
size ? 1 : 2, t, size, /* nlink, mtime, size */
3, 1, 0, 0, nsize, 0, /* devj, devm, nsize, CRC */
0U, 0U, /* uid, gid */
size ? 1U : 2U, t, size, /* nlink, mtime, size */
3U, 1U, 0U, 0U, nsize, 0U, /* devj, devm, nsize, CRC */
name); /* name, pad */
return write_data(fd, buf, bufsize);
......@@ -2030,8 +2030,34 @@ static int xx_xtsdeduplist_add(struct intel_uclist_entry * const e,
return 0;
}
static int xx_xtsdeduplist_check_and_add(struct intel_uclist_entry * const e,
struct microcode_id_entry **list)
/**
* xtsdeduplist_check_and_add() - track mcu objects for dedup
*
* @e: entry to add signature from to the list
* @list: pointer to the head of the list used to track duplicates
*
* Duplicate tracking is done by storing and comparing struct
* intel_uclist_entry->uc pointers. This will work _only_ to dedup
* several instances of the same microcode due to extended signature
* processing.
*
* It cannot detect multiple copies of the same data stored in
* multiple objects.
*
* To use:
* Init the list head to NULL. Call xtsdeduplist_check_and_add() for
* every struct intel_uclist_entry element you want to track.
*
* One should use free_xtsdeduplist() to free the tracking list after
* use.
*
* Returns:
* ENOMEM: cannot allocate memory to add entry to list
* EEXIST: entry is a duplicate
* 0: entry is not a duplicate
*/
static int xtsdeduplist_check_and_add(struct intel_uclist_entry * const e,
struct microcode_id_entry **list)
{
const void *id = e->uc;
......@@ -2043,7 +2069,14 @@ static int xx_xtsdeduplist_check_and_add(struct intel_uclist_entry * const e,
return xx_xtsdeduplist_add(e, list);
}
static void xx_free_xtsdeduplist(struct microcode_id_entry *list)
/**
* free_xtsdeduplist() - frees mcu dedup tracking list
* @list: head of the list to be freed
*
* Frees every element of the list. @list will be invalid
* after this function returns.
*/
static void free_xtsdeduplist(struct microcode_id_entry *list)
{
struct microcode_id_entry *e;
......@@ -2066,7 +2099,7 @@ static int uclist_annotate_extsig_dup(struct intel_uclist_entry * const uclist)
e = uclist;
while (e) {
if (unlikely(e->flags & INTEL_UCLE_HASXST)) {
rc = xx_xtsdeduplist_check_and_add(e, &dlist);
rc = xtsdeduplist_check_and_add(e, &dlist);
if (rc == EEXIST) {
e->flags |= INTEL_UCLE_NOWR;
} else if (!rc) {
......@@ -2078,7 +2111,7 @@ static int uclist_annotate_extsig_dup(struct intel_uclist_entry * const uclist)
e = e->next;
}
xx_free_xtsdeduplist(dlist);
free_xtsdeduplist(dlist);
return (rc != EEXIST) ? rc : 0;
}
......@@ -2151,7 +2184,8 @@ static int check_downgrade_shadowing(const struct intel_uclist_entry * uclist)
"pf_mask 0x%02x (entries: " UCODE_ID_FMT_UU
" rev 0x%x, and " UCODE_ID_FMT_UU " rev 0x%x)",
sig, (pfm & e->pfm),
gid, uclist->id, rev, e->gid, e->id, e->uc_rev);
gid, uclist->id, (uint32_t) rev,
e->gid, e->id, (uint32_t) e->uc_rev);
res = EEXIST;
}
e = e->next;
......@@ -2202,18 +2236,20 @@ static int xx_process_ucode_signature_cb(void * const userdata,
if (list_all_microcodes) {
if (!sig_count)
printf(" " UCODE_ID_FMT_UU ": sig 0x%08x, pf_mask 0x%02x, "
fprintf(stdout,
" " UCODE_ID_FMT_UU ": sig 0x%08x, pf_mask 0x%02x, "
"%04x-%02x-%02x, rev 0x%04x, size %u\n",
ctx->current_bundle->id, ctx->current_uc,
cpuid, pf_mask,
m.date_year, m.date_month, m.date_day,
m.revision, uc_size);
(uint32_t) m.revision, uc_size);
else
printf(" sig 0x%08x, pf_mask 0x%02x, "
fprintf(stdout,
" sig 0x%08x, pf_mask 0x%02x, "
"%04x-%02x-%02x, rev 0x%04x\n",
cpuid, pf_mask,
m.date_year, m.date_month, m.date_day,
m.revision);
(uint32_t) m.revision);
}
add_status = uclist_add_signature(ctx->current_uc,
......@@ -2300,7 +2336,7 @@ static int do_process_microcodes(void)
while (mcb) {
if ((list_all_microcodes || list_sel_microcodes) && verbosity > 0)
printf("microcode bundle %u: %s\n", mcb->id,
fprintf(stdout, "microcode bundle %u: %s\n", mcb->id,
mcb->filename ? mcb->filename : "");
microcode_iterator_data.current_bundle = mcb;
......@@ -2334,11 +2370,12 @@ static int do_process_microcodes(void)
if (list_sel_microcodes || datefilter_loose || verbosity >= 2) {
struct intel_uclist_entry *uce = microcodes;
struct intel_uclist_entry *ucl = all_microcodes;
struct microcode_id_entry *dl = NULL;
unsigned long int uccount = 0;
unsigned long int sigcount = 0;
if (list_sel_microcodes)
printf("selected microcodes:\n");
fprintf(stdout, "selected microcodes:\n");
while (uce) {
/*
......@@ -2349,8 +2386,10 @@ static int do_process_microcodes(void)
xx_datefilter_loose_inplaceinsert(&uce, &ucl)))
return 1;
if (likely(!(uce->flags & INTEL_UCLE_EXTSIG)))
uccount++;
/* note: we ignore ENOMEM results for performance */
if (likely(!(uce->flags & INTEL_UCLE_HASXST) ||
!xtsdeduplist_check_and_add(uce, &dl)))
uccount++;
sigcount++;
......@@ -2359,15 +2398,18 @@ static int do_process_microcodes(void)
if (unlikely(intel_ucode_getmetadata(uce->uc, &m) != INTEL_UCODE_NOERROR))
exit(EXIT_SWFAILURE); /* memory corruption */
printf(" " UCODE_ID_FMT_UU ": sig 0x%08x, pf_mask 0x%02x, "
fprintf(stdout,
" " UCODE_ID_FMT_UU ": sig 0x%08x, pf_mask 0x%02x, "
"%04x-%02x-%02x, rev 0x%04x, size %u\n",
uce->gid, uce->id, uce->cpuid, uce->pfm,
m.date_year, m.date_month, m.date_day,
m.revision, uce->uc_size);
(uint32_t) m.revision, uce->uc_size);
}
uce = uce->next;
}
free_xtsdeduplist(dl);
print_msg(2, "selected %lu microcode(s), %lu signature(s)",
uccount, sigcount);
}
......@@ -2449,7 +2491,7 @@ static int do_write_named(const char * const dirname,
while (p && !rc) {
if (!(p->flags & INTEL_UCLE_DUPSIG)) {
snprintf(fn, sizeof(fn), "s%08X_m%08X_r%08X.fw",
p->cpuid, p->pfm, p->uc_rev);
p->cpuid, p->pfm, (uint32_t) p->uc_rev);
memcpy(&e, p, sizeof(e));
e.next = NULL;
......
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