summaryrefslogtreecommitdiff
path: root/tools/binman/ftest.py
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2019-07-24 16:24:50 -0400
committerTom Rini <trini@konsulko.com>2019-07-24 16:24:50 -0400
commitf9b65c76b4828efbf8093c6b02bee5af0045b98b (patch)
tree1429cb8e3cdfea42b63778ddf06ad0b33fb7bcf0 /tools/binman/ftest.py
parenta9aa4c5700c68c070d63a391b51ea8d341b6e8a6 (diff)
parent44e02e39a91cd91aae5a28d90259d3a6996010bf (diff)
Merge tag 'dm-pull-24jul19-take3' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm
Minor driver-model fixes and tweaks A few device-tree fixes Binman support for extracting files from an image
Diffstat (limited to 'tools/binman/ftest.py')
-rw-r--r--tools/binman/ftest.py1039
1 files changed, 974 insertions, 65 deletions
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index cc57ef3e04..6a40d1fdbb 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
@@ -16,14 +18,19 @@ import tempfile
import unittest
import binman
+import cbfs_util
import cmdline
import command
import control
import elf
import fdt
+from etype import fdtmap
+from etype import image_header
import fdt_util
import fmap_util
import test_util
+import gzip
+from image import Image
import state
import tools
import tout
@@ -59,9 +66,11 @@ 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'
+EXTRACT_DTB_SIZE = 0x3c9
+
class TestFunctional(unittest.TestCase):
"""Functional tests for binman
@@ -131,13 +140,46 @@ 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"""
- 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,
+ toolpath=None, verbosity=None):
+ """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.
+ toolpath: ist of paths to use for tools
+ """
+ cls.preserve_indir = preserve_indir
+ cls.preserve_outdirs = preserve_outdirs
+ cls.toolpath = toolpath
+ cls.verbosity = verbosity
+
+ 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)
@@ -145,7 +187,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):
@@ -167,7 +212,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:
@@ -175,16 +220,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,
@@ -202,17 +245,23 @@ 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('-up')
+ args.append('-u')
if not use_real_dtb:
args.append('--fake-dtb')
- if verbosity is not None:
- args.append('-v%d' % verbosity)
if entry_args:
for arg, value in entry_args.items():
args.append('-a%s=%s' % (arg, value))
@@ -323,6 +372,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
@@ -419,16 +479,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 = {}
@@ -470,20 +530,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))
@@ -495,26 +555,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))
@@ -526,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
@@ -537,7 +597,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:
@@ -545,7 +605,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:
@@ -601,7 +661,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"""
@@ -645,7 +705,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"""
@@ -703,7 +763,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"""
@@ -711,7 +771,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"""
@@ -724,7 +784,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):
@@ -775,7 +835,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):
@@ -783,7 +843,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):
@@ -806,8 +866,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"""
@@ -820,6 +880,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):
@@ -1156,16 +1219,20 @@ 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))
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 "
- '2 to 1', 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"""
@@ -1242,7 +1309,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))
@@ -1286,7 +1354,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):
@@ -1471,7 +1539,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,
@@ -1487,8 +1555,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,
@@ -1560,19 +1627,11 @@ 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"""
+ self._CheckLz4()
data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
use_real_dtb=True, update_dtb=True)
dtb = fdt.Fdt(out_dtb_fname)
@@ -1594,12 +1653,13 @@ 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']
entries = image.GetEntries()
files = entries['files']
- entries = files._section._entries
+ entries = files._entries
orig = b''
for i in range(1, 3):
@@ -1755,10 +1815,12 @@ class TestFunctional(unittest.TestCase):
"""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')
- def testElfStripg(self):
+ def testElfStrip(self):
"""Basic test of ELF entries"""
self._SetupSplElf()
with open(self.TestFile('bss_data'), 'rb') as fd:
@@ -1784,7 +1846,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)])
@@ -1810,6 +1872,853 @@ 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)
+
+ 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))
+
+ 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)
+
+ 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._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))
+
+ 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))
+
+ 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:])
+
+ 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)
+
+ 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)
+
+ 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))
+
+ 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(0, 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(0x100, 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)
+
+ 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))
+
+ def testFindImageHeader(self):
+ """Test locating a image header"""
+ self._CheckLz4()
+ data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
+ 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.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
+ 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))
+
+ 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.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))
+
+ 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'])
+
+ 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 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:
+ 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')
+
+ 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))
+
+ 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()