Log a message after a successful boot-time microcode update.
Reviewed by: kib Approved by: re (delphij) Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D17135
This commit is contained in:
parent
7f8b422b28
commit
b957d780d1
@ -362,7 +362,7 @@ update_intel(int cpu, cpuctl_update_args_t *args, struct thread *td)
|
||||
set_cpu(cpu, td);
|
||||
critical_enter();
|
||||
|
||||
ret = ucode_intel_load(ptr, true);
|
||||
ret = ucode_intel_load(ptr, true, NULL, NULL);
|
||||
|
||||
critical_exit();
|
||||
restore_cpu(oldcpu, is_bound, td);
|
||||
|
@ -58,7 +58,8 @@ struct ucode_intel_extsig_table {
|
||||
} entries[0];
|
||||
};
|
||||
|
||||
int ucode_intel_load(void *data, bool unsafe);
|
||||
int ucode_intel_load(void *data, bool unsafe,
|
||||
uint64_t *nrevp, uint64_t *orevp);
|
||||
size_t ucode_load_bsp(uintptr_t free);
|
||||
void ucode_load_ap(int cpu);
|
||||
void ucode_reload(void);
|
||||
|
@ -59,7 +59,7 @@ static int ucode_intel_verify(struct ucode_intel_header *hdr,
|
||||
|
||||
static struct ucode_ops {
|
||||
const char *vendor;
|
||||
int (*load)(void *, bool);
|
||||
int (*load)(void *, bool, uint64_t *, uint64_t *);
|
||||
void *(*match)(uint8_t *, size_t *);
|
||||
} loaders[] = {
|
||||
{
|
||||
@ -72,35 +72,46 @@ static struct ucode_ops {
|
||||
/* Selected microcode update data. */
|
||||
static void *early_ucode_data;
|
||||
static void *ucode_data;
|
||||
static struct ucode_ops *ucode_loader;
|
||||
|
||||
static char errbuf[128];
|
||||
|
||||
static void __printflike(1, 2)
|
||||
log_err(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
/* Variables used for reporting success or failure. */
|
||||
enum {
|
||||
NO_ERROR,
|
||||
NO_MATCH,
|
||||
VERIFICATION_FAILED,
|
||||
} ucode_error = NO_ERROR;
|
||||
static uint64_t ucode_nrev, ucode_orev;
|
||||
|
||||
static void
|
||||
print_err(void *arg __unused)
|
||||
log_msg(void *arg __unused)
|
||||
{
|
||||
|
||||
if (errbuf[0] != '\0')
|
||||
printf("microcode load error: %s\n", errbuf);
|
||||
if (ucode_nrev != 0) {
|
||||
printf("CPU microcode: updated from %#jx to %#jx\n",
|
||||
(uintmax_t)ucode_orev, (uintmax_t)ucode_nrev);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ucode_error) {
|
||||
case NO_MATCH:
|
||||
printf("CPU microcode: no matching update found\n");
|
||||
break;
|
||||
case VERIFICATION_FAILED:
|
||||
printf("CPU microcode: microcode verification failed\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
SYSINIT(ucode_print_err, SI_SUB_CPU, SI_ORDER_FIRST, print_err, NULL);
|
||||
SYSINIT(ucode_log, SI_SUB_CPU, SI_ORDER_FIRST, log_msg, NULL);
|
||||
|
||||
int
|
||||
ucode_intel_load(void *data, bool unsafe)
|
||||
ucode_intel_load(void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp)
|
||||
{
|
||||
uint64_t rev0, rev1;
|
||||
uint64_t nrev, orev;
|
||||
uint32_t cpuid[4];
|
||||
|
||||
rev0 = rdmsr(MSR_BIOS_SIGN);
|
||||
orev = rdmsr(MSR_BIOS_SIGN) >> 32;
|
||||
|
||||
/*
|
||||
* Perform update. Flush caches first to work around seemingly
|
||||
@ -118,8 +129,15 @@ ucode_intel_load(void *data, bool unsafe)
|
||||
*/
|
||||
do_cpuid(0, cpuid);
|
||||
|
||||
rev1 = rdmsr(MSR_BIOS_SIGN);
|
||||
if (rev1 <= rev0)
|
||||
/*
|
||||
* Verify that the microcode revision changed.
|
||||
*/
|
||||
nrev = rdmsr(MSR_BIOS_SIGN) >> 32;
|
||||
if (nrevp != NULL)
|
||||
*nrevp = nrev;
|
||||
if (orevp != NULL)
|
||||
*orevp = orev;
|
||||
if (nrev <= orev)
|
||||
return (EEXIST);
|
||||
return (0);
|
||||
}
|
||||
@ -130,36 +148,26 @@ ucode_intel_verify(struct ucode_intel_header *hdr, size_t resid)
|
||||
uint32_t cksum, *data, size;
|
||||
int i;
|
||||
|
||||
if (resid < sizeof(struct ucode_intel_header)) {
|
||||
log_err("truncated update header");
|
||||
if (resid < sizeof(struct ucode_intel_header))
|
||||
return (1);
|
||||
}
|
||||
size = hdr->total_size;
|
||||
if (size == 0)
|
||||
size = UCODE_INTEL_DEFAULT_DATA_SIZE +
|
||||
sizeof(struct ucode_intel_header);
|
||||
|
||||
if (hdr->header_version != 1) {
|
||||
log_err("unexpected header version %u", hdr->header_version);
|
||||
if (hdr->header_version != 1)
|
||||
return (1);
|
||||
}
|
||||
if (size % 16 != 0) {
|
||||
log_err("unexpected update size %u", hdr->total_size);
|
||||
if (size % 16 != 0)
|
||||
return (1);
|
||||
}
|
||||
if (resid < size) {
|
||||
log_err("truncated update");
|
||||
if (resid < size)
|
||||
return (1);
|
||||
}
|
||||
|
||||
cksum = 0;
|
||||
data = (uint32_t *)hdr;
|
||||
for (i = 0; i < size / sizeof(uint32_t); i++)
|
||||
cksum += data[i];
|
||||
if (cksum != 0) {
|
||||
log_err("checksum failed");
|
||||
if (cksum != 0)
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -182,8 +190,10 @@ ucode_intel_match(uint8_t *data, size_t *len)
|
||||
|
||||
for (resid = *len; resid > 0; data += total_size, resid -= total_size) {
|
||||
hdr = (struct ucode_intel_header *)data;
|
||||
if (ucode_intel_verify(hdr, resid) != 0)
|
||||
if (ucode_intel_verify(hdr, resid) != 0) {
|
||||
ucode_error = VERIFICATION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
data_size = hdr->data_size;
|
||||
total_size = hdr->total_size;
|
||||
@ -264,7 +274,7 @@ ucode_load_ap(int cpu)
|
||||
#endif
|
||||
|
||||
if (ucode_data != NULL)
|
||||
(void)ucode_intel_load(ucode_data, false);
|
||||
(void)ucode_loader->load(ucode_data, false, NULL, NULL);
|
||||
}
|
||||
|
||||
static void *
|
||||
@ -308,11 +318,12 @@ ucode_load_bsp(uintptr_t free)
|
||||
uint32_t regs[4];
|
||||
char vendor[13];
|
||||
} cpuid;
|
||||
struct ucode_ops *loader;
|
||||
uint8_t *addr, *fileaddr, *match;
|
||||
char *type;
|
||||
uint64_t nrev, orev;
|
||||
caddr_t file;
|
||||
size_t i, len, ucode_len;
|
||||
size_t i, len;
|
||||
int error;
|
||||
|
||||
KASSERT(free % PAGE_SIZE == 0, ("unaligned boundary %p", (void *)free));
|
||||
|
||||
@ -320,17 +331,16 @@ ucode_load_bsp(uintptr_t free)
|
||||
cpuid.regs[0] = cpuid.regs[1];
|
||||
cpuid.regs[1] = cpuid.regs[3];
|
||||
cpuid.vendor[12] = '\0';
|
||||
for (i = 0, loader = NULL; i < nitems(loaders); i++)
|
||||
for (i = 0; i < nitems(loaders); i++)
|
||||
if (strcmp(cpuid.vendor, loaders[i].vendor) == 0) {
|
||||
loader = &loaders[i];
|
||||
ucode_loader = &loaders[i];
|
||||
break;
|
||||
}
|
||||
if (loader == NULL)
|
||||
if (ucode_loader == NULL)
|
||||
return (0);
|
||||
|
||||
file = 0;
|
||||
fileaddr = match = NULL;
|
||||
ucode_len = 0;
|
||||
for (;;) {
|
||||
file = preload_search_next_name(file);
|
||||
if (file == 0)
|
||||
@ -341,7 +351,7 @@ ucode_load_bsp(uintptr_t free)
|
||||
|
||||
fileaddr = preload_fetch_addr(file);
|
||||
len = preload_fetch_size(file);
|
||||
match = loader->match(fileaddr, &len);
|
||||
match = ucode_loader->match(fileaddr, &len);
|
||||
if (match != NULL) {
|
||||
addr = map_ucode(free, len);
|
||||
/* We can't use memcpy() before ifunc resolution. */
|
||||
@ -349,18 +359,19 @@ ucode_load_bsp(uintptr_t free)
|
||||
addr[i] = ((volatile uint8_t *)match)[i];
|
||||
match = addr;
|
||||
|
||||
if (loader->load(match, false) == 0) {
|
||||
ucode_data = match;
|
||||
ucode_len = len;
|
||||
early_ucode_data = ucode_data;
|
||||
break;
|
||||
error = ucode_loader->load(match, false, &nrev, &orev);
|
||||
if (error == 0) {
|
||||
ucode_data = early_ucode_data = match;
|
||||
ucode_nrev = nrev;
|
||||
ucode_orev = orev;
|
||||
return (len);
|
||||
}
|
||||
unmap_ucode(free, len);
|
||||
}
|
||||
}
|
||||
if (fileaddr != NULL && ucode_data == NULL)
|
||||
log_err("no matching update found");
|
||||
return (ucode_len);
|
||||
if (fileaddr != NULL && ucode_error == NO_ERROR)
|
||||
ucode_error = NO_MATCH;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user