[PATCH i-g-t v2 5/6] tools/intel-gfx-fw-info: Add proper HuC parser

Lucas De Marchi lucas.demarchi at intel.com
Tue Aug 20 23:29:27 UTC 2024


Initial implementation to parse HuC's header was lazy and assumed the
manifest was the first entry in the cpd, which is not necessarily true.
Add proper parsing for the headers that matches the one documented
in https://docs.kernel.org/gpu/xe/xe_firmware.html#firmware-layout
as "GSC-based HuC firmware layout ".

Before (wrong):
	$ intel-gfx-fw-info -c /lib/firmware/xe/lnl_huc.bin
	header-type: GSC
	version: 13.91.1
	checksum: 320e765cbe42b0f5f95333794a6a00a4e67246d6ad8393b59b64efdc3506cfe9

After (fixed):
	$ intel-gfx-fw-info -c /lib/firmware/xe/lnl_huc.bin
	header-type: GSC
	version: 9.4.13
	checksum: 320e765cbe42b0f5f95333794a6a00a4e67246d6ad8393b59b64efdc3506cfe9

Signed-off-by: Lucas De Marchi <lucas.demarchi at intel.com>
---
 tools/intel-gfx-fw-info | 106 ++++++++++++++++++++++++++++++++--------
 1 file changed, 85 insertions(+), 21 deletions(-)

diff --git a/tools/intel-gfx-fw-info b/tools/intel-gfx-fw-info
index 57d6f935b..cbabda913 100755
--- a/tools/intel-gfx-fw-info
+++ b/tools/intel-gfx-fw-info
@@ -60,19 +60,68 @@ struct uc_css_header {
 	u32 header_info;
 };
 
-#define HUC_GSC_VERSION_HI_DW		44
-#define   HUC_GSC_MAJOR_VER_HI_MASK	(0xFF << 0)
-#define   HUC_GSC_MINOR_VER_HI_MASK	(0xFF << 16)
-#define HUC_GSC_VERSION_LO_DW		45
-#define   HUC_GSC_PATCH_VER_LO_MASK	(0xFF << 0)
-
-// Add a fake definition for the GSC's header so this script can still
-// check the version
-
-struct uc_huc_gsc_header {
-	u32 rsvd[HUC_GSC_VERSION_HI_DW];
-	u32 ver_hi;
-	u32 ver_lo;
+/* Code partition directory (CPD) structures */
+#define GSC_CPD_HEADER_MARKER 0x44504324
+struct gsc_cpd_header_v2 {
+	u32 header_marker;
+
+	u32 num_of_entries;
+	u8 header_version;
+	u8 entry_version;
+	u8 header_length; /* in bytes */
+	u8 flags;
+	u32 partition_name;
+	u32 crc32;
+};
+
+// Added as python code
+// #define GSC_CPD_ENTRY_OFFSET_MASK GENMASK(24, 0)
+
+struct gsc_version {
+	u16 major;
+	u16 minor;
+	u16 hotfix;
+	u16 build;
+};
+
+struct gsc_cpd_entry {
+	u8 name[12];
+
+	/*
+	 * Bits 0-24: offset from the beginning of the code partition
+	 * Bit 25: huffman compressed
+	 * Bits 26-31: reserved
+	 */
+	u32 offset;
+
+	/*
+	 * Module/Item length, in bytes. For Huffman-compressed modules, this
+	 * refers to the uncompressed size. For software-compressed modules,
+	 * this refers to the compressed size.
+	 */
+	u32 length;
+
+	u8 reserved[4];
+};
+
+struct gsc_manifest_header {
+	u32 header_type; /* 0x4 for manifest type */
+	u32 header_length; /* in dwords */
+	u32 header_version;
+	u32 flags;
+	u32 vendor;
+	u32 date;
+	u32 size; /* In dwords, size of entire manifest (header + extensions) */
+	u32 header_id;
+	u32 internal_data;
+	struct gsc_version fw_version;
+	u32 security_version;
+	struct gsc_version meu_kit_version;
+	u32 meu_manifest_version;
+	u8 general_data[4];
+	u8 reserved3[56];
+	u32 modulus_size; /* in dwords */
+	u32 exponent_size; /* in dwords */
 };
 
 struct magic {
@@ -91,6 +140,9 @@ except:
     raise SystemExit(1)
 
 
+GSC_CPD_ENTRY_OFFSET_MASK = 0x1FFFFFF
+
+
 def ffs(x: int) -> int:
     """Returns the index, counting from 0, of the
     least significant set bit in `x`.
@@ -181,17 +233,28 @@ class FwGsc(Fw):
 
     def decode(self):
         self.f.seek(0, 0)
-        self.fw = self.cparser.uc_huc_gsc_header(self.f)
+        self.fw = self.cparser.gsc_cpd_header_v2(self.f)
 
         data = ["header-type: GSC"]
 
-        HUC_GSC_MINOR_VER_HI_MASK = 0xFF << 16
-        HUC_GSC_MAJOR_VER_HI_MASK = 0xFF
-        HUC_GSC_PATCH_VER_LO_MASK = 0xFF
-        major = FIELD_GET(HUC_GSC_MAJOR_VER_HI_MASK, self.fw.ver_hi)
-        minor = FIELD_GET(HUC_GSC_MINOR_VER_HI_MASK, self.fw.ver_hi)
-        patch = FIELD_GET(HUC_GSC_PATCH_VER_LO_MASK, self.fw.ver_lo)
-        data += [f"version: {major}.{minor}.{patch}"]
+        # find manifest entry
+        self.f.seek(self.fw.header_length, 0)
+        for _ in range(self.fw.num_of_entries):
+            entry = self.cparser.gsc_cpd_entry(self.f)
+            s = "".join(map(chr, entry.name)).rstrip("\x00")
+            if s == "HUCP.man":
+                offset = entry.offset & GSC_CPD_ENTRY_OFFSET_MASK
+                self.f.seek(offset, 0)
+                break
+        else:
+            logging.fatal("Unknown/corrupted firmware - no manifest available")
+            sys.exit(1)
+
+        self.fw = self.cparser.gsc_manifest_header(self.f)
+        major = self.fw.fw_version.major
+        minor = self.fw.fw_version.minor
+        hotfix = self.fw.fw_version.hotfix
+        data += [f"version: {major}.{minor}.{hotfix}"]
 
         return data
 
@@ -222,6 +285,7 @@ def main(argv: typing.List[str]) -> int:
             fw = Fw.create(f)
             if not fw:
                 logging.fatal("Unknown firmware type in '{args.filename}'")
+                sys.exit(1)
 
             decoded_data = fw.decode()
             if args.checksum:
-- 
2.43.0



More information about the igt-dev mailing list