Download raw body.
check minimum microcode versions
Some AMD microcode now lists a minimum version for performing an
MSR based update. If the microcode is not at that level it seems a
protection fault will be generated. Only some server (Epyc) parts have
a minimum version at the moment. And not in the version currently in ports.
https://gitlab.com/kernel-firmware/linux-firmware/-/blob/main/amd-ucode/README?ref_type=heads
"Minimum base ucode version for loading"
"#GP fault will occur if attempting to hot load microcode on older BIOS."
https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7033.html
Fam-Model-Step Codename Minimum microcode patch
19-01-01 Milan-B1 0x0a0011d9
19-01-02 Milan-X B2 0x0a001242
19-11-01 Genoa-B1 0x0a101153
19-11-02 Genoa-X B2 0x0a10124e
19-a0-02 Bergamo A2 0x0aa00218
1a-02-01 Turin 0x0b002140
1a-11-00 Turin Dense 0x0b101040
Some Intel microcode also has a non-zero minimum version.
From the latest 20250812 release:
fam-model-step patch level minimum
06-55-03 01000191 0100015b
06-55-04 02007006 02006b06
06-55-07 05003901 05003102
06-55-0b 07002b01 07002402
06-56-05 0e000015 0e00000f
06-5f-01 0000003e 0000002e
06-6a-06 0d000410 0d000311
06-6c-01 010002e0 010001d1
06-7e-05 000000ca 000000a8
06-8c-01 000000bc 000000a4
06-8c-02 0000003c 00000022
06-8d-01 00000056 0000003c
06-8e-09 000000f6 000000ea
06-8e-0a 000000f6 000000ea
06-8e-0b 000000f6 000000ea
06-8e-0c 00000100 000000ea
06-8f-07 2b000643 2b000161
06-8f-08 2c000401 2c0001d0
06-97-02 0000003a 0000001f
06-97-05 0000003a 0000001f
06-9a-03 00000437 00000419
06-9a-04 00000437 00000419
06-9e-09 000000f8 000000ea
06-9e-0a 000000fa 000000ea
06-9e-0b 000000f6 000000ea
06-9e-0c 000000f8 000000ea
06-9e-0d 00000104 000000ea
06-a5-02 00000100 000000ea
06-a5-03 00000100 000000ea
06-a5-05 00000100 000000ea
06-a6-00 00000102 000000ea
06-a6-01 00000100 000000ea
06-a7-01 00000064 00000051
06-ad-01 010003d0 00000001
06-af-03 03000362 03000132
06-b7-01 0000012f 0000010b
06-ba-02 00004129 0000410c
06-ba-03 00004129 0000410c
06-be-00 0000001d 0000000f
06-bf-02 0000003a 0000001f
06-bf-05 0000003a 0000001f
06-cf-02 210002b3 21000200
Index: sys/arch/amd64/amd64/ucode.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/ucode.c,v
diff -u -p -r1.9 ucode.c
--- sys/arch/amd64/amd64/ucode.c 3 Apr 2024 02:01:21 -0000 1.9
+++ sys/arch/amd64/amd64/ucode.c 26 Oct 2025 00:06:11 -0000
@@ -48,7 +48,9 @@ struct intel_ucode_header {
uint32_t processor_flags;
uint32_t data_size;
uint32_t total_size;
- uint32_t reserved[3];
+ uint32_t metadata_size;
+ uint32_t min_revision;
+ uint32_t reserved;
};
struct intel_ucode_ext_sig_header {
@@ -127,9 +129,14 @@ struct amd_equiv {
struct amd_patch {
uint32_t type;
uint32_t len;
- uint32_t a;
+ uint32_t date;
uint32_t level;
- uint8_t c[16];
+ uint16_t data_id;
+ uint8_t data_len;
+ uint8_t flag;
+ uint32_t data_val;
+ uint32_t nb_dev;
+ uint32_t sb_dev;
uint16_t eid;
} __packed;
@@ -191,6 +198,13 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
if (ap.type == 1 && ap.eid == eid && ap.level > level) {
start = (uint64_t)&cpu_ucode_data[i + 8];
patch_len = ap.len;
+
+ /* check minimum version */
+ if (ci->ci_family >= 0x19 && level < ap.data_val) {
+ DPRINTF(("%s: ucode %#llx < min %#x\n",
+ __func__, level, ap.data_val));
+ goto out;
+ }
}
if (i + ap.len + 8 > cpu_ucode_size) {
DPRINTF(("%s: truncated patch\n", __func__));
@@ -244,6 +258,11 @@ cpu_ucode_intel_apply(struct cpu_info *c
}
if (update->update_revision == old_rev) {
DPRINTF(("%s: microcode already up-to-date\n", __func__));
+ goto out;
+ }
+ if (old_rev < update->min_revision) {
+ DPRINTF(("%s: cur %#x < min %#x\n", __func__, old_rev,
+ update->min_revision));
goto out;
}
Index: sys/arch/i386/i386/ucode.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/ucode.c,v
diff -u -p -r1.6 ucode.c
--- sys/arch/i386/i386/ucode.c 10 Sep 2023 09:32:31 -0000 1.6
+++ sys/arch/i386/i386/ucode.c 25 Oct 2025 23:53:12 -0000
@@ -48,7 +48,9 @@ struct intel_ucode_header {
uint32_t processor_flags;
uint32_t data_size;
uint32_t total_size;
- uint32_t reserved[3];
+ uint32_t metadata_size;
+ uint32_t min_revision;
+ uint32_t reserved;
};
struct intel_ucode_ext_sig_header {
@@ -150,9 +152,14 @@ struct amd_equiv {
struct amd_patch {
uint32_t type;
uint32_t len;
- uint32_t a;
+ uint32_t date;
uint32_t level;
- uint8_t c[16];
+ uint16_t data_id;
+ uint8_t data_len;
+ uint8_t flag;
+ uint32_t data_val;
+ uint32_t nb_dev;
+ uint32_t sb_dev;
uint16_t eid;
} __packed;
@@ -214,6 +221,13 @@ cpu_ucode_amd_apply(struct cpu_info *ci)
if (ap.type == 1 && ap.eid == eid && ap.level > level) {
start = (uint64_t)&cpu_ucode_data[i + 8];
patch_len = ap.len;
+
+ /* check minimum version */
+ if (ci->ci_family >= 0x19 && level < ap.data_val) {
+ DPRINTF(("%s: ucode %#llx < min %#x\n",
+ __func__, level, ap.data_val));
+ goto out;
+ }
}
if (i + ap.len + 8 > cpu_ucode_size) {
DPRINTF(("%s: truncated patch\n", __func__));
@@ -267,6 +281,11 @@ cpu_ucode_intel_apply(struct cpu_info *c
}
if (update->update_revision == old_rev) {
DPRINTF(("%s: microcode already up-to-date\n", __func__));
+ goto out;
+ }
+ if (old_rev < update->min_revision) {
+ DPRINTF(("%s: cur %#x < min %#x\n", __func__, old_rev,
+ update->min_revision));
goto out;
}
check minimum microcode versions