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