summaryrefslogtreecommitdiff
path: root/src/cpu/intel/microcode
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/intel/microcode')
-rw-r--r--src/cpu/intel/microcode/microcode.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c
index 51823ca6de..45996dfdc3 100644
--- a/src/cpu/intel/microcode/microcode.c
+++ b/src/cpu/intel/microcode/microcode.c
@@ -29,6 +29,18 @@ struct microcode {
u32 reserved[3];
};
+struct ext_sig_table {
+ u32 ext_sig_cnt;
+ u32 ext_tbl_chksm;
+ u32 res[3];
+};
+
+struct ext_sig_entry {
+ u32 sig;
+ u32 pf;
+ u32 chksm;
+};
+
static inline u32 read_microcode_rev(void)
{
/* Some Intel CPUs can be very finicky about the
@@ -117,9 +129,31 @@ uint32_t get_microcode_checksum(const void *microcode)
return ((struct microcode *)microcode)->cksum;
}
+
+static struct ext_sig_table *ucode_get_ext_sig_table(const struct microcode *ucode)
+{
+ struct ext_sig_table *ext_tbl;
+ /* header + ucode data blob size */
+ u32 size = ucode->data_size + sizeof(struct microcode);
+
+ size_t ext_tbl_len = ucode->total_size - size;
+
+ if (ext_tbl_len < sizeof(struct ext_sig_table))
+ return NULL;
+
+ ext_tbl = (struct ext_sig_table *)((uintptr_t)ucode + size);
+
+ if (ext_tbl_len < (sizeof(struct ext_sig_table) +
+ ext_tbl->ext_sig_cnt * sizeof(struct ext_sig_entry)))
+ return NULL;
+
+ return ext_tbl;
+}
+
static const void *find_cbfs_microcode(void)
{
const struct microcode *ucode_updates;
+ struct ext_sig_table *ext_tbl;
size_t microcode_len;
u32 eax;
u32 pf, rev, sig, update_size;
@@ -163,6 +197,22 @@ static const void *find_cbfs_microcode(void)
if ((ucode_updates->sig == sig) && (ucode_updates->pf & pf))
return ucode_updates;
+
+ /* Check if there is extended signature table */
+ ext_tbl = ucode_get_ext_sig_table(ucode_updates);
+
+ if (ext_tbl != NULL) {
+ int i;
+ struct ext_sig_entry *entry = (struct ext_sig_entry *)(ext_tbl + 1);
+
+ for (i = 0; i < ext_tbl->ext_sig_cnt; i++, entry++) {
+
+ if ((sig == entry->sig) && (pf & entry->pf)) {
+ return ucode_updates;
+ }
+ }
+ }
+
ucode_updates = (void *)((char *)ucode_updates + update_size);
microcode_len -= update_size;
}