src/intel/microcode: Add support for extended signature table

Microcode header supports advertising support for only one CPU
signature and processor flags. If there are multiple processor
families supported by this microcode blob, they are mentioned in
the extended signature table.

Add support to parse the extended processor signature table to
determine if the microcode blob supports the currently running CPU.

BUG=b:182234962
TEST=Booted ADL brya system with a processor whose signature/pf are
in the extended signature table of a microcode patch. Was able to
match and load the patch appropriately.

Signed-off-by: Rizwan Qureshi <rizwan.qureshi@intel.com>
Change-Id: I1466caf4a4ba1f9a0214bdde19cce57dd65dacbd
Reviewed-on: https://review.coreboot.org/c/coreboot/+/54734
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
diff --git a/src/cpu/intel/microcode/microcode.c b/src/cpu/intel/microcode/microcode.c
index 51823ca..45996df 100644
--- a/src/cpu/intel/microcode/microcode.c
+++ b/src/cpu/intel/microcode/microcode.c
@@ -29,6 +29,18 @@
 	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 @@
 	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 @@
 		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;
 	}