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