[PATCH v2 07/10] binman: tests: Add test coverage for a FIT with embedded Linux+initrd and /chosen

Alexey Charkov <[email protected]> Fri, 31 Jul 2026 21:10:51 +0400
Newsgroups gmane.comp.boot-loaders.u-boot
Message-ID <[email protected]>
Add a test for a FIT image with a fake Linux kernel and initrd, and a
valid device tree into which a /chosen node is added (containing a
bootargs property, as is relevant for Falcon mode boot).

Signed-off-by: Alexey Charkov <[email protected]>
---
 tools/binman/ftest.py                          | 107 +++++++++++++++++++++++++
 tools/binman/test/fit/fit_chosen.dts           |  62 ++++++++++++++
 tools/binman/test/fit/fit_chosen_no_initrd.dts |  60 ++++++++++++++
 tools/binman/test/fit/fit_chosen_no_load.dts   |  57 +++++++++++++
 4 files changed, 286 insertions(+)

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 9553eb6b7366..bc65cb25ef25 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -4397,6 +4397,113 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
                       str(e.exception))
 
+    def testFitChosen(self):
+        """Test patching /chosen (bootargs + initrd) into generated FIT FDTs"""
+        kernel = b'\x01\x02\x03\x04 kernel'
+        initrd = b'initramfs-contents'
+        self._MakeInputFile('test-kernel.bin', kernel)
+        self._MakeInputFile('test-initrd.bin', initrd)
+        entry_args = {
+            'of-list': 'model1 model2',
+            'default-dt': 'model2',
+            'linux-kernel-path': 'test-kernel.bin',
+            'linux-initrd-path': 'test-initrd.bin',
+        }
+        testdir, _ = self.SetupAlternateDts()
+        data = self._DoReadFileDtb(
+            'fit/fit_chosen.dts', use_real_dtb=True, update_dtb=True,
+            entry_args=entry_args, extra_indirs=[testdir])[0]
+        fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
+        fit = fdt.Fdt.FromData(fit_data)
+        fit.Scan()
+
+        # ramdisk is loaded at 0x1000 (see fit_chosen.dts)
+        rd_start = 0x1000
+        rd_end = rd_start + len(initrd)
+        for seq in (1, 2):
+            fnode = fit.GetNode('/images/fdt-%d' % seq)
+            self.assertIsNotNone(fnode)
+            dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
+            dtb.Scan()
+            chosen = dtb.GetNode('/chosen')
+            self.assertIsNotNone(chosen)
+            self.assertEqual(b'console=ttyS0 root=/dev/ram\0',
+                             chosen.props['bootargs'].bytes)
+            start = int.from_bytes(chosen.props['linux,initrd-start'].bytes,
+                                   'big')
+            end = int.from_bytes(chosen.props['linux,initrd-end'].bytes, 'big')
+            self.assertEqual(rd_start, start)
+            self.assertEqual(rd_end, end)
+            # The initramfs region must be reserved in the FDT
+            fdt_obj = dtb.GetFdtObj()
+            self.assertEqual(1, fdt_obj.num_mem_rsv())
+            _, addr, size = fdt_obj.get_mem_rsv(0)
+            self.assertEqual(rd_start, addr)
+            self.assertEqual(len(initrd), size)
+
+    def testFitChosenNoInitrd(self):
+        """Test a Falcon-mode FIT where the optional initramfs is not supplied"""
+        self._MakeInputFile('test-kernel.bin', b'\x01\x02\x03\x04 kernel')
+        entry_args = {
+            'of-list': 'model1 model2',
+            'default-dt': 'model2',
+            'linux-kernel-path': 'test-kernel.bin',
+            'linux-initrd-path': '',
+        }
+        testdir, _ = self.SetupAlternateDts()
+        with terminal.capture() as (stdout, stderr):
+            data = self._DoReadFileDtb(
+                'fit/fit_chosen_no_initrd.dts', use_real_dtb=True,
+                update_dtb=True, entry_args=entry_args,
+                extra_indirs=[testdir], allow_fake_blobs=False)[0]
+        self.assertRegex(
+            stderr.getvalue(),
+            "Image '.*' is missing optional external blobs but is still functional: linux-initrd")
+
+        fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
+        fit = fdt.Fdt.FromData(fit_data)
+        fit.Scan()
+
+        for seq in (1, 2):
+            # The node is still emitted and still listed as a loadable, as is
+            # already the case for an optional OP-TEE which was not supplied
+            # (see testFitFirmwareLoadables), but it carries no data
+            cnode = fit.GetNode('/configurations/config-%d' % seq)
+            self.assertEqual(b'kernel\0', cnode.props['firmware'].bytes)
+            self.assertEqual(['ramdisk'],
+                             fdt_util.GetStringList(cnode, 'loadables'))
+            self.assertEqual(b'', fit.GetNode('/images/ramdisk')
+                             .props['data'].bytes)
+
+            # bootargs is still patched in, but the initrd properties are not
+            fnode = fit.GetNode('/images/fdt-%d' % seq)
+            dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
+            dtb.Scan()
+            chosen = dtb.GetNode('/chosen')
+            self.assertEqual(b'console=ttyS0\0', chosen.props['bootargs'].bytes)
+            self.assertNotIn('linux,initrd-start', chosen.props)
+            self.assertNotIn('linux,initrd-end', chosen.props)
+            self.assertEqual(0, dtb.GetFdtObj().num_mem_rsv())
+
+    def testFitChosenNoLoad(self):
+        """Test a fit,initrd image which is missing its load address"""
+        self._MakeInputFile('test-kernel.bin', b'\x01\x02\x03\x04 kernel')
+        self._MakeInputFile('test-initrd.bin', b'initramfs-contents')
+        entry_args = {
+            'of-list': 'model1 model2',
+            'default-dt': 'model2',
+            'linux-kernel-path': 'test-kernel.bin',
+            'linux-initrd-path': 'test-initrd.bin',
+        }
+        testdir, _ = self.SetupAlternateDts()
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFileDtb(
+                'fit/fit_chosen_no_load.dts', use_real_dtb=True,
+                update_dtb=True, entry_args=entry_args,
+                extra_indirs=[testdir])
+        self.assertIn("fit,initrd image 'ramdisk' has no 'load' address",
+                      str(e.exception))
+
     def testFitExtblobMissingHelp(self):
         """Test display of help messages when an external blob is missing"""
         control.missing_blob_help = control._ReadMissingBlobHelp()
diff --git a/tools/binman/test/fit/fit_chosen.dts b/tools/binman/test/fit/fit_chosen.dts
new file mode 100644
index 000000000000..ae2e4a084af6
--- /dev/null
+++ b/tools/binman/test/fit/fit_chosen.dts
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+		fit {
+			description = "test-desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				kernel {
+					description = "Linux kernel";
+					type = "kernel";
+					arch = "arm64";
+					os = "linux";
+					compression = "none";
+					load = <0x100>;
+					entry = <0x100>;
+					linux-kernel {
+					};
+				};
+				ramdisk {
+					description = "ramdisk";
+					type = "ramdisk";
+					compression = "none";
+					load = <0x1000>;
+					linux-initrd {
+					};
+				};
+				@fdt-SEQ {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					compression = "none";
+					fit,bootargs = "console=ttyS0 root=/dev/ram";
+					fit,initrd = "ramdisk";
+					hash {
+						algo = "sha256";
+					};
+				};
+			};
+
+			configurations {
+				default = "@config-DEFAULT-SEQ";
+				@config-SEQ {
+					description = "conf-NAME.dtb";
+					firmware = "kernel";
+					loadables = "ramdisk";
+					fdt = "fdt-SEQ";
+				};
+			};
+		};
+		u-boot-nodtb {
+		};
+	};
+};
diff --git a/tools/binman/test/fit/fit_chosen_no_initrd.dts b/tools/binman/test/fit/fit_chosen_no_initrd.dts
new file mode 100644
index 000000000000..82468e94dcdb
--- /dev/null
+++ b/tools/binman/test/fit/fit_chosen_no_initrd.dts
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+		fit {
+			description = "test-desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				kernel {
+					description = "Linux kernel";
+					type = "kernel";
+					arch = "arm64";
+					os = "linux";
+					compression = "none";
+					load = <0x100>;
+					entry = <0x100>;
+					linux-kernel {
+					};
+				};
+				ramdisk {
+					description = "ramdisk";
+					type = "ramdisk";
+					compression = "none";
+					load = <0x1000>;
+					linux-initrd {
+						optional;
+					};
+				};
+				@fdt-SEQ {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					compression = "none";
+					fit,bootargs = "console=ttyS0";
+					fit,initrd = "ramdisk";
+				};
+			};
+
+			configurations {
+				default = "@config-DEFAULT-SEQ";
+				@config-SEQ {
+					description = "conf-NAME.dtb";
+					fit,firmware = "kernel", "ramdisk";
+					fit,loadables;
+					fdt = "fdt-SEQ";
+				};
+			};
+		};
+		u-boot-nodtb {
+		};
+	};
+};
diff --git a/tools/binman/test/fit/fit_chosen_no_load.dts b/tools/binman/test/fit/fit_chosen_no_load.dts
new file mode 100644
index 000000000000..7a3d393dd210
--- /dev/null
+++ b/tools/binman/test/fit/fit_chosen_no_load.dts
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+		fit {
+			description = "test-desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				kernel {
+					description = "Linux kernel";
+					type = "kernel";
+					arch = "arm64";
+					os = "linux";
+					compression = "none";
+					load = <0x100>;
+					entry = <0x100>;
+					linux-kernel {
+					};
+				};
+				ramdisk {
+					description = "ramdisk";
+					type = "ramdisk";
+					compression = "none";
+					linux-initrd {
+					};
+				};
+				@fdt-SEQ {
+					description = "fdt-NAME.dtb";
+					type = "flat_dt";
+					compression = "none";
+					fit,initrd = "ramdisk";
+				};
+			};
+
+			configurations {
+				default = "@config-DEFAULT-SEQ";
+				@config-SEQ {
+					description = "conf-NAME.dtb";
+					firmware = "kernel";
+					loadables = "ramdisk";
+					fdt = "fdt-SEQ";
+				};
+			};
+		};
+		u-boot-nodtb {
+		};
+	};
+};

-- 
2.54.0