Some boards need to load an ELF file using the 'loadables' property, but
the file has segments at different memory addresses. This means that it
cannot be supplied as a flat binary.

Allow generating a separate node in the FIT for each segment in the ELF,
with a different load address for each.

Signed-off-by: Simon Glass <s...@chromium.org>
---

 tools/binman/entries.rst                     | 146 +++++++++++
 tools/binman/etype/fit.py                    | 259 ++++++++++++++++++-
 tools/binman/ftest.py                        | 116 +++++++++
 tools/binman/test/221_fit_split_elf.dts      |  67 +++++
 tools/binman/test/222_fit_bad_dir.dts        |   9 +
 tools/binman/test/223_fit_bad_dir_config.dts |   9 +
 6 files changed, 594 insertions(+), 12 deletions(-)
 create mode 100644 tools/binman/test/221_fit_split_elf.dts
 create mode 100644 tools/binman/test/222_fit_bad_dir.dts
 create mode 100644 tools/binman/test/223_fit_bad_dir_config.dts

diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index d483169712..079fed1a9c 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -612,6 +612,9 @@ gen-fdt-nodes
     Generate FDT nodes as above. This is the default if there is no
     `fit,operation` property.
 
+split-elf
+    Split an ELF file into a separate node for each segment.
+
 Generating nodes from an FDT list (gen-fdt-nodes)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -655,6 +658,149 @@ for each of your two files.
 Note that if no devicetree files are provided (with '-a of-list' as above)
 then no nodes will be generated.
 
+Generating nodes from an ELF file (split-elf)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This uses the node as a template to generate multiple nodes. The following
+special properties are available:
+
+split-elf
+    Split an ELF file into a separate node for each segment. This uses the
+    node as a template to generate multiple nodes. The following special
+    properties are available:
+
+    fit,load
+        Generates a `load = <...>` property with the load address of the
+        segmnet
+
+    fit,entry
+        Generates a `entry = <...>` property with the entry address of the
+        ELF. This is only produced for the first entry
+
+    fit,data
+        Generates a `data = <...>` property with the contents of the segment
+
+    fit,loadables
+        Generates a `loadable = <...>` property with a list of the generated
+        nodes (including all nodes if this operation is used multiple times)
+
+
+Here is an example showing ATF, TEE and a device tree all combined::
+
+    fit {
+        description = "test-desc";
+        #address-cells = <1>;
+        fit,fdt-list = "of-list";
+
+        images {
+            u-boot {
+                description = "U-Boot (64-bit)";
+                type = "standalone";
+                os = "U-Boot";
+                arch = "arm64";
+                compression = "none";
+                load = <CONFIG_SYS_TEXT_BASE>;
+                u-boot-nodtb {
+                };
+            };
+            @fdt-SEQ {
+                description = "fdt-NAME.dtb";
+                type = "flat_dt";
+                compression = "none";
+            };
+            @atf-SEQ {
+                fit,operation = "split-elf";
+                description = "ARM Trusted Firmware";
+                type = "firmware";
+                arch = "arm64";
+                os = "arm-trusted-firmware";
+                compression = "none";
+                fit,load;
+                fit,entry;
+                fit,data;
+
+                atf-bl31 {
+                };
+            };
+
+            @tee-SEQ {
+                fit,operation = "split-elf";
+                description = "TEE";
+                type = "tee";
+                arch = "arm64";
+                os = "tee";
+                compression = "none";
+                fit,load;
+                fit,entry;
+                fit,data;
+
+                op-tee {
+                };
+            };
+        };
+
+        configurations {
+            default = "@config-DEFAULT-SEQ";
+            @config-SEQ {
+                description = "conf-NAME.dtb";
+                fdt = "fdt-SEQ";
+                firmware = "u-boot";
+                fit,loadables;
+            };
+        };
+    };
+
+If ATF-BL31 is available, this generates a node for each segment in the
+ELF file, for example::
+
+    images {
+        atf-1 {
+            data = <...contents of first segment...>;
+            data-offset = <0x00000000>;
+            entry = <0x00040000>;
+            load = <0x00040000>;
+            compression = "none";
+            os = "arm-trusted-firmware";
+            arch = "arm64";
+            type = "firmware";
+            description = "ARM Trusted Firmware";
+        };
+        atf-2 {
+            data = <...contents of second segment...>;
+            load = <0xff3b0000>;
+            compression = "none";
+            os = "arm-trusted-firmware";
+            arch = "arm64";
+            type = "firmware";
+            description = "ARM Trusted Firmware";
+        };
+    };
+
+The same applies for OP-TEE if that is available.
+
+If each binary is not available, the relevant template node (@atf-SEQ or
+@tee-SEQ) is removed from the output.
+
+This also generates a `config-xxx` node for each device tree in `of-list`.
+Note that the U-Boot build system uses `-a of-list=$(CONFIG_OF_LIST)`
+so you can use `CONFIG_OF_LIST` to define that list. In this example it is
+set up for `firefly-rk3399` with a single device tree and the default set
+with `-a default-dt=$(CONFIG_DEFAULT_DEVICE_TREE)`, so the resulting output
+is::
+
+    configurations {
+        default = "config-1";
+        config-1 {
+            loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2";
+            description = "rk3399-firefly.dtb";
+            fdt = "fdt-1";
+            firmware = "u-boot";
+        };
+    };
+
+U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables
+(ATF and TEE), then proceed with the boot.
+
 
 
 Entry: fmap: An entry which contains an Fmap section
diff --git a/tools/binman/etype/fit.py b/tools/binman/etype/fit.py
index 6210deeef7..b2a037c742 100644
--- a/tools/binman/etype/fit.py
+++ b/tools/binman/etype/fit.py
@@ -6,17 +6,20 @@
 #
 
 from collections import defaultdict, OrderedDict
+import io
 import libfdt
 
 from binman.entry import Entry, EntryArg
+from binman import elf
 from dtoc import fdt_util
 from dtoc.fdt import Fdt
 from patman import tools
 
 # Supported operations, with the fit,operation property
-OP_GEN_FDT_NODES = range(1)
+OP_GEN_FDT_NODES, OP_SPLIT_ELF = range(2)
 OPERATIONS = {
     'gen-fdt-nodes': OP_GEN_FDT_NODES,
+    'split-elf': OP_SPLIT_ELF,
     }
 
 class Entry_fit(Entry):
@@ -111,6 +114,9 @@ class Entry_fit(Entry):
         Generate FDT nodes as above. This is the default if there is no
         `fit,operation` property.
 
+    split-elf
+        Split an ELF file into a separate node for each segment.
+
     Generating nodes from an FDT list (gen-fdt-nodes)
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -153,6 +159,149 @@ class Entry_fit(Entry):
 
     Note that if no devicetree files are provided (with '-a of-list' as above)
     then no nodes will be generated.
+
+    Generating nodes from an ELF file (split-elf)
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    This uses the node as a template to generate multiple nodes. The following
+    special properties are available:
+
+    split-elf
+        Split an ELF file into a separate node for each segment. This uses the
+        node as a template to generate multiple nodes. The following special
+        properties are available:
+
+        fit,load
+            Generates a `load = <...>` property with the load address of the
+            segmnet
+
+        fit,entry
+            Generates a `entry = <...>` property with the entry address of the
+            ELF. This is only produced for the first entry
+
+        fit,data
+            Generates a `data = <...>` property with the contents of the 
segment
+
+        fit,loadables
+            Generates a `loadable = <...>` property with a list of the 
generated
+            nodes (including all nodes if this operation is used multiple 
times)
+
+
+    Here is an example showing ATF, TEE and a device tree all combined::
+
+        fit {
+            description = "test-desc";
+            #address-cells = <1>;
+            fit,fdt-list = "of-list";
+
+            images {
+                u-boot {
+                    description = "U-Boot (64-bit)";
+                    type = "standalone";
+                    os = "U-Boot";
+                    arch = "arm64";
+                    compression = "none";
+                    load = <CONFIG_SYS_TEXT_BASE>;
+                    u-boot-nodtb {
+                    };
+                };
+                @fdt-SEQ {
+                    description = "fdt-NAME.dtb";
+                    type = "flat_dt";
+                    compression = "none";
+                };
+                @atf-SEQ {
+                    fit,operation = "split-elf";
+                    description = "ARM Trusted Firmware";
+                    type = "firmware";
+                    arch = "arm64";
+                    os = "arm-trusted-firmware";
+                    compression = "none";
+                    fit,load;
+                    fit,entry;
+                    fit,data;
+
+                    atf-bl31 {
+                    };
+                };
+
+                @tee-SEQ {
+                    fit,operation = "split-elf";
+                    description = "TEE";
+                    type = "tee";
+                    arch = "arm64";
+                    os = "tee";
+                    compression = "none";
+                    fit,load;
+                    fit,entry;
+                    fit,data;
+
+                    op-tee {
+                    };
+                };
+            };
+
+            configurations {
+                default = "@config-DEFAULT-SEQ";
+                @config-SEQ {
+                    description = "conf-NAME.dtb";
+                    fdt = "fdt-SEQ";
+                    firmware = "u-boot";
+                    fit,loadables;
+                };
+            };
+        };
+
+    If ATF-BL31 is available, this generates a node for each segment in the
+    ELF file, for example::
+
+        images {
+            atf-1 {
+                data = <...contents of first segment...>;
+                data-offset = <0x00000000>;
+                entry = <0x00040000>;
+                load = <0x00040000>;
+                compression = "none";
+                os = "arm-trusted-firmware";
+                arch = "arm64";
+                type = "firmware";
+                description = "ARM Trusted Firmware";
+            };
+            atf-2 {
+                data = <...contents of second segment...>;
+                load = <0xff3b0000>;
+                compression = "none";
+                os = "arm-trusted-firmware";
+                arch = "arm64";
+                type = "firmware";
+                description = "ARM Trusted Firmware";
+            };
+        };
+
+    The same applies for OP-TEE if that is available.
+
+    If each binary is not available, the relevant template node (@atf-SEQ or
+    @tee-SEQ) is removed from the output.
+
+    This also generates a `config-xxx` node for each device tree in `of-list`.
+    Note that the U-Boot build system uses `-a of-list=$(CONFIG_OF_LIST)`
+    so you can use `CONFIG_OF_LIST` to define that list. In this example it is
+    set up for `firefly-rk3399` with a single device tree and the default set
+    with `-a default-dt=$(CONFIG_DEFAULT_DEVICE_TREE)`, so the resulting output
+    is::
+
+        configurations {
+            default = "config-1";
+            config-1 {
+                loadables = "atf-1", "atf-2", "atf-3", "tee-1", "tee-2";
+                description = "rk3399-firefly.dtb";
+                fdt = "fdt-1";
+                firmware = "u-boot";
+            };
+        };
+
+    U-Boot SPL can then load the firmware (U-Boot proper) and all the loadables
+    (ATF and TEE), then proceed with the boot.
     """
     def __init__(self, section, etype, node):
         """
@@ -182,6 +331,12 @@ class Entry_fit(Entry):
                                                                   str)])[0]
         self.mkimage = None
 
+        # List of generated split-elf nodes, each a None
+        self._loadables = []
+
+        # /configurations/xxx node used as a template
+        self._config_node = None
+
     def ReadNode(self):
         self.ReadEntries()
         super().ReadNode()
@@ -251,19 +406,21 @@ class Entry_fit(Entry):
                 in_images: True if this is inside the 'images' node, so that
                     'data' properties should be generated
             """
+            if depth == 1 and not in_images:
+                self._config_node = subnode
             if self._fdts:
                 # Generate nodes for each FDT
                 for seq, fdt_fname in enumerate(self._fdts):
-                    node_name = subnode.name[1:].replace('SEQ',
-                                                         str(seq + 1))
+                    node_name = subnode.name[1:].replace('SEQ', str(seq + 1))
                     fname = tools.GetInputFilename(fdt_fname + '.dtb')
                     with fsw.add_node(node_name):
                         for pname, prop in subnode.props.items():
-                            val = prop.bytes.replace(
-                                b'NAME', tools.ToBytes(fdt_fname))
-                            val = val.replace(
-                                b'SEQ', tools.ToBytes(str(seq + 1)))
-                            fsw.property(pname, val)
+                            if not pname.startswith('fit,'):
+                                val = prop.bytes.replace(
+                                    b'NAME', tools.ToBytes(fdt_fname))
+                                val = val.replace(
+                                    b'SEQ', tools.ToBytes(str(seq + 1)))
+                                fsw.property(pname, val)
 
                         # Add data for 'images' nodes (but not 'config')
                         if depth == 1 and in_images:
@@ -277,7 +434,18 @@ class Entry_fit(Entry):
                     else:
                         self.Raise("Generator node requires 'fit,fdt-list' 
property")
 
-        def _scan_node(subnode, depth, in_images):
+        def _scan_split_elf(subnode, rel_path):
+            #data, input_fname, uniq = self.collect_contents_to_file(
+            entry = Entry.Create(self.section, subnode, etype='section')
+            entry.ReadNode()
+            self._fit_sections[rel_path] = entry
+
+            # Add this as a dummy node so we know the required position in the
+            # output FIT. It is replaced later in _BuildInput().
+            with fsw.add_node(subnode.name):
+                pass
+
+        def _scan_node(subnode, depth, in_images, rel_path):
             """Generate nodes from a template
 
             This creates one node for each member of self._fdts using the
@@ -291,10 +459,14 @@ class Entry_fit(Entry):
                 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
+                rel_path (str): Path of subnode relative to the toplevel 'fit'
+                    node
             """
             oper = self._get_operation(subnode)
             if oper == OP_GEN_FDT_NODES:
                 _scan_gen_fdt_nodes(subnode, depth, in_images)
+            elif oper == OP_SPLIT_ELF:
+                _scan_split_elf(subnode, rel_path)
 
         def _AddNode(base_node, depth, node):
             """Add a node to the FIT
@@ -334,7 +506,8 @@ class Entry_fit(Entry):
                     # fsw.add_node() or _AddNode() for it.
                     pass
                 elif self.GetImage().generate and subnode.name.startswith('@'):
-                    _scan_node(subnode, depth, in_images)
+                    _scan_node(subnode, depth, in_images,
+                               f'{rel_path}/{subnode.name}')
                 else:
                     with fsw.add_node(subnode.name):
                         _AddNode(base_node, depth + 1, subnode)
@@ -383,6 +556,45 @@ class Entry_fit(Entry):
 
         return True
 
+    def _add_split_elf(self, orig_node, node, data, missing):
+        """Add nodes for the ELF file, one per group of contiguous segments
+
+        The existing placeholder node is replaced
+
+        Args:
+            orig_node (Node): Template node from the binman definition
+            node (Node): Node to replace (in the FIT being built)
+            data (bytes): ELF-format data to process (may be empty)
+        """
+        # If any pieces are missing, skip this. The missing entries will show
+        # an error
+        if not missing:
+            try:
+                segments, entry = elf.read_segments(data)
+            except ValueError as exc:
+                self.Raise(f'Failed to read ELF file for {orig_node.path}: 
{str(exc)}')
+            parent = node.parent
+            for (seq, start, data) in segments:
+                node_name = orig_node.name[1:].replace('SEQ', str(seq + 1))
+                subnode = parent.AddSubnode(node_name) #, before=node)
+                self._loadables.append(subnode)
+                for pname, prop in orig_node.props.items():
+                    if not pname.startswith('fit,'):
+                        subnode.AddData(pname, prop.bytes)
+                    elif pname == 'fit,load':
+                        subnode.AddInt('load', start)
+                    elif pname == 'fit,entry':
+                        if not seq:
+                            subnode.AddInt('entry', entry)
+                    elif pname == 'fit,data':
+                        subnode.AddData('data', data)
+                    elif pname != 'fit,operation':
+                        self.Raise(
+                            f"Unknown directive in '{subnode.path}': 
'{pname}'")
+
+        # Delete the template node as it has served its purpose
+        node.Delete()
+
     def _BuildInput(self, fdt):
         """Finish the FIT by adding the 'data' properties to it
 
@@ -393,13 +605,36 @@ class Entry_fit(Entry):
             New fdt contents (bytes)
         """
         for path, section in self._fit_sections.items():
-            node = fdt.GetNode(path)
             # Entry_section.ObtainContents() either returns True or
             # raises an exception.
             section.ObtainContents()
             section.Pack(0)
             data = section.GetData()
-            node.AddData('data', data)
+            missing_list = []
+            section.CheckMissing(missing_list)
+
+            node = fdt.GetNode(path)
+            oper = self._get_operation(section._node)
+            if oper == OP_GEN_FDT_NODES:
+                node.AddData('data', data)
+            elif oper == OP_SPLIT_ELF:
+                self._add_split_elf(section._node, node, data,
+                                    bool(missing_list))
+
+        # Set up the 'firmware' and 'loadables' properties in all
+        # 'configurations' nodes, but only if we are generating FDTs. Note that
+        # self._config_node is set in _scan_gen_fdt_nodes()
+        node = fdt.GetNode('/configurations')
+        if self._config_node:
+            for subnode in node.subnodes:
+                for pname, prop in self._config_node.props.items():
+                    if pname == 'fit,loadables':
+                        subnode.AddStringList(
+                            'loadables',
+                            [node.name for node in self._loadables])
+                    elif pname.startswith('fit,'):
+                        self.Raise(
+                            f"Unknown directive in '{subnode.path}': 
'{pname}'")
 
         fdt.Sync(auto_resize=True)
         data = fdt.GetContents()
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 5a0dc70ed9..dbaf412e9d 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -197,6 +197,13 @@ class TestFunctional(unittest.TestCase):
 
         TestFunctional._MakeInputFile('env.txt', ENV_DATA)
 
+        # ELF file with two sections in different parts of memory, used for 
both
+        # ATF and OP_TEE
+        TestFunctional._MakeInputFile('bl31.elf',
+            tools.ReadFile(cls.ElfTestFile('elf_sections')))
+        TestFunctional._MakeInputFile('tee.elf',
+            tools.ReadFile(cls.ElfTestFile('elf_sections')))
+
         cls.have_lz4 = comp_util.HAVE_LZ4
 
     @classmethod
@@ -5125,6 +5132,115 @@ fdt         fdtmap                Extract the 
devicetree blob from the fdtmap
         self.assertIn("Node '/binman/fit': Unknown operation 'unknown'",
                       str(exc.exception))
 
+    def testFitSplitElf(self):
+        """Test an image with an FIT with an split-elf operation"""
+        entry_args = {
+            'of-list': 'test-fdt1 test-fdt2',
+            'default-dt': 'test-fdt2',
+            'atf-bl31-path': 'bl31.elf',
+            'op-tee-path': 'tee.elf',
+        }
+        test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+        data = self._DoReadFileDtb(
+            '221_fit_split_elf.dts',
+            entry_args=entry_args,
+            extra_indirs=[test_subdir])[0]
+
+        self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
+        fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
+
+        base_keys = {'description', 'type', 'arch', 'os', 'compression',
+                     'data', 'load'}
+        dtb = fdt.Fdt.FromData(fit_data)
+        dtb.Scan()
+
+        elf_data = tools.ReadFile(os.path.join(self._indir, 'bl31.elf'))
+        segments, entry = elf.read_segments(elf_data)
+
+        # We assume there are two segments
+        self.assertEquals(2, len(segments))
+
+        atf1 = dtb.GetNode('/images/atf-1')
+        _, start, data = segments[0]
+        self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
+        self.assertEqual(entry,
+                         fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
+        self.assertEqual(start,
+                         fdt_util.fdt32_to_cpu(atf1.props['load'].value))
+        self.assertEqual(data, atf1.props['data'].bytes)
+
+        atf2 = dtb.GetNode('/images/atf-2')
+        self.assertEqual(base_keys, atf2.props.keys())
+        _, start, data = segments[1]
+        self.assertEqual(start,
+                         fdt_util.fdt32_to_cpu(atf2.props['load'].value))
+        self.assertEqual(data, atf2.props['data'].bytes)
+
+        conf = dtb.GetNode('/configurations')
+        self.assertEqual({'default'}, conf.props.keys())
+
+        for subnode in conf.subnodes:
+            self.assertEqual({'description', 'fdt', 'loadables'},
+                             subnode.props.keys())
+            self.assertEqual(
+                ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
+                fdt_util.GetStringList(subnode, 'loadables'))
+
+    def _check_bad_fit(self, dts):
+        """Check a bad FIT
+
+        This runs with the given dts and returns the assertion raised
+
+        Args:
+            dts (str): dts filename to use
+
+        Returns:
+            str: Assertion string raised
+        """
+        entry_args = {
+            'of-list': 'test-fdt1 test-fdt2',
+            'default-dt': 'test-fdt2',
+            'atf-bl31-path': 'bl31.elf',
+            'op-tee-path': 'tee.elf',
+        }
+        test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+        with self.assertRaises(ValueError) as exc:
+            self._DoReadFileDtb(dts, entry_args=entry_args,
+                                extra_indirs=[test_subdir])[0]
+        return str(exc.exception)
+
+    def testFitSplitElfBadElf(self):
+        """Test a FIT split-elf operation with an invalid ELF file"""
+        TestFunctional._MakeInputFile('bad.elf', tools.GetBytes(100, 100))
+        entry_args = {
+            'of-list': 'test-fdt1 test-fdt2',
+            'default-dt': 'test-fdt2',
+            'atf-bl31-path': 'bad.elf',
+        }
+        test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
+        with self.assertRaises(ValueError) as exc:
+            self._DoReadFileDtb(
+                '221_fit_split_elf.dts',
+                entry_args=entry_args,
+                extra_indirs=[test_subdir])[0]
+        self.assertIn(
+            "Node '/binman/fit': Failed to read ELF file for 
/binman/fit/images/@atf-SEQ: Magic number does not match",
+            str(exc.exception))
+
+    def testFitSplitElfBadDirective(self):
+        """Test a FIT split-elf invalid fit,xxx directive in an image node"""
+        err = self._check_bad_fit('222_fit_bad_dir.dts')
+        self.assertIn(
+            "Node '/binman/fit': Unknown directive in '/images/atf-1': 
'fit,something'",
+            err)
+
+    def testFitSplitElfBadDirectiveConfig(self):
+        """Test a FIT split-elf with invalid fit,xxx directive in config"""
+        err = self._check_bad_fit('223_fit_bad_dir_config.dts')
+        self.assertEqual(
+            "Node '/binman/fit': Unknown directive in 
'/configurations/config-1': 'fit,config'",
+            err)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/221_fit_split_elf.dts 
b/tools/binman/test/221_fit_split_elf.dts
new file mode 100644
index 0000000000..ec771bd116
--- /dev/null
+++ b/tools/binman/test/221_fit_split_elf.dts
@@ -0,0 +1,67 @@
+// 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 {
+                               @fdt-SEQ {
+                                       description = "fdt-NAME.dtb";
+                                       type = "flat_dt";
+                                       compression = "none";
+                               };
+                               atf: @atf-SEQ {
+                                       fit,operation = "split-elf";
+                                       description = "ARM Trusted Firmware";
+                                       type = "firmware";
+                                       arch = "arm64";
+                                       os = "arm-trusted-firmware";
+                                       compression = "none";
+                                       fit,load;
+                                       fit,entry;
+                                       fit,data;
+
+                                       atf-bl31 {
+                                       };
+                               };
+
+                               @tee-SEQ {
+                                       fit,operation = "split-elf";
+                                       description = "TEE";
+                                       type = "tee";
+                                       arch = "arm64";
+                                       os = "tee";
+                                       compression = "none";
+                                       fit,load;
+                                       fit,entry;
+                                       fit,data;
+
+                                       op-tee {
+                                       };
+                               };
+                       };
+
+                       configurations {
+                               default = "@config-DEFAULT-SEQ";
+                               config: @config-SEQ {
+                                       description = "conf-NAME.dtb";
+                                       fdt = "fdt-SEQ";
+                                       fit,loadables;
+                               };
+                       };
+               };
+
+               u-boot-nodtb {
+               };
+       };
+};
diff --git a/tools/binman/test/222_fit_bad_dir.dts 
b/tools/binman/test/222_fit_bad_dir.dts
new file mode 100644
index 0000000000..91733c74c4
--- /dev/null
+++ b/tools/binman/test/222_fit_bad_dir.dts
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+#include "221_fit_split_elf.dts"
+
+&atf {
+       fit,something = "bad";
+};
diff --git a/tools/binman/test/223_fit_bad_dir_config.dts 
b/tools/binman/test/223_fit_bad_dir_config.dts
new file mode 100644
index 0000000000..17dae0c5b6
--- /dev/null
+++ b/tools/binman/test/223_fit_bad_dir_config.dts
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+#include "221_fit_split_elf.dts"
+
+&config {
+       fit,config = "bad";
+};
-- 
2.35.0.263.gb82422642f-goog

Reply via email to