Date: Sat, 27 Sep 2025 14:31:00 GMT From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: d9f03a43f2fe - main - ucode: use wrmsr_early_safe() for early CPU microcode update Message-ID: <202509271431.58REV0as099292@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=d9f03a43f2fec917c31d48b05d751e547c8775c7 commit d9f03a43f2fec917c31d48b05d751e547c8775c7 Author: Gleb Smirnoff <glebius@FreeBSD.org> AuthorDate: 2025-09-27 14:30:40 +0000 Commit: Gleb Smirnoff <glebius@FreeBSD.org> CommitDate: 2025-09-27 14:30:40 +0000 ucode: use wrmsr_early_safe() for early CPU microcode update Use the new method for wrmsr that is able to set up fault handler even at the very early stage of kernel boot. This prevents panic with new microcode for some new AMD EPYCs, that requires certain patchlevel of microcode to be already present in the CPU. If BSP patching failed, we print the message and we don't try to patch APs. This has been tested only on AMD booted in EFI mode. Reviewed by: stas, kib Differential Revision: https://reviews.freebsd.org/D52643 --- sys/dev/cpuctl/cpuctl.c | 2 +- sys/x86/include/ucode.h | 6 ++++-- sys/x86/x86/ucode.c | 56 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/sys/dev/cpuctl/cpuctl.c b/sys/dev/cpuctl/cpuctl.c index b0ab3467df69..deaabaaaa1fc 100644 --- a/sys/dev/cpuctl/cpuctl.c +++ b/sys/dev/cpuctl/cpuctl.c @@ -344,7 +344,7 @@ ucode_intel_load_rv(void *arg) d = arg; if (PCPU_GET(cpuid) == d->cpu) - d->ret = ucode_intel_load(d->ptr, true, NULL, NULL); + d->ret = ucode_intel_load(d->ptr, SAFE, NULL, NULL); } static int diff --git a/sys/x86/include/ucode.h b/sys/x86/include/ucode.h index 75b9ff3afbd0..ea7cb07669a4 100644 --- a/sys/x86/include/ucode.h +++ b/sys/x86/include/ucode.h @@ -62,12 +62,14 @@ struct ucode_intel_extsig_table { } entries[0]; }; +typedef enum { SAFE, UNSAFE, EARLY } ucode_load_how; + const void *ucode_amd_find(const char *path, uint32_t signature, uint32_t *revision, const uint8_t *fw_data, size_t fw_size, size_t *selected_sizep); -int ucode_intel_load(const void *data, bool unsafe, +int ucode_intel_load(const void *data, ucode_load_how unsafe, uint64_t *nrevp, uint64_t *orevp); -int ucode_amd_load(const void *data, bool unsafe, +int ucode_amd_load(const void *data, ucode_load_how how, uint64_t *nrevp, uint64_t *orevp); size_t ucode_load_bsp(uintptr_t free); void ucode_load_ap(int cpu); diff --git a/sys/x86/x86/ucode.c b/sys/x86/x86/ucode.c index 1973047fafd1..72133de211f8 100644 --- a/sys/x86/x86/ucode.c +++ b/sys/x86/x86/ucode.c @@ -40,6 +40,7 @@ #include <machine/atomic.h> #include <machine/cpufunc.h> +#include <machine/md_var.h> #include <x86/specialreg.h> #include <x86/ucode.h> #include <x86/x86_smp.h> @@ -58,7 +59,7 @@ static const void *ucode_amd_match(const uint8_t *data, size_t *len); static struct ucode_ops { const char *vendor; - int (*load)(const void *, bool, uint64_t *, uint64_t *); + int (*load)(const void *, ucode_load_how how, uint64_t *, uint64_t *); const void *(*match)(const uint8_t *, size_t *); } loaders[] = { { @@ -83,6 +84,7 @@ enum { NO_ERROR, NO_MATCH, VERIFICATION_FAILED, + LOAD_FAILED, } ucode_error = NO_ERROR; static uint64_t ucode_nrev, ucode_orev; @@ -103,6 +105,9 @@ log_msg(void *arg __unused) case VERIFICATION_FAILED: printf("CPU microcode: microcode verification failed\n"); break; + case LOAD_FAILED: + printf("CPU microcode load failed. BIOS update advised\n"); + break; default: break; } @@ -110,7 +115,8 @@ log_msg(void *arg __unused) SYSINIT(ucode_log, SI_SUB_CPU, SI_ORDER_FIRST, log_msg, NULL); int -ucode_intel_load(const void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp) +ucode_intel_load(const void *data, ucode_load_how how, uint64_t *nrevp, + uint64_t *orevp) { uint64_t nrev, orev; uint32_t cpuid[4]; @@ -122,10 +128,23 @@ ucode_intel_load(const void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp * undocumented errata applying to some Broadwell CPUs. */ wbinvd(); - if (unsafe) + switch (how) { + case SAFE: wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); - else + break; + case EARLY: +#ifdef __amd64__ + wrmsr_early_safe_start(); + if (wrmsr_early_safe(MSR_BIOS_UPDT_TRIG, + (uint64_t)(uintptr_t)data) != 0) + ucode_error = LOAD_FAILED; + wrmsr_early_safe_end(); + break; +#endif + case UNSAFE: wrmsr(MSR_BIOS_UPDT_TRIG, (uint64_t)(uintptr_t)data); + break; + } wrmsr(MSR_BIOS_SIGN, 0); /* @@ -233,20 +252,31 @@ ucode_intel_match(const uint8_t *data, size_t *len) } int -ucode_amd_load(const void *data, bool unsafe, uint64_t *nrevp, uint64_t *orevp) +ucode_amd_load(const void *data, ucode_load_how how, uint64_t *nrevp, + uint64_t *orevp) { uint64_t nrev, orev; uint32_t cpuid[4]; orev = rdmsr(MSR_BIOS_SIGN); - /* - * Perform update. - */ - if (unsafe) + switch (how) { + case SAFE: wrmsr_safe(MSR_K8_UCODE_UPDATE, (uint64_t)(uintptr_t)data); - else + break; + case EARLY: +#ifdef __amd64__ + wrmsr_early_safe_start(); + if (wrmsr_early_safe(MSR_K8_UCODE_UPDATE, + (uint64_t)(uintptr_t)data) != 0) + ucode_error = LOAD_FAILED; + wrmsr_early_safe_end(); + break; +#endif + case UNSAFE: wrmsr(MSR_K8_UCODE_UPDATE, (uint64_t)(uintptr_t)data); + break; + } /* * Serialize instruction flow. @@ -327,8 +357,8 @@ ucode_load_ap(int cpu) return; #endif - if (ucode_data != NULL) - (void)ucode_loader->load(ucode_data, false, NULL, NULL); + if (ucode_data != NULL && ucode_error != LOAD_FAILED) + (void)ucode_loader->load(ucode_data, UNSAFE, NULL, NULL); } static void * @@ -415,7 +445,7 @@ ucode_load_bsp(uintptr_t free) memcpy_early(addr, match, len); match = addr; - error = ucode_loader->load(match, false, &nrev, &orev); + error = ucode_loader->load(match, EARLY, &nrev, &orev); if (error == 0) { ucode_data = early_ucode_data = match; ucode_nrev = nrev;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202509271431.58REV0as099292>