binman: Support reading an image into an Image object
authorSimon Glass <sjg@chromium.org>
Mon, 8 Jul 2019 20:25:46 +0000 (14:25 -0600)
committerSimon Glass <sjg@chromium.org>
Wed, 24 Jul 2019 19:54:08 +0000 (12:54 -0700)
It is possible to read an Image, locate its FDT map and then read it into
the binman data structures. This allows full access to the entries that
were written to the image. Add support for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/entry.py
tools/binman/ftest.py
tools/binman/image.py
tools/binman/test/129_decode_image_nohdr.dts [new file with mode: 0644]

index ee63d183532a7696a3192215a6e827201a4bc13e..6c74f2a2175c4accc1fac57c69bf9978f3cd7dbc 100644 (file)
@@ -162,6 +162,11 @@ class Entry(object):
         self.orig_offset = self.offset
         self.orig_size = self.size
 
+        # These should not be set in input files, but are set in an FDT map,
+        # which is also read by this code.
+        self.image_pos = fdt_util.GetInt(self._node, 'image-pos')
+        self.uncomp_size = fdt_util.GetInt(self._node, 'uncomp-size')
+
         self.align = fdt_util.GetInt(self._node, 'align')
         if tools.NotPowerOfTwo(self.align):
             raise ValueError("Node '%s': Alignment %s must be a power of two" %
index ce66e3a2f206776caf191398b719b7495591e216..f3a8e64ad13e8a1ffb88d458ca857333a7855197 100644 (file)
@@ -30,6 +30,7 @@ import fdt_util
 import fmap_util
 import test_util
 import gzip
+from image import Image
 import state
 import tools
 import tout
@@ -2286,8 +2287,7 @@ class TestFunctional(unittest.TestCase):
     def testFindImageHeader(self):
         """Test locating a image header"""
         self._CheckLz4()
-        data = self._DoReadFileDtb('128_decode_image.dts', use_real_dtb=True,
-                                   update_dtb=True)[0]
+        data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
         image = control.images['image']
         entries = image.GetEntries()
         entry = entries['fdtmap']
@@ -2296,8 +2296,7 @@ class TestFunctional(unittest.TestCase):
 
     def testFindImageHeaderStart(self):
         """Test locating a image header located at the start of an image"""
-        data = self._DoReadFileDtb('117_fdtmap_hdr_start.dts',
-                                   use_real_dtb=True, update_dtb=True)[0]
+        data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
         image = control.images['image']
         entries = image.GetEntries()
         entry = entries['fdtmap']
@@ -2309,6 +2308,38 @@ class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('005_simple.dts')
         self.assertEqual(None, image_header.LocateHeaderOffset(data))
 
+    def testReadImage(self):
+        """Test reading an image and accessing its FDT map"""
+        self._CheckLz4()
+        data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        orig_image = control.images['image']
+        image = Image.FromFile(image_fname)
+        self.assertEqual(orig_image.GetEntries().keys(),
+                         image.GetEntries().keys())
+
+        orig_entry = orig_image.GetEntries()['fdtmap']
+        entry = image.GetEntries()['fdtmap']
+        self.assertEquals(orig_entry.offset, entry.offset)
+        self.assertEquals(orig_entry.size, entry.size)
+        self.assertEquals(orig_entry.image_pos, entry.image_pos)
+
+    def testReadImageNoHeader(self):
+        """Test accessing an image's FDT map without an image header"""
+        self._CheckLz4()
+        data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        image = Image.FromFile(image_fname)
+        self.assertTrue(isinstance(image, Image))
+        self.assertEqual('image', image._name)
+
+    def testReadImageFail(self):
+        """Test failing to read an image image's FDT map"""
+        self._DoReadFile('005_simple.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        with self.assertRaises(ValueError) as e:
+            image = Image.FromFile(image_fname)
+        self.assertIn("Cannot find FDT map in image", str(e.exception))
 
 if __name__ == "__main__":
     unittest.main()
index 6f4bd5d37b252a707d7e8efeaa52fa1fb1693b82..f890350a8d0451a1947d8773f4973ea1a140093a 100644 (file)
@@ -12,6 +12,9 @@ from operator import attrgetter
 import re
 import sys
 
+from etype import fdtmap
+from etype import image_header
+import fdt
 import fdt_util
 import bsection
 import tools
@@ -47,6 +50,41 @@ class Image:
         else:
             self._ReadNode()
 
+    @classmethod
+    def FromFile(cls, fname):
+        """Convert an image file into an Image for use in binman
+
+        Args:
+            fname: Filename of image file to read
+
+        Returns:
+            Image object on success
+
+        Raises:
+            ValueError if something goes wrong
+        """
+        data = tools.ReadFile(fname)
+        size = len(data)
+
+        # First look for an image header
+        pos = image_header.LocateHeaderOffset(data)
+        if pos is None:
+            # Look for the FDT map
+            pos = fdtmap.LocateFdtmap(data)
+        if pos is None:
+            raise ValueError('Cannot find FDT map in image')
+
+        # We don't know the FDT size, so check its header first
+        probe_dtb = fdt.Fdt.FromData(
+            data[pos + fdtmap.FDTMAP_HDR_LEN:pos + 256])
+        dtb_size = probe_dtb.GetFdtObj().totalsize()
+        fdtmap_data = data[pos:pos + dtb_size + fdtmap.FDTMAP_HDR_LEN]
+        dtb = fdt.Fdt.FromData(fdtmap_data[fdtmap.FDTMAP_HDR_LEN:])
+        dtb.Scan()
+
+        # Return an Image with the associated nodes
+        return Image('image', dtb.GetRoot())
+
     def _ReadNode(self):
         """Read properties from the image node"""
         self._size = fdt_util.GetInt(self._node, 'size')
diff --git a/tools/binman/test/129_decode_image_nohdr.dts b/tools/binman/test/129_decode_image_nohdr.dts
new file mode 100644 (file)
index 0000000..90fdd88
--- /dev/null
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               size = <0xc00>;
+               u-boot {
+               };
+               section {
+                       align = <0x100>;
+                       cbfs {
+                               size = <0x400>;
+                               u-boot {
+                                       cbfs-type = "raw";
+                               };
+                               u-boot-dtb {
+                                       cbfs-type = "raw";
+                                       cbfs-compress = "lzma";
+                                       cbfs-offset = <0x80>;
+                               };
+                       };
+                       u-boot-dtb {
+                               compress = "lz4";
+                       };
+               };
+               fdtmap {
+               };
+       };
+};