diff --git a/sys/x86/x86/ucode_subr.c b/sys/x86/x86/ucode_subr.c --- a/sys/x86/x86/ucode_subr.c +++ b/sys/x86/x86/ucode_subr.c @@ -88,6 +88,33 @@ #define AMD_10H_EQUIV_TABLE_TYPE 0 #define AMD_10H_uCODE_TYPE 1 +#ifdef _KERNEL +/* + * List of known minimum required patch levels. Attempt to update from a + * lower patch level will result in wrmsr() fault. That means panic at the + * very beginning of the kernel start. Late upgrade via cpuctl(4) is allowed + * to try these. + */ +static const struct amd_patchlevel_dependency_t { + uint32_t cpu; + uint32_t newrev; + uint32_t reqrev; +} amd_patchdeps[] = { + { .cpu = 0xaa0f02, .newrev = 0x0aa0021c, .reqrev = 0x0aa00219 }, +}; + +static bool +amd_patch_ok(uint32_t cpu, uint32_t oldrev, uint32_t newrev) +{ + for (u_int i = 0; i < nitems(amd_patchdeps); i++) + if (cpu == amd_patchdeps[i].cpu && + oldrev < amd_patchdeps[i].reqrev && + newrev >= amd_patchdeps[i].newrev) + return (false); + return (true); +} +#endif + /* * NB: the format of microcode update files is not documented by AMD. * It has been reverse engineered from studying Coreboot, illumos and Linux @@ -217,6 +244,10 @@ fw_header->patch_id, *revision); continue; /* not newer revision */ } +#ifdef _KERNEL + if (!amd_patch_ok(signature, *revision, fw_header->patch_id)) + continue; +#endif if (fw_header->nb_dev_id != 0 || fw_header->sb_dev_id != 0) { WARNX(2, "Chipset-specific microcode is not supported"); }