Merge tag 'dm-pull-9jul19-take2' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm
[oweals/u-boot.git] / tools / binman / ftest.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
4 #
5 # To run a single test, change to this directory, and:
6 #
7 #    python -m unittest func_test.TestFunctional.testHelp
8
9 import hashlib
10 from optparse import OptionParser
11 import os
12 import shutil
13 import struct
14 import sys
15 import tempfile
16 import unittest
17
18 import binman
19 import cmdline
20 import command
21 import control
22 import elf
23 import fdt
24 import fdt_util
25 import fmap_util
26 import test_util
27 import state
28 import tools
29 import tout
30
31 # Contents of test files, corresponding to different entry types
32 U_BOOT_DATA           = b'1234'
33 U_BOOT_IMG_DATA       = b'img'
34 U_BOOT_SPL_DATA       = b'56780123456789abcde'
35 U_BOOT_TPL_DATA       = b'tpl'
36 BLOB_DATA             = b'89'
37 ME_DATA               = b'0abcd'
38 VGA_DATA              = b'vga'
39 U_BOOT_DTB_DATA       = b'udtb'
40 U_BOOT_SPL_DTB_DATA   = b'spldtb'
41 U_BOOT_TPL_DTB_DATA   = b'tpldtb'
42 X86_START16_DATA      = b'start16'
43 X86_START16_SPL_DATA  = b'start16spl'
44 X86_START16_TPL_DATA  = b'start16tpl'
45 PPC_MPC85XX_BR_DATA   = b'ppcmpc85xxbr'
46 U_BOOT_NODTB_DATA     = b'nodtb with microcode pointer somewhere in here'
47 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
48 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
49 FSP_DATA              = b'fsp'
50 CMC_DATA              = b'cmc'
51 VBT_DATA              = b'vbt'
52 MRC_DATA              = b'mrc'
53 TEXT_DATA             = 'text'
54 TEXT_DATA2            = 'text2'
55 TEXT_DATA3            = 'text3'
56 CROS_EC_RW_DATA       = b'ecrw'
57 GBB_DATA              = b'gbbd'
58 BMPBLK_DATA           = b'bmp'
59 VBLOCK_DATA           = b'vblk'
60 FILES_DATA            = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
61                          b"sorry you're alive\n")
62 COMPRESS_DATA         = b'data to compress'
63 REFCODE_DATA          = b'refcode'
64
65
66 class TestFunctional(unittest.TestCase):
67     """Functional tests for binman
68
69     Most of these use a sample .dts file to build an image and then check
70     that it looks correct. The sample files are in the test/ subdirectory
71     and are numbered.
72
73     For each entry type a very small test file is created using fixed
74     string contents. This makes it easy to test that things look right, and
75     debug problems.
76
77     In some cases a 'real' file must be used - these are also supplied in
78     the test/ diurectory.
79     """
80     @classmethod
81     def setUpClass(self):
82         global entry
83         import entry
84
85         # Handle the case where argv[0] is 'python'
86         self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
87         self._binman_pathname = os.path.join(self._binman_dir, 'binman')
88
89         # Create a temporary directory for input files
90         self._indir = tempfile.mkdtemp(prefix='binmant.')
91
92         # Create some test files
93         TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
94         TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
95         TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
96         TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
97         TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
98         TestFunctional._MakeInputFile('me.bin', ME_DATA)
99         TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
100         self._ResetDtbs()
101         TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
102         TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
103         TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
104                                       X86_START16_SPL_DATA)
105         TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
106                                       X86_START16_TPL_DATA)
107         TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
108         TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
109                                       U_BOOT_SPL_NODTB_DATA)
110         TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
111                                       U_BOOT_TPL_NODTB_DATA)
112         TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
113         TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
114         TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
115         TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
116         TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
117         TestFunctional._MakeInputDir('devkeys')
118         TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
119         TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
120
121         # ELF file with a '_dt_ucode_base_size' symbol
122         with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
123             TestFunctional._MakeInputFile('u-boot', fd.read())
124
125         # Intel flash descriptor file
126         with open(self.TestFile('descriptor.bin'), 'rb') as fd:
127             TestFunctional._MakeInputFile('descriptor.bin', fd.read())
128
129         shutil.copytree(self.TestFile('files'),
130                         os.path.join(self._indir, 'files'))
131
132         TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
133
134     @classmethod
135     def tearDownClass(self):
136         """Remove the temporary input directory and its contents"""
137         if self._indir:
138             shutil.rmtree(self._indir)
139         self._indir = None
140
141     def setUp(self):
142         # Enable this to turn on debugging output
143         # tout.Init(tout.DEBUG)
144         command.test_result = None
145
146     def tearDown(self):
147         """Remove the temporary output directory"""
148         tools._FinaliseForTest()
149
150     @classmethod
151     def _ResetDtbs(self):
152         TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
153         TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
154         TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
155
156     def _RunBinman(self, *args, **kwargs):
157         """Run binman using the command line
158
159         Args:
160             Arguments to pass, as a list of strings
161             kwargs: Arguments to pass to Command.RunPipe()
162         """
163         result = command.RunPipe([[self._binman_pathname] + list(args)],
164                 capture=True, capture_stderr=True, raise_on_error=False)
165         if result.return_code and kwargs.get('raise_on_error', True):
166             raise Exception("Error running '%s': %s" % (' '.join(args),
167                             result.stdout + result.stderr))
168         return result
169
170     def _DoBinman(self, *args):
171         """Run binman using directly (in the same process)
172
173         Args:
174             Arguments to pass, as a list of strings
175         Returns:
176             Return value (0 for success)
177         """
178         args = list(args)
179         if '-D' in sys.argv:
180             args = args + ['-D']
181         (options, args) = cmdline.ParseArgs(args)
182         options.pager = 'binman-invalid-pager'
183         options.build_dir = self._indir
184
185         # For testing, you can force an increase in verbosity here
186         # options.verbosity = tout.DEBUG
187         return control.Binman(options, args)
188
189     def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
190                     entry_args=None, images=None, use_real_dtb=False,
191                     verbosity=None):
192         """Run binman with a given test file
193
194         Args:
195             fname: Device-tree source filename to use (e.g. 005_simple.dts)
196             debug: True to enable debugging output
197             map: True to output map files for the images
198             update_dtb: Update the offset and size of each entry in the device
199                 tree before packing it into the image
200             entry_args: Dict of entry args to supply to binman
201                 key: arg name
202                 value: value of that arg
203             images: List of image names to build
204         """
205         args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
206         if debug:
207             args.append('-D')
208         if map:
209             args.append('-m')
210         if update_dtb:
211             args.append('-up')
212         if not use_real_dtb:
213             args.append('--fake-dtb')
214         if verbosity is not None:
215             args.append('-v%d' % verbosity)
216         if entry_args:
217             for arg, value in entry_args.items():
218                 args.append('-a%s=%s' % (arg, value))
219         if images:
220             for image in images:
221                 args += ['-i', image]
222         return self._DoBinman(*args)
223
224     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
225         """Set up a new test device-tree file
226
227         The given file is compiled and set up as the device tree to be used
228         for ths test.
229
230         Args:
231             fname: Filename of .dts file to read
232             outfile: Output filename for compiled device-tree binary
233
234         Returns:
235             Contents of device-tree binary
236         """
237         tools.PrepareOutputDir(None)
238         dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
239         with open(dtb, 'rb') as fd:
240             data = fd.read()
241             TestFunctional._MakeInputFile(outfile, data)
242         tools.FinaliseOutputDir()
243         return data
244
245     def _GetDtbContentsForSplTpl(self, dtb_data, name):
246         """Create a version of the main DTB for SPL or SPL
247
248         For testing we don't actually have different versions of the DTB. With
249         U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
250         we don't normally have any unwanted nodes.
251
252         We still want the DTBs for SPL and TPL to be different though, since
253         otherwise it is confusing to know which one we are looking at. So add
254         an 'spl' or 'tpl' property to the top-level node.
255         """
256         dtb = fdt.Fdt.FromData(dtb_data)
257         dtb.Scan()
258         dtb.GetNode('/binman').AddZeroProp(name)
259         dtb.Sync(auto_resize=True)
260         dtb.Pack()
261         return dtb.GetContents()
262
263     def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
264                        update_dtb=False, entry_args=None, reset_dtbs=True):
265         """Run binman and return the resulting image
266
267         This runs binman with a given test file and then reads the resulting
268         output file. It is a shortcut function since most tests need to do
269         these steps.
270
271         Raises an assertion failure if binman returns a non-zero exit code.
272
273         Args:
274             fname: Device-tree source filename to use (e.g. 005_simple.dts)
275             use_real_dtb: True to use the test file as the contents of
276                 the u-boot-dtb entry. Normally this is not needed and the
277                 test contents (the U_BOOT_DTB_DATA string) can be used.
278                 But in some test we need the real contents.
279             map: True to output map files for the images
280             update_dtb: Update the offset and size of each entry in the device
281                 tree before packing it into the image
282
283         Returns:
284             Tuple:
285                 Resulting image contents
286                 Device tree contents
287                 Map data showing contents of image (or None if none)
288                 Output device tree binary filename ('u-boot.dtb' path)
289         """
290         dtb_data = None
291         # Use the compiled test file as the u-boot-dtb input
292         if use_real_dtb:
293             dtb_data = self._SetupDtb(fname)
294
295             # For testing purposes, make a copy of the DT for SPL and TPL. Add
296             # a node indicating which it is, so aid verification.
297             for name in ['spl', 'tpl']:
298                 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
299                 outfile = os.path.join(self._indir, dtb_fname)
300                 TestFunctional._MakeInputFile(dtb_fname,
301                         self._GetDtbContentsForSplTpl(dtb_data, name))
302
303         try:
304             retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
305                     entry_args=entry_args, use_real_dtb=use_real_dtb)
306             self.assertEqual(0, retcode)
307             out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
308
309             # Find the (only) image, read it and return its contents
310             image = control.images['image']
311             image_fname = tools.GetOutputFilename('image.bin')
312             self.assertTrue(os.path.exists(image_fname))
313             if map:
314                 map_fname = tools.GetOutputFilename('image.map')
315                 with open(map_fname) as fd:
316                     map_data = fd.read()
317             else:
318                 map_data = None
319             with open(image_fname, 'rb') as fd:
320                 return fd.read(), dtb_data, map_data, out_dtb_fname
321         finally:
322             # Put the test file back
323             if reset_dtbs and use_real_dtb:
324                 self._ResetDtbs()
325
326     def _DoReadFile(self, fname, use_real_dtb=False):
327         """Helper function which discards the device-tree binary
328
329         Args:
330             fname: Device-tree source filename to use (e.g. 005_simple.dts)
331             use_real_dtb: True to use the test file as the contents of
332                 the u-boot-dtb entry. Normally this is not needed and the
333                 test contents (the U_BOOT_DTB_DATA string) can be used.
334                 But in some test we need the real contents.
335
336         Returns:
337             Resulting image contents
338         """
339         return self._DoReadFileDtb(fname, use_real_dtb)[0]
340
341     @classmethod
342     def _MakeInputFile(self, fname, contents):
343         """Create a new test input file, creating directories as needed
344
345         Args:
346             fname: Filename to create
347             contents: File contents to write in to the file
348         Returns:
349             Full pathname of file created
350         """
351         pathname = os.path.join(self._indir, fname)
352         dirname = os.path.dirname(pathname)
353         if dirname and not os.path.exists(dirname):
354             os.makedirs(dirname)
355         with open(pathname, 'wb') as fd:
356             fd.write(contents)
357         return pathname
358
359     @classmethod
360     def _MakeInputDir(self, dirname):
361         """Create a new test input directory, creating directories as needed
362
363         Args:
364             dirname: Directory name to create
365
366         Returns:
367             Full pathname of directory created
368         """
369         pathname = os.path.join(self._indir, dirname)
370         if not os.path.exists(pathname):
371             os.makedirs(pathname)
372         return pathname
373
374     @classmethod
375     def _SetupSplElf(self, src_fname='bss_data'):
376         """Set up an ELF file with a '_dt_ucode_base_size' symbol
377
378         Args:
379             Filename of ELF file to use as SPL
380         """
381         with open(self.TestFile(src_fname), 'rb') as fd:
382             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
383
384     @classmethod
385     def TestFile(self, fname):
386         return os.path.join(self._binman_dir, 'test', fname)
387
388     def AssertInList(self, grep_list, target):
389         """Assert that at least one of a list of things is in a target
390
391         Args:
392             grep_list: List of strings to check
393             target: Target string
394         """
395         for grep in grep_list:
396             if grep in target:
397                 return
398         self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
399
400     def CheckNoGaps(self, entries):
401         """Check that all entries fit together without gaps
402
403         Args:
404             entries: List of entries to check
405         """
406         offset = 0
407         for entry in entries.values():
408             self.assertEqual(offset, entry.offset)
409             offset += entry.size
410
411     def GetFdtLen(self, dtb):
412         """Get the totalsize field from a device-tree binary
413
414         Args:
415             dtb: Device-tree binary contents
416
417         Returns:
418             Total size of device-tree binary, from the header
419         """
420         return struct.unpack('>L', dtb[4:8])[0]
421
422     def _GetPropTree(self, dtb, prop_names):
423         def AddNode(node, path):
424             if node.name != '/':
425                 path += '/' + node.name
426             for subnode in node.subnodes:
427                 for prop in subnode.props.values():
428                     if prop.name in prop_names:
429                         prop_path = path + '/' + subnode.name + ':' + prop.name
430                         tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
431                             prop.value)
432                 AddNode(subnode, path)
433
434         tree = {}
435         AddNode(dtb.GetRoot(), '')
436         return tree
437
438     def testRun(self):
439         """Test a basic run with valid args"""
440         result = self._RunBinman('-h')
441
442     def testFullHelp(self):
443         """Test that the full help is displayed with -H"""
444         result = self._RunBinman('-H')
445         help_file = os.path.join(self._binman_dir, 'README')
446         # Remove possible extraneous strings
447         extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
448         gothelp = result.stdout.replace(extra, '')
449         self.assertEqual(len(gothelp), os.path.getsize(help_file))
450         self.assertEqual(0, len(result.stderr))
451         self.assertEqual(0, result.return_code)
452
453     def testFullHelpInternal(self):
454         """Test that the full help is displayed with -H"""
455         try:
456             command.test_result = command.CommandResult()
457             result = self._DoBinman('-H')
458             help_file = os.path.join(self._binman_dir, 'README')
459         finally:
460             command.test_result = None
461
462     def testHelp(self):
463         """Test that the basic help is displayed with -h"""
464         result = self._RunBinman('-h')
465         self.assertTrue(len(result.stdout) > 200)
466         self.assertEqual(0, len(result.stderr))
467         self.assertEqual(0, result.return_code)
468
469     def testBoard(self):
470         """Test that we can run it with a specific board"""
471         self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
472         TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
473         result = self._DoBinman('-b', 'sandbox')
474         self.assertEqual(0, result)
475
476     def testNeedBoard(self):
477         """Test that we get an error when no board ius supplied"""
478         with self.assertRaises(ValueError) as e:
479             result = self._DoBinman()
480         self.assertIn("Must provide a board to process (use -b <board>)",
481                 str(e.exception))
482
483     def testMissingDt(self):
484         """Test that an invalid device-tree file generates an error"""
485         with self.assertRaises(Exception) as e:
486             self._RunBinman('-d', 'missing_file')
487         # We get one error from libfdt, and a different one from fdtget.
488         self.AssertInList(["Couldn't open blob from 'missing_file'",
489                            'No such file or directory'], str(e.exception))
490
491     def testBrokenDt(self):
492         """Test that an invalid device-tree source file generates an error
493
494         Since this is a source file it should be compiled and the error
495         will come from the device-tree compiler (dtc).
496         """
497         with self.assertRaises(Exception) as e:
498             self._RunBinman('-d', self.TestFile('001_invalid.dts'))
499         self.assertIn("FATAL ERROR: Unable to parse input tree",
500                 str(e.exception))
501
502     def testMissingNode(self):
503         """Test that a device tree without a 'binman' node generates an error"""
504         with self.assertRaises(Exception) as e:
505             self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
506         self.assertIn("does not have a 'binman' node", str(e.exception))
507
508     def testEmpty(self):
509         """Test that an empty binman node works OK (i.e. does nothing)"""
510         result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
511         self.assertEqual(0, len(result.stderr))
512         self.assertEqual(0, result.return_code)
513
514     def testInvalidEntry(self):
515         """Test that an invalid entry is flagged"""
516         with self.assertRaises(Exception) as e:
517             result = self._RunBinman('-d',
518                                      self.TestFile('004_invalid_entry.dts'))
519         self.assertIn("Unknown entry type 'not-a-valid-type' in node "
520                 "'/binman/not-a-valid-type'", str(e.exception))
521
522     def testSimple(self):
523         """Test a simple binman with a single file"""
524         data = self._DoReadFile('005_simple.dts')
525         self.assertEqual(U_BOOT_DATA, data)
526
527     def testSimpleDebug(self):
528         """Test a simple binman run with debugging enabled"""
529         data = self._DoTestFile('005_simple.dts', debug=True)
530
531     def testDual(self):
532         """Test that we can handle creating two images
533
534         This also tests image padding.
535         """
536         retcode = self._DoTestFile('006_dual_image.dts')
537         self.assertEqual(0, retcode)
538
539         image = control.images['image1']
540         self.assertEqual(len(U_BOOT_DATA), image._size)
541         fname = tools.GetOutputFilename('image1.bin')
542         self.assertTrue(os.path.exists(fname))
543         with open(fname, 'rb') as fd:
544             data = fd.read()
545             self.assertEqual(U_BOOT_DATA, data)
546
547         image = control.images['image2']
548         self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
549         fname = tools.GetOutputFilename('image2.bin')
550         self.assertTrue(os.path.exists(fname))
551         with open(fname, 'rb') as fd:
552             data = fd.read()
553             self.assertEqual(U_BOOT_DATA, data[3:7])
554             self.assertEqual(tools.GetBytes(0, 3), data[:3])
555             self.assertEqual(tools.GetBytes(0, 5), data[7:])
556
557     def testBadAlign(self):
558         """Test that an invalid alignment value is detected"""
559         with self.assertRaises(ValueError) as e:
560             self._DoTestFile('007_bad_align.dts')
561         self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
562                       "of two", str(e.exception))
563
564     def testPackSimple(self):
565         """Test that packing works as expected"""
566         retcode = self._DoTestFile('008_pack.dts')
567         self.assertEqual(0, retcode)
568         self.assertIn('image', control.images)
569         image = control.images['image']
570         entries = image.GetEntries()
571         self.assertEqual(5, len(entries))
572
573         # First u-boot
574         self.assertIn('u-boot', entries)
575         entry = entries['u-boot']
576         self.assertEqual(0, entry.offset)
577         self.assertEqual(len(U_BOOT_DATA), entry.size)
578
579         # Second u-boot, aligned to 16-byte boundary
580         self.assertIn('u-boot-align', entries)
581         entry = entries['u-boot-align']
582         self.assertEqual(16, entry.offset)
583         self.assertEqual(len(U_BOOT_DATA), entry.size)
584
585         # Third u-boot, size 23 bytes
586         self.assertIn('u-boot-size', entries)
587         entry = entries['u-boot-size']
588         self.assertEqual(20, entry.offset)
589         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
590         self.assertEqual(23, entry.size)
591
592         # Fourth u-boot, placed immediate after the above
593         self.assertIn('u-boot-next', entries)
594         entry = entries['u-boot-next']
595         self.assertEqual(43, entry.offset)
596         self.assertEqual(len(U_BOOT_DATA), entry.size)
597
598         # Fifth u-boot, placed at a fixed offset
599         self.assertIn('u-boot-fixed', entries)
600         entry = entries['u-boot-fixed']
601         self.assertEqual(61, entry.offset)
602         self.assertEqual(len(U_BOOT_DATA), entry.size)
603
604         self.assertEqual(65, image._size)
605
606     def testPackExtra(self):
607         """Test that extra packing feature works as expected"""
608         retcode = self._DoTestFile('009_pack_extra.dts')
609
610         self.assertEqual(0, retcode)
611         self.assertIn('image', control.images)
612         image = control.images['image']
613         entries = image.GetEntries()
614         self.assertEqual(5, len(entries))
615
616         # First u-boot with padding before and after
617         self.assertIn('u-boot', entries)
618         entry = entries['u-boot']
619         self.assertEqual(0, entry.offset)
620         self.assertEqual(3, entry.pad_before)
621         self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
622
623         # Second u-boot has an aligned size, but it has no effect
624         self.assertIn('u-boot-align-size-nop', entries)
625         entry = entries['u-boot-align-size-nop']
626         self.assertEqual(12, entry.offset)
627         self.assertEqual(4, entry.size)
628
629         # Third u-boot has an aligned size too
630         self.assertIn('u-boot-align-size', entries)
631         entry = entries['u-boot-align-size']
632         self.assertEqual(16, entry.offset)
633         self.assertEqual(32, entry.size)
634
635         # Fourth u-boot has an aligned end
636         self.assertIn('u-boot-align-end', entries)
637         entry = entries['u-boot-align-end']
638         self.assertEqual(48, entry.offset)
639         self.assertEqual(16, entry.size)
640
641         # Fifth u-boot immediately afterwards
642         self.assertIn('u-boot-align-both', entries)
643         entry = entries['u-boot-align-both']
644         self.assertEqual(64, entry.offset)
645         self.assertEqual(64, entry.size)
646
647         self.CheckNoGaps(entries)
648         self.assertEqual(128, image._size)
649
650     def testPackAlignPowerOf2(self):
651         """Test that invalid entry alignment is detected"""
652         with self.assertRaises(ValueError) as e:
653             self._DoTestFile('010_pack_align_power2.dts')
654         self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
655                       "of two", str(e.exception))
656
657     def testPackAlignSizePowerOf2(self):
658         """Test that invalid entry size alignment is detected"""
659         with self.assertRaises(ValueError) as e:
660             self._DoTestFile('011_pack_align_size_power2.dts')
661         self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
662                       "power of two", str(e.exception))
663
664     def testPackInvalidAlign(self):
665         """Test detection of an offset that does not match its alignment"""
666         with self.assertRaises(ValueError) as e:
667             self._DoTestFile('012_pack_inv_align.dts')
668         self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
669                       "align 0x4 (4)", str(e.exception))
670
671     def testPackInvalidSizeAlign(self):
672         """Test that invalid entry size alignment is detected"""
673         with self.assertRaises(ValueError) as e:
674             self._DoTestFile('013_pack_inv_size_align.dts')
675         self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
676                       "align-size 0x4 (4)", str(e.exception))
677
678     def testPackOverlap(self):
679         """Test that overlapping regions are detected"""
680         with self.assertRaises(ValueError) as e:
681             self._DoTestFile('014_pack_overlap.dts')
682         self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
683                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
684                       str(e.exception))
685
686     def testPackEntryOverflow(self):
687         """Test that entries that overflow their size are detected"""
688         with self.assertRaises(ValueError) as e:
689             self._DoTestFile('015_pack_overflow.dts')
690         self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
691                       "but entry size is 0x3 (3)", str(e.exception))
692
693     def testPackImageOverflow(self):
694         """Test that entries which overflow the image size are detected"""
695         with self.assertRaises(ValueError) as e:
696             self._DoTestFile('016_pack_image_overflow.dts')
697         self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
698                       "size 0x3 (3)", str(e.exception))
699
700     def testPackImageSize(self):
701         """Test that the image size can be set"""
702         retcode = self._DoTestFile('017_pack_image_size.dts')
703         self.assertEqual(0, retcode)
704         self.assertIn('image', control.images)
705         image = control.images['image']
706         self.assertEqual(7, image._size)
707
708     def testPackImageSizeAlign(self):
709         """Test that image size alignemnt works as expected"""
710         retcode = self._DoTestFile('018_pack_image_align.dts')
711         self.assertEqual(0, retcode)
712         self.assertIn('image', control.images)
713         image = control.images['image']
714         self.assertEqual(16, image._size)
715
716     def testPackInvalidImageAlign(self):
717         """Test that invalid image alignment is detected"""
718         with self.assertRaises(ValueError) as e:
719             self._DoTestFile('019_pack_inv_image_align.dts')
720         self.assertIn("Section '/binman': Size 0x7 (7) does not match "
721                       "align-size 0x8 (8)", str(e.exception))
722
723     def testPackAlignPowerOf2(self):
724         """Test that invalid image alignment is detected"""
725         with self.assertRaises(ValueError) as e:
726             self._DoTestFile('020_pack_inv_image_align_power2.dts')
727         self.assertIn("Section '/binman': Alignment size 131 must be a power of "
728                       "two", str(e.exception))
729
730     def testImagePadByte(self):
731         """Test that the image pad byte can be specified"""
732         self._SetupSplElf()
733         data = self._DoReadFile('021_image_pad.dts')
734         self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
735                          U_BOOT_DATA, data)
736
737     def testImageName(self):
738         """Test that image files can be named"""
739         retcode = self._DoTestFile('022_image_name.dts')
740         self.assertEqual(0, retcode)
741         image = control.images['image1']
742         fname = tools.GetOutputFilename('test-name')
743         self.assertTrue(os.path.exists(fname))
744
745         image = control.images['image2']
746         fname = tools.GetOutputFilename('test-name.xx')
747         self.assertTrue(os.path.exists(fname))
748
749     def testBlobFilename(self):
750         """Test that generic blobs can be provided by filename"""
751         data = self._DoReadFile('023_blob.dts')
752         self.assertEqual(BLOB_DATA, data)
753
754     def testPackSorted(self):
755         """Test that entries can be sorted"""
756         self._SetupSplElf()
757         data = self._DoReadFile('024_sorted.dts')
758         self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
759                          tools.GetBytes(0, 2) + U_BOOT_DATA, data)
760
761     def testPackZeroOffset(self):
762         """Test that an entry at offset 0 is not given a new offset"""
763         with self.assertRaises(ValueError) as e:
764             self._DoTestFile('025_pack_zero_size.dts')
765         self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
766                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
767                       str(e.exception))
768
769     def testPackUbootDtb(self):
770         """Test that a device tree can be added to U-Boot"""
771         data = self._DoReadFile('026_pack_u_boot_dtb.dts')
772         self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
773
774     def testPackX86RomNoSize(self):
775         """Test that the end-at-4gb property requires a size property"""
776         with self.assertRaises(ValueError) as e:
777             self._DoTestFile('027_pack_4gb_no_size.dts')
778         self.assertIn("Section '/binman': Section size must be provided when "
779                       "using end-at-4gb", str(e.exception))
780
781     def test4gbAndSkipAtStartTogether(self):
782         """Test that the end-at-4gb and skip-at-size property can't be used
783         together"""
784         with self.assertRaises(ValueError) as e:
785             self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
786         self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
787                       "'skip-at-start'", str(e.exception))
788
789     def testPackX86RomOutside(self):
790         """Test that the end-at-4gb property checks for offset boundaries"""
791         with self.assertRaises(ValueError) as e:
792             self._DoTestFile('028_pack_4gb_outside.dts')
793         self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
794                       "the section starting at 0xffffffe0 (4294967264)",
795                       str(e.exception))
796
797     def testPackX86Rom(self):
798         """Test that a basic x86 ROM can be created"""
799         self._SetupSplElf()
800         data = self._DoReadFile('029_x86-rom.dts')
801         self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
802                          tools.GetBytes(0, 2), data)
803
804     def testPackX86RomMeNoDesc(self):
805         """Test that an invalid Intel descriptor entry is detected"""
806         TestFunctional._MakeInputFile('descriptor.bin', b'')
807         with self.assertRaises(ValueError) as e:
808             self._DoTestFile('031_x86-rom-me.dts')
809         self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
810                       "signature", str(e.exception))
811
812     def testPackX86RomBadDesc(self):
813         """Test that the Intel requires a descriptor entry"""
814         with self.assertRaises(ValueError) as e:
815             self._DoTestFile('030_x86-rom-me-no-desc.dts')
816         self.assertIn("Node '/binman/intel-me': No offset set with "
817                       "offset-unset: should another entry provide this correct "
818                       "offset?", str(e.exception))
819
820     def testPackX86RomMe(self):
821         """Test that an x86 ROM with an ME region can be created"""
822         data = self._DoReadFile('031_x86-rom-me.dts')
823         self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
824
825     def testPackVga(self):
826         """Test that an image with a VGA binary can be created"""
827         data = self._DoReadFile('032_intel-vga.dts')
828         self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
829
830     def testPackStart16(self):
831         """Test that an image with an x86 start16 region can be created"""
832         data = self._DoReadFile('033_x86-start16.dts')
833         self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
834
835     def testPackPowerpcMpc85xxBootpgResetvec(self):
836         """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
837         created"""
838         data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
839         self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
840
841     def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
842         """Handle running a test for insertion of microcode
843
844         Args:
845             dts_fname: Name of test .dts file
846             nodtb_data: Data that we expect in the first section
847             ucode_second: True if the microsecond entry is second instead of
848                 third
849
850         Returns:
851             Tuple:
852                 Contents of first region (U-Boot or SPL)
853                 Offset and size components of microcode pointer, as inserted
854                     in the above (two 4-byte words)
855         """
856         data = self._DoReadFile(dts_fname, True)
857
858         # Now check the device tree has no microcode
859         if ucode_second:
860             ucode_content = data[len(nodtb_data):]
861             ucode_pos = len(nodtb_data)
862             dtb_with_ucode = ucode_content[16:]
863             fdt_len = self.GetFdtLen(dtb_with_ucode)
864         else:
865             dtb_with_ucode = data[len(nodtb_data):]
866             fdt_len = self.GetFdtLen(dtb_with_ucode)
867             ucode_content = dtb_with_ucode[fdt_len:]
868             ucode_pos = len(nodtb_data) + fdt_len
869         fname = tools.GetOutputFilename('test.dtb')
870         with open(fname, 'wb') as fd:
871             fd.write(dtb_with_ucode)
872         dtb = fdt.FdtScan(fname)
873         ucode = dtb.GetNode('/microcode')
874         self.assertTrue(ucode)
875         for node in ucode.subnodes:
876             self.assertFalse(node.props.get('data'))
877
878         # Check that the microcode appears immediately after the Fdt
879         # This matches the concatenation of the data properties in
880         # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
881         ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
882                                  0x78235609)
883         self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
884
885         # Check that the microcode pointer was inserted. It should match the
886         # expected offset and size
887         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
888                                    len(ucode_data))
889         u_boot = data[:len(nodtb_data)]
890         return u_boot, pos_and_size
891
892     def testPackUbootMicrocode(self):
893         """Test that x86 microcode can be handled correctly
894
895         We expect to see the following in the image, in order:
896             u-boot-nodtb.bin with a microcode pointer inserted at the correct
897                 place
898             u-boot.dtb with the microcode removed
899             the microcode
900         """
901         first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
902                                                      U_BOOT_NODTB_DATA)
903         self.assertEqual(b'nodtb with microcode' + pos_and_size +
904                          b' somewhere in here', first)
905
906     def _RunPackUbootSingleMicrocode(self):
907         """Test that x86 microcode can be handled correctly
908
909         We expect to see the following in the image, in order:
910             u-boot-nodtb.bin with a microcode pointer inserted at the correct
911                 place
912             u-boot.dtb with the microcode
913             an empty microcode region
914         """
915         # We need the libfdt library to run this test since only that allows
916         # finding the offset of a property. This is required by
917         # Entry_u_boot_dtb_with_ucode.ObtainContents().
918         data = self._DoReadFile('035_x86_single_ucode.dts', True)
919
920         second = data[len(U_BOOT_NODTB_DATA):]
921
922         fdt_len = self.GetFdtLen(second)
923         third = second[fdt_len:]
924         second = second[:fdt_len]
925
926         ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
927         self.assertIn(ucode_data, second)
928         ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
929
930         # Check that the microcode pointer was inserted. It should match the
931         # expected offset and size
932         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
933                                    len(ucode_data))
934         first = data[:len(U_BOOT_NODTB_DATA)]
935         self.assertEqual(b'nodtb with microcode' + pos_and_size +
936                          b' somewhere in here', first)
937
938     def testPackUbootSingleMicrocode(self):
939         """Test that x86 microcode can be handled correctly with fdt_normal.
940         """
941         self._RunPackUbootSingleMicrocode()
942
943     def testUBootImg(self):
944         """Test that u-boot.img can be put in a file"""
945         data = self._DoReadFile('036_u_boot_img.dts')
946         self.assertEqual(U_BOOT_IMG_DATA, data)
947
948     def testNoMicrocode(self):
949         """Test that a missing microcode region is detected"""
950         with self.assertRaises(ValueError) as e:
951             self._DoReadFile('037_x86_no_ucode.dts', True)
952         self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
953                       "node found in ", str(e.exception))
954
955     def testMicrocodeWithoutNode(self):
956         """Test that a missing u-boot-dtb-with-ucode node is detected"""
957         with self.assertRaises(ValueError) as e:
958             self._DoReadFile('038_x86_ucode_missing_node.dts', True)
959         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
960                 "microcode region u-boot-dtb-with-ucode", str(e.exception))
961
962     def testMicrocodeWithoutNode2(self):
963         """Test that a missing u-boot-ucode node is detected"""
964         with self.assertRaises(ValueError) as e:
965             self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
966         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
967             "microcode region u-boot-ucode", str(e.exception))
968
969     def testMicrocodeWithoutPtrInElf(self):
970         """Test that a U-Boot binary without the microcode symbol is detected"""
971         # ELF file without a '_dt_ucode_base_size' symbol
972         try:
973             with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
974                 TestFunctional._MakeInputFile('u-boot', fd.read())
975
976             with self.assertRaises(ValueError) as e:
977                 self._RunPackUbootSingleMicrocode()
978             self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
979                     "_dt_ucode_base_size symbol in u-boot", str(e.exception))
980
981         finally:
982             # Put the original file back
983             with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
984                 TestFunctional._MakeInputFile('u-boot', fd.read())
985
986     def testMicrocodeNotInImage(self):
987         """Test that microcode must be placed within the image"""
988         with self.assertRaises(ValueError) as e:
989             self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
990         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
991                 "pointer _dt_ucode_base_size at fffffe14 is outside the "
992                 "section ranging from 00000000 to 0000002e", str(e.exception))
993
994     def testWithoutMicrocode(self):
995         """Test that we can cope with an image without microcode (e.g. qemu)"""
996         with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
997             TestFunctional._MakeInputFile('u-boot', fd.read())
998         data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
999
1000         # Now check the device tree has no microcode
1001         self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1002         second = data[len(U_BOOT_NODTB_DATA):]
1003
1004         fdt_len = self.GetFdtLen(second)
1005         self.assertEqual(dtb, second[:fdt_len])
1006
1007         used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1008         third = data[used_len:]
1009         self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1010
1011     def testUnknownPosSize(self):
1012         """Test that microcode must be placed within the image"""
1013         with self.assertRaises(ValueError) as e:
1014             self._DoReadFile('041_unknown_pos_size.dts', True)
1015         self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1016                 "entry 'invalid-entry'", str(e.exception))
1017
1018     def testPackFsp(self):
1019         """Test that an image with a FSP binary can be created"""
1020         data = self._DoReadFile('042_intel-fsp.dts')
1021         self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1022
1023     def testPackCmc(self):
1024         """Test that an image with a CMC binary can be created"""
1025         data = self._DoReadFile('043_intel-cmc.dts')
1026         self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1027
1028     def testPackVbt(self):
1029         """Test that an image with a VBT binary can be created"""
1030         data = self._DoReadFile('046_intel-vbt.dts')
1031         self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1032
1033     def testSplBssPad(self):
1034         """Test that we can pad SPL's BSS with zeros"""
1035         # ELF file with a '__bss_size' symbol
1036         self._SetupSplElf()
1037         data = self._DoReadFile('047_spl_bss_pad.dts')
1038         self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1039                          data)
1040
1041     def testSplBssPadMissing(self):
1042         """Test that a missing symbol is detected"""
1043         self._SetupSplElf('u_boot_ucode_ptr')
1044         with self.assertRaises(ValueError) as e:
1045             self._DoReadFile('047_spl_bss_pad.dts')
1046         self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1047                       str(e.exception))
1048
1049     def testPackStart16Spl(self):
1050         """Test that an image with an x86 start16 SPL region can be created"""
1051         data = self._DoReadFile('048_x86-start16-spl.dts')
1052         self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1053
1054     def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1055         """Helper function for microcode tests
1056
1057         We expect to see the following in the image, in order:
1058             u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1059                 correct place
1060             u-boot.dtb with the microcode removed
1061             the microcode
1062
1063         Args:
1064             dts: Device tree file to use for test
1065             ucode_second: True if the microsecond entry is second instead of
1066                 third
1067         """
1068         self._SetupSplElf('u_boot_ucode_ptr')
1069         first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1070                                                      ucode_second=ucode_second)
1071         self.assertEqual(b'splnodtb with microc' + pos_and_size +
1072                          b'ter somewhere in here', first)
1073
1074     def testPackUbootSplMicrocode(self):
1075         """Test that x86 microcode can be handled correctly in SPL"""
1076         self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1077
1078     def testPackUbootSplMicrocodeReorder(self):
1079         """Test that order doesn't matter for microcode entries
1080
1081         This is the same as testPackUbootSplMicrocode but when we process the
1082         u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1083         entry, so we reply on binman to try later.
1084         """
1085         self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1086                                     ucode_second=True)
1087
1088     def testPackMrc(self):
1089         """Test that an image with an MRC binary can be created"""
1090         data = self._DoReadFile('050_intel_mrc.dts')
1091         self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1092
1093     def testSplDtb(self):
1094         """Test that an image with spl/u-boot-spl.dtb can be created"""
1095         data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1096         self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1097
1098     def testSplNoDtb(self):
1099         """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1100         data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1101         self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1102
1103     def testSymbols(self):
1104         """Test binman can assign symbols embedded in U-Boot"""
1105         elf_fname = self.TestFile('u_boot_binman_syms')
1106         syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1107         addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1108         self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1109
1110         self._SetupSplElf('u_boot_binman_syms')
1111         data = self._DoReadFile('053_symbols.dts')
1112         sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1113         expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1114                     tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1115                     U_BOOT_SPL_DATA[16:])
1116         self.assertEqual(expected, data)
1117
1118     def testPackUnitAddress(self):
1119         """Test that we support multiple binaries with the same name"""
1120         data = self._DoReadFile('054_unit_address.dts')
1121         self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1122
1123     def testSections(self):
1124         """Basic test of sections"""
1125         data = self._DoReadFile('055_sections.dts')
1126         expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1127                     U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1128                     U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1129         self.assertEqual(expected, data)
1130
1131     def testMap(self):
1132         """Tests outputting a map of the images"""
1133         _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1134         self.assertEqual('''ImagePos    Offset      Size  Name
1135 00000000  00000000  00000028  main-section
1136 00000000   00000000  00000010  section@0
1137 00000000    00000000  00000004  u-boot
1138 00000010   00000010  00000010  section@1
1139 00000010    00000000  00000004  u-boot
1140 00000020   00000020  00000004  section@2
1141 00000020    00000000  00000004  u-boot
1142 ''', map_data)
1143
1144     def testNamePrefix(self):
1145         """Tests that name prefixes are used"""
1146         _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1147         self.assertEqual('''ImagePos    Offset      Size  Name
1148 00000000  00000000  00000028  main-section
1149 00000000   00000000  00000010  section@0
1150 00000000    00000000  00000004  ro-u-boot
1151 00000010   00000010  00000010  section@1
1152 00000010    00000000  00000004  rw-u-boot
1153 ''', map_data)
1154
1155     def testUnknownContents(self):
1156         """Test that obtaining the contents works as expected"""
1157         with self.assertRaises(ValueError) as e:
1158             self._DoReadFile('057_unknown_contents.dts', True)
1159         self.assertIn("Section '/binman': Internal error: Could not complete "
1160                 "processing of contents: remaining [<_testing.Entry__testing ",
1161                 str(e.exception))
1162
1163     def testBadChangeSize(self):
1164         """Test that trying to change the size of an entry fails"""
1165         with self.assertRaises(ValueError) as e:
1166             self._DoReadFile('059_change_size.dts', True)
1167         self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1168                       '2 to 1', str(e.exception))
1169
1170     def testUpdateFdt(self):
1171         """Test that we can update the device tree with offset/size info"""
1172         _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1173                                                      update_dtb=True)
1174         dtb = fdt.Fdt(out_dtb_fname)
1175         dtb.Scan()
1176         props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
1177         self.assertEqual({
1178             'image-pos': 0,
1179             'offset': 0,
1180             '_testing:offset': 32,
1181             '_testing:size': 1,
1182             '_testing:image-pos': 32,
1183             'section@0/u-boot:offset': 0,
1184             'section@0/u-boot:size': len(U_BOOT_DATA),
1185             'section@0/u-boot:image-pos': 0,
1186             'section@0:offset': 0,
1187             'section@0:size': 16,
1188             'section@0:image-pos': 0,
1189
1190             'section@1/u-boot:offset': 0,
1191             'section@1/u-boot:size': len(U_BOOT_DATA),
1192             'section@1/u-boot:image-pos': 16,
1193             'section@1:offset': 16,
1194             'section@1:size': 16,
1195             'section@1:image-pos': 16,
1196             'size': 40
1197         }, props)
1198
1199     def testUpdateFdtBad(self):
1200         """Test that we detect when ProcessFdt never completes"""
1201         with self.assertRaises(ValueError) as e:
1202             self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1203         self.assertIn('Could not complete processing of Fdt: remaining '
1204                       '[<_testing.Entry__testing', str(e.exception))
1205
1206     def testEntryArgs(self):
1207         """Test passing arguments to entries from the command line"""
1208         entry_args = {
1209             'test-str-arg': 'test1',
1210             'test-int-arg': '456',
1211         }
1212         self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1213         self.assertIn('image', control.images)
1214         entry = control.images['image'].GetEntries()['_testing']
1215         self.assertEqual('test0', entry.test_str_fdt)
1216         self.assertEqual('test1', entry.test_str_arg)
1217         self.assertEqual(123, entry.test_int_fdt)
1218         self.assertEqual(456, entry.test_int_arg)
1219
1220     def testEntryArgsMissing(self):
1221         """Test missing arguments and properties"""
1222         entry_args = {
1223             'test-int-arg': '456',
1224         }
1225         self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1226         entry = control.images['image'].GetEntries()['_testing']
1227         self.assertEqual('test0', entry.test_str_fdt)
1228         self.assertEqual(None, entry.test_str_arg)
1229         self.assertEqual(None, entry.test_int_fdt)
1230         self.assertEqual(456, entry.test_int_arg)
1231
1232     def testEntryArgsRequired(self):
1233         """Test missing arguments and properties"""
1234         entry_args = {
1235             'test-int-arg': '456',
1236         }
1237         with self.assertRaises(ValueError) as e:
1238             self._DoReadFileDtb('064_entry_args_required.dts')
1239         self.assertIn("Node '/binman/_testing': Missing required "
1240             'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1241             str(e.exception))
1242
1243     def testEntryArgsInvalidFormat(self):
1244         """Test that an invalid entry-argument format is detected"""
1245         args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
1246         with self.assertRaises(ValueError) as e:
1247             self._DoBinman(*args)
1248         self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1249
1250     def testEntryArgsInvalidInteger(self):
1251         """Test that an invalid entry-argument integer is detected"""
1252         entry_args = {
1253             'test-int-arg': 'abc',
1254         }
1255         with self.assertRaises(ValueError) as e:
1256             self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1257         self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1258                       "'test-int-arg' (value 'abc') to integer",
1259             str(e.exception))
1260
1261     def testEntryArgsInvalidDatatype(self):
1262         """Test that an invalid entry-argument datatype is detected
1263
1264         This test could be written in entry_test.py except that it needs
1265         access to control.entry_args, which seems more than that module should
1266         be able to see.
1267         """
1268         entry_args = {
1269             'test-bad-datatype-arg': '12',
1270         }
1271         with self.assertRaises(ValueError) as e:
1272             self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1273                                 entry_args=entry_args)
1274         self.assertIn('GetArg() internal error: Unknown data type ',
1275                       str(e.exception))
1276
1277     def testText(self):
1278         """Test for a text entry type"""
1279         entry_args = {
1280             'test-id': TEXT_DATA,
1281             'test-id2': TEXT_DATA2,
1282             'test-id3': TEXT_DATA3,
1283         }
1284         data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1285                                             entry_args=entry_args)
1286         expected = (tools.ToBytes(TEXT_DATA) +
1287                     tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1288                     tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1289                     b'some text')
1290         self.assertEqual(expected, data)
1291
1292     def testEntryDocs(self):
1293         """Test for creation of entry documentation"""
1294         with test_util.capture_sys_output() as (stdout, stderr):
1295             control.WriteEntryDocs(binman.GetEntryModules())
1296         self.assertTrue(len(stdout.getvalue()) > 0)
1297
1298     def testEntryDocsMissing(self):
1299         """Test handling of missing entry documentation"""
1300         with self.assertRaises(ValueError) as e:
1301             with test_util.capture_sys_output() as (stdout, stderr):
1302                 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1303         self.assertIn('Documentation is missing for modules: u_boot',
1304                       str(e.exception))
1305
1306     def testFmap(self):
1307         """Basic test of generation of a flashrom fmap"""
1308         data = self._DoReadFile('067_fmap.dts')
1309         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1310         expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1311                     U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1312         self.assertEqual(expected, data[:32])
1313         self.assertEqual(b'__FMAP__', fhdr.signature)
1314         self.assertEqual(1, fhdr.ver_major)
1315         self.assertEqual(0, fhdr.ver_minor)
1316         self.assertEqual(0, fhdr.base)
1317         self.assertEqual(16 + 16 +
1318                          fmap_util.FMAP_HEADER_LEN +
1319                          fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1320         self.assertEqual(b'FMAP', fhdr.name)
1321         self.assertEqual(3, fhdr.nareas)
1322         for fentry in fentries:
1323             self.assertEqual(0, fentry.flags)
1324
1325         self.assertEqual(0, fentries[0].offset)
1326         self.assertEqual(4, fentries[0].size)
1327         self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1328
1329         self.assertEqual(16, fentries[1].offset)
1330         self.assertEqual(4, fentries[1].size)
1331         self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1332
1333         self.assertEqual(32, fentries[2].offset)
1334         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1335                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1336         self.assertEqual(b'FMAP', fentries[2].name)
1337
1338     def testBlobNamedByArg(self):
1339         """Test we can add a blob with the filename coming from an entry arg"""
1340         entry_args = {
1341             'cros-ec-rw-path': 'ecrw.bin',
1342         }
1343         data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1344                                             entry_args=entry_args)
1345
1346     def testFill(self):
1347         """Test for an fill entry type"""
1348         data = self._DoReadFile('069_fill.dts')
1349         expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1350         self.assertEqual(expected, data)
1351
1352     def testFillNoSize(self):
1353         """Test for an fill entry type with no size"""
1354         with self.assertRaises(ValueError) as e:
1355             self._DoReadFile('070_fill_no_size.dts')
1356         self.assertIn("'fill' entry must have a size property",
1357                       str(e.exception))
1358
1359     def _HandleGbbCommand(self, pipe_list):
1360         """Fake calls to the futility utility"""
1361         if pipe_list[0][0] == 'futility':
1362             fname = pipe_list[0][-1]
1363             # Append our GBB data to the file, which will happen every time the
1364             # futility command is called.
1365             with open(fname, 'ab') as fd:
1366                 fd.write(GBB_DATA)
1367             return command.CommandResult()
1368
1369     def testGbb(self):
1370         """Test for the Chromium OS Google Binary Block"""
1371         command.test_result = self._HandleGbbCommand
1372         entry_args = {
1373             'keydir': 'devkeys',
1374             'bmpblk': 'bmpblk.bin',
1375         }
1376         data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1377
1378         # Since futility
1379         expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1380                     tools.GetBytes(0, 0x2180 - 16))
1381         self.assertEqual(expected, data)
1382
1383     def testGbbTooSmall(self):
1384         """Test for the Chromium OS Google Binary Block being large enough"""
1385         with self.assertRaises(ValueError) as e:
1386             self._DoReadFileDtb('072_gbb_too_small.dts')
1387         self.assertIn("Node '/binman/gbb': GBB is too small",
1388                       str(e.exception))
1389
1390     def testGbbNoSize(self):
1391         """Test for the Chromium OS Google Binary Block having a size"""
1392         with self.assertRaises(ValueError) as e:
1393             self._DoReadFileDtb('073_gbb_no_size.dts')
1394         self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1395                       str(e.exception))
1396
1397     def _HandleVblockCommand(self, pipe_list):
1398         """Fake calls to the futility utility"""
1399         if pipe_list[0][0] == 'futility':
1400             fname = pipe_list[0][3]
1401             with open(fname, 'wb') as fd:
1402                 fd.write(VBLOCK_DATA)
1403             return command.CommandResult()
1404
1405     def testVblock(self):
1406         """Test for the Chromium OS Verified Boot Block"""
1407         command.test_result = self._HandleVblockCommand
1408         entry_args = {
1409             'keydir': 'devkeys',
1410         }
1411         data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1412                                             entry_args=entry_args)
1413         expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1414         self.assertEqual(expected, data)
1415
1416     def testVblockNoContent(self):
1417         """Test we detect a vblock which has no content to sign"""
1418         with self.assertRaises(ValueError) as e:
1419             self._DoReadFile('075_vblock_no_content.dts')
1420         self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1421                       'property', str(e.exception))
1422
1423     def testVblockBadPhandle(self):
1424         """Test that we detect a vblock with an invalid phandle in contents"""
1425         with self.assertRaises(ValueError) as e:
1426             self._DoReadFile('076_vblock_bad_phandle.dts')
1427         self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1428                       '1000', str(e.exception))
1429
1430     def testVblockBadEntry(self):
1431         """Test that we detect an entry that points to a non-entry"""
1432         with self.assertRaises(ValueError) as e:
1433             self._DoReadFile('077_vblock_bad_entry.dts')
1434         self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1435                       "'other'", str(e.exception))
1436
1437     def testTpl(self):
1438         """Test that an image with TPL and ots device tree can be created"""
1439         # ELF file with a '__bss_size' symbol
1440         with open(self.TestFile('bss_data'), 'rb') as fd:
1441             TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1442         data = self._DoReadFile('078_u_boot_tpl.dts')
1443         self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1444
1445     def testUsesPos(self):
1446         """Test that the 'pos' property cannot be used anymore"""
1447         with self.assertRaises(ValueError) as e:
1448            data = self._DoReadFile('079_uses_pos.dts')
1449         self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1450                       "'pos'", str(e.exception))
1451
1452     def testFillZero(self):
1453         """Test for an fill entry type with a size of 0"""
1454         data = self._DoReadFile('080_fill_empty.dts')
1455         self.assertEqual(tools.GetBytes(0, 16), data)
1456
1457     def testTextMissing(self):
1458         """Test for a text entry type where there is no text"""
1459         with self.assertRaises(ValueError) as e:
1460             self._DoReadFileDtb('066_text.dts',)
1461         self.assertIn("Node '/binman/text': No value provided for text label "
1462                       "'test-id'", str(e.exception))
1463
1464     def testPackStart16Tpl(self):
1465         """Test that an image with an x86 start16 TPL region can be created"""
1466         data = self._DoReadFile('081_x86-start16-tpl.dts')
1467         self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1468
1469     def testSelectImage(self):
1470         """Test that we can select which images to build"""
1471         expected = 'Skipping images: image1'
1472
1473         # We should only get the expected message in verbose mode
1474         for verbosity in (None, 2):
1475             with test_util.capture_sys_output() as (stdout, stderr):
1476                 retcode = self._DoTestFile('006_dual_image.dts',
1477                                            verbosity=verbosity,
1478                                            images=['image2'])
1479             self.assertEqual(0, retcode)
1480             if verbosity:
1481                 self.assertIn(expected, stdout.getvalue())
1482             else:
1483                 self.assertNotIn(expected, stdout.getvalue())
1484
1485             self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1486             self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1487
1488     def testUpdateFdtAll(self):
1489         """Test that all device trees are updated with offset/size info"""
1490         data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1491                                             use_real_dtb=True, update_dtb=True)
1492
1493         base_expected = {
1494             'section:image-pos': 0,
1495             'u-boot-tpl-dtb:size': 513,
1496             'u-boot-spl-dtb:size': 513,
1497             'u-boot-spl-dtb:offset': 493,
1498             'image-pos': 0,
1499             'section/u-boot-dtb:image-pos': 0,
1500             'u-boot-spl-dtb:image-pos': 493,
1501             'section/u-boot-dtb:size': 493,
1502             'u-boot-tpl-dtb:image-pos': 1006,
1503             'section/u-boot-dtb:offset': 0,
1504             'section:size': 493,
1505             'offset': 0,
1506             'section:offset': 0,
1507             'u-boot-tpl-dtb:offset': 1006,
1508             'size': 1519
1509         }
1510
1511         # We expect three device-tree files in the output, one after the other.
1512         # Read them in sequence. We look for an 'spl' property in the SPL tree,
1513         # and 'tpl' in the TPL tree, to make sure they are distinct from the
1514         # main U-Boot tree. All three should have the same postions and offset.
1515         start = 0
1516         for item in ['', 'spl', 'tpl']:
1517             dtb = fdt.Fdt.FromData(data[start:])
1518             dtb.Scan()
1519             props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1520                                             'spl', 'tpl'])
1521             expected = dict(base_expected)
1522             if item:
1523                 expected[item] = 0
1524             self.assertEqual(expected, props)
1525             start += dtb._fdt_obj.totalsize()
1526
1527     def testUpdateFdtOutput(self):
1528         """Test that output DTB files are updated"""
1529         try:
1530             data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1531                     use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1532
1533             # Unfortunately, compiling a source file always results in a file
1534             # called source.dtb (see fdt_util.EnsureCompiled()). The test
1535             # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1536             # binman as a file called u-boot.dtb. To fix this, copy the file
1537             # over to the expected place.
1538             #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1539                     #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1540             start = 0
1541             for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1542                           'tpl/u-boot-tpl.dtb.out']:
1543                 dtb = fdt.Fdt.FromData(data[start:])
1544                 size = dtb._fdt_obj.totalsize()
1545                 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1546                 outdata = tools.ReadFile(pathname)
1547                 name = os.path.split(fname)[0]
1548
1549                 if name:
1550                     orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1551                 else:
1552                     orig_indata = dtb_data
1553                 self.assertNotEqual(outdata, orig_indata,
1554                         "Expected output file '%s' be updated" % pathname)
1555                 self.assertEqual(outdata, data[start:start + size],
1556                         "Expected output file '%s' to match output image" %
1557                         pathname)
1558                 start += size
1559         finally:
1560             self._ResetDtbs()
1561
1562     def _decompress(self, data):
1563         out = os.path.join(self._indir, 'lz4.tmp')
1564         with open(out, 'wb') as fd:
1565             fd.write(data)
1566         return tools.Run('lz4', '-dc', out, binary=True)
1567         '''
1568         try:
1569             orig = lz4.frame.decompress(data)
1570         except AttributeError:
1571             orig = lz4.decompress(data)
1572         '''
1573
1574     def testCompress(self):
1575         """Test compression of blobs"""
1576         data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1577                                             use_real_dtb=True, update_dtb=True)
1578         dtb = fdt.Fdt(out_dtb_fname)
1579         dtb.Scan()
1580         props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1581         orig = self._decompress(data)
1582         self.assertEquals(COMPRESS_DATA, orig)
1583         expected = {
1584             'blob:uncomp-size': len(COMPRESS_DATA),
1585             'blob:size': len(data),
1586             'size': len(data),
1587             }
1588         self.assertEqual(expected, props)
1589
1590     def testFiles(self):
1591         """Test bringing in multiple files"""
1592         data = self._DoReadFile('084_files.dts')
1593         self.assertEqual(FILES_DATA, data)
1594
1595     def testFilesCompress(self):
1596         """Test bringing in multiple files and compressing them"""
1597         data = self._DoReadFile('085_files_compress.dts')
1598
1599         image = control.images['image']
1600         entries = image.GetEntries()
1601         files = entries['files']
1602         entries = files._section._entries
1603
1604         orig = b''
1605         for i in range(1, 3):
1606             key = '%d.dat' % i
1607             start = entries[key].image_pos
1608             len = entries[key].size
1609             chunk = data[start:start + len]
1610             orig += self._decompress(chunk)
1611
1612         self.assertEqual(FILES_DATA, orig)
1613
1614     def testFilesMissing(self):
1615         """Test missing files"""
1616         with self.assertRaises(ValueError) as e:
1617             data = self._DoReadFile('086_files_none.dts')
1618         self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1619                       'no files', str(e.exception))
1620
1621     def testFilesNoPattern(self):
1622         """Test missing files"""
1623         with self.assertRaises(ValueError) as e:
1624             data = self._DoReadFile('087_files_no_pattern.dts')
1625         self.assertIn("Node '/binman/files': Missing 'pattern' property",
1626                       str(e.exception))
1627
1628     def testExpandSize(self):
1629         """Test an expanding entry"""
1630         data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1631                                                    map=True)
1632         expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1633                   MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1634                   tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1635                   tools.GetBytes(ord('d'), 8))
1636         self.assertEqual(expect, data)
1637         self.assertEqual('''ImagePos    Offset      Size  Name
1638 00000000  00000000  00000028  main-section
1639 00000000   00000000  00000008  fill
1640 00000008   00000008  00000004  u-boot
1641 0000000c   0000000c  00000004  section
1642 0000000c    00000000  00000003  intel-mrc
1643 00000010   00000010  00000004  u-boot2
1644 00000014   00000014  0000000c  section2
1645 00000014    00000000  00000008  fill
1646 0000001c    00000008  00000004  u-boot
1647 00000020   00000020  00000008  fill2
1648 ''', map_data)
1649
1650     def testExpandSizeBad(self):
1651         """Test an expanding entry which fails to provide contents"""
1652         with test_util.capture_sys_output() as (stdout, stderr):
1653             with self.assertRaises(ValueError) as e:
1654                 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1655         self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1656                       'expanding entry', str(e.exception))
1657
1658     def testHash(self):
1659         """Test hashing of the contents of an entry"""
1660         _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1661                 use_real_dtb=True, update_dtb=True)
1662         dtb = fdt.Fdt(out_dtb_fname)
1663         dtb.Scan()
1664         hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1665         m = hashlib.sha256()
1666         m.update(U_BOOT_DATA)
1667         self.assertEqual(m.digest(), b''.join(hash_node.value))
1668
1669     def testHashNoAlgo(self):
1670         with self.assertRaises(ValueError) as e:
1671             self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1672         self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1673                       'hash node', str(e.exception))
1674
1675     def testHashBadAlgo(self):
1676         with self.assertRaises(ValueError) as e:
1677             self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1678         self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1679                       str(e.exception))
1680
1681     def testHashSection(self):
1682         """Test hashing of the contents of an entry"""
1683         _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1684                 use_real_dtb=True, update_dtb=True)
1685         dtb = fdt.Fdt(out_dtb_fname)
1686         dtb.Scan()
1687         hash_node = dtb.GetNode('/binman/section/hash').props['value']
1688         m = hashlib.sha256()
1689         m.update(U_BOOT_DATA)
1690         m.update(tools.GetBytes(ord('a'), 16))
1691         self.assertEqual(m.digest(), b''.join(hash_node.value))
1692
1693     def testPackUBootTplMicrocode(self):
1694         """Test that x86 microcode can be handled correctly in TPL
1695
1696         We expect to see the following in the image, in order:
1697             u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1698                 place
1699             u-boot-tpl.dtb with the microcode removed
1700             the microcode
1701         """
1702         with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1703             TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1704         first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1705                                                      U_BOOT_TPL_NODTB_DATA)
1706         self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1707                          b'ter somewhere in here', first)
1708
1709     def testFmapX86(self):
1710         """Basic test of generation of a flashrom fmap"""
1711         data = self._DoReadFile('094_fmap_x86.dts')
1712         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1713         expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1714         self.assertEqual(expected, data[:32])
1715         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1716
1717         self.assertEqual(0x100, fhdr.image_size)
1718
1719         self.assertEqual(0, fentries[0].offset)
1720         self.assertEqual(4, fentries[0].size)
1721         self.assertEqual(b'U_BOOT', fentries[0].name)
1722
1723         self.assertEqual(4, fentries[1].offset)
1724         self.assertEqual(3, fentries[1].size)
1725         self.assertEqual(b'INTEL_MRC', fentries[1].name)
1726
1727         self.assertEqual(32, fentries[2].offset)
1728         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1729                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1730         self.assertEqual(b'FMAP', fentries[2].name)
1731
1732     def testFmapX86Section(self):
1733         """Basic test of generation of a flashrom fmap"""
1734         data = self._DoReadFile('095_fmap_x86_section.dts')
1735         expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1736         self.assertEqual(expected, data[:32])
1737         fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1738
1739         self.assertEqual(0x100, fhdr.image_size)
1740
1741         self.assertEqual(0, fentries[0].offset)
1742         self.assertEqual(4, fentries[0].size)
1743         self.assertEqual(b'U_BOOT', fentries[0].name)
1744
1745         self.assertEqual(4, fentries[1].offset)
1746         self.assertEqual(3, fentries[1].size)
1747         self.assertEqual(b'INTEL_MRC', fentries[1].name)
1748
1749         self.assertEqual(36, fentries[2].offset)
1750         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1751                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1752         self.assertEqual(b'FMAP', fentries[2].name)
1753
1754     def testElf(self):
1755         """Basic test of ELF entries"""
1756         self._SetupSplElf()
1757         with open(self.TestFile('bss_data'), 'rb') as fd:
1758             TestFunctional._MakeInputFile('-boot', fd.read())
1759         data = self._DoReadFile('096_elf.dts')
1760
1761     def testElfStripg(self):
1762         """Basic test of ELF entries"""
1763         self._SetupSplElf()
1764         with open(self.TestFile('bss_data'), 'rb') as fd:
1765             TestFunctional._MakeInputFile('-boot', fd.read())
1766         data = self._DoReadFile('097_elf_strip.dts')
1767
1768     def testPackOverlapMap(self):
1769         """Test that overlapping regions are detected"""
1770         with test_util.capture_sys_output() as (stdout, stderr):
1771             with self.assertRaises(ValueError) as e:
1772                 self._DoTestFile('014_pack_overlap.dts', map=True)
1773         map_fname = tools.GetOutputFilename('image.map')
1774         self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1775                          stdout.getvalue())
1776
1777         # We should not get an inmage, but there should be a map file
1778         self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1779         self.assertTrue(os.path.exists(map_fname))
1780         map_data = tools.ReadFile(map_fname, binary=False)
1781         self.assertEqual('''ImagePos    Offset      Size  Name
1782 <none>    00000000  00000007  main-section
1783 <none>     00000000  00000004  u-boot
1784 <none>     00000003  00000004  u-boot-align
1785 ''', map_data)
1786
1787     def testPacRefCode(self):
1788         """Test that an image with an Intel Reference code binary works"""
1789         data = self._DoReadFile('100_intel_refcode.dts')
1790         self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1791
1792     def testSectionOffset(self):
1793         """Tests use of a section with an offset"""
1794         data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1795                                                    map=True)
1796         self.assertEqual('''ImagePos    Offset      Size  Name
1797 00000000  00000000  00000038  main-section
1798 00000004   00000004  00000010  section@0
1799 00000004    00000000  00000004  u-boot
1800 00000018   00000018  00000010  section@1
1801 00000018    00000000  00000004  u-boot
1802 0000002c   0000002c  00000004  section@2
1803 0000002c    00000000  00000004  u-boot
1804 ''', map_data)
1805         self.assertEqual(data,
1806                          tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1807                              tools.GetBytes(0x21, 12) +
1808                          tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1809                              tools.GetBytes(0x61, 12) +
1810                          tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1811                              tools.GetBytes(0x26, 8))
1812
1813
1814 if __name__ == "__main__":
1815     unittest.main()