binman: Allow symbols to be resolved inside sections
[platform/kernel/u-boot.git] / tools / binman / ftest.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
4 #
5 # To run a single test, change to this directory, and:
6 #
7 #    python -m unittest func_test.TestFunctional.testHelp
8
9 from __future__ import print_function
10
11 import hashlib
12 from optparse import OptionParser
13 import os
14 import shutil
15 import struct
16 import sys
17 import tempfile
18 import unittest
19
20 import binman
21 import cbfs_util
22 import cmdline
23 import command
24 import control
25 import elf
26 import elf_test
27 import fdt
28 from etype import fdtmap
29 from etype import image_header
30 import fdt_util
31 import fmap_util
32 import test_util
33 import gzip
34 from image import Image
35 import state
36 import tools
37 import tout
38
39 # Contents of test files, corresponding to different entry types
40 U_BOOT_DATA           = b'1234'
41 U_BOOT_IMG_DATA       = b'img'
42 U_BOOT_SPL_DATA       = b'56780123456789abcde'
43 U_BOOT_TPL_DATA       = b'tpl9876543210fedcb'
44 BLOB_DATA             = b'89'
45 ME_DATA               = b'0abcd'
46 VGA_DATA              = b'vga'
47 U_BOOT_DTB_DATA       = b'udtb'
48 U_BOOT_SPL_DTB_DATA   = b'spldtb'
49 U_BOOT_TPL_DTB_DATA   = b'tpldtb'
50 X86_START16_DATA      = b'start16'
51 X86_START16_SPL_DATA  = b'start16spl'
52 X86_START16_TPL_DATA  = b'start16tpl'
53 X86_RESET16_DATA      = b'reset16'
54 X86_RESET16_SPL_DATA  = b'reset16spl'
55 X86_RESET16_TPL_DATA  = b'reset16tpl'
56 PPC_MPC85XX_BR_DATA   = b'ppcmpc85xxbr'
57 U_BOOT_NODTB_DATA     = b'nodtb with microcode pointer somewhere in here'
58 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
59 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
60 FSP_DATA              = b'fsp'
61 CMC_DATA              = b'cmc'
62 VBT_DATA              = b'vbt'
63 MRC_DATA              = b'mrc'
64 TEXT_DATA             = 'text'
65 TEXT_DATA2            = 'text2'
66 TEXT_DATA3            = 'text3'
67 CROS_EC_RW_DATA       = b'ecrw'
68 GBB_DATA              = b'gbbd'
69 BMPBLK_DATA           = b'bmp'
70 VBLOCK_DATA           = b'vblk'
71 FILES_DATA            = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
72                          b"sorry you're alive\n")
73 COMPRESS_DATA         = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
74 REFCODE_DATA          = b'refcode'
75
76 # The expected size for the device tree in some tests
77 EXTRACT_DTB_SIZE = 0x3c9
78
79 # Properties expected to be in the device tree when update_dtb is used
80 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
81
82 # Extra properties expected to be in the device tree when allow-repack is used
83 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
84
85
86 class TestFunctional(unittest.TestCase):
87     """Functional tests for binman
88
89     Most of these use a sample .dts file to build an image and then check
90     that it looks correct. The sample files are in the test/ subdirectory
91     and are numbered.
92
93     For each entry type a very small test file is created using fixed
94     string contents. This makes it easy to test that things look right, and
95     debug problems.
96
97     In some cases a 'real' file must be used - these are also supplied in
98     the test/ diurectory.
99     """
100     @classmethod
101     def setUpClass(cls):
102         global entry
103         import entry
104
105         # Handle the case where argv[0] is 'python'
106         cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
107         cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
108
109         # Create a temporary directory for input files
110         cls._indir = tempfile.mkdtemp(prefix='binmant.')
111
112         # Create some test files
113         TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
114         TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
115         TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
116         TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
117         TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
118         TestFunctional._MakeInputFile('me.bin', ME_DATA)
119         TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
120         cls._ResetDtbs()
121
122         TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
123
124         TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
125         TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
126                                       X86_START16_SPL_DATA)
127         TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
128                                       X86_START16_TPL_DATA)
129
130         TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
131                                       X86_RESET16_DATA)
132         TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
133                                       X86_RESET16_SPL_DATA)
134         TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
135                                       X86_RESET16_TPL_DATA)
136
137         TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
138         TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
139                                       U_BOOT_SPL_NODTB_DATA)
140         TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
141                                       U_BOOT_TPL_NODTB_DATA)
142         TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
143         TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
144         TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
145         TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
146         TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
147         TestFunctional._MakeInputDir('devkeys')
148         TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
149         TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
150
151         cls._elf_testdir = os.path.join(cls._indir, 'elftest')
152         elf_test.BuildElfTestFiles(cls._elf_testdir)
153
154         # ELF file with a '_dt_ucode_base_size' symbol
155         TestFunctional._MakeInputFile('u-boot',
156             tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
157
158         # Intel flash descriptor file
159         with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
160             TestFunctional._MakeInputFile('descriptor.bin', fd.read())
161
162         shutil.copytree(cls.TestFile('files'),
163                         os.path.join(cls._indir, 'files'))
164
165         TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
166
167         # Travis-CI may have an old lz4
168         cls.have_lz4 = True
169         try:
170             tools.Run('lz4', '--no-frame-crc', '-c',
171                       os.path.join(cls._indir, 'u-boot.bin'))
172         except:
173             cls.have_lz4 = False
174
175     @classmethod
176     def tearDownClass(cls):
177         """Remove the temporary input directory and its contents"""
178         if cls.preserve_indir:
179             print('Preserving input dir: %s' % cls._indir)
180         else:
181             if cls._indir:
182                 shutil.rmtree(cls._indir)
183         cls._indir = None
184
185     @classmethod
186     def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
187                         toolpath=None, verbosity=None):
188         """Accept arguments controlling test execution
189
190         Args:
191             preserve_indir: Preserve the shared input directory used by all
192                 tests in this class.
193             preserve_outdir: Preserve the output directories used by tests. Each
194                 test has its own, so this is normally only useful when running a
195                 single test.
196             toolpath: ist of paths to use for tools
197         """
198         cls.preserve_indir = preserve_indir
199         cls.preserve_outdirs = preserve_outdirs
200         cls.toolpath = toolpath
201         cls.verbosity = verbosity
202
203     def _CheckLz4(self):
204         if not self.have_lz4:
205             self.skipTest('lz4 --no-frame-crc not available')
206
207     def _CleanupOutputDir(self):
208         """Remove the temporary output directory"""
209         if self.preserve_outdirs:
210             print('Preserving output dir: %s' % tools.outdir)
211         else:
212             tools._FinaliseForTest()
213
214     def setUp(self):
215         # Enable this to turn on debugging output
216         # tout.Init(tout.DEBUG)
217         command.test_result = None
218
219     def tearDown(self):
220         """Remove the temporary output directory"""
221         self._CleanupOutputDir()
222
223     def _SetupImageInTmpdir(self):
224         """Set up the output image in a new temporary directory
225
226         This is used when an image has been generated in the output directory,
227         but we want to run binman again. This will create a new output
228         directory and fail to delete the original one.
229
230         This creates a new temporary directory, copies the image to it (with a
231         new name) and removes the old output directory.
232
233         Returns:
234             Tuple:
235                 Temporary directory to use
236                 New image filename
237         """
238         image_fname = tools.GetOutputFilename('image.bin')
239         tmpdir = tempfile.mkdtemp(prefix='binman.')
240         updated_fname = os.path.join(tmpdir, 'image-updated.bin')
241         tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
242         self._CleanupOutputDir()
243         return tmpdir, updated_fname
244
245     @classmethod
246     def _ResetDtbs(cls):
247         TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
248         TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
249         TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
250
251     def _RunBinman(self, *args, **kwargs):
252         """Run binman using the command line
253
254         Args:
255             Arguments to pass, as a list of strings
256             kwargs: Arguments to pass to Command.RunPipe()
257         """
258         result = command.RunPipe([[self._binman_pathname] + list(args)],
259                 capture=True, capture_stderr=True, raise_on_error=False)
260         if result.return_code and kwargs.get('raise_on_error', True):
261             raise Exception("Error running '%s': %s" % (' '.join(args),
262                             result.stdout + result.stderr))
263         return result
264
265     def _DoBinman(self, *argv):
266         """Run binman using directly (in the same process)
267
268         Args:
269             Arguments to pass, as a list of strings
270         Returns:
271             Return value (0 for success)
272         """
273         argv = list(argv)
274         args = cmdline.ParseArgs(argv)
275         args.pager = 'binman-invalid-pager'
276         args.build_dir = self._indir
277
278         # For testing, you can force an increase in verbosity here
279         # args.verbosity = tout.DEBUG
280         return control.Binman(args)
281
282     def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
283                     entry_args=None, images=None, use_real_dtb=False,
284                     verbosity=None):
285         """Run binman with a given test file
286
287         Args:
288             fname: Device-tree source filename to use (e.g. 005_simple.dts)
289             debug: True to enable debugging output
290             map: True to output map files for the images
291             update_dtb: Update the offset and size of each entry in the device
292                 tree before packing it into the image
293             entry_args: Dict of entry args to supply to binman
294                 key: arg name
295                 value: value of that arg
296             images: List of image names to build
297         """
298         args = []
299         if debug:
300             args.append('-D')
301         if verbosity is not None:
302             args.append('-v%d' % verbosity)
303         elif self.verbosity:
304             args.append('-v%d' % self.verbosity)
305         if self.toolpath:
306             for path in self.toolpath:
307                 args += ['--toolpath', path]
308         args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
309         if map:
310             args.append('-m')
311         if update_dtb:
312             args.append('-u')
313         if not use_real_dtb:
314             args.append('--fake-dtb')
315         if entry_args:
316             for arg, value in entry_args.items():
317                 args.append('-a%s=%s' % (arg, value))
318         if images:
319             for image in images:
320                 args += ['-i', image]
321         return self._DoBinman(*args)
322
323     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
324         """Set up a new test device-tree file
325
326         The given file is compiled and set up as the device tree to be used
327         for ths test.
328
329         Args:
330             fname: Filename of .dts file to read
331             outfile: Output filename for compiled device-tree binary
332
333         Returns:
334             Contents of device-tree binary
335         """
336         tmpdir = tempfile.mkdtemp(prefix='binmant.')
337         dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
338         with open(dtb, 'rb') as fd:
339             data = fd.read()
340             TestFunctional._MakeInputFile(outfile, data)
341         shutil.rmtree(tmpdir)
342         return data
343
344     def _GetDtbContentsForSplTpl(self, dtb_data, name):
345         """Create a version of the main DTB for SPL or SPL
346
347         For testing we don't actually have different versions of the DTB. With
348         U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
349         we don't normally have any unwanted nodes.
350
351         We still want the DTBs for SPL and TPL to be different though, since
352         otherwise it is confusing to know which one we are looking at. So add
353         an 'spl' or 'tpl' property to the top-level node.
354         """
355         dtb = fdt.Fdt.FromData(dtb_data)
356         dtb.Scan()
357         dtb.GetNode('/binman').AddZeroProp(name)
358         dtb.Sync(auto_resize=True)
359         dtb.Pack()
360         return dtb.GetContents()
361
362     def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
363                        update_dtb=False, entry_args=None, reset_dtbs=True):
364         """Run binman and return the resulting image
365
366         This runs binman with a given test file and then reads the resulting
367         output file. It is a shortcut function since most tests need to do
368         these steps.
369
370         Raises an assertion failure if binman returns a non-zero exit code.
371
372         Args:
373             fname: Device-tree source filename to use (e.g. 005_simple.dts)
374             use_real_dtb: True to use the test file as the contents of
375                 the u-boot-dtb entry. Normally this is not needed and the
376                 test contents (the U_BOOT_DTB_DATA string) can be used.
377                 But in some test we need the real contents.
378             map: True to output map files for the images
379             update_dtb: Update the offset and size of each entry in the device
380                 tree before packing it into the image
381
382         Returns:
383             Tuple:
384                 Resulting image contents
385                 Device tree contents
386                 Map data showing contents of image (or None if none)
387                 Output device tree binary filename ('u-boot.dtb' path)
388         """
389         dtb_data = None
390         # Use the compiled test file as the u-boot-dtb input
391         if use_real_dtb:
392             dtb_data = self._SetupDtb(fname)
393
394             # For testing purposes, make a copy of the DT for SPL and TPL. Add
395             # a node indicating which it is, so aid verification.
396             for name in ['spl', 'tpl']:
397                 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
398                 outfile = os.path.join(self._indir, dtb_fname)
399                 TestFunctional._MakeInputFile(dtb_fname,
400                         self._GetDtbContentsForSplTpl(dtb_data, name))
401
402         try:
403             retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
404                     entry_args=entry_args, use_real_dtb=use_real_dtb)
405             self.assertEqual(0, retcode)
406             out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
407
408             # Find the (only) image, read it and return its contents
409             image = control.images['image']
410             image_fname = tools.GetOutputFilename('image.bin')
411             self.assertTrue(os.path.exists(image_fname))
412             if map:
413                 map_fname = tools.GetOutputFilename('image.map')
414                 with open(map_fname) as fd:
415                     map_data = fd.read()
416             else:
417                 map_data = None
418             with open(image_fname, 'rb') as fd:
419                 return fd.read(), dtb_data, map_data, out_dtb_fname
420         finally:
421             # Put the test file back
422             if reset_dtbs and use_real_dtb:
423                 self._ResetDtbs()
424
425     def _DoReadFileRealDtb(self, fname):
426         """Run binman with a real .dtb file and return the resulting data
427
428         Args:
429             fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
430
431         Returns:
432             Resulting image contents
433         """
434         return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
435
436     def _DoReadFile(self, fname, use_real_dtb=False):
437         """Helper function which discards the device-tree binary
438
439         Args:
440             fname: Device-tree source filename to use (e.g. 005_simple.dts)
441             use_real_dtb: True to use the test file as the contents of
442                 the u-boot-dtb entry. Normally this is not needed and the
443                 test contents (the U_BOOT_DTB_DATA string) can be used.
444                 But in some test we need the real contents.
445
446         Returns:
447             Resulting image contents
448         """
449         return self._DoReadFileDtb(fname, use_real_dtb)[0]
450
451     @classmethod
452     def _MakeInputFile(cls, fname, contents):
453         """Create a new test input file, creating directories as needed
454
455         Args:
456             fname: Filename to create
457             contents: File contents to write in to the file
458         Returns:
459             Full pathname of file created
460         """
461         pathname = os.path.join(cls._indir, fname)
462         dirname = os.path.dirname(pathname)
463         if dirname and not os.path.exists(dirname):
464             os.makedirs(dirname)
465         with open(pathname, 'wb') as fd:
466             fd.write(contents)
467         return pathname
468
469     @classmethod
470     def _MakeInputDir(cls, dirname):
471         """Create a new test input directory, creating directories as needed
472
473         Args:
474             dirname: Directory name to create
475
476         Returns:
477             Full pathname of directory created
478         """
479         pathname = os.path.join(cls._indir, dirname)
480         if not os.path.exists(pathname):
481             os.makedirs(pathname)
482         return pathname
483
484     @classmethod
485     def _SetupSplElf(cls, src_fname='bss_data'):
486         """Set up an ELF file with a '_dt_ucode_base_size' symbol
487
488         Args:
489             Filename of ELF file to use as SPL
490         """
491         TestFunctional._MakeInputFile('spl/u-boot-spl',
492             tools.ReadFile(cls.ElfTestFile(src_fname)))
493
494     @classmethod
495     def _SetupTplElf(cls, src_fname='bss_data'):
496         """Set up an ELF file with a '_dt_ucode_base_size' symbol
497
498         Args:
499             Filename of ELF file to use as TPL
500         """
501         TestFunctional._MakeInputFile('tpl/u-boot-tpl',
502             tools.ReadFile(cls.ElfTestFile(src_fname)))
503
504     @classmethod
505     def TestFile(cls, fname):
506         return os.path.join(cls._binman_dir, 'test', fname)
507
508     @classmethod
509     def ElfTestFile(cls, fname):
510         return os.path.join(cls._elf_testdir, fname)
511
512     def AssertInList(self, grep_list, target):
513         """Assert that at least one of a list of things is in a target
514
515         Args:
516             grep_list: List of strings to check
517             target: Target string
518         """
519         for grep in grep_list:
520             if grep in target:
521                 return
522         self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
523
524     def CheckNoGaps(self, entries):
525         """Check that all entries fit together without gaps
526
527         Args:
528             entries: List of entries to check
529         """
530         offset = 0
531         for entry in entries.values():
532             self.assertEqual(offset, entry.offset)
533             offset += entry.size
534
535     def GetFdtLen(self, dtb):
536         """Get the totalsize field from a device-tree binary
537
538         Args:
539             dtb: Device-tree binary contents
540
541         Returns:
542             Total size of device-tree binary, from the header
543         """
544         return struct.unpack('>L', dtb[4:8])[0]
545
546     def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
547         def AddNode(node, path):
548             if node.name != '/':
549                 path += '/' + node.name
550             for prop in node.props.values():
551                 if prop.name in prop_names:
552                     prop_path = path + ':' + prop.name
553                     tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
554                         prop.value)
555             for subnode in node.subnodes:
556                 AddNode(subnode, path)
557
558         tree = {}
559         AddNode(dtb.GetRoot(), '')
560         return tree
561
562     def testRun(self):
563         """Test a basic run with valid args"""
564         result = self._RunBinman('-h')
565
566     def testFullHelp(self):
567         """Test that the full help is displayed with -H"""
568         result = self._RunBinman('-H')
569         help_file = os.path.join(self._binman_dir, 'README')
570         # Remove possible extraneous strings
571         extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
572         gothelp = result.stdout.replace(extra, '')
573         self.assertEqual(len(gothelp), os.path.getsize(help_file))
574         self.assertEqual(0, len(result.stderr))
575         self.assertEqual(0, result.return_code)
576
577     def testFullHelpInternal(self):
578         """Test that the full help is displayed with -H"""
579         try:
580             command.test_result = command.CommandResult()
581             result = self._DoBinman('-H')
582             help_file = os.path.join(self._binman_dir, 'README')
583         finally:
584             command.test_result = None
585
586     def testHelp(self):
587         """Test that the basic help is displayed with -h"""
588         result = self._RunBinman('-h')
589         self.assertTrue(len(result.stdout) > 200)
590         self.assertEqual(0, len(result.stderr))
591         self.assertEqual(0, result.return_code)
592
593     def testBoard(self):
594         """Test that we can run it with a specific board"""
595         self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
596         TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
597         result = self._DoBinman('build', '-b', 'sandbox')
598         self.assertEqual(0, result)
599
600     def testNeedBoard(self):
601         """Test that we get an error when no board ius supplied"""
602         with self.assertRaises(ValueError) as e:
603             result = self._DoBinman('build')
604         self.assertIn("Must provide a board to process (use -b <board>)",
605                 str(e.exception))
606
607     def testMissingDt(self):
608         """Test that an invalid device-tree file generates an error"""
609         with self.assertRaises(Exception) as e:
610             self._RunBinman('build', '-d', 'missing_file')
611         # We get one error from libfdt, and a different one from fdtget.
612         self.AssertInList(["Couldn't open blob from 'missing_file'",
613                            'No such file or directory'], str(e.exception))
614
615     def testBrokenDt(self):
616         """Test that an invalid device-tree source file generates an error
617
618         Since this is a source file it should be compiled and the error
619         will come from the device-tree compiler (dtc).
620         """
621         with self.assertRaises(Exception) as e:
622             self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
623         self.assertIn("FATAL ERROR: Unable to parse input tree",
624                 str(e.exception))
625
626     def testMissingNode(self):
627         """Test that a device tree without a 'binman' node generates an error"""
628         with self.assertRaises(Exception) as e:
629             self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
630         self.assertIn("does not have a 'binman' node", str(e.exception))
631
632     def testEmpty(self):
633         """Test that an empty binman node works OK (i.e. does nothing)"""
634         result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
635         self.assertEqual(0, len(result.stderr))
636         self.assertEqual(0, result.return_code)
637
638     def testInvalidEntry(self):
639         """Test that an invalid entry is flagged"""
640         with self.assertRaises(Exception) as e:
641             result = self._RunBinman('build', '-d',
642                                      self.TestFile('004_invalid_entry.dts'))
643         self.assertIn("Unknown entry type 'not-a-valid-type' in node "
644                 "'/binman/not-a-valid-type'", str(e.exception))
645
646     def testSimple(self):
647         """Test a simple binman with a single file"""
648         data = self._DoReadFile('005_simple.dts')
649         self.assertEqual(U_BOOT_DATA, data)
650
651     def testSimpleDebug(self):
652         """Test a simple binman run with debugging enabled"""
653         self._DoTestFile('005_simple.dts', debug=True)
654
655     def testDual(self):
656         """Test that we can handle creating two images
657
658         This also tests image padding.
659         """
660         retcode = self._DoTestFile('006_dual_image.dts')
661         self.assertEqual(0, retcode)
662
663         image = control.images['image1']
664         self.assertEqual(len(U_BOOT_DATA), image.size)
665         fname = tools.GetOutputFilename('image1.bin')
666         self.assertTrue(os.path.exists(fname))
667         with open(fname, 'rb') as fd:
668             data = fd.read()
669             self.assertEqual(U_BOOT_DATA, data)
670
671         image = control.images['image2']
672         self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
673         fname = tools.GetOutputFilename('image2.bin')
674         self.assertTrue(os.path.exists(fname))
675         with open(fname, 'rb') as fd:
676             data = fd.read()
677             self.assertEqual(U_BOOT_DATA, data[3:7])
678             self.assertEqual(tools.GetBytes(0, 3), data[:3])
679             self.assertEqual(tools.GetBytes(0, 5), data[7:])
680
681     def testBadAlign(self):
682         """Test that an invalid alignment value is detected"""
683         with self.assertRaises(ValueError) as e:
684             self._DoTestFile('007_bad_align.dts')
685         self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
686                       "of two", str(e.exception))
687
688     def testPackSimple(self):
689         """Test that packing works as expected"""
690         retcode = self._DoTestFile('008_pack.dts')
691         self.assertEqual(0, retcode)
692         self.assertIn('image', control.images)
693         image = control.images['image']
694         entries = image.GetEntries()
695         self.assertEqual(5, len(entries))
696
697         # First u-boot
698         self.assertIn('u-boot', entries)
699         entry = entries['u-boot']
700         self.assertEqual(0, entry.offset)
701         self.assertEqual(len(U_BOOT_DATA), entry.size)
702
703         # Second u-boot, aligned to 16-byte boundary
704         self.assertIn('u-boot-align', entries)
705         entry = entries['u-boot-align']
706         self.assertEqual(16, entry.offset)
707         self.assertEqual(len(U_BOOT_DATA), entry.size)
708
709         # Third u-boot, size 23 bytes
710         self.assertIn('u-boot-size', entries)
711         entry = entries['u-boot-size']
712         self.assertEqual(20, entry.offset)
713         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
714         self.assertEqual(23, entry.size)
715
716         # Fourth u-boot, placed immediate after the above
717         self.assertIn('u-boot-next', entries)
718         entry = entries['u-boot-next']
719         self.assertEqual(43, entry.offset)
720         self.assertEqual(len(U_BOOT_DATA), entry.size)
721
722         # Fifth u-boot, placed at a fixed offset
723         self.assertIn('u-boot-fixed', entries)
724         entry = entries['u-boot-fixed']
725         self.assertEqual(61, entry.offset)
726         self.assertEqual(len(U_BOOT_DATA), entry.size)
727
728         self.assertEqual(65, image.size)
729
730     def testPackExtra(self):
731         """Test that extra packing feature works as expected"""
732         retcode = self._DoTestFile('009_pack_extra.dts')
733
734         self.assertEqual(0, retcode)
735         self.assertIn('image', control.images)
736         image = control.images['image']
737         entries = image.GetEntries()
738         self.assertEqual(5, len(entries))
739
740         # First u-boot with padding before and after
741         self.assertIn('u-boot', entries)
742         entry = entries['u-boot']
743         self.assertEqual(0, entry.offset)
744         self.assertEqual(3, entry.pad_before)
745         self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
746
747         # Second u-boot has an aligned size, but it has no effect
748         self.assertIn('u-boot-align-size-nop', entries)
749         entry = entries['u-boot-align-size-nop']
750         self.assertEqual(12, entry.offset)
751         self.assertEqual(4, entry.size)
752
753         # Third u-boot has an aligned size too
754         self.assertIn('u-boot-align-size', entries)
755         entry = entries['u-boot-align-size']
756         self.assertEqual(16, entry.offset)
757         self.assertEqual(32, entry.size)
758
759         # Fourth u-boot has an aligned end
760         self.assertIn('u-boot-align-end', entries)
761         entry = entries['u-boot-align-end']
762         self.assertEqual(48, entry.offset)
763         self.assertEqual(16, entry.size)
764
765         # Fifth u-boot immediately afterwards
766         self.assertIn('u-boot-align-both', entries)
767         entry = entries['u-boot-align-both']
768         self.assertEqual(64, entry.offset)
769         self.assertEqual(64, entry.size)
770
771         self.CheckNoGaps(entries)
772         self.assertEqual(128, image.size)
773
774     def testPackAlignPowerOf2(self):
775         """Test that invalid entry alignment is detected"""
776         with self.assertRaises(ValueError) as e:
777             self._DoTestFile('010_pack_align_power2.dts')
778         self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
779                       "of two", str(e.exception))
780
781     def testPackAlignSizePowerOf2(self):
782         """Test that invalid entry size alignment is detected"""
783         with self.assertRaises(ValueError) as e:
784             self._DoTestFile('011_pack_align_size_power2.dts')
785         self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
786                       "power of two", str(e.exception))
787
788     def testPackInvalidAlign(self):
789         """Test detection of an offset that does not match its alignment"""
790         with self.assertRaises(ValueError) as e:
791             self._DoTestFile('012_pack_inv_align.dts')
792         self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
793                       "align 0x4 (4)", str(e.exception))
794
795     def testPackInvalidSizeAlign(self):
796         """Test that invalid entry size alignment is detected"""
797         with self.assertRaises(ValueError) as e:
798             self._DoTestFile('013_pack_inv_size_align.dts')
799         self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
800                       "align-size 0x4 (4)", str(e.exception))
801
802     def testPackOverlap(self):
803         """Test that overlapping regions are detected"""
804         with self.assertRaises(ValueError) as e:
805             self._DoTestFile('014_pack_overlap.dts')
806         self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
807                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
808                       str(e.exception))
809
810     def testPackEntryOverflow(self):
811         """Test that entries that overflow their size are detected"""
812         with self.assertRaises(ValueError) as e:
813             self._DoTestFile('015_pack_overflow.dts')
814         self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
815                       "but entry size is 0x3 (3)", str(e.exception))
816
817     def testPackImageOverflow(self):
818         """Test that entries which overflow the image size are detected"""
819         with self.assertRaises(ValueError) as e:
820             self._DoTestFile('016_pack_image_overflow.dts')
821         self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
822                       "size 0x3 (3)", str(e.exception))
823
824     def testPackImageSize(self):
825         """Test that the image size can be set"""
826         retcode = self._DoTestFile('017_pack_image_size.dts')
827         self.assertEqual(0, retcode)
828         self.assertIn('image', control.images)
829         image = control.images['image']
830         self.assertEqual(7, image.size)
831
832     def testPackImageSizeAlign(self):
833         """Test that image size alignemnt works as expected"""
834         retcode = self._DoTestFile('018_pack_image_align.dts')
835         self.assertEqual(0, retcode)
836         self.assertIn('image', control.images)
837         image = control.images['image']
838         self.assertEqual(16, image.size)
839
840     def testPackInvalidImageAlign(self):
841         """Test that invalid image alignment is detected"""
842         with self.assertRaises(ValueError) as e:
843             self._DoTestFile('019_pack_inv_image_align.dts')
844         self.assertIn("Section '/binman': Size 0x7 (7) does not match "
845                       "align-size 0x8 (8)", str(e.exception))
846
847     def testPackAlignPowerOf2(self):
848         """Test that invalid image alignment is detected"""
849         with self.assertRaises(ValueError) as e:
850             self._DoTestFile('020_pack_inv_image_align_power2.dts')
851         self.assertIn("Image '/binman': Alignment size 131 must be a power of "
852                       "two", str(e.exception))
853
854     def testImagePadByte(self):
855         """Test that the image pad byte can be specified"""
856         self._SetupSplElf()
857         data = self._DoReadFile('021_image_pad.dts')
858         self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
859                          U_BOOT_DATA, data)
860
861     def testImageName(self):
862         """Test that image files can be named"""
863         retcode = self._DoTestFile('022_image_name.dts')
864         self.assertEqual(0, retcode)
865         image = control.images['image1']
866         fname = tools.GetOutputFilename('test-name')
867         self.assertTrue(os.path.exists(fname))
868
869         image = control.images['image2']
870         fname = tools.GetOutputFilename('test-name.xx')
871         self.assertTrue(os.path.exists(fname))
872
873     def testBlobFilename(self):
874         """Test that generic blobs can be provided by filename"""
875         data = self._DoReadFile('023_blob.dts')
876         self.assertEqual(BLOB_DATA, data)
877
878     def testPackSorted(self):
879         """Test that entries can be sorted"""
880         self._SetupSplElf()
881         data = self._DoReadFile('024_sorted.dts')
882         self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
883                          tools.GetBytes(0, 2) + U_BOOT_DATA, data)
884
885     def testPackZeroOffset(self):
886         """Test that an entry at offset 0 is not given a new offset"""
887         with self.assertRaises(ValueError) as e:
888             self._DoTestFile('025_pack_zero_size.dts')
889         self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
890                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
891                       str(e.exception))
892
893     def testPackUbootDtb(self):
894         """Test that a device tree can be added to U-Boot"""
895         data = self._DoReadFile('026_pack_u_boot_dtb.dts')
896         self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
897
898     def testPackX86RomNoSize(self):
899         """Test that the end-at-4gb property requires a size property"""
900         with self.assertRaises(ValueError) as e:
901             self._DoTestFile('027_pack_4gb_no_size.dts')
902         self.assertIn("Image '/binman': Section size must be provided when "
903                       "using end-at-4gb", str(e.exception))
904
905     def test4gbAndSkipAtStartTogether(self):
906         """Test that the end-at-4gb and skip-at-size property can't be used
907         together"""
908         with self.assertRaises(ValueError) as e:
909             self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
910         self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
911                       "'skip-at-start'", str(e.exception))
912
913     def testPackX86RomOutside(self):
914         """Test that the end-at-4gb property checks for offset boundaries"""
915         with self.assertRaises(ValueError) as e:
916             self._DoTestFile('028_pack_4gb_outside.dts')
917         self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
918                       "the section starting at 0xffffffe0 (4294967264)",
919                       str(e.exception))
920
921     def testPackX86Rom(self):
922         """Test that a basic x86 ROM can be created"""
923         self._SetupSplElf()
924         data = self._DoReadFile('029_x86-rom.dts')
925         self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
926                          tools.GetBytes(0, 2), data)
927
928     def testPackX86RomMeNoDesc(self):
929         """Test that an invalid Intel descriptor entry is detected"""
930         TestFunctional._MakeInputFile('descriptor.bin', b'')
931         with self.assertRaises(ValueError) as e:
932             self._DoTestFile('031_x86-rom-me.dts')
933         self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
934                       str(e.exception))
935
936     def testPackX86RomBadDesc(self):
937         """Test that the Intel requires a descriptor entry"""
938         with self.assertRaises(ValueError) as e:
939             self._DoTestFile('030_x86-rom-me-no-desc.dts')
940         self.assertIn("Node '/binman/intel-me': No offset set with "
941                       "offset-unset: should another entry provide this correct "
942                       "offset?", str(e.exception))
943
944     def testPackX86RomMe(self):
945         """Test that an x86 ROM with an ME region can be created"""
946         data = self._DoReadFile('031_x86-rom-me.dts')
947         expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
948         if data[:0x1000] != expected_desc:
949             self.fail('Expected descriptor binary at start of image')
950         self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
951
952     def testPackVga(self):
953         """Test that an image with a VGA binary can be created"""
954         data = self._DoReadFile('032_intel-vga.dts')
955         self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
956
957     def testPackStart16(self):
958         """Test that an image with an x86 start16 region can be created"""
959         data = self._DoReadFile('033_x86-start16.dts')
960         self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
961
962     def testPackPowerpcMpc85xxBootpgResetvec(self):
963         """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
964         created"""
965         data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
966         self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
967
968     def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
969         """Handle running a test for insertion of microcode
970
971         Args:
972             dts_fname: Name of test .dts file
973             nodtb_data: Data that we expect in the first section
974             ucode_second: True if the microsecond entry is second instead of
975                 third
976
977         Returns:
978             Tuple:
979                 Contents of first region (U-Boot or SPL)
980                 Offset and size components of microcode pointer, as inserted
981                     in the above (two 4-byte words)
982         """
983         data = self._DoReadFile(dts_fname, True)
984
985         # Now check the device tree has no microcode
986         if ucode_second:
987             ucode_content = data[len(nodtb_data):]
988             ucode_pos = len(nodtb_data)
989             dtb_with_ucode = ucode_content[16:]
990             fdt_len = self.GetFdtLen(dtb_with_ucode)
991         else:
992             dtb_with_ucode = data[len(nodtb_data):]
993             fdt_len = self.GetFdtLen(dtb_with_ucode)
994             ucode_content = dtb_with_ucode[fdt_len:]
995             ucode_pos = len(nodtb_data) + fdt_len
996         fname = tools.GetOutputFilename('test.dtb')
997         with open(fname, 'wb') as fd:
998             fd.write(dtb_with_ucode)
999         dtb = fdt.FdtScan(fname)
1000         ucode = dtb.GetNode('/microcode')
1001         self.assertTrue(ucode)
1002         for node in ucode.subnodes:
1003             self.assertFalse(node.props.get('data'))
1004
1005         # Check that the microcode appears immediately after the Fdt
1006         # This matches the concatenation of the data properties in
1007         # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1008         ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1009                                  0x78235609)
1010         self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1011
1012         # Check that the microcode pointer was inserted. It should match the
1013         # expected offset and size
1014         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1015                                    len(ucode_data))
1016         u_boot = data[:len(nodtb_data)]
1017         return u_boot, pos_and_size
1018
1019     def testPackUbootMicrocode(self):
1020         """Test that x86 microcode can be handled correctly
1021
1022         We expect to see the following in the image, in order:
1023             u-boot-nodtb.bin with a microcode pointer inserted at the correct
1024                 place
1025             u-boot.dtb with the microcode removed
1026             the microcode
1027         """
1028         first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1029                                                      U_BOOT_NODTB_DATA)
1030         self.assertEqual(b'nodtb with microcode' + pos_and_size +
1031                          b' somewhere in here', first)
1032
1033     def _RunPackUbootSingleMicrocode(self):
1034         """Test that x86 microcode can be handled correctly
1035
1036         We expect to see the following in the image, in order:
1037             u-boot-nodtb.bin with a microcode pointer inserted at the correct
1038                 place
1039             u-boot.dtb with the microcode
1040             an empty microcode region
1041         """
1042         # We need the libfdt library to run this test since only that allows
1043         # finding the offset of a property. This is required by
1044         # Entry_u_boot_dtb_with_ucode.ObtainContents().
1045         data = self._DoReadFile('035_x86_single_ucode.dts', True)
1046
1047         second = data[len(U_BOOT_NODTB_DATA):]
1048
1049         fdt_len = self.GetFdtLen(second)
1050         third = second[fdt_len:]
1051         second = second[:fdt_len]
1052
1053         ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1054         self.assertIn(ucode_data, second)
1055         ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1056
1057         # Check that the microcode pointer was inserted. It should match the
1058         # expected offset and size
1059         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1060                                    len(ucode_data))
1061         first = data[:len(U_BOOT_NODTB_DATA)]
1062         self.assertEqual(b'nodtb with microcode' + pos_and_size +
1063                          b' somewhere in here', first)
1064
1065     def testPackUbootSingleMicrocode(self):
1066         """Test that x86 microcode can be handled correctly with fdt_normal.
1067         """
1068         self._RunPackUbootSingleMicrocode()
1069
1070     def testUBootImg(self):
1071         """Test that u-boot.img can be put in a file"""
1072         data = self._DoReadFile('036_u_boot_img.dts')
1073         self.assertEqual(U_BOOT_IMG_DATA, data)
1074
1075     def testNoMicrocode(self):
1076         """Test that a missing microcode region is detected"""
1077         with self.assertRaises(ValueError) as e:
1078             self._DoReadFile('037_x86_no_ucode.dts', True)
1079         self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1080                       "node found in ", str(e.exception))
1081
1082     def testMicrocodeWithoutNode(self):
1083         """Test that a missing u-boot-dtb-with-ucode node is detected"""
1084         with self.assertRaises(ValueError) as e:
1085             self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1086         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1087                 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1088
1089     def testMicrocodeWithoutNode2(self):
1090         """Test that a missing u-boot-ucode node is detected"""
1091         with self.assertRaises(ValueError) as e:
1092             self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1093         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1094             "microcode region u-boot-ucode", str(e.exception))
1095
1096     def testMicrocodeWithoutPtrInElf(self):
1097         """Test that a U-Boot binary without the microcode symbol is detected"""
1098         # ELF file without a '_dt_ucode_base_size' symbol
1099         try:
1100             TestFunctional._MakeInputFile('u-boot',
1101                 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1102
1103             with self.assertRaises(ValueError) as e:
1104                 self._RunPackUbootSingleMicrocode()
1105             self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1106                     "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1107
1108         finally:
1109             # Put the original file back
1110             TestFunctional._MakeInputFile('u-boot',
1111                 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1112
1113     def testMicrocodeNotInImage(self):
1114         """Test that microcode must be placed within the image"""
1115         with self.assertRaises(ValueError) as e:
1116             self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1117         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1118                 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1119                 "section ranging from 00000000 to 0000002e", str(e.exception))
1120
1121     def testWithoutMicrocode(self):
1122         """Test that we can cope with an image without microcode (e.g. qemu)"""
1123         TestFunctional._MakeInputFile('u-boot',
1124             tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1125         data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1126
1127         # Now check the device tree has no microcode
1128         self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1129         second = data[len(U_BOOT_NODTB_DATA):]
1130
1131         fdt_len = self.GetFdtLen(second)
1132         self.assertEqual(dtb, second[:fdt_len])
1133
1134         used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1135         third = data[used_len:]
1136         self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1137
1138     def testUnknownPosSize(self):
1139         """Test that microcode must be placed within the image"""
1140         with self.assertRaises(ValueError) as e:
1141             self._DoReadFile('041_unknown_pos_size.dts', True)
1142         self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1143                 "entry 'invalid-entry'", str(e.exception))
1144
1145     def testPackFsp(self):
1146         """Test that an image with a FSP binary can be created"""
1147         data = self._DoReadFile('042_intel-fsp.dts')
1148         self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1149
1150     def testPackCmc(self):
1151         """Test that an image with a CMC binary can be created"""
1152         data = self._DoReadFile('043_intel-cmc.dts')
1153         self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1154
1155     def testPackVbt(self):
1156         """Test that an image with a VBT binary can be created"""
1157         data = self._DoReadFile('046_intel-vbt.dts')
1158         self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1159
1160     def testSplBssPad(self):
1161         """Test that we can pad SPL's BSS with zeros"""
1162         # ELF file with a '__bss_size' symbol
1163         self._SetupSplElf()
1164         data = self._DoReadFile('047_spl_bss_pad.dts')
1165         self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1166                          data)
1167
1168     def testSplBssPadMissing(self):
1169         """Test that a missing symbol is detected"""
1170         self._SetupSplElf('u_boot_ucode_ptr')
1171         with self.assertRaises(ValueError) as e:
1172             self._DoReadFile('047_spl_bss_pad.dts')
1173         self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1174                       str(e.exception))
1175
1176     def testPackStart16Spl(self):
1177         """Test that an image with an x86 start16 SPL region can be created"""
1178         data = self._DoReadFile('048_x86-start16-spl.dts')
1179         self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1180
1181     def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1182         """Helper function for microcode tests
1183
1184         We expect to see the following in the image, in order:
1185             u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1186                 correct place
1187             u-boot.dtb with the microcode removed
1188             the microcode
1189
1190         Args:
1191             dts: Device tree file to use for test
1192             ucode_second: True if the microsecond entry is second instead of
1193                 third
1194         """
1195         self._SetupSplElf('u_boot_ucode_ptr')
1196         first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1197                                                      ucode_second=ucode_second)
1198         self.assertEqual(b'splnodtb with microc' + pos_and_size +
1199                          b'ter somewhere in here', first)
1200
1201     def testPackUbootSplMicrocode(self):
1202         """Test that x86 microcode can be handled correctly in SPL"""
1203         self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1204
1205     def testPackUbootSplMicrocodeReorder(self):
1206         """Test that order doesn't matter for microcode entries
1207
1208         This is the same as testPackUbootSplMicrocode but when we process the
1209         u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1210         entry, so we reply on binman to try later.
1211         """
1212         self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1213                                     ucode_second=True)
1214
1215     def testPackMrc(self):
1216         """Test that an image with an MRC binary can be created"""
1217         data = self._DoReadFile('050_intel_mrc.dts')
1218         self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1219
1220     def testSplDtb(self):
1221         """Test that an image with spl/u-boot-spl.dtb can be created"""
1222         data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1223         self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1224
1225     def testSplNoDtb(self):
1226         """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1227         data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1228         self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1229
1230     def testSymbols(self):
1231         """Test binman can assign symbols embedded in U-Boot"""
1232         elf_fname = self.ElfTestFile('u_boot_binman_syms')
1233         syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1234         addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1235         self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1236
1237         self._SetupSplElf('u_boot_binman_syms')
1238         data = self._DoReadFile('053_symbols.dts')
1239         sym_values = struct.pack('<LQL', 0, 24, 20)
1240         expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1241                     tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1242                     U_BOOT_SPL_DATA[16:])
1243         self.assertEqual(expected, data)
1244
1245     def testPackUnitAddress(self):
1246         """Test that we support multiple binaries with the same name"""
1247         data = self._DoReadFile('054_unit_address.dts')
1248         self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1249
1250     def testSections(self):
1251         """Basic test of sections"""
1252         data = self._DoReadFile('055_sections.dts')
1253         expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1254                     U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1255                     U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1256         self.assertEqual(expected, data)
1257
1258     def testMap(self):
1259         """Tests outputting a map of the images"""
1260         _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1261         self.assertEqual('''ImagePos    Offset      Size  Name
1262 00000000  00000000  00000028  main-section
1263 00000000   00000000  00000010  section@0
1264 00000000    00000000  00000004  u-boot
1265 00000010   00000010  00000010  section@1
1266 00000010    00000000  00000004  u-boot
1267 00000020   00000020  00000004  section@2
1268 00000020    00000000  00000004  u-boot
1269 ''', map_data)
1270
1271     def testNamePrefix(self):
1272         """Tests that name prefixes are used"""
1273         _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1274         self.assertEqual('''ImagePos    Offset      Size  Name
1275 00000000  00000000  00000028  main-section
1276 00000000   00000000  00000010  section@0
1277 00000000    00000000  00000004  ro-u-boot
1278 00000010   00000010  00000010  section@1
1279 00000010    00000000  00000004  rw-u-boot
1280 ''', map_data)
1281
1282     def testUnknownContents(self):
1283         """Test that obtaining the contents works as expected"""
1284         with self.assertRaises(ValueError) as e:
1285             self._DoReadFile('057_unknown_contents.dts', True)
1286         self.assertIn("Image '/binman': Internal error: Could not complete "
1287                 "processing of contents: remaining [<_testing.Entry__testing ",
1288                 str(e.exception))
1289
1290     def testBadChangeSize(self):
1291         """Test that trying to change the size of an entry fails"""
1292         try:
1293             state.SetAllowEntryExpansion(False)
1294             with self.assertRaises(ValueError) as e:
1295                 self._DoReadFile('059_change_size.dts', True)
1296             self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1297                           str(e.exception))
1298         finally:
1299             state.SetAllowEntryExpansion(True)
1300
1301     def testUpdateFdt(self):
1302         """Test that we can update the device tree with offset/size info"""
1303         _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1304                                                      update_dtb=True)
1305         dtb = fdt.Fdt(out_dtb_fname)
1306         dtb.Scan()
1307         props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1308         self.assertEqual({
1309             'image-pos': 0,
1310             'offset': 0,
1311             '_testing:offset': 32,
1312             '_testing:size': 2,
1313             '_testing:image-pos': 32,
1314             'section@0/u-boot:offset': 0,
1315             'section@0/u-boot:size': len(U_BOOT_DATA),
1316             'section@0/u-boot:image-pos': 0,
1317             'section@0:offset': 0,
1318             'section@0:size': 16,
1319             'section@0:image-pos': 0,
1320
1321             'section@1/u-boot:offset': 0,
1322             'section@1/u-boot:size': len(U_BOOT_DATA),
1323             'section@1/u-boot:image-pos': 16,
1324             'section@1:offset': 16,
1325             'section@1:size': 16,
1326             'section@1:image-pos': 16,
1327             'size': 40
1328         }, props)
1329
1330     def testUpdateFdtBad(self):
1331         """Test that we detect when ProcessFdt never completes"""
1332         with self.assertRaises(ValueError) as e:
1333             self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1334         self.assertIn('Could not complete processing of Fdt: remaining '
1335                       '[<_testing.Entry__testing', str(e.exception))
1336
1337     def testEntryArgs(self):
1338         """Test passing arguments to entries from the command line"""
1339         entry_args = {
1340             'test-str-arg': 'test1',
1341             'test-int-arg': '456',
1342         }
1343         self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1344         self.assertIn('image', control.images)
1345         entry = control.images['image'].GetEntries()['_testing']
1346         self.assertEqual('test0', entry.test_str_fdt)
1347         self.assertEqual('test1', entry.test_str_arg)
1348         self.assertEqual(123, entry.test_int_fdt)
1349         self.assertEqual(456, entry.test_int_arg)
1350
1351     def testEntryArgsMissing(self):
1352         """Test missing arguments and properties"""
1353         entry_args = {
1354             'test-int-arg': '456',
1355         }
1356         self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1357         entry = control.images['image'].GetEntries()['_testing']
1358         self.assertEqual('test0', entry.test_str_fdt)
1359         self.assertEqual(None, entry.test_str_arg)
1360         self.assertEqual(None, entry.test_int_fdt)
1361         self.assertEqual(456, entry.test_int_arg)
1362
1363     def testEntryArgsRequired(self):
1364         """Test missing arguments and properties"""
1365         entry_args = {
1366             'test-int-arg': '456',
1367         }
1368         with self.assertRaises(ValueError) as e:
1369             self._DoReadFileDtb('064_entry_args_required.dts')
1370         self.assertIn("Node '/binman/_testing': Missing required "
1371             'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1372             str(e.exception))
1373
1374     def testEntryArgsInvalidFormat(self):
1375         """Test that an invalid entry-argument format is detected"""
1376         args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1377                 '-ano-value']
1378         with self.assertRaises(ValueError) as e:
1379             self._DoBinman(*args)
1380         self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1381
1382     def testEntryArgsInvalidInteger(self):
1383         """Test that an invalid entry-argument integer is detected"""
1384         entry_args = {
1385             'test-int-arg': 'abc',
1386         }
1387         with self.assertRaises(ValueError) as e:
1388             self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1389         self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1390                       "'test-int-arg' (value 'abc') to integer",
1391             str(e.exception))
1392
1393     def testEntryArgsInvalidDatatype(self):
1394         """Test that an invalid entry-argument datatype is detected
1395
1396         This test could be written in entry_test.py except that it needs
1397         access to control.entry_args, which seems more than that module should
1398         be able to see.
1399         """
1400         entry_args = {
1401             'test-bad-datatype-arg': '12',
1402         }
1403         with self.assertRaises(ValueError) as e:
1404             self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1405                                 entry_args=entry_args)
1406         self.assertIn('GetArg() internal error: Unknown data type ',
1407                       str(e.exception))
1408
1409     def testText(self):
1410         """Test for a text entry type"""
1411         entry_args = {
1412             'test-id': TEXT_DATA,
1413             'test-id2': TEXT_DATA2,
1414             'test-id3': TEXT_DATA3,
1415         }
1416         data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1417                                             entry_args=entry_args)
1418         expected = (tools.ToBytes(TEXT_DATA) +
1419                     tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1420                     tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1421                     b'some text' + b'more text')
1422         self.assertEqual(expected, data)
1423
1424     def testEntryDocs(self):
1425         """Test for creation of entry documentation"""
1426         with test_util.capture_sys_output() as (stdout, stderr):
1427             control.WriteEntryDocs(binman.GetEntryModules())
1428         self.assertTrue(len(stdout.getvalue()) > 0)
1429
1430     def testEntryDocsMissing(self):
1431         """Test handling of missing entry documentation"""
1432         with self.assertRaises(ValueError) as e:
1433             with test_util.capture_sys_output() as (stdout, stderr):
1434                 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1435         self.assertIn('Documentation is missing for modules: u_boot',
1436                       str(e.exception))
1437
1438     def testFmap(self):
1439         """Basic test of generation of a flashrom fmap"""
1440         data = self._DoReadFile('067_fmap.dts')
1441         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1442         expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1443                     U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1444         self.assertEqual(expected, data[:32])
1445         self.assertEqual(b'__FMAP__', fhdr.signature)
1446         self.assertEqual(1, fhdr.ver_major)
1447         self.assertEqual(0, fhdr.ver_minor)
1448         self.assertEqual(0, fhdr.base)
1449         self.assertEqual(16 + 16 +
1450                          fmap_util.FMAP_HEADER_LEN +
1451                          fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1452         self.assertEqual(b'FMAP', fhdr.name)
1453         self.assertEqual(3, fhdr.nareas)
1454         for fentry in fentries:
1455             self.assertEqual(0, fentry.flags)
1456
1457         self.assertEqual(0, fentries[0].offset)
1458         self.assertEqual(4, fentries[0].size)
1459         self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1460
1461         self.assertEqual(16, fentries[1].offset)
1462         self.assertEqual(4, fentries[1].size)
1463         self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1464
1465         self.assertEqual(32, fentries[2].offset)
1466         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1467                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1468         self.assertEqual(b'FMAP', fentries[2].name)
1469
1470     def testBlobNamedByArg(self):
1471         """Test we can add a blob with the filename coming from an entry arg"""
1472         entry_args = {
1473             'cros-ec-rw-path': 'ecrw.bin',
1474         }
1475         data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1476                                             entry_args=entry_args)
1477
1478     def testFill(self):
1479         """Test for an fill entry type"""
1480         data = self._DoReadFile('069_fill.dts')
1481         expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1482         self.assertEqual(expected, data)
1483
1484     def testFillNoSize(self):
1485         """Test for an fill entry type with no size"""
1486         with self.assertRaises(ValueError) as e:
1487             self._DoReadFile('070_fill_no_size.dts')
1488         self.assertIn("'fill' entry must have a size property",
1489                       str(e.exception))
1490
1491     def _HandleGbbCommand(self, pipe_list):
1492         """Fake calls to the futility utility"""
1493         if pipe_list[0][0] == 'futility':
1494             fname = pipe_list[0][-1]
1495             # Append our GBB data to the file, which will happen every time the
1496             # futility command is called.
1497             with open(fname, 'ab') as fd:
1498                 fd.write(GBB_DATA)
1499             return command.CommandResult()
1500
1501     def testGbb(self):
1502         """Test for the Chromium OS Google Binary Block"""
1503         command.test_result = self._HandleGbbCommand
1504         entry_args = {
1505             'keydir': 'devkeys',
1506             'bmpblk': 'bmpblk.bin',
1507         }
1508         data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1509
1510         # Since futility
1511         expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1512                     tools.GetBytes(0, 0x2180 - 16))
1513         self.assertEqual(expected, data)
1514
1515     def testGbbTooSmall(self):
1516         """Test for the Chromium OS Google Binary Block being large enough"""
1517         with self.assertRaises(ValueError) as e:
1518             self._DoReadFileDtb('072_gbb_too_small.dts')
1519         self.assertIn("Node '/binman/gbb': GBB is too small",
1520                       str(e.exception))
1521
1522     def testGbbNoSize(self):
1523         """Test for the Chromium OS Google Binary Block having a size"""
1524         with self.assertRaises(ValueError) as e:
1525             self._DoReadFileDtb('073_gbb_no_size.dts')
1526         self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1527                       str(e.exception))
1528
1529     def _HandleVblockCommand(self, pipe_list):
1530         """Fake calls to the futility utility"""
1531         if pipe_list[0][0] == 'futility':
1532             fname = pipe_list[0][3]
1533             with open(fname, 'wb') as fd:
1534                 fd.write(VBLOCK_DATA)
1535             return command.CommandResult()
1536
1537     def testVblock(self):
1538         """Test for the Chromium OS Verified Boot Block"""
1539         command.test_result = self._HandleVblockCommand
1540         entry_args = {
1541             'keydir': 'devkeys',
1542         }
1543         data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1544                                             entry_args=entry_args)
1545         expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1546         self.assertEqual(expected, data)
1547
1548     def testVblockNoContent(self):
1549         """Test we detect a vblock which has no content to sign"""
1550         with self.assertRaises(ValueError) as e:
1551             self._DoReadFile('075_vblock_no_content.dts')
1552         self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1553                       'property', str(e.exception))
1554
1555     def testVblockBadPhandle(self):
1556         """Test that we detect a vblock with an invalid phandle in contents"""
1557         with self.assertRaises(ValueError) as e:
1558             self._DoReadFile('076_vblock_bad_phandle.dts')
1559         self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1560                       '1000', str(e.exception))
1561
1562     def testVblockBadEntry(self):
1563         """Test that we detect an entry that points to a non-entry"""
1564         with self.assertRaises(ValueError) as e:
1565             self._DoReadFile('077_vblock_bad_entry.dts')
1566         self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1567                       "'other'", str(e.exception))
1568
1569     def testTpl(self):
1570         """Test that an image with TPL and its device tree can be created"""
1571         # ELF file with a '__bss_size' symbol
1572         self._SetupTplElf()
1573         data = self._DoReadFile('078_u_boot_tpl.dts')
1574         self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1575
1576     def testUsesPos(self):
1577         """Test that the 'pos' property cannot be used anymore"""
1578         with self.assertRaises(ValueError) as e:
1579            data = self._DoReadFile('079_uses_pos.dts')
1580         self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1581                       "'pos'", str(e.exception))
1582
1583     def testFillZero(self):
1584         """Test for an fill entry type with a size of 0"""
1585         data = self._DoReadFile('080_fill_empty.dts')
1586         self.assertEqual(tools.GetBytes(0, 16), data)
1587
1588     def testTextMissing(self):
1589         """Test for a text entry type where there is no text"""
1590         with self.assertRaises(ValueError) as e:
1591             self._DoReadFileDtb('066_text.dts',)
1592         self.assertIn("Node '/binman/text': No value provided for text label "
1593                       "'test-id'", str(e.exception))
1594
1595     def testPackStart16Tpl(self):
1596         """Test that an image with an x86 start16 TPL region can be created"""
1597         data = self._DoReadFile('081_x86-start16-tpl.dts')
1598         self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1599
1600     def testSelectImage(self):
1601         """Test that we can select which images to build"""
1602         expected = 'Skipping images: image1'
1603
1604         # We should only get the expected message in verbose mode
1605         for verbosity in (0, 2):
1606             with test_util.capture_sys_output() as (stdout, stderr):
1607                 retcode = self._DoTestFile('006_dual_image.dts',
1608                                            verbosity=verbosity,
1609                                            images=['image2'])
1610             self.assertEqual(0, retcode)
1611             if verbosity:
1612                 self.assertIn(expected, stdout.getvalue())
1613             else:
1614                 self.assertNotIn(expected, stdout.getvalue())
1615
1616             self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1617             self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1618             self._CleanupOutputDir()
1619
1620     def testUpdateFdtAll(self):
1621         """Test that all device trees are updated with offset/size info"""
1622         data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1623
1624         base_expected = {
1625             'section:image-pos': 0,
1626             'u-boot-tpl-dtb:size': 513,
1627             'u-boot-spl-dtb:size': 513,
1628             'u-boot-spl-dtb:offset': 493,
1629             'image-pos': 0,
1630             'section/u-boot-dtb:image-pos': 0,
1631             'u-boot-spl-dtb:image-pos': 493,
1632             'section/u-boot-dtb:size': 493,
1633             'u-boot-tpl-dtb:image-pos': 1006,
1634             'section/u-boot-dtb:offset': 0,
1635             'section:size': 493,
1636             'offset': 0,
1637             'section:offset': 0,
1638             'u-boot-tpl-dtb:offset': 1006,
1639             'size': 1519
1640         }
1641
1642         # We expect three device-tree files in the output, one after the other.
1643         # Read them in sequence. We look for an 'spl' property in the SPL tree,
1644         # and 'tpl' in the TPL tree, to make sure they are distinct from the
1645         # main U-Boot tree. All three should have the same postions and offset.
1646         start = 0
1647         for item in ['', 'spl', 'tpl']:
1648             dtb = fdt.Fdt.FromData(data[start:])
1649             dtb.Scan()
1650             props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1651                                       ['spl', 'tpl'])
1652             expected = dict(base_expected)
1653             if item:
1654                 expected[item] = 0
1655             self.assertEqual(expected, props)
1656             start += dtb._fdt_obj.totalsize()
1657
1658     def testUpdateFdtOutput(self):
1659         """Test that output DTB files are updated"""
1660         try:
1661             data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1662                     use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1663
1664             # Unfortunately, compiling a source file always results in a file
1665             # called source.dtb (see fdt_util.EnsureCompiled()). The test
1666             # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1667             # binman as a file called u-boot.dtb. To fix this, copy the file
1668             # over to the expected place.
1669             #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1670                     #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1671             start = 0
1672             for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1673                           'tpl/u-boot-tpl.dtb.out']:
1674                 dtb = fdt.Fdt.FromData(data[start:])
1675                 size = dtb._fdt_obj.totalsize()
1676                 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1677                 outdata = tools.ReadFile(pathname)
1678                 name = os.path.split(fname)[0]
1679
1680                 if name:
1681                     orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1682                 else:
1683                     orig_indata = dtb_data
1684                 self.assertNotEqual(outdata, orig_indata,
1685                         "Expected output file '%s' be updated" % pathname)
1686                 self.assertEqual(outdata, data[start:start + size],
1687                         "Expected output file '%s' to match output image" %
1688                         pathname)
1689                 start += size
1690         finally:
1691             self._ResetDtbs()
1692
1693     def _decompress(self, data):
1694         return tools.Decompress(data, 'lz4')
1695
1696     def testCompress(self):
1697         """Test compression of blobs"""
1698         self._CheckLz4()
1699         data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1700                                             use_real_dtb=True, update_dtb=True)
1701         dtb = fdt.Fdt(out_dtb_fname)
1702         dtb.Scan()
1703         props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1704         orig = self._decompress(data)
1705         self.assertEquals(COMPRESS_DATA, orig)
1706         expected = {
1707             'blob:uncomp-size': len(COMPRESS_DATA),
1708             'blob:size': len(data),
1709             'size': len(data),
1710             }
1711         self.assertEqual(expected, props)
1712
1713     def testFiles(self):
1714         """Test bringing in multiple files"""
1715         data = self._DoReadFile('084_files.dts')
1716         self.assertEqual(FILES_DATA, data)
1717
1718     def testFilesCompress(self):
1719         """Test bringing in multiple files and compressing them"""
1720         self._CheckLz4()
1721         data = self._DoReadFile('085_files_compress.dts')
1722
1723         image = control.images['image']
1724         entries = image.GetEntries()
1725         files = entries['files']
1726         entries = files._entries
1727
1728         orig = b''
1729         for i in range(1, 3):
1730             key = '%d.dat' % i
1731             start = entries[key].image_pos
1732             len = entries[key].size
1733             chunk = data[start:start + len]
1734             orig += self._decompress(chunk)
1735
1736         self.assertEqual(FILES_DATA, orig)
1737
1738     def testFilesMissing(self):
1739         """Test missing files"""
1740         with self.assertRaises(ValueError) as e:
1741             data = self._DoReadFile('086_files_none.dts')
1742         self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1743                       'no files', str(e.exception))
1744
1745     def testFilesNoPattern(self):
1746         """Test missing files"""
1747         with self.assertRaises(ValueError) as e:
1748             data = self._DoReadFile('087_files_no_pattern.dts')
1749         self.assertIn("Node '/binman/files': Missing 'pattern' property",
1750                       str(e.exception))
1751
1752     def testExpandSize(self):
1753         """Test an expanding entry"""
1754         data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1755                                                    map=True)
1756         expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1757                   MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1758                   tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1759                   tools.GetBytes(ord('d'), 8))
1760         self.assertEqual(expect, data)
1761         self.assertEqual('''ImagePos    Offset      Size  Name
1762 00000000  00000000  00000028  main-section
1763 00000000   00000000  00000008  fill
1764 00000008   00000008  00000004  u-boot
1765 0000000c   0000000c  00000004  section
1766 0000000c    00000000  00000003  intel-mrc
1767 00000010   00000010  00000004  u-boot2
1768 00000014   00000014  0000000c  section2
1769 00000014    00000000  00000008  fill
1770 0000001c    00000008  00000004  u-boot
1771 00000020   00000020  00000008  fill2
1772 ''', map_data)
1773
1774     def testExpandSizeBad(self):
1775         """Test an expanding entry which fails to provide contents"""
1776         with test_util.capture_sys_output() as (stdout, stderr):
1777             with self.assertRaises(ValueError) as e:
1778                 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1779         self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1780                       'expanding entry', str(e.exception))
1781
1782     def testHash(self):
1783         """Test hashing of the contents of an entry"""
1784         _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1785                 use_real_dtb=True, update_dtb=True)
1786         dtb = fdt.Fdt(out_dtb_fname)
1787         dtb.Scan()
1788         hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1789         m = hashlib.sha256()
1790         m.update(U_BOOT_DATA)
1791         self.assertEqual(m.digest(), b''.join(hash_node.value))
1792
1793     def testHashNoAlgo(self):
1794         with self.assertRaises(ValueError) as e:
1795             self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1796         self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1797                       'hash node', str(e.exception))
1798
1799     def testHashBadAlgo(self):
1800         with self.assertRaises(ValueError) as e:
1801             self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1802         self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1803                       str(e.exception))
1804
1805     def testHashSection(self):
1806         """Test hashing of the contents of an entry"""
1807         _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1808                 use_real_dtb=True, update_dtb=True)
1809         dtb = fdt.Fdt(out_dtb_fname)
1810         dtb.Scan()
1811         hash_node = dtb.GetNode('/binman/section/hash').props['value']
1812         m = hashlib.sha256()
1813         m.update(U_BOOT_DATA)
1814         m.update(tools.GetBytes(ord('a'), 16))
1815         self.assertEqual(m.digest(), b''.join(hash_node.value))
1816
1817     def testPackUBootTplMicrocode(self):
1818         """Test that x86 microcode can be handled correctly in TPL
1819
1820         We expect to see the following in the image, in order:
1821             u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1822                 place
1823             u-boot-tpl.dtb with the microcode removed
1824             the microcode
1825         """
1826         self._SetupTplElf('u_boot_ucode_ptr')
1827         first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1828                                                      U_BOOT_TPL_NODTB_DATA)
1829         self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1830                          b'ter somewhere in here', first)
1831
1832     def testFmapX86(self):
1833         """Basic test of generation of a flashrom fmap"""
1834         data = self._DoReadFile('094_fmap_x86.dts')
1835         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1836         expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1837         self.assertEqual(expected, data[:32])
1838         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1839
1840         self.assertEqual(0x100, fhdr.image_size)
1841
1842         self.assertEqual(0, fentries[0].offset)
1843         self.assertEqual(4, fentries[0].size)
1844         self.assertEqual(b'U_BOOT', fentries[0].name)
1845
1846         self.assertEqual(4, fentries[1].offset)
1847         self.assertEqual(3, fentries[1].size)
1848         self.assertEqual(b'INTEL_MRC', fentries[1].name)
1849
1850         self.assertEqual(32, fentries[2].offset)
1851         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1852                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1853         self.assertEqual(b'FMAP', fentries[2].name)
1854
1855     def testFmapX86Section(self):
1856         """Basic test of generation of a flashrom fmap"""
1857         data = self._DoReadFile('095_fmap_x86_section.dts')
1858         expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1859         self.assertEqual(expected, data[:32])
1860         fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1861
1862         self.assertEqual(0x100, fhdr.image_size)
1863
1864         self.assertEqual(0, fentries[0].offset)
1865         self.assertEqual(4, fentries[0].size)
1866         self.assertEqual(b'U_BOOT', fentries[0].name)
1867
1868         self.assertEqual(4, fentries[1].offset)
1869         self.assertEqual(3, fentries[1].size)
1870         self.assertEqual(b'INTEL_MRC', fentries[1].name)
1871
1872         self.assertEqual(36, fentries[2].offset)
1873         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1874                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1875         self.assertEqual(b'FMAP', fentries[2].name)
1876
1877     def testElf(self):
1878         """Basic test of ELF entries"""
1879         self._SetupSplElf()
1880         self._SetupTplElf()
1881         with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1882             TestFunctional._MakeInputFile('-boot', fd.read())
1883         data = self._DoReadFile('096_elf.dts')
1884
1885     def testElfStrip(self):
1886         """Basic test of ELF entries"""
1887         self._SetupSplElf()
1888         with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1889             TestFunctional._MakeInputFile('-boot', fd.read())
1890         data = self._DoReadFile('097_elf_strip.dts')
1891
1892     def testPackOverlapMap(self):
1893         """Test that overlapping regions are detected"""
1894         with test_util.capture_sys_output() as (stdout, stderr):
1895             with self.assertRaises(ValueError) as e:
1896                 self._DoTestFile('014_pack_overlap.dts', map=True)
1897         map_fname = tools.GetOutputFilename('image.map')
1898         self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1899                          stdout.getvalue())
1900
1901         # We should not get an inmage, but there should be a map file
1902         self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1903         self.assertTrue(os.path.exists(map_fname))
1904         map_data = tools.ReadFile(map_fname, binary=False)
1905         self.assertEqual('''ImagePos    Offset      Size  Name
1906 <none>    00000000  00000007  main-section
1907 <none>     00000000  00000004  u-boot
1908 <none>     00000003  00000004  u-boot-align
1909 ''', map_data)
1910
1911     def testPackRefCode(self):
1912         """Test that an image with an Intel Reference code binary works"""
1913         data = self._DoReadFile('100_intel_refcode.dts')
1914         self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1915
1916     def testSectionOffset(self):
1917         """Tests use of a section with an offset"""
1918         data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1919                                                    map=True)
1920         self.assertEqual('''ImagePos    Offset      Size  Name
1921 00000000  00000000  00000038  main-section
1922 00000004   00000004  00000010  section@0
1923 00000004    00000000  00000004  u-boot
1924 00000018   00000018  00000010  section@1
1925 00000018    00000000  00000004  u-boot
1926 0000002c   0000002c  00000004  section@2
1927 0000002c    00000000  00000004  u-boot
1928 ''', map_data)
1929         self.assertEqual(data,
1930                          tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1931                              tools.GetBytes(0x21, 12) +
1932                          tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1933                              tools.GetBytes(0x61, 12) +
1934                          tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1935                              tools.GetBytes(0x26, 8))
1936
1937     def testCbfsRaw(self):
1938         """Test base handling of a Coreboot Filesystem (CBFS)
1939
1940         The exact contents of the CBFS is verified by similar tests in
1941         cbfs_util_test.py. The tests here merely check that the files added to
1942         the CBFS can be found in the final image.
1943         """
1944         data = self._DoReadFile('102_cbfs_raw.dts')
1945         size = 0xb0
1946
1947         cbfs = cbfs_util.CbfsReader(data)
1948         self.assertEqual(size, cbfs.rom_size)
1949
1950         self.assertIn('u-boot-dtb', cbfs.files)
1951         cfile = cbfs.files['u-boot-dtb']
1952         self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1953
1954     def testCbfsArch(self):
1955         """Test on non-x86 architecture"""
1956         data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1957         size = 0x100
1958
1959         cbfs = cbfs_util.CbfsReader(data)
1960         self.assertEqual(size, cbfs.rom_size)
1961
1962         self.assertIn('u-boot-dtb', cbfs.files)
1963         cfile = cbfs.files['u-boot-dtb']
1964         self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1965
1966     def testCbfsStage(self):
1967         """Tests handling of a Coreboot Filesystem (CBFS)"""
1968         if not elf.ELF_TOOLS:
1969             self.skipTest('Python elftools not available')
1970         elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1971         elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1972         size = 0xb0
1973
1974         data = self._DoReadFile('104_cbfs_stage.dts')
1975         cbfs = cbfs_util.CbfsReader(data)
1976         self.assertEqual(size, cbfs.rom_size)
1977
1978         self.assertIn('u-boot', cbfs.files)
1979         cfile = cbfs.files['u-boot']
1980         self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1981
1982     def testCbfsRawCompress(self):
1983         """Test handling of compressing raw files"""
1984         self._CheckLz4()
1985         data = self._DoReadFile('105_cbfs_raw_compress.dts')
1986         size = 0x140
1987
1988         cbfs = cbfs_util.CbfsReader(data)
1989         self.assertIn('u-boot', cbfs.files)
1990         cfile = cbfs.files['u-boot']
1991         self.assertEqual(COMPRESS_DATA, cfile.data)
1992
1993     def testCbfsBadArch(self):
1994         """Test handling of a bad architecture"""
1995         with self.assertRaises(ValueError) as e:
1996             self._DoReadFile('106_cbfs_bad_arch.dts')
1997         self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1998
1999     def testCbfsNoSize(self):
2000         """Test handling of a missing size property"""
2001         with self.assertRaises(ValueError) as e:
2002             self._DoReadFile('107_cbfs_no_size.dts')
2003         self.assertIn('entry must have a size property', str(e.exception))
2004
2005     def testCbfsNoCOntents(self):
2006         """Test handling of a CBFS entry which does not provide contentsy"""
2007         with self.assertRaises(ValueError) as e:
2008             self._DoReadFile('108_cbfs_no_contents.dts')
2009         self.assertIn('Could not complete processing of contents',
2010                       str(e.exception))
2011
2012     def testCbfsBadCompress(self):
2013         """Test handling of a bad architecture"""
2014         with self.assertRaises(ValueError) as e:
2015             self._DoReadFile('109_cbfs_bad_compress.dts')
2016         self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2017                       str(e.exception))
2018
2019     def testCbfsNamedEntries(self):
2020         """Test handling of named entries"""
2021         data = self._DoReadFile('110_cbfs_name.dts')
2022
2023         cbfs = cbfs_util.CbfsReader(data)
2024         self.assertIn('FRED', cbfs.files)
2025         cfile1 = cbfs.files['FRED']
2026         self.assertEqual(U_BOOT_DATA, cfile1.data)
2027
2028         self.assertIn('hello', cbfs.files)
2029         cfile2 = cbfs.files['hello']
2030         self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2031
2032     def _SetupIfwi(self, fname):
2033         """Set up to run an IFWI test
2034
2035         Args:
2036             fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2037         """
2038         self._SetupSplElf()
2039         self._SetupTplElf()
2040
2041         # Intel Integrated Firmware Image (IFWI) file
2042         with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2043             data = fd.read()
2044         TestFunctional._MakeInputFile(fname,data)
2045
2046     def _CheckIfwi(self, data):
2047         """Check that an image with an IFWI contains the correct output
2048
2049         Args:
2050             data: Conents of output file
2051         """
2052         expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2053         if data[:0x1000] != expected_desc:
2054             self.fail('Expected descriptor binary at start of image')
2055
2056         # We expect to find the TPL wil in subpart IBBP entry IBBL
2057         image_fname = tools.GetOutputFilename('image.bin')
2058         tpl_fname = tools.GetOutputFilename('tpl.out')
2059         tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2060                           subpart='IBBP', entry_name='IBBL')
2061
2062         tpl_data = tools.ReadFile(tpl_fname)
2063         self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2064
2065     def testPackX86RomIfwi(self):
2066         """Test that an x86 ROM with Integrated Firmware Image can be created"""
2067         self._SetupIfwi('fitimage.bin')
2068         data = self._DoReadFile('111_x86-rom-ifwi.dts')
2069         self._CheckIfwi(data)
2070
2071     def testPackX86RomIfwiNoDesc(self):
2072         """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2073         self._SetupIfwi('ifwi.bin')
2074         data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2075         self._CheckIfwi(data)
2076
2077     def testPackX86RomIfwiNoData(self):
2078         """Test that an x86 ROM with IFWI handles missing data"""
2079         self._SetupIfwi('ifwi.bin')
2080         with self.assertRaises(ValueError) as e:
2081             data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2082         self.assertIn('Could not complete processing of contents',
2083                       str(e.exception))
2084
2085     def testCbfsOffset(self):
2086         """Test a CBFS with files at particular offsets
2087
2088         Like all CFBS tests, this is just checking the logic that calls
2089         cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2090         """
2091         data = self._DoReadFile('114_cbfs_offset.dts')
2092         size = 0x200
2093
2094         cbfs = cbfs_util.CbfsReader(data)
2095         self.assertEqual(size, cbfs.rom_size)
2096
2097         self.assertIn('u-boot', cbfs.files)
2098         cfile = cbfs.files['u-boot']
2099         self.assertEqual(U_BOOT_DATA, cfile.data)
2100         self.assertEqual(0x40, cfile.cbfs_offset)
2101
2102         self.assertIn('u-boot-dtb', cbfs.files)
2103         cfile2 = cbfs.files['u-boot-dtb']
2104         self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2105         self.assertEqual(0x140, cfile2.cbfs_offset)
2106
2107     def testFdtmap(self):
2108         """Test an FDT map can be inserted in the image"""
2109         data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2110         fdtmap_data = data[len(U_BOOT_DATA):]
2111         magic = fdtmap_data[:8]
2112         self.assertEqual('_FDTMAP_', magic)
2113         self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2114
2115         fdt_data = fdtmap_data[16:]
2116         dtb = fdt.Fdt.FromData(fdt_data)
2117         dtb.Scan()
2118         props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2119         self.assertEqual({
2120             'image-pos': 0,
2121             'offset': 0,
2122             'u-boot:offset': 0,
2123             'u-boot:size': len(U_BOOT_DATA),
2124             'u-boot:image-pos': 0,
2125             'fdtmap:image-pos': 4,
2126             'fdtmap:offset': 4,
2127             'fdtmap:size': len(fdtmap_data),
2128             'size': len(data),
2129         }, props)
2130
2131     def testFdtmapNoMatch(self):
2132         """Check handling of an FDT map when the section cannot be found"""
2133         self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2134
2135         # Mangle the section name, which should cause a mismatch between the
2136         # correct FDT path and the one expected by the section
2137         image = control.images['image']
2138         image._node.path += '-suffix'
2139         entries = image.GetEntries()
2140         fdtmap = entries['fdtmap']
2141         with self.assertRaises(ValueError) as e:
2142             fdtmap._GetFdtmap()
2143         self.assertIn("Cannot locate node for path '/binman-suffix'",
2144                       str(e.exception))
2145
2146     def testFdtmapHeader(self):
2147         """Test an FDT map and image header can be inserted in the image"""
2148         data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2149         fdtmap_pos = len(U_BOOT_DATA)
2150         fdtmap_data = data[fdtmap_pos:]
2151         fdt_data = fdtmap_data[16:]
2152         dtb = fdt.Fdt.FromData(fdt_data)
2153         fdt_size = dtb.GetFdtObj().totalsize()
2154         hdr_data = data[-8:]
2155         self.assertEqual('BinM', hdr_data[:4])
2156         offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2157         self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2158
2159     def testFdtmapHeaderStart(self):
2160         """Test an image header can be inserted at the image start"""
2161         data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2162         fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2163         hdr_data = data[:8]
2164         self.assertEqual('BinM', hdr_data[:4])
2165         offset = struct.unpack('<I', hdr_data[4:])[0]
2166         self.assertEqual(fdtmap_pos, offset)
2167
2168     def testFdtmapHeaderPos(self):
2169         """Test an image header can be inserted at a chosen position"""
2170         data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2171         fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2172         hdr_data = data[0x80:0x88]
2173         self.assertEqual('BinM', hdr_data[:4])
2174         offset = struct.unpack('<I', hdr_data[4:])[0]
2175         self.assertEqual(fdtmap_pos, offset)
2176
2177     def testHeaderMissingFdtmap(self):
2178         """Test an image header requires an fdtmap"""
2179         with self.assertRaises(ValueError) as e:
2180             self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2181         self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2182                       str(e.exception))
2183
2184     def testHeaderNoLocation(self):
2185         """Test an image header with a no specified location is detected"""
2186         with self.assertRaises(ValueError) as e:
2187             self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2188         self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2189                       str(e.exception))
2190
2191     def testEntryExpand(self):
2192         """Test expanding an entry after it is packed"""
2193         data = self._DoReadFile('121_entry_expand.dts')
2194         self.assertEqual(b'aaa', data[:3])
2195         self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2196         self.assertEqual(b'aaa', data[-3:])
2197
2198     def testEntryExpandBad(self):
2199         """Test expanding an entry after it is packed, twice"""
2200         with self.assertRaises(ValueError) as e:
2201             self._DoReadFile('122_entry_expand_twice.dts')
2202         self.assertIn("Image '/binman': Entries changed size after packing",
2203                       str(e.exception))
2204
2205     def testEntryExpandSection(self):
2206         """Test expanding an entry within a section after it is packed"""
2207         data = self._DoReadFile('123_entry_expand_section.dts')
2208         self.assertEqual(b'aaa', data[:3])
2209         self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2210         self.assertEqual(b'aaa', data[-3:])
2211
2212     def testCompressDtb(self):
2213         """Test that compress of device-tree files is supported"""
2214         self._CheckLz4()
2215         data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2216         self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2217         comp_data = data[len(U_BOOT_DATA):]
2218         orig = self._decompress(comp_data)
2219         dtb = fdt.Fdt.FromData(orig)
2220         dtb.Scan()
2221         props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2222         expected = {
2223             'u-boot:size': len(U_BOOT_DATA),
2224             'u-boot-dtb:uncomp-size': len(orig),
2225             'u-boot-dtb:size': len(comp_data),
2226             'size': len(data),
2227             }
2228         self.assertEqual(expected, props)
2229
2230     def testCbfsUpdateFdt(self):
2231         """Test that we can update the device tree with CBFS offset/size info"""
2232         self._CheckLz4()
2233         data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2234                                                         update_dtb=True)
2235         dtb = fdt.Fdt(out_dtb_fname)
2236         dtb.Scan()
2237         props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2238         del props['cbfs/u-boot:size']
2239         self.assertEqual({
2240             'offset': 0,
2241             'size': len(data),
2242             'image-pos': 0,
2243             'cbfs:offset': 0,
2244             'cbfs:size': len(data),
2245             'cbfs:image-pos': 0,
2246             'cbfs/u-boot:offset': 0x38,
2247             'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2248             'cbfs/u-boot:image-pos': 0x38,
2249             'cbfs/u-boot-dtb:offset': 0xb8,
2250             'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2251             'cbfs/u-boot-dtb:image-pos': 0xb8,
2252             }, props)
2253
2254     def testCbfsBadType(self):
2255         """Test an image header with a no specified location is detected"""
2256         with self.assertRaises(ValueError) as e:
2257             self._DoReadFile('126_cbfs_bad_type.dts')
2258         self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2259
2260     def testList(self):
2261         """Test listing the files in an image"""
2262         self._CheckLz4()
2263         data = self._DoReadFile('127_list.dts')
2264         image = control.images['image']
2265         entries = image.BuildEntryList()
2266         self.assertEqual(7, len(entries))
2267
2268         ent = entries[0]
2269         self.assertEqual(0, ent.indent)
2270         self.assertEqual('main-section', ent.name)
2271         self.assertEqual('section', ent.etype)
2272         self.assertEqual(len(data), ent.size)
2273         self.assertEqual(0, ent.image_pos)
2274         self.assertEqual(None, ent.uncomp_size)
2275         self.assertEqual(0, ent.offset)
2276
2277         ent = entries[1]
2278         self.assertEqual(1, ent.indent)
2279         self.assertEqual('u-boot', ent.name)
2280         self.assertEqual('u-boot', ent.etype)
2281         self.assertEqual(len(U_BOOT_DATA), ent.size)
2282         self.assertEqual(0, ent.image_pos)
2283         self.assertEqual(None, ent.uncomp_size)
2284         self.assertEqual(0, ent.offset)
2285
2286         ent = entries[2]
2287         self.assertEqual(1, ent.indent)
2288         self.assertEqual('section', ent.name)
2289         self.assertEqual('section', ent.etype)
2290         section_size = ent.size
2291         self.assertEqual(0x100, ent.image_pos)
2292         self.assertEqual(None, ent.uncomp_size)
2293         self.assertEqual(0x100, ent.offset)
2294
2295         ent = entries[3]
2296         self.assertEqual(2, ent.indent)
2297         self.assertEqual('cbfs', ent.name)
2298         self.assertEqual('cbfs', ent.etype)
2299         self.assertEqual(0x400, ent.size)
2300         self.assertEqual(0x100, ent.image_pos)
2301         self.assertEqual(None, ent.uncomp_size)
2302         self.assertEqual(0, ent.offset)
2303
2304         ent = entries[4]
2305         self.assertEqual(3, ent.indent)
2306         self.assertEqual('u-boot', ent.name)
2307         self.assertEqual('u-boot', ent.etype)
2308         self.assertEqual(len(U_BOOT_DATA), ent.size)
2309         self.assertEqual(0x138, ent.image_pos)
2310         self.assertEqual(None, ent.uncomp_size)
2311         self.assertEqual(0x38, ent.offset)
2312
2313         ent = entries[5]
2314         self.assertEqual(3, ent.indent)
2315         self.assertEqual('u-boot-dtb', ent.name)
2316         self.assertEqual('text', ent.etype)
2317         self.assertGreater(len(COMPRESS_DATA), ent.size)
2318         self.assertEqual(0x178, ent.image_pos)
2319         self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2320         self.assertEqual(0x78, ent.offset)
2321
2322         ent = entries[6]
2323         self.assertEqual(2, ent.indent)
2324         self.assertEqual('u-boot-dtb', ent.name)
2325         self.assertEqual('u-boot-dtb', ent.etype)
2326         self.assertEqual(0x500, ent.image_pos)
2327         self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2328         dtb_size = ent.size
2329         # Compressing this data expands it since headers are added
2330         self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2331         self.assertEqual(0x400, ent.offset)
2332
2333         self.assertEqual(len(data), 0x100 + section_size)
2334         self.assertEqual(section_size, 0x400 + dtb_size)
2335
2336     def testFindFdtmap(self):
2337         """Test locating an FDT map in an image"""
2338         self._CheckLz4()
2339         data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2340         image = control.images['image']
2341         entries = image.GetEntries()
2342         entry = entries['fdtmap']
2343         self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2344
2345     def testFindFdtmapMissing(self):
2346         """Test failing to locate an FDP map"""
2347         data = self._DoReadFile('005_simple.dts')
2348         self.assertEqual(None, fdtmap.LocateFdtmap(data))
2349
2350     def testFindImageHeader(self):
2351         """Test locating a image header"""
2352         self._CheckLz4()
2353         data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2354         image = control.images['image']
2355         entries = image.GetEntries()
2356         entry = entries['fdtmap']
2357         # The header should point to the FDT map
2358         self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2359
2360     def testFindImageHeaderStart(self):
2361         """Test locating a image header located at the start of an image"""
2362         data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2363         image = control.images['image']
2364         entries = image.GetEntries()
2365         entry = entries['fdtmap']
2366         # The header should point to the FDT map
2367         self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2368
2369     def testFindImageHeaderMissing(self):
2370         """Test failing to locate an image header"""
2371         data = self._DoReadFile('005_simple.dts')
2372         self.assertEqual(None, image_header.LocateHeaderOffset(data))
2373
2374     def testReadImage(self):
2375         """Test reading an image and accessing its FDT map"""
2376         self._CheckLz4()
2377         data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2378         image_fname = tools.GetOutputFilename('image.bin')
2379         orig_image = control.images['image']
2380         image = Image.FromFile(image_fname)
2381         self.assertEqual(orig_image.GetEntries().keys(),
2382                          image.GetEntries().keys())
2383
2384         orig_entry = orig_image.GetEntries()['fdtmap']
2385         entry = image.GetEntries()['fdtmap']
2386         self.assertEquals(orig_entry.offset, entry.offset)
2387         self.assertEquals(orig_entry.size, entry.size)
2388         self.assertEquals(orig_entry.image_pos, entry.image_pos)
2389
2390     def testReadImageNoHeader(self):
2391         """Test accessing an image's FDT map without an image header"""
2392         self._CheckLz4()
2393         data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2394         image_fname = tools.GetOutputFilename('image.bin')
2395         image = Image.FromFile(image_fname)
2396         self.assertTrue(isinstance(image, Image))
2397         self.assertEqual('image', image.image_name[-5:])
2398
2399     def testReadImageFail(self):
2400         """Test failing to read an image image's FDT map"""
2401         self._DoReadFile('005_simple.dts')
2402         image_fname = tools.GetOutputFilename('image.bin')
2403         with self.assertRaises(ValueError) as e:
2404             image = Image.FromFile(image_fname)
2405         self.assertIn("Cannot find FDT map in image", str(e.exception))
2406
2407     def testListCmd(self):
2408         """Test listing the files in an image using an Fdtmap"""
2409         self._CheckLz4()
2410         data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2411
2412         # lz4 compression size differs depending on the version
2413         image = control.images['image']
2414         entries = image.GetEntries()
2415         section_size = entries['section'].size
2416         fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2417         fdtmap_offset = entries['fdtmap'].offset
2418
2419         try:
2420             tmpdir, updated_fname = self._SetupImageInTmpdir()
2421             with test_util.capture_sys_output() as (stdout, stderr):
2422                 self._DoBinman('ls', '-i', updated_fname)
2423         finally:
2424             shutil.rmtree(tmpdir)
2425         lines = stdout.getvalue().splitlines()
2426         expected = [
2427 'Name              Image-pos  Size  Entry-type    Offset  Uncomp-size',
2428 '----------------------------------------------------------------------',
2429 'main-section              0   c00  section            0',
2430 '  u-boot                  0     4  u-boot             0',
2431 '  section               100   %x  section          100' % section_size,
2432 '    cbfs                100   400  cbfs               0',
2433 '      u-boot            138     4  u-boot            38',
2434 '      u-boot-dtb        180   10f  u-boot-dtb        80          3c9',
2435 '    u-boot-dtb          500   %x  u-boot-dtb       400          3c9' % fdt_size,
2436 '  fdtmap                %x   3b4  fdtmap           %x' %
2437         (fdtmap_offset, fdtmap_offset),
2438 '  image-header          bf8     8  image-header     bf8',
2439             ]
2440         self.assertEqual(expected, lines)
2441
2442     def testListCmdFail(self):
2443         """Test failing to list an image"""
2444         self._DoReadFile('005_simple.dts')
2445         try:
2446             tmpdir, updated_fname = self._SetupImageInTmpdir()
2447             with self.assertRaises(ValueError) as e:
2448                 self._DoBinman('ls', '-i', updated_fname)
2449         finally:
2450             shutil.rmtree(tmpdir)
2451         self.assertIn("Cannot find FDT map in image", str(e.exception))
2452
2453     def _RunListCmd(self, paths, expected):
2454         """List out entries and check the result
2455
2456         Args:
2457             paths: List of paths to pass to the list command
2458             expected: Expected list of filenames to be returned, in order
2459         """
2460         self._CheckLz4()
2461         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2462         image_fname = tools.GetOutputFilename('image.bin')
2463         image = Image.FromFile(image_fname)
2464         lines = image.GetListEntries(paths)[1]
2465         files = [line[0].strip() for line in lines[1:]]
2466         self.assertEqual(expected, files)
2467
2468     def testListCmdSection(self):
2469         """Test listing the files in a section"""
2470         self._RunListCmd(['section'],
2471             ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2472
2473     def testListCmdFile(self):
2474         """Test listing a particular file"""
2475         self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2476
2477     def testListCmdWildcard(self):
2478         """Test listing a wildcarded file"""
2479         self._RunListCmd(['*boot*'],
2480             ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2481
2482     def testListCmdWildcardMulti(self):
2483         """Test listing a wildcarded file"""
2484         self._RunListCmd(['*cb*', '*head*'],
2485             ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2486
2487     def testListCmdEmpty(self):
2488         """Test listing a wildcarded file"""
2489         self._RunListCmd(['nothing'], [])
2490
2491     def testListCmdPath(self):
2492         """Test listing the files in a sub-entry of a section"""
2493         self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2494
2495     def _RunExtractCmd(self, entry_name, decomp=True):
2496         """Extract an entry from an image
2497
2498         Args:
2499             entry_name: Entry name to extract
2500             decomp: True to decompress the data if compressed, False to leave
2501                 it in its raw uncompressed format
2502
2503         Returns:
2504             data from entry
2505         """
2506         self._CheckLz4()
2507         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2508         image_fname = tools.GetOutputFilename('image.bin')
2509         return control.ReadEntry(image_fname, entry_name, decomp)
2510
2511     def testExtractSimple(self):
2512         """Test extracting a single file"""
2513         data = self._RunExtractCmd('u-boot')
2514         self.assertEqual(U_BOOT_DATA, data)
2515
2516     def testExtractSection(self):
2517         """Test extracting the files in a section"""
2518         data = self._RunExtractCmd('section')
2519         cbfs_data = data[:0x400]
2520         cbfs = cbfs_util.CbfsReader(cbfs_data)
2521         self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2522         dtb_data = data[0x400:]
2523         dtb = self._decompress(dtb_data)
2524         self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2525
2526     def testExtractCompressed(self):
2527         """Test extracting compressed data"""
2528         data = self._RunExtractCmd('section/u-boot-dtb')
2529         self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2530
2531     def testExtractRaw(self):
2532         """Test extracting compressed data without decompressing it"""
2533         data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2534         dtb = self._decompress(data)
2535         self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2536
2537     def testExtractCbfs(self):
2538         """Test extracting CBFS data"""
2539         data = self._RunExtractCmd('section/cbfs/u-boot')
2540         self.assertEqual(U_BOOT_DATA, data)
2541
2542     def testExtractCbfsCompressed(self):
2543         """Test extracting CBFS compressed data"""
2544         data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2545         self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2546
2547     def testExtractCbfsRaw(self):
2548         """Test extracting CBFS compressed data without decompressing it"""
2549         data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2550         dtb = tools.Decompress(data, 'lzma', with_header=False)
2551         self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2552
2553     def testExtractBadEntry(self):
2554         """Test extracting a bad section path"""
2555         with self.assertRaises(ValueError) as e:
2556             self._RunExtractCmd('section/does-not-exist')
2557         self.assertIn("Entry 'does-not-exist' not found in '/section'",
2558                       str(e.exception))
2559
2560     def testExtractMissingFile(self):
2561         """Test extracting file that does not exist"""
2562         with self.assertRaises(IOError) as e:
2563             control.ReadEntry('missing-file', 'name')
2564
2565     def testExtractBadFile(self):
2566         """Test extracting an invalid file"""
2567         fname = os.path.join(self._indir, 'badfile')
2568         tools.WriteFile(fname, b'')
2569         with self.assertRaises(ValueError) as e:
2570             control.ReadEntry(fname, 'name')
2571
2572     def testExtractCmd(self):
2573         """Test extracting a file fron an image on the command line"""
2574         self._CheckLz4()
2575         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2576         fname = os.path.join(self._indir, 'output.extact')
2577         try:
2578             tmpdir, updated_fname = self._SetupImageInTmpdir()
2579             with test_util.capture_sys_output() as (stdout, stderr):
2580                 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2581                                '-f', fname)
2582         finally:
2583             shutil.rmtree(tmpdir)
2584         data = tools.ReadFile(fname)
2585         self.assertEqual(U_BOOT_DATA, data)
2586
2587     def testExtractOneEntry(self):
2588         """Test extracting a single entry fron an image """
2589         self._CheckLz4()
2590         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2591         image_fname = tools.GetOutputFilename('image.bin')
2592         fname = os.path.join(self._indir, 'output.extact')
2593         control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2594         data = tools.ReadFile(fname)
2595         self.assertEqual(U_BOOT_DATA, data)
2596
2597     def _CheckExtractOutput(self, decomp):
2598         """Helper to test file output with and without decompression
2599
2600         Args:
2601             decomp: True to decompress entry data, False to output it raw
2602         """
2603         def _CheckPresent(entry_path, expect_data, expect_size=None):
2604             """Check and remove expected file
2605
2606             This checks the data/size of a file and removes the file both from
2607             the outfiles set and from the output directory. Once all files are
2608             processed, both the set and directory should be empty.
2609
2610             Args:
2611                 entry_path: Entry path
2612                 expect_data: Data to expect in file, or None to skip check
2613                 expect_size: Size of data to expect in file, or None to skip
2614             """
2615             path = os.path.join(outdir, entry_path)
2616             data = tools.ReadFile(path)
2617             os.remove(path)
2618             if expect_data:
2619                 self.assertEqual(expect_data, data)
2620             elif expect_size:
2621                 self.assertEqual(expect_size, len(data))
2622             outfiles.remove(path)
2623
2624         def _CheckDirPresent(name):
2625             """Remove expected directory
2626
2627             This gives an error if the directory does not exist as expected
2628
2629             Args:
2630                 name: Name of directory to remove
2631             """
2632             path = os.path.join(outdir, name)
2633             os.rmdir(path)
2634
2635         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2636         image_fname = tools.GetOutputFilename('image.bin')
2637         outdir = os.path.join(self._indir, 'extract')
2638         einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2639
2640         # Create a set of all file that were output (should be 9)
2641         outfiles = set()
2642         for root, dirs, files in os.walk(outdir):
2643             outfiles |= set([os.path.join(root, fname) for fname in files])
2644         self.assertEqual(9, len(outfiles))
2645         self.assertEqual(9, len(einfos))
2646
2647         image = control.images['image']
2648         entries = image.GetEntries()
2649
2650         # Check the 9 files in various ways
2651         section = entries['section']
2652         section_entries = section.GetEntries()
2653         cbfs_entries = section_entries['cbfs'].GetEntries()
2654         _CheckPresent('u-boot', U_BOOT_DATA)
2655         _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2656         dtb_len = EXTRACT_DTB_SIZE
2657         if not decomp:
2658             dtb_len = cbfs_entries['u-boot-dtb'].size
2659         _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2660         if not decomp:
2661             dtb_len = section_entries['u-boot-dtb'].size
2662         _CheckPresent('section/u-boot-dtb', None, dtb_len)
2663
2664         fdtmap = entries['fdtmap']
2665         _CheckPresent('fdtmap', fdtmap.data)
2666         hdr = entries['image-header']
2667         _CheckPresent('image-header', hdr.data)
2668
2669         _CheckPresent('section/root', section.data)
2670         cbfs = section_entries['cbfs']
2671         _CheckPresent('section/cbfs/root', cbfs.data)
2672         data = tools.ReadFile(image_fname)
2673         _CheckPresent('root', data)
2674
2675         # There should be no files left. Remove all the directories to check.
2676         # If there are any files/dirs remaining, one of these checks will fail.
2677         self.assertEqual(0, len(outfiles))
2678         _CheckDirPresent('section/cbfs')
2679         _CheckDirPresent('section')
2680         _CheckDirPresent('')
2681         self.assertFalse(os.path.exists(outdir))
2682
2683     def testExtractAllEntries(self):
2684         """Test extracting all entries"""
2685         self._CheckLz4()
2686         self._CheckExtractOutput(decomp=True)
2687
2688     def testExtractAllEntriesRaw(self):
2689         """Test extracting all entries without decompressing them"""
2690         self._CheckLz4()
2691         self._CheckExtractOutput(decomp=False)
2692
2693     def testExtractSelectedEntries(self):
2694         """Test extracting some entries"""
2695         self._CheckLz4()
2696         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2697         image_fname = tools.GetOutputFilename('image.bin')
2698         outdir = os.path.join(self._indir, 'extract')
2699         einfos = control.ExtractEntries(image_fname, None, outdir,
2700                                         ['*cb*', '*head*'])
2701
2702         # File output is tested by testExtractAllEntries(), so just check that
2703         # the expected entries are selected
2704         names = [einfo.name for einfo in einfos]
2705         self.assertEqual(names,
2706                          ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2707
2708     def testExtractNoEntryPaths(self):
2709         """Test extracting some entries"""
2710         self._CheckLz4()
2711         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2712         image_fname = tools.GetOutputFilename('image.bin')
2713         with self.assertRaises(ValueError) as e:
2714             control.ExtractEntries(image_fname, 'fname', None, [])
2715         self.assertIn('Must specify an entry path to write with -f',
2716                       str(e.exception))
2717
2718     def testExtractTooManyEntryPaths(self):
2719         """Test extracting some entries"""
2720         self._CheckLz4()
2721         self._DoReadFileRealDtb('130_list_fdtmap.dts')
2722         image_fname = tools.GetOutputFilename('image.bin')
2723         with self.assertRaises(ValueError) as e:
2724             control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2725         self.assertIn('Must specify exactly one entry path to write with -f',
2726                       str(e.exception))
2727
2728     def testPackAlignSection(self):
2729         """Test that sections can have alignment"""
2730         self._DoReadFile('131_pack_align_section.dts')
2731
2732         self.assertIn('image', control.images)
2733         image = control.images['image']
2734         entries = image.GetEntries()
2735         self.assertEqual(3, len(entries))
2736
2737         # First u-boot
2738         self.assertIn('u-boot', entries)
2739         entry = entries['u-boot']
2740         self.assertEqual(0, entry.offset)
2741         self.assertEqual(0, entry.image_pos)
2742         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2743         self.assertEqual(len(U_BOOT_DATA), entry.size)
2744
2745         # Section0
2746         self.assertIn('section0', entries)
2747         section0 = entries['section0']
2748         self.assertEqual(0x10, section0.offset)
2749         self.assertEqual(0x10, section0.image_pos)
2750         self.assertEqual(len(U_BOOT_DATA), section0.size)
2751
2752         # Second u-boot
2753         section_entries = section0.GetEntries()
2754         self.assertIn('u-boot', section_entries)
2755         entry = section_entries['u-boot']
2756         self.assertEqual(0, entry.offset)
2757         self.assertEqual(0x10, entry.image_pos)
2758         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2759         self.assertEqual(len(U_BOOT_DATA), entry.size)
2760
2761         # Section1
2762         self.assertIn('section1', entries)
2763         section1 = entries['section1']
2764         self.assertEqual(0x14, section1.offset)
2765         self.assertEqual(0x14, section1.image_pos)
2766         self.assertEqual(0x20, section1.size)
2767
2768         # Second u-boot
2769         section_entries = section1.GetEntries()
2770         self.assertIn('u-boot', section_entries)
2771         entry = section_entries['u-boot']
2772         self.assertEqual(0, entry.offset)
2773         self.assertEqual(0x14, entry.image_pos)
2774         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2775         self.assertEqual(len(U_BOOT_DATA), entry.size)
2776
2777         # Section2
2778         self.assertIn('section2', section_entries)
2779         section2 = section_entries['section2']
2780         self.assertEqual(0x4, section2.offset)
2781         self.assertEqual(0x18, section2.image_pos)
2782         self.assertEqual(4, section2.size)
2783
2784         # Third u-boot
2785         section_entries = section2.GetEntries()
2786         self.assertIn('u-boot', section_entries)
2787         entry = section_entries['u-boot']
2788         self.assertEqual(0, entry.offset)
2789         self.assertEqual(0x18, entry.image_pos)
2790         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2791         self.assertEqual(len(U_BOOT_DATA), entry.size)
2792
2793     def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2794                        dts='132_replace.dts'):
2795         """Replace an entry in an image
2796
2797         This writes the entry data to update it, then opens the updated file and
2798         returns the value that it now finds there.
2799
2800         Args:
2801             entry_name: Entry name to replace
2802             data: Data to replace it with
2803             decomp: True to compress the data if needed, False if data is
2804                 already compressed so should be used as is
2805             allow_resize: True to allow entries to change size, False to raise
2806                 an exception
2807
2808         Returns:
2809             Tuple:
2810                 data from entry
2811                 data from fdtmap (excluding header)
2812                 Image object that was modified
2813         """
2814         dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2815                                        update_dtb=True)[1]
2816
2817         self.assertIn('image', control.images)
2818         image = control.images['image']
2819         entries = image.GetEntries()
2820         orig_dtb_data = entries['u-boot-dtb'].data
2821         orig_fdtmap_data = entries['fdtmap'].data
2822
2823         image_fname = tools.GetOutputFilename('image.bin')
2824         updated_fname = tools.GetOutputFilename('image-updated.bin')
2825         tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2826         image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2827                                    allow_resize)
2828         data = control.ReadEntry(updated_fname, entry_name, decomp)
2829
2830         # The DT data should not change unless resized:
2831         if not allow_resize:
2832             new_dtb_data = entries['u-boot-dtb'].data
2833             self.assertEqual(new_dtb_data, orig_dtb_data)
2834             new_fdtmap_data = entries['fdtmap'].data
2835             self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2836
2837         return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2838
2839     def testReplaceSimple(self):
2840         """Test replacing a single file"""
2841         expected = b'x' * len(U_BOOT_DATA)
2842         data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2843                                                     allow_resize=False)
2844         self.assertEqual(expected, data)
2845
2846         # Test that the state looks right. There should be an FDT for the fdtmap
2847         # that we jsut read back in, and it should match what we find in the
2848         # 'control' tables. Checking for an FDT that does not exist should
2849         # return None.
2850         path, fdtmap = state.GetFdtContents('fdtmap')
2851         self.assertIsNotNone(path)
2852         self.assertEqual(expected_fdtmap, fdtmap)
2853
2854         dtb = state.GetFdtForEtype('fdtmap')
2855         self.assertEqual(dtb.GetContents(), fdtmap)
2856
2857         missing_path, missing_fdtmap = state.GetFdtContents('missing')
2858         self.assertIsNone(missing_path)
2859         self.assertIsNone(missing_fdtmap)
2860
2861         missing_dtb = state.GetFdtForEtype('missing')
2862         self.assertIsNone(missing_dtb)
2863
2864         self.assertEqual('/binman', state.fdt_path_prefix)
2865
2866     def testReplaceResizeFail(self):
2867         """Test replacing a file by something larger"""
2868         expected = U_BOOT_DATA + b'x'
2869         with self.assertRaises(ValueError) as e:
2870             self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2871                                 dts='139_replace_repack.dts')
2872         self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2873                       str(e.exception))
2874
2875     def testReplaceMulti(self):
2876         """Test replacing entry data where multiple images are generated"""
2877         data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2878                                    update_dtb=True)[0]
2879         expected = b'x' * len(U_BOOT_DATA)
2880         updated_fname = tools.GetOutputFilename('image-updated.bin')
2881         tools.WriteFile(updated_fname, data)
2882         entry_name = 'u-boot'
2883         control.WriteEntry(updated_fname, entry_name, expected,
2884                            allow_resize=False)
2885         data = control.ReadEntry(updated_fname, entry_name)
2886         self.assertEqual(expected, data)
2887
2888         # Check the state looks right.
2889         self.assertEqual('/binman/image', state.fdt_path_prefix)
2890
2891         # Now check we can write the first image
2892         image_fname = tools.GetOutputFilename('first-image.bin')
2893         updated_fname = tools.GetOutputFilename('first-updated.bin')
2894         tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2895         entry_name = 'u-boot'
2896         control.WriteEntry(updated_fname, entry_name, expected,
2897                            allow_resize=False)
2898         data = control.ReadEntry(updated_fname, entry_name)
2899         self.assertEqual(expected, data)
2900
2901         # Check the state looks right.
2902         self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2903
2904     def testUpdateFdtAllRepack(self):
2905         """Test that all device trees are updated with offset/size info"""
2906         data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2907         SECTION_SIZE = 0x300
2908         DTB_SIZE = 602
2909         FDTMAP_SIZE = 608
2910         base_expected = {
2911             'offset': 0,
2912             'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2913             'image-pos': 0,
2914             'section:offset': 0,
2915             'section:size': SECTION_SIZE,
2916             'section:image-pos': 0,
2917             'section/u-boot-dtb:offset': 4,
2918             'section/u-boot-dtb:size': 636,
2919             'section/u-boot-dtb:image-pos': 4,
2920             'u-boot-spl-dtb:offset': SECTION_SIZE,
2921             'u-boot-spl-dtb:size': DTB_SIZE,
2922             'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2923             'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2924             'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2925             'u-boot-tpl-dtb:size': DTB_SIZE,
2926             'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2927             'fdtmap:size': FDTMAP_SIZE,
2928             'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2929         }
2930         main_expected = {
2931             'section:orig-size': SECTION_SIZE,
2932             'section/u-boot-dtb:orig-offset': 4,
2933         }
2934
2935         # We expect three device-tree files in the output, with the first one
2936         # within a fixed-size section.
2937         # Read them in sequence. We look for an 'spl' property in the SPL tree,
2938         # and 'tpl' in the TPL tree, to make sure they are distinct from the
2939         # main U-Boot tree. All three should have the same positions and offset
2940         # except that the main tree should include the main_expected properties
2941         start = 4
2942         for item in ['', 'spl', 'tpl', None]:
2943             if item is None:
2944                 start += 16  # Move past fdtmap header
2945             dtb = fdt.Fdt.FromData(data[start:])
2946             dtb.Scan()
2947             props = self._GetPropTree(dtb,
2948                 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2949                 prefix='/' if item is None else '/binman/')
2950             expected = dict(base_expected)
2951             if item:
2952                 expected[item] = 0
2953             else:
2954                 # Main DTB and fdtdec should include the 'orig-' properties
2955                 expected.update(main_expected)
2956             # Helpful for debugging:
2957             #for prop in sorted(props):
2958                 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2959             self.assertEqual(expected, props)
2960             if item == '':
2961                 start = SECTION_SIZE
2962             else:
2963                 start += dtb._fdt_obj.totalsize()
2964
2965     def testFdtmapHeaderMiddle(self):
2966         """Test an FDT map in the middle of an image when it should be at end"""
2967         with self.assertRaises(ValueError) as e:
2968             self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2969         self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2970                       str(e.exception))
2971
2972     def testFdtmapHeaderStartBad(self):
2973         """Test an FDT map in middle of an image when it should be at start"""
2974         with self.assertRaises(ValueError) as e:
2975             self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2976         self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2977                       str(e.exception))
2978
2979     def testFdtmapHeaderEndBad(self):
2980         """Test an FDT map at the start of an image when it should be at end"""
2981         with self.assertRaises(ValueError) as e:
2982             self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2983         self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2984                       str(e.exception))
2985
2986     def testFdtmapHeaderNoSize(self):
2987         """Test an image header at the end of an image with undefined size"""
2988         self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2989
2990     def testReplaceResize(self):
2991         """Test replacing a single file in an entry with a larger file"""
2992         expected = U_BOOT_DATA + b'x'
2993         data, _, image = self._RunReplaceCmd('u-boot', expected,
2994                                              dts='139_replace_repack.dts')
2995         self.assertEqual(expected, data)
2996
2997         entries = image.GetEntries()
2998         dtb_data = entries['u-boot-dtb'].data
2999         dtb = fdt.Fdt.FromData(dtb_data)
3000         dtb.Scan()
3001
3002         # The u-boot section should now be larger in the dtb
3003         node = dtb.GetNode('/binman/u-boot')
3004         self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3005
3006         # Same for the fdtmap
3007         fdata = entries['fdtmap'].data
3008         fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3009         fdtb.Scan()
3010         fnode = fdtb.GetNode('/u-boot')
3011         self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3012
3013     def testReplaceResizeNoRepack(self):
3014         """Test replacing an entry with a larger file when not allowed"""
3015         expected = U_BOOT_DATA + b'x'
3016         with self.assertRaises(ValueError) as e:
3017             self._RunReplaceCmd('u-boot', expected)
3018         self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3019                       str(e.exception))
3020
3021     def testEntryShrink(self):
3022         """Test contracting an entry after it is packed"""
3023         try:
3024             state.SetAllowEntryContraction(True)
3025             data = self._DoReadFileDtb('140_entry_shrink.dts',
3026                                        update_dtb=True)[0]
3027         finally:
3028             state.SetAllowEntryContraction(False)
3029         self.assertEqual(b'a', data[:1])
3030         self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3031         self.assertEqual(b'a', data[-1:])
3032
3033     def testEntryShrinkFail(self):
3034         """Test not being allowed to contract an entry after it is packed"""
3035         data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3036
3037         # In this case there is a spare byte at the end of the data. The size of
3038         # the contents is only 1 byte but we still have the size before it
3039         # shrunk.
3040         self.assertEqual(b'a\0', data[:2])
3041         self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3042         self.assertEqual(b'a\0', data[-2:])
3043
3044     def testDescriptorOffset(self):
3045         """Test that the Intel descriptor is always placed at at the start"""
3046         data = self._DoReadFileDtb('141_descriptor_offset.dts')
3047         image = control.images['image']
3048         entries = image.GetEntries()
3049         desc = entries['intel-descriptor']
3050         self.assertEqual(0xff800000, desc.offset);
3051         self.assertEqual(0xff800000, desc.image_pos);
3052
3053     def testReplaceCbfs(self):
3054         """Test replacing a single file in CBFS without changing the size"""
3055         self._CheckLz4()
3056         expected = b'x' * len(U_BOOT_DATA)
3057         data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3058         updated_fname = tools.GetOutputFilename('image-updated.bin')
3059         tools.WriteFile(updated_fname, data)
3060         entry_name = 'section/cbfs/u-boot'
3061         control.WriteEntry(updated_fname, entry_name, expected,
3062                            allow_resize=True)
3063         data = control.ReadEntry(updated_fname, entry_name)
3064         self.assertEqual(expected, data)
3065
3066     def testReplaceResizeCbfs(self):
3067         """Test replacing a single file in CBFS with one of a different size"""
3068         self._CheckLz4()
3069         expected = U_BOOT_DATA + b'x'
3070         data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3071         updated_fname = tools.GetOutputFilename('image-updated.bin')
3072         tools.WriteFile(updated_fname, data)
3073         entry_name = 'section/cbfs/u-boot'
3074         control.WriteEntry(updated_fname, entry_name, expected,
3075                            allow_resize=True)
3076         data = control.ReadEntry(updated_fname, entry_name)
3077         self.assertEqual(expected, data)
3078
3079     def _SetupForReplace(self):
3080         """Set up some files to use to replace entries
3081
3082         This generates an image, copies it to a new file, extracts all the files
3083         in it and updates some of them
3084
3085         Returns:
3086             List
3087                 Image filename
3088                 Output directory
3089                 Expected values for updated entries, each a string
3090         """
3091         data = self._DoReadFileRealDtb('143_replace_all.dts')
3092
3093         updated_fname = tools.GetOutputFilename('image-updated.bin')
3094         tools.WriteFile(updated_fname, data)
3095
3096         outdir = os.path.join(self._indir, 'extract')
3097         einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3098
3099         expected1 = b'x' + U_BOOT_DATA + b'y'
3100         u_boot_fname1 = os.path.join(outdir, 'u-boot')
3101         tools.WriteFile(u_boot_fname1, expected1)
3102
3103         expected2 = b'a' + U_BOOT_DATA + b'b'
3104         u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3105         tools.WriteFile(u_boot_fname2, expected2)
3106
3107         expected_text = b'not the same text'
3108         text_fname = os.path.join(outdir, 'text')
3109         tools.WriteFile(text_fname, expected_text)
3110
3111         dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3112         dtb = fdt.FdtScan(dtb_fname)
3113         node = dtb.GetNode('/binman/text')
3114         node.AddString('my-property', 'the value')
3115         dtb.Sync(auto_resize=True)
3116         dtb.Flush()
3117
3118         return updated_fname, outdir, expected1, expected2, expected_text
3119
3120     def _CheckReplaceMultiple(self, entry_paths):
3121         """Handle replacing the contents of multiple entries
3122
3123         Args:
3124             entry_paths: List of entry paths to replace
3125
3126         Returns:
3127             List
3128                 Dict of entries in the image:
3129                     key: Entry name
3130                     Value: Entry object
3131             Expected values for updated entries, each a string
3132         """
3133         updated_fname, outdir, expected1, expected2, expected_text = (
3134             self._SetupForReplace())
3135         control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3136
3137         image = Image.FromFile(updated_fname)
3138         image.LoadData()
3139         return image.GetEntries(), expected1, expected2, expected_text
3140
3141     def testReplaceAll(self):
3142         """Test replacing the contents of all entries"""
3143         entries, expected1, expected2, expected_text = (
3144             self._CheckReplaceMultiple([]))
3145         data = entries['u-boot'].data
3146         self.assertEqual(expected1, data)
3147
3148         data = entries['u-boot2'].data
3149         self.assertEqual(expected2, data)
3150
3151         data = entries['text'].data
3152         self.assertEqual(expected_text, data)
3153
3154         # Check that the device tree is updated
3155         data = entries['u-boot-dtb'].data
3156         dtb = fdt.Fdt.FromData(data)
3157         dtb.Scan()
3158         node = dtb.GetNode('/binman/text')
3159         self.assertEqual('the value', node.props['my-property'].value)
3160
3161     def testReplaceSome(self):
3162         """Test replacing the contents of a few entries"""
3163         entries, expected1, expected2, expected_text = (
3164             self._CheckReplaceMultiple(['u-boot2', 'text']))
3165
3166         # This one should not change
3167         data = entries['u-boot'].data
3168         self.assertEqual(U_BOOT_DATA, data)
3169
3170         data = entries['u-boot2'].data
3171         self.assertEqual(expected2, data)
3172
3173         data = entries['text'].data
3174         self.assertEqual(expected_text, data)
3175
3176     def testReplaceCmd(self):
3177         """Test replacing a file fron an image on the command line"""
3178         self._DoReadFileRealDtb('143_replace_all.dts')
3179
3180         try:
3181             tmpdir, updated_fname = self._SetupImageInTmpdir()
3182
3183             fname = os.path.join(tmpdir, 'update-u-boot.bin')
3184             expected = b'x' * len(U_BOOT_DATA)
3185             tools.WriteFile(fname, expected)
3186
3187             self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3188             data = tools.ReadFile(updated_fname)
3189             self.assertEqual(expected, data[:len(expected)])
3190             map_fname = os.path.join(tmpdir, 'image-updated.map')
3191             self.assertFalse(os.path.exists(map_fname))
3192         finally:
3193             shutil.rmtree(tmpdir)
3194
3195     def testReplaceCmdSome(self):
3196         """Test replacing some files fron an image on the command line"""
3197         updated_fname, outdir, expected1, expected2, expected_text = (
3198             self._SetupForReplace())
3199
3200         self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3201                        'u-boot2', 'text')
3202
3203         tools.PrepareOutputDir(None)
3204         image = Image.FromFile(updated_fname)
3205         image.LoadData()
3206         entries = image.GetEntries()
3207
3208         # This one should not change
3209         data = entries['u-boot'].data
3210         self.assertEqual(U_BOOT_DATA, data)
3211
3212         data = entries['u-boot2'].data
3213         self.assertEqual(expected2, data)
3214
3215         data = entries['text'].data
3216         self.assertEqual(expected_text, data)
3217
3218     def testReplaceMissing(self):
3219         """Test replacing entries where the file is missing"""
3220         updated_fname, outdir, expected1, expected2, expected_text = (
3221             self._SetupForReplace())
3222
3223         # Remove one of the files, to generate a warning
3224         u_boot_fname1 = os.path.join(outdir, 'u-boot')
3225         os.remove(u_boot_fname1)
3226
3227         with test_util.capture_sys_output() as (stdout, stderr):
3228             control.ReplaceEntries(updated_fname, None, outdir, [])
3229         self.assertIn("Skipping entry '/u-boot' from missing file",
3230                       stdout.getvalue())
3231
3232     def testReplaceCmdMap(self):
3233         """Test replacing a file fron an image on the command line"""
3234         self._DoReadFileRealDtb('143_replace_all.dts')
3235
3236         try:
3237             tmpdir, updated_fname = self._SetupImageInTmpdir()
3238
3239             fname = os.path.join(self._indir, 'update-u-boot.bin')
3240             expected = b'x' * len(U_BOOT_DATA)
3241             tools.WriteFile(fname, expected)
3242
3243             self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3244                            '-f', fname, '-m')
3245             map_fname = os.path.join(tmpdir, 'image-updated.map')
3246             self.assertTrue(os.path.exists(map_fname))
3247         finally:
3248             shutil.rmtree(tmpdir)
3249
3250     def testReplaceNoEntryPaths(self):
3251         """Test replacing an entry without an entry path"""
3252         self._DoReadFileRealDtb('143_replace_all.dts')
3253         image_fname = tools.GetOutputFilename('image.bin')
3254         with self.assertRaises(ValueError) as e:
3255             control.ReplaceEntries(image_fname, 'fname', None, [])
3256         self.assertIn('Must specify an entry path to read with -f',
3257                       str(e.exception))
3258
3259     def testReplaceTooManyEntryPaths(self):
3260         """Test extracting some entries"""
3261         self._DoReadFileRealDtb('143_replace_all.dts')
3262         image_fname = tools.GetOutputFilename('image.bin')
3263         with self.assertRaises(ValueError) as e:
3264             control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3265         self.assertIn('Must specify exactly one entry path to write with -f',
3266                       str(e.exception))
3267
3268     def testPackReset16(self):
3269         """Test that an image with an x86 reset16 region can be created"""
3270         data = self._DoReadFile('144_x86_reset16.dts')
3271         self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3272
3273     def testPackReset16Spl(self):
3274         """Test that an image with an x86 reset16-spl region can be created"""
3275         data = self._DoReadFile('145_x86_reset16_spl.dts')
3276         self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3277
3278     def testPackReset16Tpl(self):
3279         """Test that an image with an x86 reset16-tpl region can be created"""
3280         data = self._DoReadFile('146_x86_reset16_tpl.dts')
3281         self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3282
3283     def testPackIntelFit(self):
3284         """Test that an image with an Intel FIT and pointer can be created"""
3285         data = self._DoReadFile('147_intel_fit.dts')
3286         self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3287         fit = data[16:32];
3288         self.assertEqual(b'_FIT_   \x01\x00\x00\x00\x00\x01\x80}' , fit)
3289         ptr = struct.unpack('<i', data[0x40:0x44])[0]
3290
3291         image = control.images['image']
3292         entries = image.GetEntries()
3293         expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3294         self.assertEqual(expected_ptr, ptr)
3295
3296     def testPackIntelFitMissing(self):
3297         """Test detection of a FIT pointer with not FIT region"""
3298         with self.assertRaises(ValueError) as e:
3299             self._DoReadFile('148_intel_fit_missing.dts')
3300         self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3301                       str(e.exception))
3302
3303     def testSymbolsTplSection(self):
3304         """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3305         self._SetupSplElf('u_boot_binman_syms')
3306         self._SetupTplElf('u_boot_binman_syms')
3307         data = self._DoReadFile('149_symbols_tpl.dts')
3308         sym_values = struct.pack('<LQL', 4, 0x18, 0x30)
3309         upto1 = 4 + len(U_BOOT_SPL_DATA)
3310         expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[16:]
3311         self.assertEqual(expected1, data[:upto1])
3312
3313         upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3314         expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[16:]
3315         self.assertEqual(expected2, data[upto1:upto2])
3316
3317         upto3 = 0x30 + len(U_BOOT_DATA)
3318         expected3 = tools.GetBytes(0xff, 5) + U_BOOT_DATA
3319         self.assertEqual(expected3, data[upto2:upto3])
3320
3321         expected4 = sym_values + U_BOOT_TPL_DATA[16:]
3322         self.assertEqual(expected4, data[upto3:])
3323
3324
3325 if __name__ == "__main__":
3326     unittest.main()