diff mbox series

[U-Boot,v2,05/31] binman: Add an FDT map

Message ID 20190708202553.225715-6-sjg@chromium.org
State Accepted
Commit 086cec9f980efd6f25e184b84f626d4a667e6645
Delegated to: Simon Glass
Headers show
Series binman: Allow reading of images to list contents | expand

Commit Message

Simon Glass July 8, 2019, 8:25 p.m. UTC
An FDT map is an entry which holds a full description of the image
entries, in FDT format. It can be discovered using the magic string at
its start. Tools can locate and read this entry to find out what entries
are in the image and where each entry is located.

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

Changes in v2: None

 tools/binman/README              |   5 +-
 tools/binman/README.entries      |  38 +++++++++++
 tools/binman/etype/fdtmap.py     | 109 +++++++++++++++++++++++++++++++
 tools/binman/ftest.py            |  52 +++++++++++++--
 tools/binman/state.py            |   2 +-
 tools/binman/test/115_fdtmap.dts |  13 ++++
 6 files changed, 211 insertions(+), 8 deletions(-)
 create mode 100644 tools/binman/etype/fdtmap.py
 create mode 100644 tools/binman/test/115_fdtmap.dts

Comments

Simon Glass July 18, 2019, 1:58 a.m. UTC | #1
An FDT map is an entry which holds a full description of the image
entries, in FDT format. It can be discovered using the magic string at
its start. Tools can locate and read this entry to find out what entries
are in the image and where each entry is located.

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

Changes in v2: None

 tools/binman/README              |   5 +-
 tools/binman/README.entries      |  38 +++++++++++
 tools/binman/etype/fdtmap.py     | 109 +++++++++++++++++++++++++++++++
 tools/binman/ftest.py            |  52 +++++++++++++--
 tools/binman/state.py            |   2 +-
 tools/binman/test/115_fdtmap.dts |  13 ++++
 6 files changed, 211 insertions(+), 8 deletions(-)
 create mode 100644 tools/binman/etype/fdtmap.py
 create mode 100644 tools/binman/test/115_fdtmap.dts

Applied to u-boot-dm, thanks!
diff mbox series

Patch

diff --git a/tools/binman/README b/tools/binman/README
index b067d3b78cf..8a5f3320dcb 100644
--- a/tools/binman/README
+++ b/tools/binman/README
@@ -638,6 +638,10 @@  the image definition, binman calculates the final values and writes these to
 the device tree. These can be used by U-Boot at run-time to find the location
 of each entry.
 
+Alternatively, an FDT map entry can be used to add a special FDT containing
+just the information about the image. This is preceded by a magic string so can
+be located anywhere in the image.
+
 
 Compression
 -----------
@@ -814,7 +818,6 @@  Some ideas:
 - Support building an image for a board (-b) more completely, with a
   configurable build directory
 - Support putting the FDT in an image with a suitable magic number
-- Support adding a pointer to the FDT map
 - Support listing files in images
 - Support logging of binman's operations, with different levels of verbosity
 - Support updating binaries in an image (with no size change / repacking)
diff --git a/tools/binman/README.entries b/tools/binman/README.entries
index 3241befc7f4..7014d36f5ff 100644
--- a/tools/binman/README.entries
+++ b/tools/binman/README.entries
@@ -223,6 +223,44 @@  updating the EC on startup via software sync.
 
 
 
+Entry: fdtmap: An entry which contains an FDT map
+-------------------------------------------------
+
+Properties / Entry arguments:
+    None
+
+An FDT map is just a header followed by an FDT containing a list of all the
+entries in the image.
+
+The header is the string _FDTMAP_ followed by 8 unused bytes.
+
+When used, this entry will be populated with an FDT map which reflects the
+entries in the current image. Hierarchy is preserved, and all offsets and
+sizes are included.
+
+Note that the -u option must be provided to ensure that binman updates the
+FDT with the position of each entry.
+
+Example output for a simple image with U-Boot and an FDT map:
+
+/ {
+    size = <0x00000112>;
+    image-pos = <0x00000000>;
+    offset = <0x00000000>;
+    u-boot {
+        size = <0x00000004>;
+        image-pos = <0x00000000>;
+        offset = <0x00000000>;
+    };
+    fdtmap {
+        size = <0x0000010e>;
+        image-pos = <0x00000004>;
+        offset = <0x00000004>;
+    };
+};
+
+
+
 Entry: files: Entry containing a set of files
 ---------------------------------------------
 
diff --git a/tools/binman/etype/fdtmap.py b/tools/binman/etype/fdtmap.py
new file mode 100644
index 00000000000..cdeb491ebdc
--- /dev/null
+++ b/tools/binman/etype/fdtmap.py
@@ -0,0 +1,109 @@ 
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2018 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+
+"""# Entry-type module for a full map of the firmware image
+
+This handles putting an FDT into the image with just the information about the
+image.
+"""
+
+import libfdt
+
+from entry import Entry
+from fdt import Fdt
+import state
+import tools
+
+FDTMAP_MAGIC = b'_FDTMAP_'
+
+class Entry_fdtmap(Entry):
+    """An entry which contains an FDT map
+
+    Properties / Entry arguments:
+        None
+
+    An FDT map is just a header followed by an FDT containing a list of all the
+    entries in the image.
+
+    The header is the string _FDTMAP_ followed by 8 unused bytes.
+
+    When used, this entry will be populated with an FDT map which reflects the
+    entries in the current image. Hierarchy is preserved, and all offsets and
+    sizes are included.
+
+    Note that the -u option must be provided to ensure that binman updates the
+    FDT with the position of each entry.
+
+    Example output for a simple image with U-Boot and an FDT map:
+
+    / {
+        size = <0x00000112>;
+        image-pos = <0x00000000>;
+        offset = <0x00000000>;
+        u-boot {
+            size = <0x00000004>;
+            image-pos = <0x00000000>;
+            offset = <0x00000000>;
+        };
+        fdtmap {
+            size = <0x0000010e>;
+            image-pos = <0x00000004>;
+            offset = <0x00000004>;
+        };
+    };
+    """
+    def __init__(self, section, etype, node):
+        Entry.__init__(self, section, etype, node)
+
+    def _GetFdtmap(self):
+        """Build an FDT map from the entries in the current image
+
+        Returns:
+            FDT map binary data
+        """
+        def _AddNode(node):
+            """Add a node to the FDT map"""
+            for pname, prop in node.props.items():
+                fsw.property(pname, prop.bytes)
+            for subnode in node.subnodes:
+                with fsw.add_node(subnode.name):
+                    _AddNode(subnode)
+
+        # Get the FDT data into an Fdt object
+        data = state.GetFdtContents()[1]
+        infdt = Fdt.FromData(data)
+        infdt.Scan()
+
+        # Find the node for the image containing the Fdt-map entry
+        path = self.section.GetPath()
+        node = infdt.GetNode(path)
+        if not node:
+            self.Raise("Internal error: Cannot locate node for path '%s'" %
+                       path)
+
+        # Build a new tree with all nodes and properties starting from that node
+        fsw = libfdt.FdtSw()
+        fsw.finish_reservemap()
+        with fsw.add_node(''):
+            _AddNode(node)
+        fdt = fsw.as_fdt()
+
+        # Pack this new FDT and return its contents
+        fdt.pack()
+        outfdt = Fdt.FromData(fdt.as_bytearray())
+        data = FDTMAP_MAGIC + tools.GetBytes(0, 8) + outfdt.GetContents()
+        return data
+
+    def ObtainContents(self):
+        """Obtain a placeholder for the fdt-map contents"""
+        self.SetContents(self._GetFdtmap())
+        return True
+
+    def ProcessContents(self):
+        """Write an updated version of the FDT map to this entry
+
+        This is necessary since new data may have been written back to it during
+        processing, e.g. the image-pos properties.
+        """
+        self.SetContents(self._GetFdtmap())
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index ed125670e2c..934145ca3cb 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -487,16 +487,16 @@  class TestFunctional(unittest.TestCase):
         """
         return struct.unpack('>L', dtb[4:8])[0]
 
-    def _GetPropTree(self, dtb, prop_names):
+    def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
         def AddNode(node, path):
             if node.name != '/':
                 path += '/' + node.name
+            for prop in node.props.values():
+                if prop.name in prop_names:
+                    prop_path = path + ':' + prop.name
+                    tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
+                        prop.value)
             for subnode in node.subnodes:
-                for prop in subnode.props.values():
-                    if prop.name in prop_names:
-                        prop_path = path + '/' + subnode.name + ':' + prop.name
-                        tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
-                            prop.value)
                 AddNode(subnode, path)
 
         tree = {}
@@ -2044,6 +2044,46 @@  class TestFunctional(unittest.TestCase):
         self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
         self.assertEqual(0x140, cfile2.cbfs_offset)
 
+    def testFdtmap(self):
+        """Test an FDT map can be inserted in the image"""
+        data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
+        fdtmap_data = data[len(U_BOOT_DATA):]
+        magic = fdtmap_data[:8]
+        self.assertEqual('_FDTMAP_', magic)
+        self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
+
+        fdt_data = fdtmap_data[16:]
+        dtb = fdt.Fdt.FromData(fdt_data)
+        dtb.Scan()
+        props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'],
+                                  prefix='/')
+        self.assertEqual({
+            'image-pos': 0,
+            'offset': 0,
+            'u-boot:offset': 0,
+            'u-boot:size': len(U_BOOT_DATA),
+            'u-boot:image-pos': 0,
+            'fdtmap:image-pos': 4,
+            'fdtmap:offset': 4,
+            'fdtmap:size': len(fdtmap_data),
+            'size': len(data),
+        }, props)
+
+    def testFdtmapNoMatch(self):
+        """Check handling of an FDT map when the section cannot be found"""
+        self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
+
+        # Mangle the section name, which should cause a mismatch between the
+        # correct FDT path and the one expected by the section
+        image = control.images['image']
+        image._section._node.path += '-suffix'
+        entries = image.GetEntries()
+        fdtmap = entries['fdtmap']
+        with self.assertRaises(ValueError) as e:
+            fdtmap._GetFdtmap()
+        self.assertIn("Cannot locate node for path '/binman-suffix'",
+                      str(e.exception))
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/state.py b/tools/binman/state.py
index af9678649cd..3ccd7855d47 100644
--- a/tools/binman/state.py
+++ b/tools/binman/state.py
@@ -59,7 +59,7 @@  def GetFdtPath(fname):
     """
     return fdt_files[fname]._fname
 
-def GetFdtContents(fname):
+def GetFdtContents(fname='u-boot.dtb'):
     """Looks up the FDT pathname and contents
 
     This is used to obtain the Fdt pathname and contents when needed by an
diff --git a/tools/binman/test/115_fdtmap.dts b/tools/binman/test/115_fdtmap.dts
new file mode 100644
index 00000000000..2450c41f200
--- /dev/null
+++ b/tools/binman/test/115_fdtmap.dts
@@ -0,0 +1,13 @@ 
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	binman {
+		u-boot {
+		};
+		fdtmap {
+		};
+	};
+};