Add a new binman etype which allows signing both the SPL and U-Boot proper
sections of i.MX93 flash.bin using CST.
The implementation is largely derived from the nxp_imx8mcst etype, as the
signing procedures for both platforms are quite similar.

Signed-off-by: Jérémie Dautheribes (Schneider Electric) 
<[email protected]>
---
 .gitignore                         |   2 +
 tools/binman/etype/nxp_imx93cst.py | 143 +++++++++++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+)

diff --git a/.gitignore b/.gitignore
index 0e09715cc60..5cb135fc58c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -82,6 +82,8 @@ fit-dtb.blob*
 /keep-syms-lto.*
 /*imx8mimage*
 /*imx8mcst*
+/*imx9image*
+/*imx93cst*
 /*rcar4-sa0*
 /drivers/video/u_boot_logo.bmp.S
 /test/fdt_overlay/test-fdt-overlay-stacked.dtbo.S
diff --git a/tools/binman/etype/nxp_imx93cst.py 
b/tools/binman/etype/nxp_imx93cst.py
new file mode 100644
index 00000000000..e1528b13102
--- /dev/null
+++ b/tools/binman/etype/nxp_imx93cst.py
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2026 (C) Bootlin
+# Author: Jérémie Dautheribes <[email protected]>
+#
+# Derived from nxp_imx8mcst.py
+# Copyright 2023-2024 Marek Vasut <[email protected]>
+
+
+# Entry-type module for generating the i.MX93 code signing tool
+# input configuration file and invocation of cst on generated
+# input configuration file and input data to be signed.
+#
+
+import configparser
+import os
+import struct
+
+from binman.etype.mkimage import Entry_mkimage
+from binman.etype.section import Entry_section
+from dtoc import fdt_util
+from u_boot_pylib import tools
+
+CONTAINER_HDR_TAG = 0x87
+SPL_CONTAINER_OFFSET = 1024  # 0x400
+CONTAINER_HDR_SIZE = 16
+AHAB_IMAGE_ENTRY_FLAGS_OFFSET = 24
+ELE_IMAGE_CORE_AND_TYPE = 0x66
+
+KEY_NAME = "sha384_secp384r1_v3_usr_crt"
+
+CSF_CONFIG_TEMPLATE = f"""
+[Header]
+  Target = AHAB
+  Version = 1.0
+
+[Install SRK]
+  File = "SRK_1_2_3_4_table.bin"
+  Source = "SRK1_{KEY_NAME}.pem"
+  Source index = 0
+  Source set = OEM
+  Revocations = 0x0
+
+[Authenticate Data]
+  File = "data.bin"
+  Offsets      = 0x400        0x490
+
+"""
+
+
+class Entry_nxp_imx93cst(Entry_mkimage):
+    """NXP i.MX93 CST .cfg file generator and cst invoker"""
+
+    def __init__(self, section, etype, node):
+        super().__init__(section, etype, node)
+
+    def ReadNode(self):
+        super().ReadNode()
+        self.srk_table = os.getenv(
+            "SRK_TABLE",
+            fdt_util.GetString(self._node, "nxp,srk-table", 
"SRK_1_2_3_4_table.bin"),
+        )
+        self.srk_crt = os.getenv(
+            "SRK_KEY",
+            fdt_util.GetString(self._node, "nxp,srk-crt", 
f"SRK1_{KEY_NAME}.pem"),
+        )
+        self.ReadEntries()
+
+    def BuildSectionData(self, required):
+        data, input_fname, uniq = self.collect_contents_to_file(
+            self._entries.values(), "input"
+        )
+
+        if struct.unpack("<B", data[3:4])[0] != CONTAINER_HDR_TAG:
+            # Unknown section type, pass input data through.
+            return data
+
+        hdr_addr = 0
+
+        # The SPL AHAB image can optionally contain and start with the ELE FW,
+        # which is already signed by NXP.
+        # In this case, the SPL container header address is not 0x0.
+
+        flags_offset = CONTAINER_HDR_SIZE + AHAB_IMAGE_ENTRY_FLAGS_OFFSET
+        image_flags = struct.unpack("<I", data[flags_offset : flags_offset + 
4])[0]
+        # Detect the ELE FW from the core/type fields of its image entries
+        if (image_flags & 0xFF) == ELE_IMAGE_CORE_AND_TYPE:
+            hdr_addr = SPL_CONTAINER_OFFSET
+
+        # Extract the signing offset from the i.MX container
+        signoffset = struct.unpack("<H", data[hdr_addr + 12 : hdr_addr + 
14])[0]
+
+        # The signing offset is relative to the container header address,
+        # so compute the absolute signing offset address
+        signoffset = signoffset + hdr_addr
+
+        # Write out customized data to be signed
+        output_dname = tools.get_output_filename(f"nxp.cst-input-data.{uniq}")
+        tools.write_file(output_dname, data)
+
+        # Generate CST configuration file used to sign payload
+        cfg_fname = tools.get_output_filename(f"nxp.csf-config-txt.{uniq}")
+        config = configparser.ConfigParser()
+        # Do not make key names lowercase
+        config.optionxform = str
+        # Load configuration template and modify keys of interest
+        config.read_string(CSF_CONFIG_TEMPLATE)
+        config["Install SRK"]["File"] = f'"{self.srk_table}"'
+        config["Install SRK"]["Source"] = f'"{self.srk_crt}"'
+        config["Authenticate Data"]["File"] = f'"{output_dname}"'
+        config["Authenticate Data"]["Offsets"] = f"{hdr_addr:#x} 
{signoffset:#x}"
+
+        with open(cfg_fname, "w") as cfgf:
+            config.write(cfgf)
+
+        output_fname = tools.get_output_filename(f"nxp.csf-output-blob.{uniq}")
+        args = ["-i", cfg_fname, "-o", output_fname]
+        if self.cst.run_cmd(*args) is not None:
+            outdata = tools.read_file(output_fname)
+            return outdata
+        else:
+            # Bintool is missing; just use the input data as the output
+            self.record_missing_bintool(self.cst)
+            return data
+
+    def SetImagePos(self, image_pos):
+        # Customized SoC specific SetImagePos which skips the mkimage etype
+        # implementation and removes the 0x48 offset introduced there. That
+        # offset is only used for uImage/fitImage, which is not the case in
+        # here.
+        upto = 0x00
+        for entry in super().GetEntries().values():
+            entry.SetOffsetSize(upto, None)
+
+            # Give up if any entries lack a size
+            if entry.size is None:
+                return
+            upto += entry.size
+
+        Entry_section.SetImagePos(self, image_pos)
+
+    def AddBintools(self, btools):
+        super().AddBintools(btools)
+        self.cst = self.AddBintool(btools, "cst")

-- 
2.55.0

Reply via email to