Merge https://gitlab.denx.de/u-boot/custodians/u-boot-marvell
[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           = '1234'
33 U_BOOT_IMG_DATA       = 'img'
34 U_BOOT_SPL_DATA       = '56780123456789abcde'
35 U_BOOT_TPL_DATA       = 'tpl'
36 BLOB_DATA             = '89'
37 ME_DATA               = '0abcd'
38 VGA_DATA              = 'vga'
39 U_BOOT_DTB_DATA       = 'udtb'
40 U_BOOT_SPL_DTB_DATA   = 'spldtb'
41 U_BOOT_TPL_DTB_DATA   = 'tpldtb'
42 X86_START16_DATA      = 'start16'
43 X86_START16_SPL_DATA  = 'start16spl'
44 X86_START16_TPL_DATA  = 'start16tpl'
45 PPC_MPC85XX_BR_DATA   = 'ppcmpc85xxbr'
46 U_BOOT_NODTB_DATA     = 'nodtb with microcode pointer somewhere in here'
47 U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
48 U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here'
49 FSP_DATA              = 'fsp'
50 CMC_DATA              = 'cmc'
51 VBT_DATA              = 'vbt'
52 MRC_DATA              = 'mrc'
53 TEXT_DATA             = 'text'
54 TEXT_DATA2            = 'text2'
55 TEXT_DATA3            = 'text3'
56 CROS_EC_RW_DATA       = 'ecrw'
57 GBB_DATA              = 'gbbd'
58 BMPBLK_DATA           = 'bmp'
59 VBLOCK_DATA           = 'vblk'
60 FILES_DATA            = ("sorry I'm late\nOh, don't bother apologising, I'm " +
61                          "sorry you're alive\n")
62 COMPRESS_DATA         = 'data to compress'
63 REFCODE_DATA          = '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')) as fd:
123             TestFunctional._MakeInputFile('u-boot', fd.read())
124
125         # Intel flash descriptor file
126         with open(self.TestFile('descriptor.bin')) 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.iteritems():
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) 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             infile = os.path.join(self._indir, 'u-boot.dtb')
295
296             # For testing purposes, make a copy of the DT for SPL and TPL. Add
297             # a node indicating which it is, so aid verification.
298             for name in ['spl', 'tpl']:
299                 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
300                 outfile = os.path.join(self._indir, dtb_fname)
301                 TestFunctional._MakeInputFile(dtb_fname,
302                         self._GetDtbContentsForSplTpl(dtb_data, name))
303
304         try:
305             retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
306                     entry_args=entry_args, use_real_dtb=use_real_dtb)
307             self.assertEqual(0, retcode)
308             out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
309
310             # Find the (only) image, read it and return its contents
311             image = control.images['image']
312             image_fname = tools.GetOutputFilename('image.bin')
313             self.assertTrue(os.path.exists(image_fname))
314             if map:
315                 map_fname = tools.GetOutputFilename('image.map')
316                 with open(map_fname) as fd:
317                     map_data = fd.read()
318             else:
319                 map_data = None
320             with open(image_fname) as fd:
321                 return fd.read(), dtb_data, map_data, out_dtb_fname
322         finally:
323             # Put the test file back
324             if reset_dtbs and use_real_dtb:
325                 self._ResetDtbs()
326
327     def _DoReadFile(self, fname, use_real_dtb=False):
328         """Helper function which discards the device-tree binary
329
330         Args:
331             fname: Device-tree source filename to use (e.g. 005_simple.dts)
332             use_real_dtb: True to use the test file as the contents of
333                 the u-boot-dtb entry. Normally this is not needed and the
334                 test contents (the U_BOOT_DTB_DATA string) can be used.
335                 But in some test we need the real contents.
336
337         Returns:
338             Resulting image contents
339         """
340         return self._DoReadFileDtb(fname, use_real_dtb)[0]
341
342     @classmethod
343     def _MakeInputFile(self, fname, contents):
344         """Create a new test input file, creating directories as needed
345
346         Args:
347             fname: Filename to create
348             contents: File contents to write in to the file
349         Returns:
350             Full pathname of file created
351         """
352         pathname = os.path.join(self._indir, fname)
353         dirname = os.path.dirname(pathname)
354         if dirname and not os.path.exists(dirname):
355             os.makedirs(dirname)
356         with open(pathname, 'wb') as fd:
357             fd.write(contents)
358         return pathname
359
360     @classmethod
361     def _MakeInputDir(self, dirname):
362         """Create a new test input directory, creating directories as needed
363
364         Args:
365             dirname: Directory name to create
366
367         Returns:
368             Full pathname of directory created
369         """
370         pathname = os.path.join(self._indir, dirname)
371         if not os.path.exists(pathname):
372             os.makedirs(pathname)
373         return pathname
374
375     @classmethod
376     def _SetupSplElf(self, src_fname='bss_data'):
377         """Set up an ELF file with a '_dt_ucode_base_size' symbol
378
379         Args:
380             Filename of ELF file to use as SPL
381         """
382         with open(self.TestFile(src_fname)) as fd:
383             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
384
385     @classmethod
386     def TestFile(self, fname):
387         return os.path.join(self._binman_dir, 'test', fname)
388
389     def AssertInList(self, grep_list, target):
390         """Assert that at least one of a list of things is in a target
391
392         Args:
393             grep_list: List of strings to check
394             target: Target string
395         """
396         for grep in grep_list:
397             if grep in target:
398                 return
399         self.fail("Error: '%' not found in '%s'" % (grep_list, target))
400
401     def CheckNoGaps(self, entries):
402         """Check that all entries fit together without gaps
403
404         Args:
405             entries: List of entries to check
406         """
407         offset = 0
408         for entry in entries.values():
409             self.assertEqual(offset, entry.offset)
410             offset += entry.size
411
412     def GetFdtLen(self, dtb):
413         """Get the totalsize field from a device-tree binary
414
415         Args:
416             dtb: Device-tree binary contents
417
418         Returns:
419             Total size of device-tree binary, from the header
420         """
421         return struct.unpack('>L', dtb[4:8])[0]
422
423     def _GetPropTree(self, dtb, prop_names):
424         def AddNode(node, path):
425             if node.name != '/':
426                 path += '/' + node.name
427             for subnode in node.subnodes:
428                 for prop in subnode.props.values():
429                     if prop.name in prop_names:
430                         prop_path = path + '/' + subnode.name + ':' + prop.name
431                         tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
432                             prop.value)
433                 AddNode(subnode, path)
434
435         tree = {}
436         AddNode(dtb.GetRoot(), '')
437         return tree
438
439     def testRun(self):
440         """Test a basic run with valid args"""
441         result = self._RunBinman('-h')
442
443     def testFullHelp(self):
444         """Test that the full help is displayed with -H"""
445         result = self._RunBinman('-H')
446         help_file = os.path.join(self._binman_dir, 'README')
447         # Remove possible extraneous strings
448         extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
449         gothelp = result.stdout.replace(extra, '')
450         self.assertEqual(len(gothelp), os.path.getsize(help_file))
451         self.assertEqual(0, len(result.stderr))
452         self.assertEqual(0, result.return_code)
453
454     def testFullHelpInternal(self):
455         """Test that the full help is displayed with -H"""
456         try:
457             command.test_result = command.CommandResult()
458             result = self._DoBinman('-H')
459             help_file = os.path.join(self._binman_dir, 'README')
460         finally:
461             command.test_result = None
462
463     def testHelp(self):
464         """Test that the basic help is displayed with -h"""
465         result = self._RunBinman('-h')
466         self.assertTrue(len(result.stdout) > 200)
467         self.assertEqual(0, len(result.stderr))
468         self.assertEqual(0, result.return_code)
469
470     def testBoard(self):
471         """Test that we can run it with a specific board"""
472         self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
473         TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
474         result = self._DoBinman('-b', 'sandbox')
475         self.assertEqual(0, result)
476
477     def testNeedBoard(self):
478         """Test that we get an error when no board ius supplied"""
479         with self.assertRaises(ValueError) as e:
480             result = self._DoBinman()
481         self.assertIn("Must provide a board to process (use -b <board>)",
482                 str(e.exception))
483
484     def testMissingDt(self):
485         """Test that an invalid device-tree file generates an error"""
486         with self.assertRaises(Exception) as e:
487             self._RunBinman('-d', 'missing_file')
488         # We get one error from libfdt, and a different one from fdtget.
489         self.AssertInList(["Couldn't open blob from 'missing_file'",
490                            'No such file or directory'], str(e.exception))
491
492     def testBrokenDt(self):
493         """Test that an invalid device-tree source file generates an error
494
495         Since this is a source file it should be compiled and the error
496         will come from the device-tree compiler (dtc).
497         """
498         with self.assertRaises(Exception) as e:
499             self._RunBinman('-d', self.TestFile('001_invalid.dts'))
500         self.assertIn("FATAL ERROR: Unable to parse input tree",
501                 str(e.exception))
502
503     def testMissingNode(self):
504         """Test that a device tree without a 'binman' node generates an error"""
505         with self.assertRaises(Exception) as e:
506             self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
507         self.assertIn("does not have a 'binman' node", str(e.exception))
508
509     def testEmpty(self):
510         """Test that an empty binman node works OK (i.e. does nothing)"""
511         result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
512         self.assertEqual(0, len(result.stderr))
513         self.assertEqual(0, result.return_code)
514
515     def testInvalidEntry(self):
516         """Test that an invalid entry is flagged"""
517         with self.assertRaises(Exception) as e:
518             result = self._RunBinman('-d',
519                                      self.TestFile('004_invalid_entry.dts'))
520         self.assertIn("Unknown entry type 'not-a-valid-type' in node "
521                 "'/binman/not-a-valid-type'", str(e.exception))
522
523     def testSimple(self):
524         """Test a simple binman with a single file"""
525         data = self._DoReadFile('005_simple.dts')
526         self.assertEqual(U_BOOT_DATA, data)
527
528     def testSimpleDebug(self):
529         """Test a simple binman run with debugging enabled"""
530         data = self._DoTestFile('005_simple.dts', debug=True)
531
532     def testDual(self):
533         """Test that we can handle creating two images
534
535         This also tests image padding.
536         """
537         retcode = self._DoTestFile('006_dual_image.dts')
538         self.assertEqual(0, retcode)
539
540         image = control.images['image1']
541         self.assertEqual(len(U_BOOT_DATA), image._size)
542         fname = tools.GetOutputFilename('image1.bin')
543         self.assertTrue(os.path.exists(fname))
544         with open(fname) as fd:
545             data = fd.read()
546             self.assertEqual(U_BOOT_DATA, data)
547
548         image = control.images['image2']
549         self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
550         fname = tools.GetOutputFilename('image2.bin')
551         self.assertTrue(os.path.exists(fname))
552         with open(fname) as fd:
553             data = fd.read()
554             self.assertEqual(U_BOOT_DATA, data[3:7])
555             self.assertEqual(chr(0) * 3, data[:3])
556             self.assertEqual(chr(0) * 5, data[7:])
557
558     def testBadAlign(self):
559         """Test that an invalid alignment value is detected"""
560         with self.assertRaises(ValueError) as e:
561             self._DoTestFile('007_bad_align.dts')
562         self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
563                       "of two", str(e.exception))
564
565     def testPackSimple(self):
566         """Test that packing works as expected"""
567         retcode = self._DoTestFile('008_pack.dts')
568         self.assertEqual(0, retcode)
569         self.assertIn('image', control.images)
570         image = control.images['image']
571         entries = image.GetEntries()
572         self.assertEqual(5, len(entries))
573
574         # First u-boot
575         self.assertIn('u-boot', entries)
576         entry = entries['u-boot']
577         self.assertEqual(0, entry.offset)
578         self.assertEqual(len(U_BOOT_DATA), entry.size)
579
580         # Second u-boot, aligned to 16-byte boundary
581         self.assertIn('u-boot-align', entries)
582         entry = entries['u-boot-align']
583         self.assertEqual(16, entry.offset)
584         self.assertEqual(len(U_BOOT_DATA), entry.size)
585
586         # Third u-boot, size 23 bytes
587         self.assertIn('u-boot-size', entries)
588         entry = entries['u-boot-size']
589         self.assertEqual(20, entry.offset)
590         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
591         self.assertEqual(23, entry.size)
592
593         # Fourth u-boot, placed immediate after the above
594         self.assertIn('u-boot-next', entries)
595         entry = entries['u-boot-next']
596         self.assertEqual(43, entry.offset)
597         self.assertEqual(len(U_BOOT_DATA), entry.size)
598
599         # Fifth u-boot, placed at a fixed offset
600         self.assertIn('u-boot-fixed', entries)
601         entry = entries['u-boot-fixed']
602         self.assertEqual(61, entry.offset)
603         self.assertEqual(len(U_BOOT_DATA), entry.size)
604
605         self.assertEqual(65, image._size)
606
607     def testPackExtra(self):
608         """Test that extra packing feature works as expected"""
609         retcode = self._DoTestFile('009_pack_extra.dts')
610
611         self.assertEqual(0, retcode)
612         self.assertIn('image', control.images)
613         image = control.images['image']
614         entries = image.GetEntries()
615         self.assertEqual(5, len(entries))
616
617         # First u-boot with padding before and after
618         self.assertIn('u-boot', entries)
619         entry = entries['u-boot']
620         self.assertEqual(0, entry.offset)
621         self.assertEqual(3, entry.pad_before)
622         self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
623
624         # Second u-boot has an aligned size, but it has no effect
625         self.assertIn('u-boot-align-size-nop', entries)
626         entry = entries['u-boot-align-size-nop']
627         self.assertEqual(12, entry.offset)
628         self.assertEqual(4, entry.size)
629
630         # Third u-boot has an aligned size too
631         self.assertIn('u-boot-align-size', entries)
632         entry = entries['u-boot-align-size']
633         self.assertEqual(16, entry.offset)
634         self.assertEqual(32, entry.size)
635
636         # Fourth u-boot has an aligned end
637         self.assertIn('u-boot-align-end', entries)
638         entry = entries['u-boot-align-end']
639         self.assertEqual(48, entry.offset)
640         self.assertEqual(16, entry.size)
641
642         # Fifth u-boot immediately afterwards
643         self.assertIn('u-boot-align-both', entries)
644         entry = entries['u-boot-align-both']
645         self.assertEqual(64, entry.offset)
646         self.assertEqual(64, entry.size)
647
648         self.CheckNoGaps(entries)
649         self.assertEqual(128, image._size)
650
651     def testPackAlignPowerOf2(self):
652         """Test that invalid entry alignment is detected"""
653         with self.assertRaises(ValueError) as e:
654             self._DoTestFile('010_pack_align_power2.dts')
655         self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
656                       "of two", str(e.exception))
657
658     def testPackAlignSizePowerOf2(self):
659         """Test that invalid entry size alignment is detected"""
660         with self.assertRaises(ValueError) as e:
661             self._DoTestFile('011_pack_align_size_power2.dts')
662         self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
663                       "power of two", str(e.exception))
664
665     def testPackInvalidAlign(self):
666         """Test detection of an offset that does not match its alignment"""
667         with self.assertRaises(ValueError) as e:
668             self._DoTestFile('012_pack_inv_align.dts')
669         self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
670                       "align 0x4 (4)", str(e.exception))
671
672     def testPackInvalidSizeAlign(self):
673         """Test that invalid entry size alignment is detected"""
674         with self.assertRaises(ValueError) as e:
675             self._DoTestFile('013_pack_inv_size_align.dts')
676         self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
677                       "align-size 0x4 (4)", str(e.exception))
678
679     def testPackOverlap(self):
680         """Test that overlapping regions are detected"""
681         with self.assertRaises(ValueError) as e:
682             self._DoTestFile('014_pack_overlap.dts')
683         self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
684                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
685                       str(e.exception))
686
687     def testPackEntryOverflow(self):
688         """Test that entries that overflow their size are detected"""
689         with self.assertRaises(ValueError) as e:
690             self._DoTestFile('015_pack_overflow.dts')
691         self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
692                       "but entry size is 0x3 (3)", str(e.exception))
693
694     def testPackImageOverflow(self):
695         """Test that entries which overflow the image size are detected"""
696         with self.assertRaises(ValueError) as e:
697             self._DoTestFile('016_pack_image_overflow.dts')
698         self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
699                       "size 0x3 (3)", str(e.exception))
700
701     def testPackImageSize(self):
702         """Test that the image size can be set"""
703         retcode = self._DoTestFile('017_pack_image_size.dts')
704         self.assertEqual(0, retcode)
705         self.assertIn('image', control.images)
706         image = control.images['image']
707         self.assertEqual(7, image._size)
708
709     def testPackImageSizeAlign(self):
710         """Test that image size alignemnt works as expected"""
711         retcode = self._DoTestFile('018_pack_image_align.dts')
712         self.assertEqual(0, retcode)
713         self.assertIn('image', control.images)
714         image = control.images['image']
715         self.assertEqual(16, image._size)
716
717     def testPackInvalidImageAlign(self):
718         """Test that invalid image alignment is detected"""
719         with self.assertRaises(ValueError) as e:
720             self._DoTestFile('019_pack_inv_image_align.dts')
721         self.assertIn("Section '/binman': Size 0x7 (7) does not match "
722                       "align-size 0x8 (8)", str(e.exception))
723
724     def testPackAlignPowerOf2(self):
725         """Test that invalid image alignment is detected"""
726         with self.assertRaises(ValueError) as e:
727             self._DoTestFile('020_pack_inv_image_align_power2.dts')
728         self.assertIn("Section '/binman': Alignment size 131 must be a power of "
729                       "two", str(e.exception))
730
731     def testImagePadByte(self):
732         """Test that the image pad byte can be specified"""
733         self._SetupSplElf()
734         data = self._DoReadFile('021_image_pad.dts')
735         self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + 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(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
759                          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 + chr(0) * 7 + U_BOOT_SPL_DATA +
802                          chr(0) * 2, data)
803
804     def testPackX86RomMeNoDesc(self):
805         """Test that an invalid Intel descriptor entry is detected"""
806         TestFunctional._MakeInputFile('descriptor.bin', '')
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('nodtb with microcode' + pos_and_size +
904                          ' 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('nodtb with microcode' + pos_and_size +
936                          ' 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')) 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')) 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')) 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(chr(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 + (chr(0) * 10) + U_BOOT_DATA, data)
1039
1040     def testSplBssPadMissing(self):
1041         """Test that a missing symbol is detected"""
1042         self._SetupSplElf('u_boot_ucode_ptr')
1043         with self.assertRaises(ValueError) as e:
1044             self._DoReadFile('047_spl_bss_pad.dts')
1045         self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1046                       str(e.exception))
1047
1048     def testPackStart16Spl(self):
1049         """Test that an image with an x86 start16 SPL region can be created"""
1050         data = self._DoReadFile('048_x86-start16-spl.dts')
1051         self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1052
1053     def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1054         """Helper function for microcode tests
1055
1056         We expect to see the following in the image, in order:
1057             u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1058                 correct place
1059             u-boot.dtb with the microcode removed
1060             the microcode
1061
1062         Args:
1063             dts: Device tree file to use for test
1064             ucode_second: True if the microsecond entry is second instead of
1065                 third
1066         """
1067         self._SetupSplElf('u_boot_ucode_ptr')
1068         first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1069                                                      ucode_second=ucode_second)
1070         self.assertEqual('splnodtb with microc' + pos_and_size +
1071                          'ter somewhere in here', first)
1072
1073     def testPackUbootSplMicrocode(self):
1074         """Test that x86 microcode can be handled correctly in SPL"""
1075         self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1076
1077     def testPackUbootSplMicrocodeReorder(self):
1078         """Test that order doesn't matter for microcode entries
1079
1080         This is the same as testPackUbootSplMicrocode but when we process the
1081         u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1082         entry, so we reply on binman to try later.
1083         """
1084         self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1085                                     ucode_second=True)
1086
1087     def testPackMrc(self):
1088         """Test that an image with an MRC binary can be created"""
1089         data = self._DoReadFile('050_intel_mrc.dts')
1090         self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1091
1092     def testSplDtb(self):
1093         """Test that an image with spl/u-boot-spl.dtb can be created"""
1094         data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1095         self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1096
1097     def testSplNoDtb(self):
1098         """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1099         data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1100         self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1101
1102     def testSymbols(self):
1103         """Test binman can assign symbols embedded in U-Boot"""
1104         elf_fname = self.TestFile('u_boot_binman_syms')
1105         syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1106         addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1107         self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1108
1109         self._SetupSplElf('u_boot_binman_syms')
1110         data = self._DoReadFile('053_symbols.dts')
1111         sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1112         expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1113                     U_BOOT_DATA +
1114                     sym_values + U_BOOT_SPL_DATA[16:])
1115         self.assertEqual(expected, data)
1116
1117     def testPackUnitAddress(self):
1118         """Test that we support multiple binaries with the same name"""
1119         data = self._DoReadFile('054_unit_address.dts')
1120         self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1121
1122     def testSections(self):
1123         """Basic test of sections"""
1124         data = self._DoReadFile('055_sections.dts')
1125         expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1126                     U_BOOT_DATA + '&' * 4)
1127         self.assertEqual(expected, data)
1128
1129     def testMap(self):
1130         """Tests outputting a map of the images"""
1131         _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1132         self.assertEqual('''ImagePos    Offset      Size  Name
1133 00000000  00000000  00000028  main-section
1134 00000000   00000000  00000010  section@0
1135 00000000    00000000  00000004  u-boot
1136 00000010   00000010  00000010  section@1
1137 00000010    00000000  00000004  u-boot
1138 00000020   00000020  00000004  section@2
1139 00000020    00000000  00000004  u-boot
1140 ''', map_data)
1141
1142     def testNamePrefix(self):
1143         """Tests that name prefixes are used"""
1144         _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1145         self.assertEqual('''ImagePos    Offset      Size  Name
1146 00000000  00000000  00000028  main-section
1147 00000000   00000000  00000010  section@0
1148 00000000    00000000  00000004  ro-u-boot
1149 00000010   00000010  00000010  section@1
1150 00000010    00000000  00000004  rw-u-boot
1151 ''', map_data)
1152
1153     def testUnknownContents(self):
1154         """Test that obtaining the contents works as expected"""
1155         with self.assertRaises(ValueError) as e:
1156             self._DoReadFile('057_unknown_contents.dts', True)
1157         self.assertIn("Section '/binman': Internal error: Could not complete "
1158                 "processing of contents: remaining [<_testing.Entry__testing ",
1159                 str(e.exception))
1160
1161     def testBadChangeSize(self):
1162         """Test that trying to change the size of an entry fails"""
1163         with self.assertRaises(ValueError) as e:
1164             self._DoReadFile('059_change_size.dts', True)
1165         self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1166                       '2 to 1', str(e.exception))
1167
1168     def testUpdateFdt(self):
1169         """Test that we can update the device tree with offset/size info"""
1170         _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1171                                                      update_dtb=True)
1172         dtb = fdt.Fdt(out_dtb_fname)
1173         dtb.Scan()
1174         props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
1175         self.assertEqual({
1176             'image-pos': 0,
1177             'offset': 0,
1178             '_testing:offset': 32,
1179             '_testing:size': 1,
1180             '_testing:image-pos': 32,
1181             'section@0/u-boot:offset': 0,
1182             'section@0/u-boot:size': len(U_BOOT_DATA),
1183             'section@0/u-boot:image-pos': 0,
1184             'section@0:offset': 0,
1185             'section@0:size': 16,
1186             'section@0:image-pos': 0,
1187
1188             'section@1/u-boot:offset': 0,
1189             'section@1/u-boot:size': len(U_BOOT_DATA),
1190             'section@1/u-boot:image-pos': 16,
1191             'section@1:offset': 16,
1192             'section@1:size': 16,
1193             'section@1:image-pos': 16,
1194             'size': 40
1195         }, props)
1196
1197     def testUpdateFdtBad(self):
1198         """Test that we detect when ProcessFdt never completes"""
1199         with self.assertRaises(ValueError) as e:
1200             self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1201         self.assertIn('Could not complete processing of Fdt: remaining '
1202                       '[<_testing.Entry__testing', str(e.exception))
1203
1204     def testEntryArgs(self):
1205         """Test passing arguments to entries from the command line"""
1206         entry_args = {
1207             'test-str-arg': 'test1',
1208             'test-int-arg': '456',
1209         }
1210         self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1211         self.assertIn('image', control.images)
1212         entry = control.images['image'].GetEntries()['_testing']
1213         self.assertEqual('test0', entry.test_str_fdt)
1214         self.assertEqual('test1', entry.test_str_arg)
1215         self.assertEqual(123, entry.test_int_fdt)
1216         self.assertEqual(456, entry.test_int_arg)
1217
1218     def testEntryArgsMissing(self):
1219         """Test missing arguments and properties"""
1220         entry_args = {
1221             'test-int-arg': '456',
1222         }
1223         self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1224         entry = control.images['image'].GetEntries()['_testing']
1225         self.assertEqual('test0', entry.test_str_fdt)
1226         self.assertEqual(None, entry.test_str_arg)
1227         self.assertEqual(None, entry.test_int_fdt)
1228         self.assertEqual(456, entry.test_int_arg)
1229
1230     def testEntryArgsRequired(self):
1231         """Test missing arguments and properties"""
1232         entry_args = {
1233             'test-int-arg': '456',
1234         }
1235         with self.assertRaises(ValueError) as e:
1236             self._DoReadFileDtb('064_entry_args_required.dts')
1237         self.assertIn("Node '/binman/_testing': Missing required "
1238             'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1239             str(e.exception))
1240
1241     def testEntryArgsInvalidFormat(self):
1242         """Test that an invalid entry-argument format is detected"""
1243         args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
1244         with self.assertRaises(ValueError) as e:
1245             self._DoBinman(*args)
1246         self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1247
1248     def testEntryArgsInvalidInteger(self):
1249         """Test that an invalid entry-argument integer is detected"""
1250         entry_args = {
1251             'test-int-arg': 'abc',
1252         }
1253         with self.assertRaises(ValueError) as e:
1254             self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1255         self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1256                       "'test-int-arg' (value 'abc') to integer",
1257             str(e.exception))
1258
1259     def testEntryArgsInvalidDatatype(self):
1260         """Test that an invalid entry-argument datatype is detected
1261
1262         This test could be written in entry_test.py except that it needs
1263         access to control.entry_args, which seems more than that module should
1264         be able to see.
1265         """
1266         entry_args = {
1267             'test-bad-datatype-arg': '12',
1268         }
1269         with self.assertRaises(ValueError) as e:
1270             self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1271                                 entry_args=entry_args)
1272         self.assertIn('GetArg() internal error: Unknown data type ',
1273                       str(e.exception))
1274
1275     def testText(self):
1276         """Test for a text entry type"""
1277         entry_args = {
1278             'test-id': TEXT_DATA,
1279             'test-id2': TEXT_DATA2,
1280             'test-id3': TEXT_DATA3,
1281         }
1282         data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1283                                             entry_args=entry_args)
1284         expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1285                     TEXT_DATA3 + 'some text')
1286         self.assertEqual(expected, data)
1287
1288     def testEntryDocs(self):
1289         """Test for creation of entry documentation"""
1290         with test_util.capture_sys_output() as (stdout, stderr):
1291             control.WriteEntryDocs(binman.GetEntryModules())
1292         self.assertTrue(len(stdout.getvalue()) > 0)
1293
1294     def testEntryDocsMissing(self):
1295         """Test handling of missing entry documentation"""
1296         with self.assertRaises(ValueError) as e:
1297             with test_util.capture_sys_output() as (stdout, stderr):
1298                 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1299         self.assertIn('Documentation is missing for modules: u_boot',
1300                       str(e.exception))
1301
1302     def testFmap(self):
1303         """Basic test of generation of a flashrom fmap"""
1304         data = self._DoReadFile('067_fmap.dts')
1305         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1306         expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1307         self.assertEqual(expected, data[:32])
1308         self.assertEqual('__FMAP__', fhdr.signature)
1309         self.assertEqual(1, fhdr.ver_major)
1310         self.assertEqual(0, fhdr.ver_minor)
1311         self.assertEqual(0, fhdr.base)
1312         self.assertEqual(16 + 16 +
1313                          fmap_util.FMAP_HEADER_LEN +
1314                          fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1315         self.assertEqual('FMAP', fhdr.name)
1316         self.assertEqual(3, fhdr.nareas)
1317         for fentry in fentries:
1318             self.assertEqual(0, fentry.flags)
1319
1320         self.assertEqual(0, fentries[0].offset)
1321         self.assertEqual(4, fentries[0].size)
1322         self.assertEqual('RO_U_BOOT', fentries[0].name)
1323
1324         self.assertEqual(16, fentries[1].offset)
1325         self.assertEqual(4, fentries[1].size)
1326         self.assertEqual('RW_U_BOOT', fentries[1].name)
1327
1328         self.assertEqual(32, fentries[2].offset)
1329         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1330                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1331         self.assertEqual('FMAP', fentries[2].name)
1332
1333     def testBlobNamedByArg(self):
1334         """Test we can add a blob with the filename coming from an entry arg"""
1335         entry_args = {
1336             'cros-ec-rw-path': 'ecrw.bin',
1337         }
1338         data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1339                                             entry_args=entry_args)
1340
1341     def testFill(self):
1342         """Test for an fill entry type"""
1343         data = self._DoReadFile('069_fill.dts')
1344         expected = 8 * chr(0xff) + 8 * chr(0)
1345         self.assertEqual(expected, data)
1346
1347     def testFillNoSize(self):
1348         """Test for an fill entry type with no size"""
1349         with self.assertRaises(ValueError) as e:
1350             self._DoReadFile('070_fill_no_size.dts')
1351         self.assertIn("'fill' entry must have a size property",
1352                       str(e.exception))
1353
1354     def _HandleGbbCommand(self, pipe_list):
1355         """Fake calls to the futility utility"""
1356         if pipe_list[0][0] == 'futility':
1357             fname = pipe_list[0][-1]
1358             # Append our GBB data to the file, which will happen every time the
1359             # futility command is called.
1360             with open(fname, 'a') as fd:
1361                 fd.write(GBB_DATA)
1362             return command.CommandResult()
1363
1364     def testGbb(self):
1365         """Test for the Chromium OS Google Binary Block"""
1366         command.test_result = self._HandleGbbCommand
1367         entry_args = {
1368             'keydir': 'devkeys',
1369             'bmpblk': 'bmpblk.bin',
1370         }
1371         data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1372
1373         # Since futility
1374         expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1375         self.assertEqual(expected, data)
1376
1377     def testGbbTooSmall(self):
1378         """Test for the Chromium OS Google Binary Block being large enough"""
1379         with self.assertRaises(ValueError) as e:
1380             self._DoReadFileDtb('072_gbb_too_small.dts')
1381         self.assertIn("Node '/binman/gbb': GBB is too small",
1382                       str(e.exception))
1383
1384     def testGbbNoSize(self):
1385         """Test for the Chromium OS Google Binary Block having a size"""
1386         with self.assertRaises(ValueError) as e:
1387             self._DoReadFileDtb('073_gbb_no_size.dts')
1388         self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1389                       str(e.exception))
1390
1391     def _HandleVblockCommand(self, pipe_list):
1392         """Fake calls to the futility utility"""
1393         if pipe_list[0][0] == 'futility':
1394             fname = pipe_list[0][3]
1395             with open(fname, 'wb') as fd:
1396                 fd.write(VBLOCK_DATA)
1397             return command.CommandResult()
1398
1399     def testVblock(self):
1400         """Test for the Chromium OS Verified Boot Block"""
1401         command.test_result = self._HandleVblockCommand
1402         entry_args = {
1403             'keydir': 'devkeys',
1404         }
1405         data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1406                                             entry_args=entry_args)
1407         expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1408         self.assertEqual(expected, data)
1409
1410     def testVblockNoContent(self):
1411         """Test we detect a vblock which has no content to sign"""
1412         with self.assertRaises(ValueError) as e:
1413             self._DoReadFile('075_vblock_no_content.dts')
1414         self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1415                       'property', str(e.exception))
1416
1417     def testVblockBadPhandle(self):
1418         """Test that we detect a vblock with an invalid phandle in contents"""
1419         with self.assertRaises(ValueError) as e:
1420             self._DoReadFile('076_vblock_bad_phandle.dts')
1421         self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1422                       '1000', str(e.exception))
1423
1424     def testVblockBadEntry(self):
1425         """Test that we detect an entry that points to a non-entry"""
1426         with self.assertRaises(ValueError) as e:
1427             self._DoReadFile('077_vblock_bad_entry.dts')
1428         self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1429                       "'other'", str(e.exception))
1430
1431     def testTpl(self):
1432         """Test that an image with TPL and ots device tree can be created"""
1433         # ELF file with a '__bss_size' symbol
1434         with open(self.TestFile('bss_data')) as fd:
1435             TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1436         data = self._DoReadFile('078_u_boot_tpl.dts')
1437         self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1438
1439     def testUsesPos(self):
1440         """Test that the 'pos' property cannot be used anymore"""
1441         with self.assertRaises(ValueError) as e:
1442            data = self._DoReadFile('079_uses_pos.dts')
1443         self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1444                       "'pos'", str(e.exception))
1445
1446     def testFillZero(self):
1447         """Test for an fill entry type with a size of 0"""
1448         data = self._DoReadFile('080_fill_empty.dts')
1449         self.assertEqual(chr(0) * 16, data)
1450
1451     def testTextMissing(self):
1452         """Test for a text entry type where there is no text"""
1453         with self.assertRaises(ValueError) as e:
1454             self._DoReadFileDtb('066_text.dts',)
1455         self.assertIn("Node '/binman/text': No value provided for text label "
1456                       "'test-id'", str(e.exception))
1457
1458     def testPackStart16Tpl(self):
1459         """Test that an image with an x86 start16 TPL region can be created"""
1460         data = self._DoReadFile('081_x86-start16-tpl.dts')
1461         self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1462
1463     def testSelectImage(self):
1464         """Test that we can select which images to build"""
1465         expected = 'Skipping images: image1'
1466
1467         # We should only get the expected message in verbose mode
1468         for verbosity in (None, 2):
1469             with test_util.capture_sys_output() as (stdout, stderr):
1470                 retcode = self._DoTestFile('006_dual_image.dts',
1471                                            verbosity=verbosity,
1472                                            images=['image2'])
1473             self.assertEqual(0, retcode)
1474             if verbosity:
1475                 self.assertIn(expected, stdout.getvalue())
1476             else:
1477                 self.assertNotIn(expected, stdout.getvalue())
1478
1479             self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1480             self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1481
1482     def testUpdateFdtAll(self):
1483         """Test that all device trees are updated with offset/size info"""
1484         data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1485                                             use_real_dtb=True, update_dtb=True)
1486
1487         base_expected = {
1488             'section:image-pos': 0,
1489             'u-boot-tpl-dtb:size': 513,
1490             'u-boot-spl-dtb:size': 513,
1491             'u-boot-spl-dtb:offset': 493,
1492             'image-pos': 0,
1493             'section/u-boot-dtb:image-pos': 0,
1494             'u-boot-spl-dtb:image-pos': 493,
1495             'section/u-boot-dtb:size': 493,
1496             'u-boot-tpl-dtb:image-pos': 1006,
1497             'section/u-boot-dtb:offset': 0,
1498             'section:size': 493,
1499             'offset': 0,
1500             'section:offset': 0,
1501             'u-boot-tpl-dtb:offset': 1006,
1502             'size': 1519
1503         }
1504
1505         # We expect three device-tree files in the output, one after the other.
1506         # Read them in sequence. We look for an 'spl' property in the SPL tree,
1507         # and 'tpl' in the TPL tree, to make sure they are distinct from the
1508         # main U-Boot tree. All three should have the same postions and offset.
1509         start = 0
1510         for item in ['', 'spl', 'tpl']:
1511             dtb = fdt.Fdt.FromData(data[start:])
1512             dtb.Scan()
1513             props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1514                                             'spl', 'tpl'])
1515             expected = dict(base_expected)
1516             if item:
1517                 expected[item] = 0
1518             self.assertEqual(expected, props)
1519             start += dtb._fdt_obj.totalsize()
1520
1521     def testUpdateFdtOutput(self):
1522         """Test that output DTB files are updated"""
1523         try:
1524             data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1525                     use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1526
1527             # Unfortunately, compiling a source file always results in a file
1528             # called source.dtb (see fdt_util.EnsureCompiled()). The test
1529             # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1530             # binman as a file called u-boot.dtb. To fix this, copy the file
1531             # over to the expected place.
1532             #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1533                     #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1534             start = 0
1535             for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1536                           'tpl/u-boot-tpl.dtb.out']:
1537                 dtb = fdt.Fdt.FromData(data[start:])
1538                 size = dtb._fdt_obj.totalsize()
1539                 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1540                 outdata = tools.ReadFile(pathname)
1541                 name = os.path.split(fname)[0]
1542
1543                 if name:
1544                     orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1545                 else:
1546                     orig_indata = dtb_data
1547                 self.assertNotEqual(outdata, orig_indata,
1548                         "Expected output file '%s' be updated" % pathname)
1549                 self.assertEqual(outdata, data[start:start + size],
1550                         "Expected output file '%s' to match output image" %
1551                         pathname)
1552                 start += size
1553         finally:
1554             self._ResetDtbs()
1555
1556     def _decompress(self, data):
1557         out = os.path.join(self._indir, 'lz4.tmp')
1558         with open(out, 'wb') as fd:
1559             fd.write(data)
1560         return tools.Run('lz4', '-dc', out)
1561         '''
1562         try:
1563             orig = lz4.frame.decompress(data)
1564         except AttributeError:
1565             orig = lz4.decompress(data)
1566         '''
1567
1568     def testCompress(self):
1569         """Test compression of blobs"""
1570         data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1571                                             use_real_dtb=True, update_dtb=True)
1572         dtb = fdt.Fdt(out_dtb_fname)
1573         dtb.Scan()
1574         props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1575         orig = self._decompress(data)
1576         self.assertEquals(COMPRESS_DATA, orig)
1577         expected = {
1578             'blob:uncomp-size': len(COMPRESS_DATA),
1579             'blob:size': len(data),
1580             'size': len(data),
1581             }
1582         self.assertEqual(expected, props)
1583
1584     def testFiles(self):
1585         """Test bringing in multiple files"""
1586         data = self._DoReadFile('084_files.dts')
1587         self.assertEqual(FILES_DATA, data)
1588
1589     def testFilesCompress(self):
1590         """Test bringing in multiple files and compressing them"""
1591         data = self._DoReadFile('085_files_compress.dts')
1592
1593         image = control.images['image']
1594         entries = image.GetEntries()
1595         files = entries['files']
1596         entries = files._section._entries
1597
1598         orig = ''
1599         for i in range(1, 3):
1600             key = '%d.dat' % i
1601             start = entries[key].image_pos
1602             len = entries[key].size
1603             chunk = data[start:start + len]
1604             orig += self._decompress(chunk)
1605
1606         self.assertEqual(FILES_DATA, orig)
1607
1608     def testFilesMissing(self):
1609         """Test missing files"""
1610         with self.assertRaises(ValueError) as e:
1611             data = self._DoReadFile('086_files_none.dts')
1612         self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1613                       'no files', str(e.exception))
1614
1615     def testFilesNoPattern(self):
1616         """Test missing files"""
1617         with self.assertRaises(ValueError) as e:
1618             data = self._DoReadFile('087_files_no_pattern.dts')
1619         self.assertIn("Node '/binman/files': Missing 'pattern' property",
1620                       str(e.exception))
1621
1622     def testExpandSize(self):
1623         """Test an expanding entry"""
1624         data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1625                                                    map=True)
1626         expect = ('a' * 8 + U_BOOT_DATA +
1627                   MRC_DATA + 'b' * 1 + U_BOOT_DATA +
1628                   'c' * 8 + U_BOOT_DATA +
1629                   'd' * 8)
1630         self.assertEqual(expect, data)
1631         self.assertEqual('''ImagePos    Offset      Size  Name
1632 00000000  00000000  00000028  main-section
1633 00000000   00000000  00000008  fill
1634 00000008   00000008  00000004  u-boot
1635 0000000c   0000000c  00000004  section
1636 0000000c    00000000  00000003  intel-mrc
1637 00000010   00000010  00000004  u-boot2
1638 00000014   00000014  0000000c  section2
1639 00000014    00000000  00000008  fill
1640 0000001c    00000008  00000004  u-boot
1641 00000020   00000020  00000008  fill2
1642 ''', map_data)
1643
1644     def testExpandSizeBad(self):
1645         """Test an expanding entry which fails to provide contents"""
1646         with test_util.capture_sys_output() as (stdout, stderr):
1647             with self.assertRaises(ValueError) as e:
1648                 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1649         self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1650                       'expanding entry', str(e.exception))
1651
1652     def testHash(self):
1653         """Test hashing of the contents of an entry"""
1654         _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1655                 use_real_dtb=True, update_dtb=True)
1656         dtb = fdt.Fdt(out_dtb_fname)
1657         dtb.Scan()
1658         hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1659         m = hashlib.sha256()
1660         m.update(U_BOOT_DATA)
1661         self.assertEqual(m.digest(), ''.join(hash_node.value))
1662
1663     def testHashNoAlgo(self):
1664         with self.assertRaises(ValueError) as e:
1665             self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1666         self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1667                       'hash node', str(e.exception))
1668
1669     def testHashBadAlgo(self):
1670         with self.assertRaises(ValueError) as e:
1671             self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1672         self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1673                       str(e.exception))
1674
1675     def testHashSection(self):
1676         """Test hashing of the contents of an entry"""
1677         _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1678                 use_real_dtb=True, update_dtb=True)
1679         dtb = fdt.Fdt(out_dtb_fname)
1680         dtb.Scan()
1681         hash_node = dtb.GetNode('/binman/section/hash').props['value']
1682         m = hashlib.sha256()
1683         m.update(U_BOOT_DATA)
1684         m.update(16 * 'a')
1685         self.assertEqual(m.digest(), ''.join(hash_node.value))
1686
1687     def testPackUBootTplMicrocode(self):
1688         """Test that x86 microcode can be handled correctly in TPL
1689
1690         We expect to see the following in the image, in order:
1691             u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1692                 place
1693             u-boot-tpl.dtb with the microcode removed
1694             the microcode
1695         """
1696         with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1697             TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1698         first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1699                                                      U_BOOT_TPL_NODTB_DATA)
1700         self.assertEqual('tplnodtb with microc' + pos_and_size +
1701                          'ter somewhere in here', first)
1702
1703     def testFmapX86(self):
1704         """Basic test of generation of a flashrom fmap"""
1705         data = self._DoReadFile('094_fmap_x86.dts')
1706         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1707         expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7)
1708         self.assertEqual(expected, data[:32])
1709         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1710
1711         self.assertEqual(0x100, fhdr.image_size)
1712
1713         self.assertEqual(0, fentries[0].offset)
1714         self.assertEqual(4, fentries[0].size)
1715         self.assertEqual('U_BOOT', fentries[0].name)
1716
1717         self.assertEqual(4, fentries[1].offset)
1718         self.assertEqual(3, fentries[1].size)
1719         self.assertEqual('INTEL_MRC', fentries[1].name)
1720
1721         self.assertEqual(32, fentries[2].offset)
1722         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1723                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1724         self.assertEqual('FMAP', fentries[2].name)
1725
1726     def testFmapX86Section(self):
1727         """Basic test of generation of a flashrom fmap"""
1728         data = self._DoReadFile('095_fmap_x86_section.dts')
1729         expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7)
1730         self.assertEqual(expected, data[:32])
1731         fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1732
1733         self.assertEqual(0x100, fhdr.image_size)
1734
1735         self.assertEqual(0, fentries[0].offset)
1736         self.assertEqual(4, fentries[0].size)
1737         self.assertEqual('U_BOOT', fentries[0].name)
1738
1739         self.assertEqual(4, fentries[1].offset)
1740         self.assertEqual(3, fentries[1].size)
1741         self.assertEqual('INTEL_MRC', fentries[1].name)
1742
1743         self.assertEqual(36, fentries[2].offset)
1744         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1745                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1746         self.assertEqual('FMAP', fentries[2].name)
1747
1748     def testElf(self):
1749         """Basic test of ELF entries"""
1750         self._SetupSplElf()
1751         with open(self.TestFile('bss_data')) as fd:
1752             TestFunctional._MakeInputFile('-boot', fd.read())
1753         data = self._DoReadFile('096_elf.dts')
1754
1755     def testElfStripg(self):
1756         """Basic test of ELF entries"""
1757         self._SetupSplElf()
1758         with open(self.TestFile('bss_data')) as fd:
1759             TestFunctional._MakeInputFile('-boot', fd.read())
1760         data = self._DoReadFile('097_elf_strip.dts')
1761
1762     def testPackOverlapMap(self):
1763         """Test that overlapping regions are detected"""
1764         with test_util.capture_sys_output() as (stdout, stderr):
1765             with self.assertRaises(ValueError) as e:
1766                 self._DoTestFile('014_pack_overlap.dts', map=True)
1767         map_fname = tools.GetOutputFilename('image.map')
1768         self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1769                          stdout.getvalue())
1770
1771         # We should not get an inmage, but there should be a map file
1772         self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1773         self.assertTrue(os.path.exists(map_fname))
1774         map_data = tools.ReadFile(map_fname)
1775         self.assertEqual('''ImagePos    Offset      Size  Name
1776 <none>    00000000  00000007  main-section
1777 <none>     00000000  00000004  u-boot
1778 <none>     00000003  00000004  u-boot-align
1779 ''', map_data)
1780
1781     def testPacRefCode(self):
1782         """Test that an image with an Intel Reference code binary works"""
1783         data = self._DoReadFile('100_intel_refcode.dts')
1784         self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1785
1786     def testSectionOffset(self):
1787         """Tests use of a section with an offset"""
1788         data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1789                                                    map=True)
1790         self.assertEqual('''ImagePos    Offset      Size  Name
1791 00000000  00000000  00000038  main-section
1792 00000004   00000004  00000010  section@0
1793 00000004    00000000  00000004  u-boot
1794 00000018   00000018  00000010  section@1
1795 00000018    00000000  00000004  u-boot
1796 0000002c   0000002c  00000004  section@2
1797 0000002c    00000000  00000004  u-boot
1798 ''', map_data)
1799         self.assertEqual(data,
1800                          4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x21) +
1801                          4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x61) +
1802                          4 * chr(0x26) + U_BOOT_DATA + 8 * chr(0x26))
1803
1804
1805 if __name__ == "__main__":
1806     unittest.main()