Merge tag 'dm-pull-26jan23' of https://source.denx.de/u-boot/custodians/u-boot-dm

FIT improvements with split-elf, especially for Rockchip
Binman positioning by ELF symbol
diff --git a/arch/arm/dts/rockchip-u-boot.dtsi b/arch/arm/dts/rockchip-u-boot.dtsi
index 234fc5d..f147dc2 100644
--- a/arch/arm/dts/rockchip-u-boot.dtsi
+++ b/arch/arm/dts/rockchip-u-boot.dtsi
@@ -37,6 +37,7 @@
 			fit,fdt-list = "of-list";
 			filename = "u-boot.itb";
 			fit,external-offset = <CONFIG_FIT_EXTERNAL_OFFSET>;
+			fit,align = <512>;
 			offset = <CONFIG_SPL_PAD_TO>;
 			images {
 				u-boot {
@@ -49,6 +50,11 @@
 					entry = <CONFIG_TEXT_BASE>;
 					u-boot-nodtb {
 					};
+#ifdef CONFIG_SPL_FIT_SIGNATURE
+					hash {
+						algo = "sha256";
+					};
+#endif
 				};
 
 				@atf-SEQ {
@@ -64,6 +70,11 @@
 
 					atf-bl31 {
 					};
+#ifdef CONFIG_SPL_FIT_SIGNATURE
+					hash {
+						algo = "sha256";
+					};
+#endif
 				};
 				@tee-SEQ {
 					fit,operation = "split-elf";
@@ -79,12 +90,22 @@
 					tee-os {
 						optional;
 					};
+#ifdef CONFIG_SPL_FIT_SIGNATURE
+					hash {
+						algo = "sha256";
+					};
+#endif
 				};
 
 				@fdt-SEQ {
 					description = "fdt-NAME";
 					compression = "none";
 					type = "flat_dt";
+#ifdef CONFIG_SPL_FIT_SIGNATURE
+					hash {
+						algo = "sha256";
+					};
+#endif
 				};
 			};
 
@@ -93,7 +114,7 @@
 				@config-SEQ {
 					description = "NAME.dtb";
 					fdt = "fdt-SEQ";
-					firmware = "u-boot";
+					fit,firmware = "atf-1", "u-boot";
 					fit,loadables;
 				};
 			};
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index 0c7d2ec..3e77832 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -39,7 +39,7 @@
 	u32 flags = dev_get_flags(dev);
 
 	/* print the first 20 characters to not break the tree-format. */
-	printf(IS_ENABLED(CONFIG_SPL_BUILD) ? " %s  %d  [ %c ]   %s  " :
+	printf(CONFIG_IS_ENABLED(USE_TINY_PRINTF) ? " %s  %d  [ %c ]   %s  " :
 	       " %-10.10s  %3d  [ %c ]   %-20.20s  ", dev->uclass->uc_drv->name,
 	       dev_get_uclass_index(dev, NULL),
 	       flags & DM_FLAG_ACTIVATED ? '+' : ' ', dev->driver->name);
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index fa8abdc..03a99a1 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -615,6 +615,14 @@
     this size. If this is not provided, it will be set to the size of the
     contents.
 
+min-size:
+    Sets the minimum size of the entry. This size includes explicit padding
+    ('pad-before' and 'pad-after'), but not padding added to meet alignment
+    requirements. While this does not affect the contents of the entry within
+    binman itself (the padding is performed only when its parent section is
+    assembled), the end result will be that the entry ends with the padding
+    bytes, so may grow. Defaults to 0.
+
 pad-before:
     Padding before the contents of the entry. Normally this is 0, meaning
     that the contents start at the beginning of the entry. This can be used
diff --git a/tools/binman/btool/mkimage.py b/tools/binman/btool/mkimage.py
index da5f344..d5b407c 100644
--- a/tools/binman/btool/mkimage.py
+++ b/tools/binman/btool/mkimage.py
@@ -22,7 +22,7 @@
 
     # pylint: disable=R0913
     def run(self, reset_timestamp=False, output_fname=None, external=False,
-            pad=None):
+            pad=None, align=None):
         """Run mkimage
 
         Args:
@@ -33,6 +33,7 @@
             pad: Bytes to use for padding the FIT devicetree output. This allows
                 other things to be easily added later, if required, such as
                 signatures
+            align: Bytes to use for alignment of the FIT and its external data
             version: True to get the mkimage version
         """
         args = []
@@ -40,6 +41,8 @@
             args.append('-E')
         if pad:
             args += ['-p', f'{pad:x}']
+        if align:
+            args += ['-B', f'{align:x}']
         if reset_timestamp:
             args.append('-t')
         if output_fname:
diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py
index 082a3e1..8cb55eb 100644
--- a/tools/binman/elf_test.py
+++ b/tools/binman/elf_test.py
@@ -242,7 +242,7 @@
         end = offset['embed_end'].offset
         data = tools.read_file(fname)
         embed_data = data[start:end]
-        expect = struct.pack('<III', 0x1234, 0x5678, 0)
+        expect = struct.pack('<IIIII', 2, 3, 0x1234, 0x5678, 0)
         self.assertEqual(expect, embed_data)
 
     def testEmbedFail(self):
@@ -358,6 +358,17 @@
         self.assertEqual(True, elf.is_valid(data))
         self.assertEqual(False, elf.is_valid(data[4:]))
 
+    def test_get_symbol_offset(self):
+        fname = self.ElfTestFile('embed_data')
+        syms = elf.GetSymbols(fname, ['embed_start', 'embed'])
+        expected = syms['embed'].address - syms['embed_start'].address
+        val = elf.GetSymbolOffset(fname, 'embed', 'embed_start')
+        self.assertEqual(expected, val)
+
+        with self.assertRaises(KeyError) as e:
+            elf.GetSymbolOffset(fname, 'embed')
+        self.assertIn('__image_copy_start', str(e.exception))
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index 2b32c13..7a04a61 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -604,6 +604,11 @@
         Indicates that the contents of the FIT are external and provides the
         external offset. This is passed to mkimage via the -E and -p flags.
 
+    fit,align
+        Indicates what alignment to use for the FIT and its external data,
+        and provides the alignment to use. This is passed to mkimage via
+        the -B flag.
+
     fit,fdt-list
         Indicates the entry argument which provides the list of device tree
         files for the gen-fdt-nodes operation (as below). This is often
@@ -716,6 +721,12 @@
     fit,data
         Generates a `data = <...>` property with the contents of the segment
 
+    fit,firmware
+        Generates a `firmware = <...>` property. Provides a list of possible
+        nodes to be used as the `firmware` property value. The first valid
+        node is picked as the firmware. Any remaining valid nodes is
+        prepended to the `loadable` property generated by `fit,loadables`
+
     fit,loadables
         Generates a `loadable = <...>` property with a list of the generated
         nodes (including all nodes if this operation is used multiple times)
@@ -757,6 +768,9 @@
 
                 atf-bl31 {
                 };
+                hash {
+                    algo = "sha256";
+                };
             };
 
             @tee-SEQ {
@@ -772,6 +786,9 @@
 
                 tee-os {
                 };
+                hash {
+                    algo = "sha256";
+                };
             };
         };
 
@@ -780,7 +797,7 @@
             @config-SEQ {
                 description = "conf-NAME.dtb";
                 fdt = "fdt-SEQ";
-                firmware = "u-boot";
+                fit,firmware = "atf-1", "u-boot";
                 fit,loadables;
             };
         };
@@ -800,6 +817,10 @@
             arch = "arm64";
             type = "firmware";
             description = "ARM Trusted Firmware";
+            hash {
+                algo = "sha256";
+                value = <...hash of first segment...>;
+            };
         };
         atf-2 {
             data = <...contents of second segment...>;
@@ -809,6 +830,10 @@
             arch = "arm64";
             type = "firmware";
             description = "ARM Trusted Firmware";
+            hash {
+                algo = "sha256";
+                value = <...hash of second segment...>;
+            };
         };
     };
 
@@ -827,15 +852,15 @@
     configurations {
         default = "config-1";
         config-1 {
-            loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2";
+            loadables = "u-boot", "atf-2", "atf-3", "tee-1", "tee-2";
             description = "rk3399-firefly.dtb";
             fdt = "fdt-1";
-            firmware = "u-boot";
+            firmware = "atf-1";
         };
     };
 
-U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables
-(ATF and TEE), then proceed with the boot.
+U-Boot SPL can then load the firmware (ATF) and all the loadables (U-Boot
+proper, ATF and TEE), then proceed with the boot.
 
 
 
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index 5d8696e..5eacc5f 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -49,6 +49,7 @@
         offset: Offset of entry within the section, None if not known yet (in
             which case it will be calculated by Pack())
         size: Entry size in bytes, None if not known
+        min_size: Minimum entry size in bytes
         pre_reset_size: size as it was before ResetForPack(). This allows us to
             keep track of the size we started with and detect size changes
         uncomp_size: Size of uncompressed data in bytes, if the entry is
@@ -114,6 +115,7 @@
         self.name = node and (name_prefix + node.name) or 'none'
         self.offset = None
         self.size = None
+        self.min_size = 0
         self.pre_reset_size = None
         self.uncomp_size = None
         self.data = None
@@ -270,6 +272,7 @@
             self.Raise("Please use 'extend-size' instead of 'expand-size'")
         self.offset = fdt_util.GetInt(self._node, 'offset')
         self.size = fdt_util.GetInt(self._node, 'size')
+        self.min_size = fdt_util.GetInt(self._node, 'min-size', 0)
         self.orig_offset = fdt_util.GetInt(self._node, 'orig-offset')
         self.orig_size = fdt_util.GetInt(self._node, 'orig-size')
         if self.GetImage().copy_to_orig:
@@ -507,6 +510,7 @@
             else:
                 self.offset = tools.align(offset, self.align)
         needed = self.pad_before + self.contents_size + self.pad_after
+        needed = max(needed, self.min_size)
         needed = tools.align(needed, self.align_size)
         size = self.size
         if not size:
diff --git a/tools/binman/entry_test.py b/tools/binman/entry_test.py
index aa470c5..a6fbf62 100644
--- a/tools/binman/entry_test.py
+++ b/tools/binman/entry_test.py
@@ -114,6 +114,25 @@
         self.assertEquals(tools.get_bytes(0, 1024), base.CompressData(b'abc'))
         self.assertEquals(tools.get_bytes(0, 1024), base.DecompressData(b'abc'))
 
+    def testLookupOffset(self):
+        """Test the lookup_offset() method of the base class"""
+        def MyFindEntryByNode(node):
+            return self.found
+
+        base = entry.Entry.Create(None, self.GetNode(), 'blob-dtb')
+        base.FindEntryByNode = MyFindEntryByNode
+        base.section = base
+        self.found = None
+        base.offset_from_elf = [self.GetNode(), 'start', 0]
+        with self.assertRaises(ValueError) as e:
+            base.lookup_offset()
+        self.assertIn("Cannot find entry for node 'u-boot'", str(e.exception))
+
+        self.found = base
+        with self.assertRaises(ValueError) as e:
+            base.lookup_offset()
+        self.assertIn("Need elf-fname property 'u-boot'", str(e.exception))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 0e9d81b..cd29435 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -70,6 +70,11 @@
             Indicates that the contents of the FIT are external and provides the
             external offset. This is passed to mkimage via the -E and -p flags.
 
+        fit,align
+            Indicates what alignment to use for the FIT and its external data,
+            and provides the alignment to use. This is passed to mkimage via
+            the -B flag.
+
         fit,fdt-list
             Indicates the entry argument which provides the list of device tree
             files for the gen-fdt-nodes operation (as below). This is often
@@ -182,6 +187,12 @@
         fit,data
             Generates a `data = <...>` property with the contents of the segment
 
+        fit,firmware
+            Generates a `firmware = <...>` property. Provides a list of possible
+            nodes to be used as the `firmware` property value. The first valid
+            node is picked as the firmware. Any remaining valid nodes is
+            prepended to the `loadable` property generated by `fit,loadables`
+
         fit,loadables
             Generates a `loadable = <...>` property with a list of the generated
             nodes (including all nodes if this operation is used multiple times)
@@ -223,6 +234,9 @@
 
                     atf-bl31 {
                     };
+                    hash {
+                        algo = "sha256";
+                    };
                 };
 
                 @tee-SEQ {
@@ -238,6 +252,9 @@
 
                     tee-os {
                     };
+                    hash {
+                        algo = "sha256";
+                    };
                 };
             };
 
@@ -246,7 +263,7 @@
                 @config-SEQ {
                     description = "conf-NAME.dtb";
                     fdt = "fdt-SEQ";
-                    firmware = "u-boot";
+                    fit,firmware = "atf-1", "u-boot";
                     fit,loadables;
                 };
             };
@@ -266,6 +283,10 @@
                 arch = "arm64";
                 type = "firmware";
                 description = "ARM Trusted Firmware";
+                hash {
+                    algo = "sha256";
+                    value = <...hash of first segment...>;
+                };
             };
             atf-2 {
                 data = <...contents of second segment...>;
@@ -275,6 +296,10 @@
                 arch = "arm64";
                 type = "firmware";
                 description = "ARM Trusted Firmware";
+                hash {
+                    algo = "sha256";
+                    value = <...hash of second segment...>;
+                };
             };
         };
 
@@ -293,15 +318,15 @@
         configurations {
             default = "config-1";
             config-1 {
-                loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2";
+                loadables = "u-boot", "atf-2", "atf-3", "tee-1", "tee-2";
                 description = "rk3399-firefly.dtb";
                 fdt = "fdt-1";
-                firmware = "u-boot";
+                firmware = "atf-1";
             };
         };
 
-    U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables
-    (ATF and TEE), then proceed with the boot.
+    U-Boot SPL can then load the firmware (ATF) and all the loadables (U-Boot
+    proper, ATF and TEE), then proceed with the boot.
     """
     def __init__(self, section, etype, node):
         """
@@ -423,6 +448,9 @@
                 'external': True,
                 'pad': fdt_util.fdt32_to_cpu(ext_offset.value)
                 }
+        align = self._fit_props.get('fit,align')
+        if align is not None:
+            args.update({'align': fdt_util.fdt32_to_cpu(align.value)})
         if self.mkimage.run(reset_timestamp=True, output_fname=output_fname,
                             **args) is None:
             # Bintool is missing; just use empty data as the output
@@ -488,6 +516,42 @@
                 return
             fsw.property(pname, prop.bytes)
 
+        def _process_firmware_prop(node):
+            """Process optional fit,firmware property
+
+            Picks the first valid entry for use as the firmware, remaining valid
+            entries is prepended to loadables
+
+            Args:
+                node (Node): Generator node to process
+
+            Returns:
+                firmware (str): Firmware or None
+                result (list): List of remaining loadables
+            """
+            val = fdt_util.GetStringList(node, 'fit,firmware')
+            if val is None:
+                return None, self._loadables
+            valid_entries = list(self._loadables)
+            for name, entry in self.GetEntries().items():
+                missing = []
+                entry.CheckMissing(missing)
+                entry.CheckOptional(missing)
+                if not missing:
+                    valid_entries.append(name)
+            firmware = None
+            result = []
+            for name in val:
+                if name in valid_entries:
+                    if not firmware:
+                        firmware = name
+                    elif name not in result:
+                        result.append(name)
+            for name in self._loadables:
+                if name != firmware and name not in result:
+                    result.append(name)
+            return firmware, result
+
         def _gen_fdt_nodes(base_node, node, depth, in_images):
             """Generate FDT nodes
 
@@ -498,20 +562,24 @@
             first.
 
             Args:
-                node (None): Generator node to process
+                node (Node): Generator node to process
                 depth: Current node depth (0 is the base 'fit' node)
                 in_images: True if this is inside the 'images' node, so that
                     'data' properties should be generated
             """
             if self._fdts:
+                firmware, fit_loadables = _process_firmware_prop(node)
                 # Generate nodes for each FDT
                 for seq, fdt_fname in enumerate(self._fdts):
                     node_name = node.name[1:].replace('SEQ', str(seq + 1))
                     fname = tools.get_input_filename(fdt_fname + '.dtb')
                     with fsw.add_node(node_name):
                         for pname, prop in node.props.items():
-                            if pname == 'fit,loadables':
-                                val = '\0'.join(self._loadables) + '\0'
+                            if pname == 'fit,firmware':
+                                if firmware:
+                                    fsw.property_string('firmware', firmware)
+                            elif pname == 'fit,loadables':
+                                val = '\0'.join(fit_loadables) + '\0'
                                 fsw.property('loadables', val.encode('utf-8'))
                             elif pname == 'fit,operation':
                                 pass
@@ -540,12 +608,13 @@
                     else:
                         self.Raise("Generator node requires 'fit,fdt-list' property")
 
-        def _gen_split_elf(base_node, node, segments, entry_addr):
+        def _gen_split_elf(base_node, node, depth, segments, entry_addr):
             """Add nodes for the ELF file, one per group of contiguous segments
 
             Args:
                 base_node (Node): Template node from the binman definition
                 node (Node): Node to replace (in the FIT being built)
+                depth: Current node depth (0 is the base 'fit' node)
                 segments (list): list of segments, each:
                     int: Segment number (0 = first)
                     int: Start address of segment in memory
@@ -570,6 +639,10 @@
                             self._raise_subnode(
                                 node, f"Unknown directive '{pname}'")
 
+                    for subnode in node.subnodes:
+                        with fsw.add_node(subnode.name):
+                            _add_node(node, depth + 1, subnode)
+
         def _gen_node(base_node, node, depth, in_images, entry):
             """Generate nodes from a template
 
@@ -623,7 +696,7 @@
                             self._raise_subnode(
                                 node, f'Failed to read ELF file: {str(exc)}')
 
-                    _gen_split_elf(base_node, node, segments, entry_addr)
+                    _gen_split_elf(base_node, node, depth, segments, entry_addr)
 
         def _add_node(base_node, depth, node):
             """Add nodes to the output FIT
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index be0aea4..6b203df 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -883,9 +883,9 @@
         self.assertIn('image', control.images)
         image = control.images['image']
         entries = image.GetEntries()
-        self.assertEqual(5, len(entries))
+        self.assertEqual(6, len(entries))
 
-        # First u-boot with padding before and after
+        # First u-boot with padding before and after (included in minimum size)
         self.assertIn('u-boot', entries)
         entry = entries['u-boot']
         self.assertEqual(0, entry.offset)
@@ -934,8 +934,17 @@
         self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
                          data[pos:pos + entry.size])
 
+        # Sixth u-boot with both minimum size and aligned size
+        self.assertIn('u-boot-min-size', entries)
+        entry = entries['u-boot-min-size']
+        self.assertEqual(128, entry.offset)
+        self.assertEqual(32, entry.size)
+        self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
+        self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
+                         data[pos:pos + entry.size])
+
         self.CheckNoGaps(entries)
-        self.assertEqual(128, image.size)
+        self.assertEqual(160, image.size)
 
         dtb = fdt.Fdt(out_dtb_fname)
         dtb.Scan()
@@ -943,7 +952,7 @@
         expected = {
             'image-pos': 0,
             'offset': 0,
-            'size': 128,
+            'size': 160,
 
             'u-boot:image-pos': 0,
             'u-boot:offset': 0,
@@ -964,6 +973,10 @@
             'u-boot-align-both:image-pos': 64,
             'u-boot-align-both:offset': 64,
             'u-boot-align-both:size': 64,
+
+            'u-boot-min-size:image-pos': 128,
+            'u-boot-min-size:offset': 128,
+            'u-boot-min-size:size': 32,
             }
         self.assertEqual(expected, props)
 
@@ -5439,6 +5452,10 @@
                          fdt_util.fdt32_to_cpu(atf1.props['load'].value))
         self.assertEqual(data, atf1.props['data'].bytes)
 
+        hash_node = atf1.FindNode('hash')
+        self.assertIsNotNone(hash_node)
+        self.assertEqual({'algo', 'value'}, hash_node.props.keys())
+
         atf2 = dtb.GetNode('/images/atf-2')
         self.assertEqual(base_keys, atf2.props.keys())
         _, start, data = segments[1]
@@ -5446,6 +5463,14 @@
                          fdt_util.fdt32_to_cpu(atf2.props['load'].value))
         self.assertEqual(data, atf2.props['data'].bytes)
 
+        hash_node = atf2.FindNode('hash')
+        self.assertIsNotNone(hash_node)
+        self.assertEqual({'algo', 'value'}, hash_node.props.keys())
+
+        hash_node = dtb.GetNode('/images/tee-1/hash-1')
+        self.assertIsNotNone(hash_node)
+        self.assertEqual({'algo', 'value'}, hash_node.props.keys())
+
         conf = dtb.GetNode('/configurations')
         self.assertEqual({'default'}, conf.props.keys())
 
@@ -6309,6 +6334,66 @@
         self.assertEqual(base + 8, inset.image_pos);
         self.assertEqual(4, inset.size);
 
+    def testFitAlign(self):
+        """Test an image with an FIT with aligned external data"""
+        data = self._DoReadFile('275_fit_align.dts')
+        self.assertEqual(4096, len(data))
+
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+
+        props = self._GetPropTree(dtb, ['data-position'])
+        expected = {
+            'u-boot:data-position': 1024,
+            'fdt-1:data-position': 2048,
+            'fdt-2:data-position': 3072,
+        }
+        self.assertEqual(expected, props)
+
+    def testFitFirmwareLoadables(self):
+        """Test an image with an FIT that use fit,firmware"""
+        if not elf.ELF_TOOLS:
+            self.skipTest('Python elftools not available')
+        entry_args = {
+            'of-list': 'test-fdt1',
+            'default-dt': 'test-fdt1',
+            'atf-bl31-path': 'bl31.elf',
+            'tee-os-path': 'missing.bin',
+        }
+        test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+        data = self._DoReadFileDtb(
+            '276_fit_firmware_loadables.dts',
+            entry_args=entry_args,
+            extra_indirs=[test_subdir])[0]
+
+        dtb = fdt.Fdt.FromData(data)
+        dtb.Scan()
+
+        node = dtb.GetNode('/configurations/conf-uboot-1')
+        self.assertEqual('u-boot', node.props['firmware'].value)
+        self.assertEqual(['atf-1', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-atf-1')
+        self.assertEqual('atf-1', node.props['firmware'].value)
+        self.assertEqual(['u-boot', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-missing-uboot-1')
+        self.assertEqual('u-boot', node.props['firmware'].value)
+        self.assertEqual(['atf-1', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-missing-atf-1')
+        self.assertEqual('atf-1', node.props['firmware'].value)
+        self.assertEqual(['u-boot', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
+        node = dtb.GetNode('/configurations/conf-missing-tee-1')
+        self.assertEqual('atf-1', node.props['firmware'].value)
+        self.assertEqual(['u-boot', 'atf-2'],
+                         fdt_util.GetStringList(node, 'loadables'))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/009_pack_extra.dts b/tools/binman/test/009_pack_extra.dts
index 1b31555..8d6f491 100644
--- a/tools/binman/test/009_pack_extra.dts
+++ b/tools/binman/test/009_pack_extra.dts
@@ -6,6 +6,7 @@
 
 	binman {
 		u-boot {
+			min-size = <12>;
 			pad-before = <3>;
 			pad-after = <5>;
 		};
@@ -31,5 +32,11 @@
 			align = <64>;
 			align-end = <128>;
 		};
+
+		u-boot-min-size {
+			type = "u-boot";
+			min-size = <24>;
+			align-size = <16>;
+		};
 	};
 };
diff --git a/tools/binman/test/226_fit_split_elf.dts b/tools/binman/test/226_fit_split_elf.dts
index fab1533..22c453e 100644
--- a/tools/binman/test/226_fit_split_elf.dts
+++ b/tools/binman/test/226_fit_split_elf.dts
@@ -33,6 +33,9 @@
 
 					atf-bl31 {
 					};
+					hash {
+						algo = "sha256";
+					};
 				};
 
 				@tee-SEQ {
@@ -48,6 +51,9 @@
 
 					tee-os {
 					};
+					hash-1 {
+						algo = "sha256";
+					};
 				};
 			};
 
diff --git a/tools/binman/test/275_fit_align.dts b/tools/binman/test/275_fit_align.dts
new file mode 100644
index 0000000..c7b06e3
--- /dev/null
+++ b/tools/binman/test/275_fit_align.dts
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		fit {
+			description = "test desc";
+			#address-cells = <1>;
+			fit,external-offset = <1024>;
+			fit,align = <1024>;
+
+			images {
+				u-boot {
+					description = "test u-boot";
+					type = "standalone";
+					arch = "arm64";
+					os = "u-boot";
+					compression = "none";
+					load = <00000000>;
+					entry = <00000000>;
+
+					u-boot-nodtb {
+					};
+				};
+
+				fdt-1 {
+					description = "test fdt";
+					type = "flat_dt";
+					compression = "none";
+
+					u-boot-dtb {
+					};
+				};
+
+				fdt-2 {
+					description = "test fdt";
+					type = "flat_dt";
+					compression = "none";
+
+					u-boot-dtb {
+					};
+				};
+			};
+
+			configurations {
+				default = "config-1";
+				config-1 {
+					description = "test config";
+					fdt = "fdt-1";
+					firmware = "u-boot";
+				};
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/276_fit_firmware_loadables.dts b/tools/binman/test/276_fit_firmware_loadables.dts
new file mode 100644
index 0000000..2f79cdc
--- /dev/null
+++ b/tools/binman/test/276_fit_firmware_loadables.dts
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		fit {
+			description = "test desc";
+			#address-cells = <1>;
+			fit,fdt-list = "of-list";
+
+			images {
+				u-boot {
+					description = "test u-boot";
+					type = "standalone";
+					arch = "arm64";
+					os = "u-boot";
+					compression = "none";
+					load = <0x00000000>;
+					entry = <0x00000000>;
+
+					u-boot-nodtb {
+					};
+				};
+				tee {
+					description = "test tee";
+					type = "tee";
+					arch = "arm64";
+					os = "tee";
+					compression = "none";
+					load = <0x00200000>;
+
+					tee-os {
+						optional;
+					};
+				};
+				@atf-SEQ {
+					fit,operation = "split-elf";
+					description = "test tf-a";
+					type = "firmware";
+					arch = "arm64";
+					os = "arm-trusted-firmware";
+					compression = "none";
+					fit,load;
+					fit,entry;
+					fit,data;
+
+					atf-bl31 {
+					};
+				};
+				@fdt-SEQ {
+					description = "test fdt";
+					type = "flat_dt";
+					compression = "none";
+				};
+			};
+
+			configurations {
+				default = "@conf-uboot-DEFAULT-SEQ";
+				@conf-uboot-SEQ {
+					description = "uboot config";
+					fdt = "fdt-SEQ";
+					fit,firmware = "u-boot";
+					fit,loadables;
+				};
+				@conf-atf-SEQ {
+					description = "atf config";
+					fdt = "fdt-SEQ";
+					fit,firmware = "atf-1", "u-boot";
+					fit,loadables;
+				};
+				@conf-missing-uboot-SEQ {
+					description = "missing uboot config";
+					fdt = "fdt-SEQ";
+					fit,firmware = "missing-1", "u-boot";
+					fit,loadables;
+				};
+				@conf-missing-atf-SEQ {
+					description = "missing atf config";
+					fdt = "fdt-SEQ";
+					fit,firmware = "missing-1", "atf-1", "u-boot";
+					fit,loadables;
+				};
+				@conf-missing-tee-SEQ {
+					description = "missing tee config";
+					fdt = "fdt-SEQ";
+					fit,firmware = "atf-1", "u-boot", "tee";
+					fit,loadables;
+				};
+			};
+		};
+	};
+};
diff --git a/tools/binman/test/embed_data.c b/tools/binman/test/embed_data.c
index 47d8c38..08b68c5 100644
--- a/tools/binman/test/embed_data.c
+++ b/tools/binman/test/embed_data.c
@@ -7,6 +7,7 @@
  */
 
 int first[10] = {1};
+int before[2] __attribute__((section(".embed"))) = {2, 3};
 int embed[3] __attribute__((section(".embed"))) = {0x1234, 0x5678};
 int second[10] = {1};