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