From 093d16868af2fe09da6f6719c1e22445f961073f Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:25 -0600
Subject: binman: Correct two typos in function names in ftest

Two functions have incorrect names. Fix them.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index cc57ef3e04..46f669e73b 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1758,7 +1758,7 @@ class TestFunctional(unittest.TestCase):
             TestFunctional._MakeInputFile('-boot', fd.read())
         data = self._DoReadFile('096_elf.dts')
 
-    def testElfStripg(self):
+    def testElfStrip(self):
         """Basic test of ELF entries"""
         self._SetupSplElf()
         with open(self.TestFile('bss_data'), 'rb') as fd:
@@ -1784,7 +1784,7 @@ class TestFunctional(unittest.TestCase):
 <none>     00000003  00000004  u-boot-align
 ''', map_data)
 
-    def testPacRefCode(self):
+    def testPackRefCode(self):
         """Test that an image with an Intel Reference code binary works"""
         data = self._DoReadFile('100_intel_refcode.dts')
         self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
-- 
cgit 


From 458be45afc79444b7ed66afc01d6e121dfa30d37 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:32 -0600
Subject: binman: Use a better error for missing Intel descriptor

FD is a bit confusing so write this out in full. Also avoid splitting the
string so that people can grep for the error message more easily.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 46f669e73b..8577adb538 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -806,8 +806,8 @@ class TestFunctional(unittest.TestCase):
         TestFunctional._MakeInputFile('descriptor.bin', b'')
         with self.assertRaises(ValueError) as e:
             self._DoTestFile('031_x86-rom-me.dts')
-        self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
-                      "signature", str(e.exception))
+        self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
+                      str(e.exception))
 
     def testPackX86RomBadDesc(self):
         """Test that the Intel requires a descriptor entry"""
-- 
cgit 


From aa88b50d8267d0ff53cd6a1300d78004fa40d2c8 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:40 -0600
Subject: binman: Allow text directly in the node

At present text entries use an indirect method to specify the text to use,
with a label pointing to the text itself.

Allow the text to be directly written into the node. This is more
convenient in cases where the text is constant.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 8577adb538..c74e12d13c 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1286,7 +1286,7 @@ class TestFunctional(unittest.TestCase):
         expected = (tools.ToBytes(TEXT_DATA) +
                     tools.GetBytes(0, 8 - len(TEXT_DATA)) +
                     tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
-                    b'some text')
+                    b'some text' + b'more text')
         self.assertEqual(expected, data)
 
     def testEntryDocs(self):
-- 
cgit 


From ff5c7e383e8c053684fff263dd0afc7aeb8040fb Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:42 -0600
Subject: binman: Use the tools.Decompress method

Update the compression test to use the tools module to decompress the
output data.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index c74e12d13c..6ff871b3c1 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -59,7 +59,7 @@ BMPBLK_DATA           = b'bmp'
 VBLOCK_DATA           = b'vblk'
 FILES_DATA            = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
                          b"sorry you're alive\n")
-COMPRESS_DATA         = b'data to compress'
+COMPRESS_DATA         = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
 REFCODE_DATA          = b'refcode'
 
 
@@ -1560,16 +1560,7 @@ class TestFunctional(unittest.TestCase):
             self._ResetDtbs()
 
     def _decompress(self, data):
-        out = os.path.join(self._indir, 'lz4.tmp')
-        with open(out, 'wb') as fd:
-            fd.write(data)
-        return tools.Run('lz4', '-dc', out, binary=True)
-        '''
-        try:
-            orig = lz4.frame.decompress(data)
-        except AttributeError:
-            orig = lz4.decompress(data)
-        '''
+        return tools.Decompress(data, 'lz4')
 
     def testCompress(self):
         """Test compression of blobs"""
-- 
cgit 


From 4c65025799d79a030a61f8d95e20954963c62db4 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:46 -0600
Subject: binman: Support ELF files for TPL

We currenty support using the ELF file in U-Boot proper and SPL, but not
TPL. Add this as it is useful both with sandbox and for CBFS to allow
adding TPL as a 'stage'.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 6ff871b3c1..9cec5f42fa 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1745,6 +1745,8 @@ class TestFunctional(unittest.TestCase):
     def testElf(self):
         """Basic test of ELF entries"""
         self._SetupSplElf()
+        with open(self.TestFile('bss_data'), 'rb') as fd:
+            TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
         with open(self.TestFile('bss_data'), 'rb') as fd:
             TestFunctional._MakeInputFile('-boot', fd.read())
         data = self._DoReadFile('096_elf.dts')
-- 
cgit 


From 2569e10f5b56649aa13e806da39a6238fdb53cab Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:47 -0600
Subject: binman: Fix up the _DoTestFile() function -u argument

This should be -u, not -up, since we don't need to preserve the output
directory in this case.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 9cec5f42fa..b1780854cf 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -208,7 +208,7 @@ class TestFunctional(unittest.TestCase):
         if map:
             args.append('-m')
         if update_dtb:
-            args.append('-up')
+            args.append('-u')
         if not use_real_dtb:
             args.append('--fake-dtb')
         if verbosity is not None:
-- 
cgit 


From ee0c9a739f219c80b8a1f1abc217338c8c2087cc Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:48 -0600
Subject: binman: Allow verbosity control when running tests

At present the -v flag is ignored with tests, so that (for example) -v2
does not have any effect. Update binman to pass this flag through to tests
so that they work just like running binman normally, except in a few
special cases where we are actually testing behaviour with different
levels of verbosity.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index b1780854cf..f5e0b9b974 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -153,6 +153,19 @@ class TestFunctional(unittest.TestCase):
         TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
         TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
 
+    def _GetVerbosity(self):
+        """Check if verbosity should be enabled
+
+        Returns:
+            list containing either:
+                - Verbosity flag (e.g. '-v2') if it is present on the cmd line
+                - nothing if the flag is not present
+        """
+        for arg in sys.argv[1:]:
+            if arg.startswith('-v'):
+                return [arg]
+        return []
+
     def _RunBinman(self, *args, **kwargs):
         """Run binman using the command line
 
@@ -213,6 +226,8 @@ class TestFunctional(unittest.TestCase):
             args.append('--fake-dtb')
         if verbosity is not None:
             args.append('-v%d' % verbosity)
+        else:
+            args += self._GetVerbosity()
         if entry_args:
             for arg, value in entry_args.items():
                 args.append('-a%s=%s' % (arg, value))
@@ -1471,7 +1486,7 @@ class TestFunctional(unittest.TestCase):
         expected = 'Skipping images: image1'
 
         # We should only get the expected message in verbose mode
-        for verbosity in (None, 2):
+        for verbosity in (0, 2):
             with test_util.capture_sys_output() as (stdout, stderr):
                 retcode = self._DoTestFile('006_dual_image.dts',
                                            verbosity=verbosity,
-- 
cgit 


From d5164a79703df76254d8c0ac67037d629d113518 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:49 -0600
Subject: binman: Allow preserving test directories

Sometimes when debugging tests it is useful to keep the input and output
directories so they can be examined later. Add an option for this and
update the binman tests to support it. This affects both the test class
and the tearDown() function called after each test.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index f5e0b9b974..256d4a1c5d 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -6,6 +6,8 @@
 #
 #    python -m unittest func_test.TestFunctional.testHelp
 
+from __future__ import print_function
+
 import hashlib
 from optparse import OptionParser
 import os
@@ -134,10 +136,27 @@ class TestFunctional(unittest.TestCase):
     @classmethod
     def tearDownClass(self):
         """Remove the temporary input directory and its contents"""
-        if self._indir:
-            shutil.rmtree(self._indir)
+        if self.preserve_indir:
+            print('Preserving input dir: %s' % self._indir)
+        else:
+            if self._indir:
+                shutil.rmtree(self._indir)
         self._indir = None
 
+    @classmethod
+    def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False):
+        """Accept arguments controlling test execution
+
+        Args:
+            preserve_indir: Preserve the shared input directory used by all
+                tests in this class.
+            preserve_outdir: Preserve the output directories used by tests. Each
+                test has its own, so this is normally only useful when running a
+                single test.
+        """
+        cls.preserve_indir = preserve_indir
+        cls.preserve_outdirs = preserve_outdirs
+
     def setUp(self):
         # Enable this to turn on debugging output
         # tout.Init(tout.DEBUG)
@@ -145,7 +164,10 @@ class TestFunctional(unittest.TestCase):
 
     def tearDown(self):
         """Remove the temporary output directory"""
-        tools._FinaliseForTest()
+        if self.preserve_outdirs:
+            print('Preserving output dir: %s' % tools.outdir)
+        else:
+            tools._FinaliseForTest()
 
     @classmethod
     def _ResetDtbs(self):
-- 
cgit 


From 8acce60b10f2d60945b71f527fd29ee62242b175 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:50 -0600
Subject: binman: Pass the toolpath to tests

Tools like ifwitool may not be available in the PATH, but are available in
the build. These tools may be needed by tests, so allow tests to use the
--toolpath flag.

Also use this flag with travis.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 256d4a1c5d..3455b8cceb 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -144,7 +144,8 @@ class TestFunctional(unittest.TestCase):
         self._indir = None
 
     @classmethod
-    def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False):
+    def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
+                        toolpath=None):
         """Accept arguments controlling test execution
 
         Args:
@@ -153,9 +154,11 @@ class TestFunctional(unittest.TestCase):
             preserve_outdir: Preserve the output directories used by tests. Each
                 test has its own, so this is normally only useful when running a
                 single test.
+            toolpath: ist of paths to use for tools
         """
         cls.preserve_indir = preserve_indir
         cls.preserve_outdirs = preserve_outdirs
+        cls.toolpath = toolpath
 
     def setUp(self):
         # Enable this to turn on debugging output
@@ -256,6 +259,9 @@ class TestFunctional(unittest.TestCase):
         if images:
             for image in images:
                 args += ['-i', image]
+        if self.toolpath:
+            for path in self.toolpath:
+                args += ['--toolpath', path]
         return self._DoBinman(*args)
 
     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
-- 
cgit 


From ac62fba459ad94d0d6b457a47d90628cc7b76496 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:53 -0600
Subject: binman: Add support for CBFS entries

Add support for putting CBFSs (Coreboot Filesystems) in an image. This
allows binman to produce firmware images used by coreboot to boot.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 3455b8cceb..14abfbf774 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -18,6 +18,7 @@ import tempfile
 import unittest
 
 import binman
+import cbfs_util
 import cmdline
 import command
 import control
@@ -133,6 +134,14 @@ class TestFunctional(unittest.TestCase):
 
         TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
 
+        # Travis-CI may have an old lz4
+        self.have_lz4 = True
+        try:
+            tools.Run('lz4', '--no-frame-crc', '-c',
+                      os.path.join(self._indir, 'u-boot.bin'))
+        except:
+            self.have_lz4 = False
+
     @classmethod
     def tearDownClass(self):
         """Remove the temporary input directory and its contents"""
@@ -160,6 +169,10 @@ class TestFunctional(unittest.TestCase):
         cls.preserve_outdirs = preserve_outdirs
         cls.toolpath = toolpath
 
+    def _CheckLz4(self):
+        if not self.have_lz4:
+            self.skipTest('lz4 --no-frame-crc not available')
+
     def setUp(self):
         # Enable this to turn on debugging output
         # tout.Init(tout.DEBUG)
@@ -1607,6 +1620,7 @@ class TestFunctional(unittest.TestCase):
 
     def testCompress(self):
         """Test compression of blobs"""
+        self._CheckLz4()
         data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
                                             use_real_dtb=True, update_dtb=True)
         dtb = fdt.Fdt(out_dtb_fname)
@@ -1628,6 +1642,7 @@ class TestFunctional(unittest.TestCase):
 
     def testFilesCompress(self):
         """Test bringing in multiple files and compressing them"""
+        self._CheckLz4()
         data = self._DoReadFile('085_files_compress.dts')
 
         image = control.images['image']
@@ -1846,6 +1861,101 @@ class TestFunctional(unittest.TestCase):
                          tools.GetBytes(0x26, 4) + U_BOOT_DATA +
                              tools.GetBytes(0x26, 8))
 
+    def testCbfsRaw(self):
+        """Test base handling of a Coreboot Filesystem (CBFS)
+
+        The exact contents of the CBFS is verified by similar tests in
+        cbfs_util_test.py. The tests here merely check that the files added to
+        the CBFS can be found in the final image.
+        """
+        data = self._DoReadFile('102_cbfs_raw.dts')
+        size = 0xb0
+
+        cbfs = cbfs_util.CbfsReader(data)
+        self.assertEqual(size, cbfs.rom_size)
+
+        self.assertIn('u-boot-dtb', cbfs.files)
+        cfile = cbfs.files['u-boot-dtb']
+        self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
+
+    def testCbfsArch(self):
+        """Test on non-x86 architecture"""
+        data = self._DoReadFile('103_cbfs_raw_ppc.dts')
+        size = 0x100
+
+        cbfs = cbfs_util.CbfsReader(data)
+        self.assertEqual(size, cbfs.rom_size)
+
+        self.assertIn('u-boot-dtb', cbfs.files)
+        cfile = cbfs.files['u-boot-dtb']
+        self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
+
+    def testCbfsStage(self):
+        """Tests handling of a Coreboot Filesystem (CBFS)"""
+        if not elf.ELF_TOOLS:
+            self.skipTest('Python elftools not available')
+        elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
+        elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
+        size = 0xb0
+
+        data = self._DoReadFile('104_cbfs_stage.dts')
+        cbfs = cbfs_util.CbfsReader(data)
+        self.assertEqual(size, cbfs.rom_size)
+
+        self.assertIn('u-boot', cbfs.files)
+        cfile = cbfs.files['u-boot']
+        self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
+
+    def testCbfsRawCompress(self):
+        """Test handling of compressing raw files"""
+        self._CheckLz4()
+        data = self._DoReadFile('105_cbfs_raw_compress.dts')
+        size = 0x140
+
+        cbfs = cbfs_util.CbfsReader(data)
+        self.assertIn('u-boot', cbfs.files)
+        cfile = cbfs.files['u-boot']
+        self.assertEqual(COMPRESS_DATA, cfile.data)
+
+    def testCbfsBadArch(self):
+        """Test handling of a bad architecture"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('106_cbfs_bad_arch.dts')
+        self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
+
+    def testCbfsNoSize(self):
+        """Test handling of a missing size property"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('107_cbfs_no_size.dts')
+        self.assertIn('entry must have a size property', str(e.exception))
+
+    def testCbfsNoCOntents(self):
+        """Test handling of a CBFS entry which does not provide contentsy"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('108_cbfs_no_contents.dts')
+        self.assertIn('Could not complete processing of contents',
+                      str(e.exception))
+
+    def testCbfsBadCompress(self):
+        """Test handling of a bad architecture"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('109_cbfs_bad_compress.dts')
+        self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
+                      str(e.exception))
+
+    def testCbfsNamedEntries(self):
+        """Test handling of named entries"""
+        data = self._DoReadFile('110_cbfs_name.dts')
+
+        cbfs = cbfs_util.CbfsReader(data)
+        self.assertIn('FRED', cbfs.files)
+        cfile1 = cbfs.files['FRED']
+        self.assertEqual(U_BOOT_DATA, cfile1.data)
+
+        self.assertIn('hello', cbfs.files)
+        cfile2 = cbfs.files['hello']
+        self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From c5ac138828c504812f09971a7a95bd73e186782e Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:54 -0600
Subject: binman: Add support for Intel IFWI entries

An Integrated Firmware Image is used to hold various binaries used for
booting with Apollolake and some later devices. Add support for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 14abfbf774..1355c4f55d 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -27,6 +27,7 @@ import fdt
 import fdt_util
 import fmap_util
 import test_util
+import gzip
 import state
 import tools
 import tout
@@ -876,6 +877,9 @@ class TestFunctional(unittest.TestCase):
     def testPackX86RomMe(self):
         """Test that an x86 ROM with an ME region can be created"""
         data = self._DoReadFile('031_x86-rom-me.dts')
+        expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
+        if data[:0x1000] != expected_desc:
+            self.fail('Expected descriptor binary at start of image')
         self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
 
     def testPackVga(self):
@@ -1956,6 +1960,57 @@ class TestFunctional(unittest.TestCase):
         cfile2 = cbfs.files['hello']
         self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
 
+    def _SetupIfwi(self, fname):
+        """Set up to run an IFWI test
+
+        Args:
+            fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
+        """
+        self._SetupSplElf()
+
+        # Intel Integrated Firmware Image (IFWI) file
+        with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
+            data = fd.read()
+        TestFunctional._MakeInputFile(fname,data)
+
+    def _CheckIfwi(self, data):
+        """Check that an image with an IFWI contains the correct output
+
+        Args:
+            data: Conents of output file
+        """
+        expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
+        if data[:0x1000] != expected_desc:
+            self.fail('Expected descriptor binary at start of image')
+
+        # We expect to find the TPL wil in subpart IBBP entry IBBL
+        image_fname = tools.GetOutputFilename('image.bin')
+        tpl_fname = tools.GetOutputFilename('tpl.out')
+        tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
+                          subpart='IBBP', entry_name='IBBL')
+
+        tpl_data = tools.ReadFile(tpl_fname)
+        self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
+
+    def testPackX86RomIfwi(self):
+        """Test that an x86 ROM with Integrated Firmware Image can be created"""
+        self._SetupIfwi('fitimage.bin')
+        data = self._DoReadFile('111_x86-rom-ifwi.dts')
+        self._CheckIfwi(data)
+
+    def testPackX86RomIfwiNoDesc(self):
+        """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
+        self._SetupIfwi('ifwi.bin')
+        data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
+        self._CheckIfwi(data)
+
+    def testPackX86RomIfwiNoData(self):
+        """Test that an x86 ROM with IFWI handles missing data"""
+        self._SetupIfwi('ifwi.bin')
+        with self.assertRaises(ValueError) as e:
+            data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
+        self.assertIn('Could not complete processing of contents',
+                      str(e.exception))
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From e073d4e14ff76f545a71dc40fa324618ce80adcb Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 13:18:56 -0600
Subject: binman: Add support for fixed-offset files in CBFS

A feature of CBFS is that it allows files to be positioned at particular
offset (as with binman in general). This is useful to support
execute-in-place (XIP) code, since this may not be relocatable.

Add a new cbfs-offset property to control this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 1355c4f55d..5bde8aa30a 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2012,5 +2012,28 @@ class TestFunctional(unittest.TestCase):
         self.assertIn('Could not complete processing of contents',
                       str(e.exception))
 
+    def testCbfsOffset(self):
+        """Test a CBFS with files at particular offsets
+
+        Like all CFBS tests, this is just checking the logic that calls
+        cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
+        """
+        data = self._DoReadFile('114_cbfs_offset.dts')
+        size = 0x200
+
+        cbfs = cbfs_util.CbfsReader(data)
+        self.assertEqual(size, cbfs.rom_size)
+
+        self.assertIn('u-boot', cbfs.files)
+        cfile = cbfs.files['u-boot']
+        self.assertEqual(U_BOOT_DATA, cfile.data)
+        self.assertEqual(0x40, cfile.cbfs_offset)
+
+        self.assertIn('u-boot-dtb', cbfs.files)
+        cfile2 = cbfs.files['u-boot-dtb']
+        self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
+        self.assertEqual(0x140, cfile2.cbfs_offset)
+
+
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 3c0813115b8ebdf940505f6ae5c182d984f49d70 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:26 -0600
Subject: binman: Add a convenience functions for real-DTB tests

Quite a few tests will use a real device tree and need it updated with the
binman metadata. Add a helper function for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 5bde8aa30a..ed125670e2 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -380,6 +380,17 @@ class TestFunctional(unittest.TestCase):
             if reset_dtbs and use_real_dtb:
                 self._ResetDtbs()
 
+    def _DoReadFileRealDtb(self, fname):
+        """Run binman with a real .dtb file and return the resulting data
+
+        Args:
+            fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
+
+        Returns:
+            Resulting image contents
+        """
+        return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
+
     def _DoReadFile(self, fname, use_real_dtb=False):
         """Helper function which discards the device-tree binary
 
@@ -1547,8 +1558,7 @@ class TestFunctional(unittest.TestCase):
 
     def testUpdateFdtAll(self):
         """Test that all device trees are updated with offset/size info"""
-        data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
-                                            use_real_dtb=True, update_dtb=True)
+        data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
 
         base_expected = {
             'section:image-pos': 0,
-- 
cgit 


From 086cec9f980efd6f25e184b84f626d4a667e6645 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:27 -0600
Subject: binman: Add an FDT map

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>
---
 tools/binman/ftest.py | 52 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 6 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index ed125670e2..934145ca3c 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()
-- 
cgit 


From cf2289435c7e1134c75d9217ef32238aec0ecdbf Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:28 -0600
Subject: binman: Add an image header

It is useful to be able to quickly locate the FDT map in the image. An
easy way to do this is with a pointer at the start or end of the image.

Add an 'image header' entry, which places a magic number followed by a
pointer to the FDT map. This can be located at the start or end of the
image, or at a chosen location.

As part of this, update GetSiblingImagePos() to detect missing siblings.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 934145ca3c..6fdecb2f3b 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2076,7 +2076,7 @@ class TestFunctional(unittest.TestCase):
         # 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'
+        image._node.path += '-suffix'
         entries = image.GetEntries()
         fdtmap = entries['fdtmap']
         with self.assertRaises(ValueError) as e:
@@ -2084,6 +2084,51 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("Cannot locate node for path '/binman-suffix'",
                       str(e.exception))
 
+    def testFdtmapHeader(self):
+        """Test an FDT map and image header can be inserted in the image"""
+        data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
+        fdtmap_pos = len(U_BOOT_DATA)
+        fdtmap_data = data[fdtmap_pos:]
+        fdt_data = fdtmap_data[16:]
+        dtb = fdt.Fdt.FromData(fdt_data)
+        fdt_size = dtb.GetFdtObj().totalsize()
+        hdr_data = data[-8:]
+        self.assertEqual('BinM', hdr_data[:4])
+        offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
+        self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
+
+    def testFdtmapHeaderStart(self):
+        """Test an image header can be inserted at the image start"""
+        data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
+        fdtmap_pos = 0x100 + len(U_BOOT_DATA)
+        hdr_data = data[:8]
+        self.assertEqual('BinM', hdr_data[:4])
+        offset = struct.unpack('<I', hdr_data[4:])[0]
+        self.assertEqual(fdtmap_pos, offset)
+
+    def testFdtmapHeaderPos(self):
+        """Test an image header can be inserted at a chosen position"""
+        data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
+        fdtmap_pos = 0x100 + len(U_BOOT_DATA)
+        hdr_data = data[0x80:0x88]
+        self.assertEqual('BinM', hdr_data[:4])
+        offset = struct.unpack('<I', hdr_data[4:])[0]
+        self.assertEqual(fdtmap_pos, offset)
+
+    def testHeaderMissingFdtmap(self):
+        """Test an image header requires an fdtmap"""
+        with self.assertRaises(ValueError) as e:
+            self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
+        self.assertIn("'image_header' section must have an 'fdtmap' sibling",
+                      str(e.exception))
+
+    def testHeaderNoLocation(self):
+        """Test an image header with a no specified location is detected"""
+        with self.assertRaises(ValueError) as e:
+            self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
+        self.assertIn("Invalid location 'None', expected 'start' or 'end'",
+                      str(e.exception))
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 53cd5d921dd76d4651f2c99681a3c050743b6ba1 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:29 -0600
Subject: binman: Convert to use ArgumentParser

This class is the new way to handle arguments in Python. Convert binman
over to use it. At the same time, introduce commands so that we can
separate out the different parts of binman functionality.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 66 +++++++++++++++++++++------------------------------
 1 file changed, 27 insertions(+), 39 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 6fdecb2f3b..c675299e1d 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -155,7 +155,7 @@ class TestFunctional(unittest.TestCase):
 
     @classmethod
     def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
-                        toolpath=None):
+                        toolpath=None, verbosity=None):
         """Accept arguments controlling test execution
 
         Args:
@@ -169,6 +169,7 @@ class TestFunctional(unittest.TestCase):
         cls.preserve_indir = preserve_indir
         cls.preserve_outdirs = preserve_outdirs
         cls.toolpath = toolpath
+        cls.verbosity = verbosity
 
     def _CheckLz4(self):
         if not self.have_lz4:
@@ -192,19 +193,6 @@ class TestFunctional(unittest.TestCase):
         TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
         TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
 
-    def _GetVerbosity(self):
-        """Check if verbosity should be enabled
-
-        Returns:
-            list containing either:
-                - Verbosity flag (e.g. '-v2') if it is present on the cmd line
-                - nothing if the flag is not present
-        """
-        for arg in sys.argv[1:]:
-            if arg.startswith('-v'):
-                return [arg]
-        return []
-
     def _RunBinman(self, *args, **kwargs):
         """Run binman using the command line
 
@@ -219,7 +207,7 @@ class TestFunctional(unittest.TestCase):
                             result.stdout + result.stderr))
         return result
 
-    def _DoBinman(self, *args):
+    def _DoBinman(self, *argv):
         """Run binman using directly (in the same process)
 
         Args:
@@ -227,16 +215,14 @@ class TestFunctional(unittest.TestCase):
         Returns:
             Return value (0 for success)
         """
-        args = list(args)
-        if '-D' in sys.argv:
-            args = args + ['-D']
-        (options, args) = cmdline.ParseArgs(args)
-        options.pager = 'binman-invalid-pager'
-        options.build_dir = self._indir
+        argv = list(argv)
+        args = cmdline.ParseArgs(argv)
+        args.pager = 'binman-invalid-pager'
+        args.build_dir = self._indir
 
         # For testing, you can force an increase in verbosity here
-        # options.verbosity = tout.DEBUG
-        return control.Binman(options, args)
+        # args.verbosity = tout.DEBUG
+        return control.Binman(args)
 
     def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
                     entry_args=None, images=None, use_real_dtb=False,
@@ -254,28 +240,29 @@ class TestFunctional(unittest.TestCase):
                 value: value of that arg
             images: List of image names to build
         """
-        args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
+        args = []
         if debug:
             args.append('-D')
+        if verbosity is not None:
+            args.append('-v%d' % verbosity)
+        elif self.verbosity:
+            args.append('-v%d' % self.verbosity)
+        if self.toolpath:
+            for path in self.toolpath:
+                args += ['--toolpath', path]
+        args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
         if map:
             args.append('-m')
         if update_dtb:
             args.append('-u')
         if not use_real_dtb:
             args.append('--fake-dtb')
-        if verbosity is not None:
-            args.append('-v%d' % verbosity)
-        else:
-            args += self._GetVerbosity()
         if entry_args:
             for arg, value in entry_args.items():
                 args.append('-a%s=%s' % (arg, value))
         if images:
             for image in images:
                 args += ['-i', image]
-        if self.toolpath:
-            for path in self.toolpath:
-                args += ['--toolpath', path]
         return self._DoBinman(*args)
 
     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
@@ -538,20 +525,20 @@ class TestFunctional(unittest.TestCase):
         """Test that we can run it with a specific board"""
         self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
         TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
-        result = self._DoBinman('-b', 'sandbox')
+        result = self._DoBinman('build', '-b', 'sandbox')
         self.assertEqual(0, result)
 
     def testNeedBoard(self):
         """Test that we get an error when no board ius supplied"""
         with self.assertRaises(ValueError) as e:
-            result = self._DoBinman()
+            result = self._DoBinman('build')
         self.assertIn("Must provide a board to process (use -b <board>)",
                 str(e.exception))
 
     def testMissingDt(self):
         """Test that an invalid device-tree file generates an error"""
         with self.assertRaises(Exception) as e:
-            self._RunBinman('-d', 'missing_file')
+            self._RunBinman('build', '-d', 'missing_file')
         # We get one error from libfdt, and a different one from fdtget.
         self.AssertInList(["Couldn't open blob from 'missing_file'",
                            'No such file or directory'], str(e.exception))
@@ -563,26 +550,26 @@ class TestFunctional(unittest.TestCase):
         will come from the device-tree compiler (dtc).
         """
         with self.assertRaises(Exception) as e:
-            self._RunBinman('-d', self.TestFile('001_invalid.dts'))
+            self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
         self.assertIn("FATAL ERROR: Unable to parse input tree",
                 str(e.exception))
 
     def testMissingNode(self):
         """Test that a device tree without a 'binman' node generates an error"""
         with self.assertRaises(Exception) as e:
-            self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
+            self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
         self.assertIn("does not have a 'binman' node", str(e.exception))
 
     def testEmpty(self):
         """Test that an empty binman node works OK (i.e. does nothing)"""
-        result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
+        result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
         self.assertEqual(0, len(result.stderr))
         self.assertEqual(0, result.return_code)
 
     def testInvalidEntry(self):
         """Test that an invalid entry is flagged"""
         with self.assertRaises(Exception) as e:
-            result = self._RunBinman('-d',
+            result = self._RunBinman('build', '-d',
                                      self.TestFile('004_invalid_entry.dts'))
         self.assertIn("Unknown entry type 'not-a-valid-type' in node "
                 "'/binman/not-a-valid-type'", str(e.exception))
@@ -1313,7 +1300,8 @@ class TestFunctional(unittest.TestCase):
 
     def testEntryArgsInvalidFormat(self):
         """Test that an invalid entry-argument format is detected"""
-        args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
+        args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
+                '-ano-value']
         with self.assertRaises(ValueError) as e:
             self._DoBinman(*args)
         self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
-- 
cgit 


From 5b463fc26ea5a932d40845ec4eac6ff7e968756f Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:33 -0600
Subject: binman: Fix up ProcessUpdateContents error and comments

This function raises an exception with its arguments around the wrong way
so the message is incorrect. Fix this as well as a few minor comment
problems.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index c675299e1d..1c917345f2 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1223,7 +1223,7 @@ class TestFunctional(unittest.TestCase):
         with self.assertRaises(ValueError) as e:
             self._DoReadFile('059_change_size.dts', True)
         self.assertIn("Node '/binman/_testing': Cannot update entry size from "
-                      '2 to 1', str(e.exception))
+                      '1 to 2', str(e.exception))
 
     def testUpdateFdt(self):
         """Test that we can update the device tree with offset/size info"""
-- 
cgit 


From c52c9e7da809e36001d125891e594c4740235055 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:37 -0600
Subject: binman: Allow entries to expand after packing

Add support for detecting entries that change size after they have already
been packed, and re-running packing when it happens.

This removes the limitation that entry size cannot change after
PackEntries() is called.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 1c917345f2..aae8dbc1b3 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1220,10 +1220,14 @@ class TestFunctional(unittest.TestCase):
 
     def testBadChangeSize(self):
         """Test that trying to change the size of an entry fails"""
-        with self.assertRaises(ValueError) as e:
-            self._DoReadFile('059_change_size.dts', True)
-        self.assertIn("Node '/binman/_testing': Cannot update entry size from "
-                      '1 to 2', str(e.exception))
+        try:
+            state.SetAllowEntryExpansion(False)
+            with self.assertRaises(ValueError) as e:
+                self._DoReadFile('059_change_size.dts', True)
+            self.assertIn("Node '/binman/_testing': Cannot update entry size from 1 to 2",
+                          str(e.exception))
+        finally:
+            state.SetAllowEntryExpansion(True)
 
     def testUpdateFdt(self):
         """Test that we can update the device tree with offset/size info"""
@@ -2117,6 +2121,27 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("Invalid location 'None', expected 'start' or 'end'",
                       str(e.exception))
 
+    def testEntryExpand(self):
+        """Test expanding an entry after it is packed"""
+        data = self._DoReadFile('121_entry_expand.dts')
+        self.assertEqual(b'aa', data[:2])
+        self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
+        self.assertEqual(b'aa', data[-2:])
+
+    def testEntryExpandBad(self):
+        """Test expanding an entry after it is packed, twice"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('122_entry_expand_twice.dts')
+        self.assertIn("Image '/binman': Entries expanded after packing",
+                      str(e.exception))
+
+    def testEntryExpandSection(self):
+        """Test expanding an entry within a section after it is packed"""
+        data = self._DoReadFile('123_entry_expand_section.dts')
+        self.assertEqual(b'aa', data[:2])
+        self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
+        self.assertEqual(b'aa', data[-2:])
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 6c223fda1e624e1e382fcb029e9d60f441444d2e Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:38 -0600
Subject: binman: Allow device-tree entries to be compressed

At present the logic skips the blob class' handling of compression, so
this is not supported with device tree entries. Fix this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index aae8dbc1b3..89e732fca3 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2142,6 +2142,24 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
         self.assertEqual(b'aa', data[-2:])
 
+    def testCompressDtb(self):
+        """Test that compress of device-tree files is supported"""
+        self._CheckLz4()
+        data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
+        self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
+        comp_data = data[len(U_BOOT_DATA):]
+        orig = self._decompress(comp_data)
+        dtb = fdt.Fdt.FromData(orig)
+        dtb.Scan()
+        props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
+        expected = {
+            'u-boot:size': len(U_BOOT_DATA),
+            'u-boot-dtb:uncomp-size': len(orig),
+            'u-boot-dtb:size': len(comp_data),
+            'size': len(data),
+            }
+        self.assertEqual(expected, props)
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 69f7cb31a083c697ef0a4180a30219d2258b3662 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:41 -0600
Subject: binman: Support FDT update for CBFS

It is useful to add the CBFS file information (offset, size, etc.) into
the FDT so that the layout is complete. Add support for this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 89e732fca3..999d8884ac 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2160,6 +2160,31 @@ class TestFunctional(unittest.TestCase):
             }
         self.assertEqual(expected, props)
 
+    def testCbfsUpdateFdt(self):
+        """Test that we can update the device tree with CBFS offset/size info"""
+        self._CheckLz4()
+        data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
+                                                        update_dtb=True)
+        dtb = fdt.Fdt(out_dtb_fname)
+        dtb.Scan()
+        props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
+                                        'uncomp-size'])
+        del props['cbfs/u-boot:size']
+        self.assertEqual({
+            'offset': 0,
+            'size': len(data),
+            'image-pos': 0,
+            'cbfs:offset': 0,
+            'cbfs:size': len(data),
+            'cbfs:image-pos': 0,
+            'cbfs/u-boot:offset': 0x38,
+            'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
+            'cbfs/u-boot:image-pos': 0x38,
+            'cbfs/u-boot-dtb:offset': 0xb8,
+            'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
+            'cbfs/u-boot-dtb:image-pos': 0xb8,
+            }, props)
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 8a1ad068deef6228fd501992bdb347ecad9da067 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:42 -0600
Subject: binman: Detect bad CBFS file types

Detect when an unknown or unsupported file type is specified and report
an error.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 999d8884ac..21bea6c9d1 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2185,6 +2185,12 @@ class TestFunctional(unittest.TestCase):
             'cbfs/u-boot-dtb:image-pos': 0xb8,
             }, props)
 
+    def testCbfsBadType(self):
+        """Test an image header with a no specified location is detected"""
+        with self.assertRaises(ValueError) as e:
+            self._DoReadFile('126_cbfs_bad_type.dts')
+        self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 41b8ba090ced0bb54733dc3dd32e945e7e332801 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:43 -0600
Subject: binman: Allow listing the entries in an image

It is useful to be able to summarise all the entries in an image, e.g. to
display this to this user. Add a new ListEntries() method to Entry, and
set up a way to call it through the Image class.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 21bea6c9d1..de459b2b3b 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2191,6 +2191,82 @@ class TestFunctional(unittest.TestCase):
             self._DoReadFile('126_cbfs_bad_type.dts')
         self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
 
+    def testList(self):
+        """Test listing the files in an image"""
+        self._CheckLz4()
+        data = self._DoReadFile('127_list.dts')
+        image = control.images['image']
+        entries = image.BuildEntryList()
+        self.assertEqual(7, len(entries))
+
+        ent = entries[0]
+        self.assertEqual(0, ent.indent)
+        self.assertEqual('main-section', ent.name)
+        self.assertEqual('section', ent.etype)
+        self.assertEqual(len(data), ent.size)
+        self.assertEqual(0, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(None, ent.offset)
+
+        ent = entries[1]
+        self.assertEqual(1, ent.indent)
+        self.assertEqual('u-boot', ent.name)
+        self.assertEqual('u-boot', ent.etype)
+        self.assertEqual(len(U_BOOT_DATA), ent.size)
+        self.assertEqual(0, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(0, ent.offset)
+
+        ent = entries[2]
+        self.assertEqual(1, ent.indent)
+        self.assertEqual('section', ent.name)
+        self.assertEqual('section', ent.etype)
+        section_size = ent.size
+        self.assertEqual(0x100, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(len(U_BOOT_DATA), ent.offset)
+
+        ent = entries[3]
+        self.assertEqual(2, ent.indent)
+        self.assertEqual('cbfs', ent.name)
+        self.assertEqual('cbfs', ent.etype)
+        self.assertEqual(0x400, ent.size)
+        self.assertEqual(0x100, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(0, ent.offset)
+
+        ent = entries[4]
+        self.assertEqual(3, ent.indent)
+        self.assertEqual('u-boot', ent.name)
+        self.assertEqual('u-boot', ent.etype)
+        self.assertEqual(len(U_BOOT_DATA), ent.size)
+        self.assertEqual(0x138, ent.image_pos)
+        self.assertEqual(None, ent.uncomp_size)
+        self.assertEqual(0x38, ent.offset)
+
+        ent = entries[5]
+        self.assertEqual(3, ent.indent)
+        self.assertEqual('u-boot-dtb', ent.name)
+        self.assertEqual('text', ent.etype)
+        self.assertGreater(len(COMPRESS_DATA), ent.size)
+        self.assertEqual(0x178, ent.image_pos)
+        self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
+        self.assertEqual(0x78, ent.offset)
+
+        ent = entries[6]
+        self.assertEqual(2, ent.indent)
+        self.assertEqual('u-boot-dtb', ent.name)
+        self.assertEqual('u-boot-dtb', ent.etype)
+        self.assertEqual(0x500, ent.image_pos)
+        self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
+        dtb_size = ent.size
+        # Compressing this data expands it since headers are added
+        self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
+        self.assertEqual(0x400, ent.offset)
+
+        self.assertEqual(len(data), 0x100 + section_size)
+        self.assertEqual(section_size, 0x400 + dtb_size)
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From e1925fa520187b1f34c0ecabc47a147754594ecd Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:44 -0600
Subject: binman: Support locating an FDT map

Add support for locating an image's Fdt map which is used to determine
the contents and structure of the image.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index de459b2b3b..d800ba1e9d 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -24,6 +24,7 @@ import command
 import control
 import elf
 import fdt
+from etype import fdtmap
 import fdt_util
 import fmap_util
 import test_util
@@ -2267,6 +2268,20 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(len(data), 0x100 + section_size)
         self.assertEqual(section_size, 0x400 + dtb_size)
 
+    def testFindFdtmap(self):
+        """Test locating an FDT map in an image"""
+        self._CheckLz4()
+        data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
+        image = control.images['image']
+        entries = image.GetEntries()
+        entry = entries['fdtmap']
+        self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
+
+    def testFindFdtmapMissing(self):
+        """Test failing to locate an FDP map"""
+        data = self._DoReadFile('005_simple.dts')
+        self.assertEqual(None, fdtmap.LocateFdtmap(data))
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 2d26003df79839d7f6b5e30eaa49e191dc9e6c87 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:45 -0600
Subject: binman: Support locating an image header

Add support for locating an image header in an image.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index d800ba1e9d..ce66e3a2f2 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -25,6 +25,7 @@ import control
 import elf
 import fdt
 from etype import fdtmap
+from etype import image_header
 import fdt_util
 import fmap_util
 import test_util
@@ -2282,6 +2283,32 @@ class TestFunctional(unittest.TestCase):
         data = self._DoReadFile('005_simple.dts')
         self.assertEqual(None, fdtmap.LocateFdtmap(data))
 
+    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]
+        image = control.images['image']
+        entries = image.GetEntries()
+        entry = entries['fdtmap']
+        # The header should point to the FDT map
+        self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
+
+    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]
+        image = control.images['image']
+        entries = image.GetEntries()
+        entry = entries['fdtmap']
+        # The header should point to the FDT map
+        self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
+
+    def testFindImageHeaderMissing(self):
+        """Test failing to locate an image header"""
+        data = self._DoReadFile('005_simple.dts')
+        self.assertEqual(None, image_header.LocateHeaderOffset(data))
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From ffded7527ad5272249ae728a88585373182cc7f4 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:46 -0600
Subject: binman: Support reading an image into an Image object

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/ftest.py | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index ce66e3a2f2..f3a8e64ad1 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -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()
-- 
cgit 


From 8beb11ea6e09726996350a21bedba110f234d983 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:47 -0600
Subject: binman: Convert Image to a subclass of Entry

When support for sections (and thus hierarchical images) was added to
binman, the decision was made to create a new Section class which could
be used by both Image and an Entry_section class. The decision between
using inheritance and composition was tricky to make, but in the end it
was decided that Image was different enough from Entry that it made sense
to put the implementation of sections in an entirely separate class. It
also has the advantage that core Image code does have to rely on an entry
class in the etype directory.

This work was mostly completed in commit:

   8f1da50ccc "binman: Refactor much of the image code into 'section'

As a result of this, the Section class has its own version of things like
offset and size and these must be kept in sync with the parent
Entry_section class in some cases.

In the last year it has become apparent that the cost of keeping things in
sync is larger than expected, since more and more code wants to access
these properties.

An alternative approach, previously considered and rejected, now seems
better.

Adjust Image to be a subclass of Entry_section. Move the code from Section
(in bsection.py) to Entry_section and delete Section. Update all tests
accordingly.

This requires substantial changes to Image. Overall the changes reduce
code size by about 240 lines. While much of that is just boilerplate from
Section, there are quite a few functions in Entry_section which now do not
need to be overiden from Entry. This suggests the change is beneficial
even without further functionality being added.

A side benefit is that the properties of sections are now consistent with
other entries. This fixes a problem in testListCmd() where some properties
are missing for sections.

Unfortunately this is a very large commit since it is not feasible to do
the migration piecemeal. Given the substantial tests available and the
100% code coverage of binman, we should be able to do this safely.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index f3a8e64ad1..4f58ce3c85 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -595,7 +595,7 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(0, retcode)
 
         image = control.images['image1']
-        self.assertEqual(len(U_BOOT_DATA), image._size)
+        self.assertEqual(len(U_BOOT_DATA), image.size)
         fname = tools.GetOutputFilename('image1.bin')
         self.assertTrue(os.path.exists(fname))
         with open(fname, 'rb') as fd:
@@ -603,7 +603,7 @@ class TestFunctional(unittest.TestCase):
             self.assertEqual(U_BOOT_DATA, data)
 
         image = control.images['image2']
-        self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
+        self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
         fname = tools.GetOutputFilename('image2.bin')
         self.assertTrue(os.path.exists(fname))
         with open(fname, 'rb') as fd:
@@ -659,7 +659,7 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(61, entry.offset)
         self.assertEqual(len(U_BOOT_DATA), entry.size)
 
-        self.assertEqual(65, image._size)
+        self.assertEqual(65, image.size)
 
     def testPackExtra(self):
         """Test that extra packing feature works as expected"""
@@ -703,7 +703,7 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(64, entry.size)
 
         self.CheckNoGaps(entries)
-        self.assertEqual(128, image._size)
+        self.assertEqual(128, image.size)
 
     def testPackAlignPowerOf2(self):
         """Test that invalid entry alignment is detected"""
@@ -761,7 +761,7 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(0, retcode)
         self.assertIn('image', control.images)
         image = control.images['image']
-        self.assertEqual(7, image._size)
+        self.assertEqual(7, image.size)
 
     def testPackImageSizeAlign(self):
         """Test that image size alignemnt works as expected"""
@@ -769,7 +769,7 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(0, retcode)
         self.assertIn('image', control.images)
         image = control.images['image']
-        self.assertEqual(16, image._size)
+        self.assertEqual(16, image.size)
 
     def testPackInvalidImageAlign(self):
         """Test that invalid image alignment is detected"""
@@ -782,7 +782,7 @@ class TestFunctional(unittest.TestCase):
         """Test that invalid image alignment is detected"""
         with self.assertRaises(ValueError) as e:
             self._DoTestFile('020_pack_inv_image_align_power2.dts')
-        self.assertIn("Section '/binman': Alignment size 131 must be a power of "
+        self.assertIn("Image '/binman': Alignment size 131 must be a power of "
                       "two", str(e.exception))
 
     def testImagePadByte(self):
@@ -833,7 +833,7 @@ class TestFunctional(unittest.TestCase):
         """Test that the end-at-4gb property requires a size property"""
         with self.assertRaises(ValueError) as e:
             self._DoTestFile('027_pack_4gb_no_size.dts')
-        self.assertIn("Section '/binman': Section size must be provided when "
+        self.assertIn("Image '/binman': Section size must be provided when "
                       "using end-at-4gb", str(e.exception))
 
     def test4gbAndSkipAtStartTogether(self):
@@ -841,7 +841,7 @@ class TestFunctional(unittest.TestCase):
         together"""
         with self.assertRaises(ValueError) as e:
             self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
-        self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
+        self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
                       "'skip-at-start'", str(e.exception))
 
     def testPackX86RomOutside(self):
@@ -1217,7 +1217,7 @@ class TestFunctional(unittest.TestCase):
         """Test that obtaining the contents works as expected"""
         with self.assertRaises(ValueError) as e:
             self._DoReadFile('057_unknown_contents.dts', True)
-        self.assertIn("Section '/binman': Internal error: Could not complete "
+        self.assertIn("Image '/binman': Internal error: Could not complete "
                 "processing of contents: remaining [<_testing.Entry__testing ",
                 str(e.exception))
 
@@ -1657,7 +1657,7 @@ class TestFunctional(unittest.TestCase):
         image = control.images['image']
         entries = image.GetEntries()
         files = entries['files']
-        entries = files._section._entries
+        entries = files._entries
 
         orig = b''
         for i in range(1, 3):
@@ -2209,7 +2209,7 @@ class TestFunctional(unittest.TestCase):
         self.assertEqual(len(data), ent.size)
         self.assertEqual(0, ent.image_pos)
         self.assertEqual(None, ent.uncomp_size)
-        self.assertEqual(None, ent.offset)
+        self.assertEqual(0, ent.offset)
 
         ent = entries[1]
         self.assertEqual(1, ent.indent)
@@ -2227,7 +2227,7 @@ class TestFunctional(unittest.TestCase):
         section_size = ent.size
         self.assertEqual(0x100, ent.image_pos)
         self.assertEqual(None, ent.uncomp_size)
-        self.assertEqual(len(U_BOOT_DATA), ent.offset)
+        self.assertEqual(0x100, ent.offset)
 
         ent = entries[3]
         self.assertEqual(2, ent.indent)
@@ -2331,7 +2331,7 @@ class TestFunctional(unittest.TestCase):
         image_fname = tools.GetOutputFilename('image.bin')
         image = Image.FromFile(image_fname)
         self.assertTrue(isinstance(image, Image))
-        self.assertEqual('image', image._name)
+        self.assertEqual('image', image.image_name)
 
     def testReadImageFail(self):
         """Test failing to read an image image's FDT map"""
@@ -2341,5 +2341,6 @@ class TestFunctional(unittest.TestCase):
             image = Image.FromFile(image_fname)
         self.assertIn("Cannot find FDT map in image", str(e.exception))
 
+
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 61f564d15f35e5f5600ed639201b257efa09d1f1 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:48 -0600
Subject: binman: Support listing an image

Add support for listing the entries in an image. This relies on the image
having an FDT map.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 4f58ce3c85..ad828041f3 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2341,6 +2341,88 @@ class TestFunctional(unittest.TestCase):
             image = Image.FromFile(image_fname)
         self.assertIn("Cannot find FDT map in image", str(e.exception))
 
+    def testListCmd(self):
+        """Test listing the files in an image using an Fdtmap"""
+        self._CheckLz4()
+        data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
+
+        # lz4 compression size differs depending on the version
+        image = control.images['image']
+        entries = image.GetEntries()
+        section_size = entries['section'].size
+        fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
+        fdtmap_offset = entries['fdtmap'].offset
+
+        image_fname = tools.GetOutputFilename('image.bin')
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self._DoBinman('ls', '-i', image_fname)
+        lines = stdout.getvalue().splitlines()
+        expected = [
+'Name              Image-pos  Size  Entry-type    Offset  Uncomp-size',
+'----------------------------------------------------------------------',
+'main-section              0   c00  section            0',
+'  u-boot                  0     4  u-boot             0',
+'  section               100   %x  section          100' % section_size,
+'    cbfs                100   400  cbfs               0',
+'      u-boot            138     4  u-boot            38',
+'      u-boot-dtb        180   10f  u-boot-dtb        80          3c9',
+'    u-boot-dtb          500   %x  u-boot-dtb       400          3c9' % fdt_size,
+'  fdtmap                %x   395  fdtmap           %x' %
+        (fdtmap_offset, fdtmap_offset),
+'  image-header          bf8     8  image-header     bf8',
+            ]
+        self.assertEqual(expected, lines)
+
+    def testListCmdFail(self):
+        """Test failing to list an image"""
+        self._DoReadFile('005_simple.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        with self.assertRaises(ValueError) as e:
+            self._DoBinman('ls', '-i', image_fname)
+        self.assertIn("Cannot find FDT map in image", str(e.exception))
+
+    def _RunListCmd(self, paths, expected):
+        """List out entries and check the result
+
+        Args:
+            paths: List of paths to pass to the list command
+            expected: Expected list of filenames to be returned, in order
+        """
+        self._CheckLz4()
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        image = Image.FromFile(image_fname)
+        lines = image.GetListEntries(paths)[1]
+        files = [line[0].strip() for line in lines[1:]]
+        self.assertEqual(expected, files)
+
+    def testListCmdSection(self):
+        """Test listing the files in a section"""
+        self._RunListCmd(['section'],
+            ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
+
+    def testListCmdFile(self):
+        """Test listing a particular file"""
+        self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
+
+    def testListCmdWildcard(self):
+        """Test listing a wildcarded file"""
+        self._RunListCmd(['*boot*'],
+            ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
+
+    def testListCmdWildcardMulti(self):
+        """Test listing a wildcarded file"""
+        self._RunListCmd(['*cb*', '*head*'],
+            ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
+
+    def testListCmdEmpty(self):
+        """Test listing a wildcarded file"""
+        self._RunListCmd(['nothing'], [])
+
+    def testListCmdPath(self):
+        """Test listing the files in a sub-entry of a section"""
+        self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From f667e45b1c0a7f21d433ee8f3ec18858d87dd2e5 Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:50 -0600
Subject: binman: Allow reading an entry from an image

It is useful to be able to extract entry contents from an image to see
what is inside. Add a simple function to read the contents of an entry,
decompressing it by default.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index ad828041f3..c11dd1b85a 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -69,6 +69,8 @@ FILES_DATA            = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
 COMPRESS_DATA         = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
 REFCODE_DATA          = b'refcode'
 
+EXTRACT_DTB_SIZE = 0x3c9
+
 
 class TestFunctional(unittest.TestCase):
     """Functional tests for binman
@@ -2423,6 +2425,46 @@ class TestFunctional(unittest.TestCase):
         """Test listing the files in a sub-entry of a section"""
         self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
 
+    def _RunExtractCmd(self, entry_name, decomp=True):
+        """Extract an entry from an image
+
+        Args:
+            entry_name: Entry name to extract
+            decomp: True to decompress the data if compressed, False to leave
+                it in its raw uncompressed format
+
+        Returns:
+            data from entry
+        """
+        self._CheckLz4()
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        return control.ReadEntry(image_fname, entry_name, decomp)
+
+    def testExtractSimple(self):
+        """Test extracting a single file"""
+        data = self._RunExtractCmd('u-boot')
+        self.assertEqual(U_BOOT_DATA, data)
+
+    def testExtractBadEntry(self):
+        """Test extracting a bad section path"""
+        with self.assertRaises(ValueError) as e:
+            self._RunExtractCmd('section/does-not-exist')
+        self.assertIn("Entry 'does-not-exist' not found in '/section'",
+                      str(e.exception))
+
+    def testExtractMissingFile(self):
+        """Test extracting file that does not exist"""
+        with self.assertRaises(IOError) as e:
+            control.ReadEntry('missing-file', 'name')
+
+    def testExtractBadFile(self):
+        """Test extracting an invalid file"""
+        fname = os.path.join(self._indir, 'badfile')
+        tools.WriteFile(fname, b'')
+        with self.assertRaises(ValueError) as e:
+            control.ReadEntry(fname, 'name')
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From 71ce0ba284aeb388ddcefb4f6f0056c759a758cc Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:52 -0600
Subject: binman: Add an 'extract' command

It is useful to be able to extract all binaries from the image, or a
subset of them. Add a new 'extract' command to handle this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 189 insertions(+)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index c11dd1b85a..709fa0adc3 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -2446,6 +2446,43 @@ class TestFunctional(unittest.TestCase):
         data = self._RunExtractCmd('u-boot')
         self.assertEqual(U_BOOT_DATA, data)
 
+    def testExtractSection(self):
+        """Test extracting the files in a section"""
+        data = self._RunExtractCmd('section')
+        cbfs_data = data[:0x400]
+        cbfs = cbfs_util.CbfsReader(cbfs_data)
+        self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
+        dtb_data = data[0x400:]
+        dtb = self._decompress(dtb_data)
+        self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
+
+    def testExtractCompressed(self):
+        """Test extracting compressed data"""
+        data = self._RunExtractCmd('section/u-boot-dtb')
+        self.assertEqual(EXTRACT_DTB_SIZE, len(data))
+
+    def testExtractRaw(self):
+        """Test extracting compressed data without decompressing it"""
+        data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
+        dtb = self._decompress(data)
+        self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
+
+    def testExtractCbfs(self):
+        """Test extracting CBFS data"""
+        data = self._RunExtractCmd('section/cbfs/u-boot')
+        self.assertEqual(U_BOOT_DATA, data)
+
+    def testExtractCbfsCompressed(self):
+        """Test extracting CBFS compressed data"""
+        data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
+        self.assertEqual(EXTRACT_DTB_SIZE, len(data))
+
+    def testExtractCbfsRaw(self):
+        """Test extracting CBFS compressed data without decompressing it"""
+        data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
+        dtb = tools.Decompress(data, 'lzma')
+        self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
+
     def testExtractBadEntry(self):
         """Test extracting a bad section path"""
         with self.assertRaises(ValueError) as e:
@@ -2465,6 +2502,158 @@ class TestFunctional(unittest.TestCase):
         with self.assertRaises(ValueError) as e:
             control.ReadEntry(fname, 'name')
 
+    def testExtractCmd(self):
+        """Test extracting a file fron an image on the command line"""
+        self._CheckLz4()
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        fname = os.path.join(self._indir, 'output.extact')
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self._DoBinman('extract', '-i', image_fname, 'u-boot', '-f', fname)
+        data = tools.ReadFile(fname)
+        self.assertEqual(U_BOOT_DATA, data)
+
+    def testExtractOneEntry(self):
+        """Test extracting a single entry fron an image """
+        self._CheckLz4()
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        fname = os.path.join(self._indir, 'output.extact')
+        control.ExtractEntries(image_fname, fname, None, ['u-boot'])
+        data = tools.ReadFile(fname)
+        self.assertEqual(U_BOOT_DATA, data)
+
+    def _CheckExtractOutput(self, decomp):
+        """Helper to test file output with and without decompression
+
+        Args:
+            decomp: True to decompress entry data, False to output it raw
+        """
+        def _CheckPresent(entry_path, expect_data, expect_size=None):
+            """Check and remove expected file
+
+            This checks the data/size of a file and removes the file both from
+            the outfiles set and from the output directory. Once all files are
+            processed, both the set and directory should be empty.
+
+            Args:
+                entry_path: Entry path
+                expect_data: Data to expect in file, or None to skip check
+                expect_size: Size of data to expect in file, or None to skip
+            """
+            path = os.path.join(outdir, entry_path)
+            data = tools.ReadFile(path)
+            os.remove(path)
+            if expect_data:
+                self.assertEqual(expect_data, data)
+            elif expect_size:
+                self.assertEqual(expect_size, len(data))
+            outfiles.remove(path)
+
+        def _CheckDirPresent(name):
+            """Remove expected directory
+
+            This gives an error if the directory does not exist as expected
+
+            Args:
+                name: Name of directory to remove
+            """
+            path = os.path.join(outdir, name)
+            os.rmdir(path)
+
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        outdir = os.path.join(self._indir, 'extract')
+        einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
+
+        # Create a set of all file that were output (should be 9)
+        outfiles = set()
+        for root, dirs, files in os.walk(outdir):
+            outfiles |= set([os.path.join(root, fname) for fname in files])
+        self.assertEqual(9, len(outfiles))
+        self.assertEqual(9, len(einfos))
+
+        image = control.images['image']
+        entries = image.GetEntries()
+
+        # Check the 9 files in various ways
+        section = entries['section']
+        section_entries = section.GetEntries()
+        cbfs_entries = section_entries['cbfs'].GetEntries()
+        _CheckPresent('u-boot', U_BOOT_DATA)
+        _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
+        dtb_len = EXTRACT_DTB_SIZE
+        if not decomp:
+            dtb_len = cbfs_entries['u-boot-dtb'].size
+        _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
+        if not decomp:
+            dtb_len = section_entries['u-boot-dtb'].size
+        _CheckPresent('section/u-boot-dtb', None, dtb_len)
+
+        fdtmap = entries['fdtmap']
+        _CheckPresent('fdtmap', fdtmap.data)
+        hdr = entries['image-header']
+        _CheckPresent('image-header', hdr.data)
+
+        _CheckPresent('section/root', section.data)
+        cbfs = section_entries['cbfs']
+        _CheckPresent('section/cbfs/root', cbfs.data)
+        data = tools.ReadFile(image_fname)
+        _CheckPresent('root', data)
+
+        # There should be no files left. Remove all the directories to check.
+        # If there are any files/dirs remaining, one of these checks will fail.
+        self.assertEqual(0, len(outfiles))
+        _CheckDirPresent('section/cbfs')
+        _CheckDirPresent('section')
+        _CheckDirPresent('')
+        self.assertFalse(os.path.exists(outdir))
+
+    def testExtractAllEntries(self):
+        """Test extracting all entries"""
+        self._CheckLz4()
+        self._CheckExtractOutput(decomp=True)
+
+    def testExtractAllEntriesRaw(self):
+        """Test extracting all entries without decompressing them"""
+        self._CheckLz4()
+        self._CheckExtractOutput(decomp=False)
+
+    def testExtractSelectedEntries(self):
+        """Test extracting some entries"""
+        self._CheckLz4()
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        outdir = os.path.join(self._indir, 'extract')
+        einfos = control.ExtractEntries(image_fname, None, outdir,
+                                        ['*cb*', '*head*'])
+
+        # File output is tested by testExtractAllEntries(), so just check that
+        # the expected entries are selected
+        names = [einfo.name for einfo in einfos]
+        self.assertEqual(names,
+                         ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
+
+    def testExtractNoEntryPaths(self):
+        """Test extracting some entries"""
+        self._CheckLz4()
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        with self.assertRaises(ValueError) as e:
+            control.ExtractEntries(image_fname, 'fname', None, [])
+        self.assertIn('Must specify an entry path to write with -o',
+                      str(e.exception))
+
+    def testExtractTooManyEntryPaths(self):
+        """Test extracting some entries"""
+        self._CheckLz4()
+        self._DoReadFileRealDtb('130_list_fdtmap.dts')
+        image_fname = tools.GetOutputFilename('image.bin')
+        with self.assertRaises(ValueError) as e:
+            control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
+        self.assertIn('Must specify exactly one entry path to write with -o',
+                      str(e.exception))
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit 


From e2705fa9c5bfa7f310047a805cfa9103990d381c Mon Sep 17 00:00:00 2001
From: Simon Glass <sjg@chromium.org>
Date: Mon, 8 Jul 2019 14:25:53 -0600
Subject: binman: Add a test for nested and aligned sections

Current test coverage is likely sufficient for the logic used to place
sections in the image. However it seems useful to add a test specifically
for nested sections, since these could have some unusual interactions.

Add a new test for this and aligned sections. This test failed before the
refactor to drop the bsection.py file (Section class), but passes now.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 tools/binman/ftest.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 66 insertions(+), 1 deletion(-)

(limited to 'tools/binman/ftest.py')

diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 709fa0adc3..6a40d1fdbb 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -586,7 +586,7 @@ class TestFunctional(unittest.TestCase):
 
     def testSimpleDebug(self):
         """Test a simple binman run with debugging enabled"""
-        data = self._DoTestFile('005_simple.dts', debug=True)
+        self._DoTestFile('005_simple.dts', debug=True)
 
     def testDual(self):
         """Test that we can handle creating two images
@@ -2654,6 +2654,71 @@ class TestFunctional(unittest.TestCase):
         self.assertIn('Must specify exactly one entry path to write with -o',
                       str(e.exception))
 
+    def testPackAlignSection(self):
+        """Test that sections can have alignment"""
+        self._DoReadFile('131_pack_align_section.dts')
+
+        self.assertIn('image', control.images)
+        image = control.images['image']
+        entries = image.GetEntries()
+        self.assertEqual(3, len(entries))
+
+        # First u-boot
+        self.assertIn('u-boot', entries)
+        entry = entries['u-boot']
+        self.assertEqual(0, entry.offset)
+        self.assertEqual(0, entry.image_pos)
+        self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+        self.assertEqual(len(U_BOOT_DATA), entry.size)
+
+        # Section0
+        self.assertIn('section0', entries)
+        section0 = entries['section0']
+        self.assertEqual(0x10, section0.offset)
+        self.assertEqual(0x10, section0.image_pos)
+        self.assertEqual(len(U_BOOT_DATA), section0.size)
+
+        # Second u-boot
+        section_entries = section0.GetEntries()
+        self.assertIn('u-boot', section_entries)
+        entry = section_entries['u-boot']
+        self.assertEqual(0, entry.offset)
+        self.assertEqual(0x10, entry.image_pos)
+        self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+        self.assertEqual(len(U_BOOT_DATA), entry.size)
+
+        # Section1
+        self.assertIn('section1', entries)
+        section1 = entries['section1']
+        self.assertEqual(0x14, section1.offset)
+        self.assertEqual(0x14, section1.image_pos)
+        self.assertEqual(0x20, section1.size)
+
+        # Second u-boot
+        section_entries = section1.GetEntries()
+        self.assertIn('u-boot', section_entries)
+        entry = section_entries['u-boot']
+        self.assertEqual(0, entry.offset)
+        self.assertEqual(0x14, entry.image_pos)
+        self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+        self.assertEqual(len(U_BOOT_DATA), entry.size)
+
+        # Section2
+        self.assertIn('section2', section_entries)
+        section2 = section_entries['section2']
+        self.assertEqual(0x4, section2.offset)
+        self.assertEqual(0x18, section2.image_pos)
+        self.assertEqual(4, section2.size)
+
+        # Third u-boot
+        section_entries = section2.GetEntries()
+        self.assertIn('u-boot', section_entries)
+        entry = section_entries['u-boot']
+        self.assertEqual(0, entry.offset)
+        self.assertEqual(0x18, entry.image_pos)
+        self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
+        self.assertEqual(len(U_BOOT_DATA), entry.size)
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
cgit