binman: Separate out testSplBssPad()
[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
119         # ELF file with a '_dt_ucode_base_size' symbol
120         with open(self.TestFile('u_boot_ucode_ptr')) as fd:
121             TestFunctional._MakeInputFile('u-boot', fd.read())
122
123         # Intel flash descriptor file
124         with open(self.TestFile('descriptor.bin')) as fd:
125             TestFunctional._MakeInputFile('descriptor.bin', fd.read())
126
127         shutil.copytree(self.TestFile('files'),
128                         os.path.join(self._indir, 'files'))
129
130         TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
131
132     @classmethod
133     def tearDownClass(self):
134         """Remove the temporary input directory and its contents"""
135         if self._indir:
136             shutil.rmtree(self._indir)
137         self._indir = None
138
139     def setUp(self):
140         # Enable this to turn on debugging output
141         # tout.Init(tout.DEBUG)
142         command.test_result = None
143
144     def tearDown(self):
145         """Remove the temporary output directory"""
146         tools._FinaliseForTest()
147
148     @classmethod
149     def _ResetDtbs(self):
150         TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
151         TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
152         TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
153
154     def _RunBinman(self, *args, **kwargs):
155         """Run binman using the command line
156
157         Args:
158             Arguments to pass, as a list of strings
159             kwargs: Arguments to pass to Command.RunPipe()
160         """
161         result = command.RunPipe([[self._binman_pathname] + list(args)],
162                 capture=True, capture_stderr=True, raise_on_error=False)
163         if result.return_code and kwargs.get('raise_on_error', True):
164             raise Exception("Error running '%s': %s" % (' '.join(args),
165                             result.stdout + result.stderr))
166         return result
167
168     def _DoBinman(self, *args):
169         """Run binman using directly (in the same process)
170
171         Args:
172             Arguments to pass, as a list of strings
173         Returns:
174             Return value (0 for success)
175         """
176         args = list(args)
177         if '-D' in sys.argv:
178             args = args + ['-D']
179         (options, args) = cmdline.ParseArgs(args)
180         options.pager = 'binman-invalid-pager'
181         options.build_dir = self._indir
182
183         # For testing, you can force an increase in verbosity here
184         # options.verbosity = tout.DEBUG
185         return control.Binman(options, args)
186
187     def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
188                     entry_args=None, images=None, use_real_dtb=False):
189         """Run binman with a given test file
190
191         Args:
192             fname: Device-tree source filename to use (e.g. 05_simple.dts)
193             debug: True to enable debugging output
194             map: True to output map files for the images
195             update_dtb: Update the offset and size of each entry in the device
196                 tree before packing it into the image
197             entry_args: Dict of entry args to supply to binman
198                 key: arg name
199                 value: value of that arg
200             images: List of image names to build
201         """
202         args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
203         if debug:
204             args.append('-D')
205         if map:
206             args.append('-m')
207         if update_dtb:
208             args.append('-up')
209         if not use_real_dtb:
210             args.append('--fake-dtb')
211         if entry_args:
212             for arg, value in entry_args.iteritems():
213                 args.append('-a%s=%s' % (arg, value))
214         if images:
215             for image in images:
216                 args += ['-i', image]
217         return self._DoBinman(*args)
218
219     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
220         """Set up a new test device-tree file
221
222         The given file is compiled and set up as the device tree to be used
223         for ths test.
224
225         Args:
226             fname: Filename of .dts file to read
227             outfile: Output filename for compiled device-tree binary
228
229         Returns:
230             Contents of device-tree binary
231         """
232         tools.PrepareOutputDir(None)
233         dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
234         with open(dtb) as fd:
235             data = fd.read()
236             TestFunctional._MakeInputFile(outfile, data)
237         tools.FinaliseOutputDir()
238         return data
239
240     def _GetDtbContentsForSplTpl(self, dtb_data, name):
241         """Create a version of the main DTB for SPL or SPL
242
243         For testing we don't actually have different versions of the DTB. With
244         U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
245         we don't normally have any unwanted nodes.
246
247         We still want the DTBs for SPL and TPL to be different though, since
248         otherwise it is confusing to know which one we are looking at. So add
249         an 'spl' or 'tpl' property to the top-level node.
250         """
251         dtb = fdt.Fdt.FromData(dtb_data)
252         dtb.Scan()
253         dtb.GetNode('/binman').AddZeroProp(name)
254         dtb.Sync(auto_resize=True)
255         dtb.Pack()
256         return dtb.GetContents()
257
258     def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
259                        update_dtb=False, entry_args=None, reset_dtbs=True):
260         """Run binman and return the resulting image
261
262         This runs binman with a given test file and then reads the resulting
263         output file. It is a shortcut function since most tests need to do
264         these steps.
265
266         Raises an assertion failure if binman returns a non-zero exit code.
267
268         Args:
269             fname: Device-tree source filename to use (e.g. 05_simple.dts)
270             use_real_dtb: True to use the test file as the contents of
271                 the u-boot-dtb entry. Normally this is not needed and the
272                 test contents (the U_BOOT_DTB_DATA string) can be used.
273                 But in some test we need the real contents.
274             map: True to output map files for the images
275             update_dtb: Update the offset and size of each entry in the device
276                 tree before packing it into the image
277
278         Returns:
279             Tuple:
280                 Resulting image contents
281                 Device tree contents
282                 Map data showing contents of image (or None if none)
283                 Output device tree binary filename ('u-boot.dtb' path)
284         """
285         dtb_data = None
286         # Use the compiled test file as the u-boot-dtb input
287         if use_real_dtb:
288             dtb_data = self._SetupDtb(fname)
289             infile = os.path.join(self._indir, 'u-boot.dtb')
290
291             # For testing purposes, make a copy of the DT for SPL and TPL. Add
292             # a node indicating which it is, so aid verification.
293             for name in ['spl', 'tpl']:
294                 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
295                 outfile = os.path.join(self._indir, dtb_fname)
296                 TestFunctional._MakeInputFile(dtb_fname,
297                         self._GetDtbContentsForSplTpl(dtb_data, name))
298
299         try:
300             retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
301                     entry_args=entry_args, use_real_dtb=use_real_dtb)
302             self.assertEqual(0, retcode)
303             out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
304
305             # Find the (only) image, read it and return its contents
306             image = control.images['image']
307             image_fname = tools.GetOutputFilename('image.bin')
308             self.assertTrue(os.path.exists(image_fname))
309             if map:
310                 map_fname = tools.GetOutputFilename('image.map')
311                 with open(map_fname) as fd:
312                     map_data = fd.read()
313             else:
314                 map_data = None
315             with open(image_fname) as fd:
316                 return fd.read(), dtb_data, map_data, out_dtb_fname
317         finally:
318             # Put the test file back
319             if reset_dtbs and use_real_dtb:
320                 self._ResetDtbs()
321
322     def _DoReadFile(self, fname, use_real_dtb=False):
323         """Helper function which discards the device-tree binary
324
325         Args:
326             fname: Device-tree source filename to use (e.g. 05_simple.dts)
327             use_real_dtb: True to use the test file as the contents of
328                 the u-boot-dtb entry. Normally this is not needed and the
329                 test contents (the U_BOOT_DTB_DATA string) can be used.
330                 But in some test we need the real contents.
331
332         Returns:
333             Resulting image contents
334         """
335         return self._DoReadFileDtb(fname, use_real_dtb)[0]
336
337     @classmethod
338     def _MakeInputFile(self, fname, contents):
339         """Create a new test input file, creating directories as needed
340
341         Args:
342             fname: Filename to create
343             contents: File contents to write in to the file
344         Returns:
345             Full pathname of file created
346         """
347         pathname = os.path.join(self._indir, fname)
348         dirname = os.path.dirname(pathname)
349         if dirname and not os.path.exists(dirname):
350             os.makedirs(dirname)
351         with open(pathname, 'wb') as fd:
352             fd.write(contents)
353         return pathname
354
355     @classmethod
356     def _MakeInputDir(self, dirname):
357         """Create a new test input directory, creating directories as needed
358
359         Args:
360             dirname: Directory name to create
361
362         Returns:
363             Full pathname of directory created
364         """
365         pathname = os.path.join(self._indir, dirname)
366         if not os.path.exists(pathname):
367             os.makedirs(pathname)
368         return pathname
369
370     @classmethod
371     def TestFile(self, fname):
372         return os.path.join(self._binman_dir, 'test', fname)
373
374     def AssertInList(self, grep_list, target):
375         """Assert that at least one of a list of things is in a target
376
377         Args:
378             grep_list: List of strings to check
379             target: Target string
380         """
381         for grep in grep_list:
382             if grep in target:
383                 return
384         self.fail("Error: '%' not found in '%s'" % (grep_list, target))
385
386     def CheckNoGaps(self, entries):
387         """Check that all entries fit together without gaps
388
389         Args:
390             entries: List of entries to check
391         """
392         offset = 0
393         for entry in entries.values():
394             self.assertEqual(offset, entry.offset)
395             offset += entry.size
396
397     def GetFdtLen(self, dtb):
398         """Get the totalsize field from a device-tree binary
399
400         Args:
401             dtb: Device-tree binary contents
402
403         Returns:
404             Total size of device-tree binary, from the header
405         """
406         return struct.unpack('>L', dtb[4:8])[0]
407
408     def _GetPropTree(self, dtb, prop_names):
409         def AddNode(node, path):
410             if node.name != '/':
411                 path += '/' + node.name
412             for subnode in node.subnodes:
413                 for prop in subnode.props.values():
414                     if prop.name in prop_names:
415                         prop_path = path + '/' + subnode.name + ':' + prop.name
416                         tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
417                             prop.value)
418                 AddNode(subnode, path)
419
420         tree = {}
421         AddNode(dtb.GetRoot(), '')
422         return tree
423
424     def testRun(self):
425         """Test a basic run with valid args"""
426         result = self._RunBinman('-h')
427
428     def testFullHelp(self):
429         """Test that the full help is displayed with -H"""
430         result = self._RunBinman('-H')
431         help_file = os.path.join(self._binman_dir, 'README')
432         # Remove possible extraneous strings
433         extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
434         gothelp = result.stdout.replace(extra, '')
435         self.assertEqual(len(gothelp), os.path.getsize(help_file))
436         self.assertEqual(0, len(result.stderr))
437         self.assertEqual(0, result.return_code)
438
439     def testFullHelpInternal(self):
440         """Test that the full help is displayed with -H"""
441         try:
442             command.test_result = command.CommandResult()
443             result = self._DoBinman('-H')
444             help_file = os.path.join(self._binman_dir, 'README')
445         finally:
446             command.test_result = None
447
448     def testHelp(self):
449         """Test that the basic help is displayed with -h"""
450         result = self._RunBinman('-h')
451         self.assertTrue(len(result.stdout) > 200)
452         self.assertEqual(0, len(result.stderr))
453         self.assertEqual(0, result.return_code)
454
455     def testBoard(self):
456         """Test that we can run it with a specific board"""
457         self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
458         TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
459         result = self._DoBinman('-b', 'sandbox')
460         self.assertEqual(0, result)
461
462     def testNeedBoard(self):
463         """Test that we get an error when no board ius supplied"""
464         with self.assertRaises(ValueError) as e:
465             result = self._DoBinman()
466         self.assertIn("Must provide a board to process (use -b <board>)",
467                 str(e.exception))
468
469     def testMissingDt(self):
470         """Test that an invalid device-tree file generates an error"""
471         with self.assertRaises(Exception) as e:
472             self._RunBinman('-d', 'missing_file')
473         # We get one error from libfdt, and a different one from fdtget.
474         self.AssertInList(["Couldn't open blob from 'missing_file'",
475                            'No such file or directory'], str(e.exception))
476
477     def testBrokenDt(self):
478         """Test that an invalid device-tree source file generates an error
479
480         Since this is a source file it should be compiled and the error
481         will come from the device-tree compiler (dtc).
482         """
483         with self.assertRaises(Exception) as e:
484             self._RunBinman('-d', self.TestFile('01_invalid.dts'))
485         self.assertIn("FATAL ERROR: Unable to parse input tree",
486                 str(e.exception))
487
488     def testMissingNode(self):
489         """Test that a device tree without a 'binman' node generates an error"""
490         with self.assertRaises(Exception) as e:
491             self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
492         self.assertIn("does not have a 'binman' node", str(e.exception))
493
494     def testEmpty(self):
495         """Test that an empty binman node works OK (i.e. does nothing)"""
496         result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
497         self.assertEqual(0, len(result.stderr))
498         self.assertEqual(0, result.return_code)
499
500     def testInvalidEntry(self):
501         """Test that an invalid entry is flagged"""
502         with self.assertRaises(Exception) as e:
503             result = self._RunBinman('-d',
504                                      self.TestFile('04_invalid_entry.dts'))
505         self.assertIn("Unknown entry type 'not-a-valid-type' in node "
506                 "'/binman/not-a-valid-type'", str(e.exception))
507
508     def testSimple(self):
509         """Test a simple binman with a single file"""
510         data = self._DoReadFile('05_simple.dts')
511         self.assertEqual(U_BOOT_DATA, data)
512
513     def testSimpleDebug(self):
514         """Test a simple binman run with debugging enabled"""
515         data = self._DoTestFile('05_simple.dts', debug=True)
516
517     def testDual(self):
518         """Test that we can handle creating two images
519
520         This also tests image padding.
521         """
522         retcode = self._DoTestFile('06_dual_image.dts')
523         self.assertEqual(0, retcode)
524
525         image = control.images['image1']
526         self.assertEqual(len(U_BOOT_DATA), image._size)
527         fname = tools.GetOutputFilename('image1.bin')
528         self.assertTrue(os.path.exists(fname))
529         with open(fname) as fd:
530             data = fd.read()
531             self.assertEqual(U_BOOT_DATA, data)
532
533         image = control.images['image2']
534         self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
535         fname = tools.GetOutputFilename('image2.bin')
536         self.assertTrue(os.path.exists(fname))
537         with open(fname) as fd:
538             data = fd.read()
539             self.assertEqual(U_BOOT_DATA, data[3:7])
540             self.assertEqual(chr(0) * 3, data[:3])
541             self.assertEqual(chr(0) * 5, data[7:])
542
543     def testBadAlign(self):
544         """Test that an invalid alignment value is detected"""
545         with self.assertRaises(ValueError) as e:
546             self._DoTestFile('07_bad_align.dts')
547         self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
548                       "of two", str(e.exception))
549
550     def testPackSimple(self):
551         """Test that packing works as expected"""
552         retcode = self._DoTestFile('08_pack.dts')
553         self.assertEqual(0, retcode)
554         self.assertIn('image', control.images)
555         image = control.images['image']
556         entries = image.GetEntries()
557         self.assertEqual(5, len(entries))
558
559         # First u-boot
560         self.assertIn('u-boot', entries)
561         entry = entries['u-boot']
562         self.assertEqual(0, entry.offset)
563         self.assertEqual(len(U_BOOT_DATA), entry.size)
564
565         # Second u-boot, aligned to 16-byte boundary
566         self.assertIn('u-boot-align', entries)
567         entry = entries['u-boot-align']
568         self.assertEqual(16, entry.offset)
569         self.assertEqual(len(U_BOOT_DATA), entry.size)
570
571         # Third u-boot, size 23 bytes
572         self.assertIn('u-boot-size', entries)
573         entry = entries['u-boot-size']
574         self.assertEqual(20, entry.offset)
575         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
576         self.assertEqual(23, entry.size)
577
578         # Fourth u-boot, placed immediate after the above
579         self.assertIn('u-boot-next', entries)
580         entry = entries['u-boot-next']
581         self.assertEqual(43, entry.offset)
582         self.assertEqual(len(U_BOOT_DATA), entry.size)
583
584         # Fifth u-boot, placed at a fixed offset
585         self.assertIn('u-boot-fixed', entries)
586         entry = entries['u-boot-fixed']
587         self.assertEqual(61, entry.offset)
588         self.assertEqual(len(U_BOOT_DATA), entry.size)
589
590         self.assertEqual(65, image._size)
591
592     def testPackExtra(self):
593         """Test that extra packing feature works as expected"""
594         retcode = self._DoTestFile('09_pack_extra.dts')
595
596         self.assertEqual(0, retcode)
597         self.assertIn('image', control.images)
598         image = control.images['image']
599         entries = image.GetEntries()
600         self.assertEqual(5, len(entries))
601
602         # First u-boot with padding before and after
603         self.assertIn('u-boot', entries)
604         entry = entries['u-boot']
605         self.assertEqual(0, entry.offset)
606         self.assertEqual(3, entry.pad_before)
607         self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
608
609         # Second u-boot has an aligned size, but it has no effect
610         self.assertIn('u-boot-align-size-nop', entries)
611         entry = entries['u-boot-align-size-nop']
612         self.assertEqual(12, entry.offset)
613         self.assertEqual(4, entry.size)
614
615         # Third u-boot has an aligned size too
616         self.assertIn('u-boot-align-size', entries)
617         entry = entries['u-boot-align-size']
618         self.assertEqual(16, entry.offset)
619         self.assertEqual(32, entry.size)
620
621         # Fourth u-boot has an aligned end
622         self.assertIn('u-boot-align-end', entries)
623         entry = entries['u-boot-align-end']
624         self.assertEqual(48, entry.offset)
625         self.assertEqual(16, entry.size)
626
627         # Fifth u-boot immediately afterwards
628         self.assertIn('u-boot-align-both', entries)
629         entry = entries['u-boot-align-both']
630         self.assertEqual(64, entry.offset)
631         self.assertEqual(64, entry.size)
632
633         self.CheckNoGaps(entries)
634         self.assertEqual(128, image._size)
635
636     def testPackAlignPowerOf2(self):
637         """Test that invalid entry alignment is detected"""
638         with self.assertRaises(ValueError) as e:
639             self._DoTestFile('10_pack_align_power2.dts')
640         self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
641                       "of two", str(e.exception))
642
643     def testPackAlignSizePowerOf2(self):
644         """Test that invalid entry size alignment is detected"""
645         with self.assertRaises(ValueError) as e:
646             self._DoTestFile('11_pack_align_size_power2.dts')
647         self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
648                       "power of two", str(e.exception))
649
650     def testPackInvalidAlign(self):
651         """Test detection of an offset that does not match its alignment"""
652         with self.assertRaises(ValueError) as e:
653             self._DoTestFile('12_pack_inv_align.dts')
654         self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
655                       "align 0x4 (4)", str(e.exception))
656
657     def testPackInvalidSizeAlign(self):
658         """Test that invalid entry size alignment is detected"""
659         with self.assertRaises(ValueError) as e:
660             self._DoTestFile('13_pack_inv_size_align.dts')
661         self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
662                       "align-size 0x4 (4)", str(e.exception))
663
664     def testPackOverlap(self):
665         """Test that overlapping regions are detected"""
666         with self.assertRaises(ValueError) as e:
667             self._DoTestFile('14_pack_overlap.dts')
668         self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
669                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
670                       str(e.exception))
671
672     def testPackEntryOverflow(self):
673         """Test that entries that overflow their size are detected"""
674         with self.assertRaises(ValueError) as e:
675             self._DoTestFile('15_pack_overflow.dts')
676         self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
677                       "but entry size is 0x3 (3)", str(e.exception))
678
679     def testPackImageOverflow(self):
680         """Test that entries which overflow the image size are detected"""
681         with self.assertRaises(ValueError) as e:
682             self._DoTestFile('16_pack_image_overflow.dts')
683         self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
684                       "size 0x3 (3)", str(e.exception))
685
686     def testPackImageSize(self):
687         """Test that the image size can be set"""
688         retcode = self._DoTestFile('17_pack_image_size.dts')
689         self.assertEqual(0, retcode)
690         self.assertIn('image', control.images)
691         image = control.images['image']
692         self.assertEqual(7, image._size)
693
694     def testPackImageSizeAlign(self):
695         """Test that image size alignemnt works as expected"""
696         retcode = self._DoTestFile('18_pack_image_align.dts')
697         self.assertEqual(0, retcode)
698         self.assertIn('image', control.images)
699         image = control.images['image']
700         self.assertEqual(16, image._size)
701
702     def testPackInvalidImageAlign(self):
703         """Test that invalid image alignment is detected"""
704         with self.assertRaises(ValueError) as e:
705             self._DoTestFile('19_pack_inv_image_align.dts')
706         self.assertIn("Section '/binman': Size 0x7 (7) does not match "
707                       "align-size 0x8 (8)", str(e.exception))
708
709     def testPackAlignPowerOf2(self):
710         """Test that invalid image alignment is detected"""
711         with self.assertRaises(ValueError) as e:
712             self._DoTestFile('20_pack_inv_image_align_power2.dts')
713         self.assertIn("Section '/binman': Alignment size 131 must be a power of "
714                       "two", str(e.exception))
715
716     def testImagePadByte(self):
717         """Test that the image pad byte can be specified"""
718         with open(self.TestFile('bss_data')) as fd:
719             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
720         data = self._DoReadFile('21_image_pad.dts')
721         self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
722
723     def testImageName(self):
724         """Test that image files can be named"""
725         retcode = self._DoTestFile('22_image_name.dts')
726         self.assertEqual(0, retcode)
727         image = control.images['image1']
728         fname = tools.GetOutputFilename('test-name')
729         self.assertTrue(os.path.exists(fname))
730
731         image = control.images['image2']
732         fname = tools.GetOutputFilename('test-name.xx')
733         self.assertTrue(os.path.exists(fname))
734
735     def testBlobFilename(self):
736         """Test that generic blobs can be provided by filename"""
737         data = self._DoReadFile('23_blob.dts')
738         self.assertEqual(BLOB_DATA, data)
739
740     def testPackSorted(self):
741         """Test that entries can be sorted"""
742         data = self._DoReadFile('24_sorted.dts')
743         self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
744                          U_BOOT_DATA, data)
745
746     def testPackZeroOffset(self):
747         """Test that an entry at offset 0 is not given a new offset"""
748         with self.assertRaises(ValueError) as e:
749             self._DoTestFile('25_pack_zero_size.dts')
750         self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
751                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
752                       str(e.exception))
753
754     def testPackUbootDtb(self):
755         """Test that a device tree can be added to U-Boot"""
756         data = self._DoReadFile('26_pack_u_boot_dtb.dts')
757         self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
758
759     def testPackX86RomNoSize(self):
760         """Test that the end-at-4gb property requires a size property"""
761         with self.assertRaises(ValueError) as e:
762             self._DoTestFile('27_pack_4gb_no_size.dts')
763         self.assertIn("Section '/binman': Section size must be provided when "
764                       "using end-at-4gb", str(e.exception))
765
766     def test4gbAndSkipAtStartTogether(self):
767         """Test that the end-at-4gb and skip-at-size property can't be used
768         together"""
769         with self.assertRaises(ValueError) as e:
770             self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
771         self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
772                       "'skip-at-start'", str(e.exception))
773
774     def testPackX86RomOutside(self):
775         """Test that the end-at-4gb property checks for offset boundaries"""
776         with self.assertRaises(ValueError) as e:
777             self._DoTestFile('28_pack_4gb_outside.dts')
778         self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
779                       "the section starting at 0xffffffe0 (4294967264)",
780                       str(e.exception))
781
782     def testPackX86Rom(self):
783         """Test that a basic x86 ROM can be created"""
784         data = self._DoReadFile('29_x86-rom.dts')
785         self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
786                          chr(0) * 2, data)
787
788     def testPackX86RomMeNoDesc(self):
789         """Test that an invalid Intel descriptor entry is detected"""
790         TestFunctional._MakeInputFile('descriptor.bin', '')
791         with self.assertRaises(ValueError) as e:
792             self._DoTestFile('31_x86-rom-me.dts')
793         self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
794                       "signature", str(e.exception))
795
796     def testPackX86RomBadDesc(self):
797         """Test that the Intel requires a descriptor entry"""
798         with self.assertRaises(ValueError) as e:
799             self._DoTestFile('30_x86-rom-me-no-desc.dts')
800         self.assertIn("Node '/binman/intel-me': No offset set with "
801                       "offset-unset: should another entry provide this correct "
802                       "offset?", str(e.exception))
803
804     def testPackX86RomMe(self):
805         """Test that an x86 ROM with an ME region can be created"""
806         data = self._DoReadFile('31_x86-rom-me.dts')
807         self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
808
809     def testPackVga(self):
810         """Test that an image with a VGA binary can be created"""
811         data = self._DoReadFile('32_intel-vga.dts')
812         self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
813
814     def testPackStart16(self):
815         """Test that an image with an x86 start16 region can be created"""
816         data = self._DoReadFile('33_x86-start16.dts')
817         self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
818
819     def testPackPowerpcMpc85xxBootpgResetvec(self):
820         """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
821         created"""
822         data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
823         self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
824
825     def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
826         """Handle running a test for insertion of microcode
827
828         Args:
829             dts_fname: Name of test .dts file
830             nodtb_data: Data that we expect in the first section
831             ucode_second: True if the microsecond entry is second instead of
832                 third
833
834         Returns:
835             Tuple:
836                 Contents of first region (U-Boot or SPL)
837                 Offset and size components of microcode pointer, as inserted
838                     in the above (two 4-byte words)
839         """
840         data = self._DoReadFile(dts_fname, True)
841
842         # Now check the device tree has no microcode
843         if ucode_second:
844             ucode_content = data[len(nodtb_data):]
845             ucode_pos = len(nodtb_data)
846             dtb_with_ucode = ucode_content[16:]
847             fdt_len = self.GetFdtLen(dtb_with_ucode)
848         else:
849             dtb_with_ucode = data[len(nodtb_data):]
850             fdt_len = self.GetFdtLen(dtb_with_ucode)
851             ucode_content = dtb_with_ucode[fdt_len:]
852             ucode_pos = len(nodtb_data) + fdt_len
853         fname = tools.GetOutputFilename('test.dtb')
854         with open(fname, 'wb') as fd:
855             fd.write(dtb_with_ucode)
856         dtb = fdt.FdtScan(fname)
857         ucode = dtb.GetNode('/microcode')
858         self.assertTrue(ucode)
859         for node in ucode.subnodes:
860             self.assertFalse(node.props.get('data'))
861
862         # Check that the microcode appears immediately after the Fdt
863         # This matches the concatenation of the data properties in
864         # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
865         ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
866                                  0x78235609)
867         self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
868
869         # Check that the microcode pointer was inserted. It should match the
870         # expected offset and size
871         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
872                                    len(ucode_data))
873         u_boot = data[:len(nodtb_data)]
874         return u_boot, pos_and_size
875
876     def testPackUbootMicrocode(self):
877         """Test that x86 microcode can be handled correctly
878
879         We expect to see the following in the image, in order:
880             u-boot-nodtb.bin with a microcode pointer inserted at the correct
881                 place
882             u-boot.dtb with the microcode removed
883             the microcode
884         """
885         first, pos_and_size = self._RunMicrocodeTest('34_x86_ucode.dts',
886                                                      U_BOOT_NODTB_DATA)
887         self.assertEqual('nodtb with microcode' + pos_and_size +
888                          ' somewhere in here', first)
889
890     def _RunPackUbootSingleMicrocode(self):
891         """Test that x86 microcode can be handled correctly
892
893         We expect to see the following in the image, in order:
894             u-boot-nodtb.bin with a microcode pointer inserted at the correct
895                 place
896             u-boot.dtb with the microcode
897             an empty microcode region
898         """
899         # We need the libfdt library to run this test since only that allows
900         # finding the offset of a property. This is required by
901         # Entry_u_boot_dtb_with_ucode.ObtainContents().
902         data = self._DoReadFile('35_x86_single_ucode.dts', True)
903
904         second = data[len(U_BOOT_NODTB_DATA):]
905
906         fdt_len = self.GetFdtLen(second)
907         third = second[fdt_len:]
908         second = second[:fdt_len]
909
910         ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
911         self.assertIn(ucode_data, second)
912         ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
913
914         # Check that the microcode pointer was inserted. It should match the
915         # expected offset and size
916         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
917                                    len(ucode_data))
918         first = data[:len(U_BOOT_NODTB_DATA)]
919         self.assertEqual('nodtb with microcode' + pos_and_size +
920                          ' somewhere in here', first)
921
922     def testPackUbootSingleMicrocode(self):
923         """Test that x86 microcode can be handled correctly with fdt_normal.
924         """
925         self._RunPackUbootSingleMicrocode()
926
927     def testUBootImg(self):
928         """Test that u-boot.img can be put in a file"""
929         data = self._DoReadFile('36_u_boot_img.dts')
930         self.assertEqual(U_BOOT_IMG_DATA, data)
931
932     def testNoMicrocode(self):
933         """Test that a missing microcode region is detected"""
934         with self.assertRaises(ValueError) as e:
935             self._DoReadFile('37_x86_no_ucode.dts', True)
936         self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
937                       "node found in ", str(e.exception))
938
939     def testMicrocodeWithoutNode(self):
940         """Test that a missing u-boot-dtb-with-ucode node is detected"""
941         with self.assertRaises(ValueError) as e:
942             self._DoReadFile('38_x86_ucode_missing_node.dts', True)
943         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
944                 "microcode region u-boot-dtb-with-ucode", str(e.exception))
945
946     def testMicrocodeWithoutNode2(self):
947         """Test that a missing u-boot-ucode node is detected"""
948         with self.assertRaises(ValueError) as e:
949             self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
950         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
951             "microcode region u-boot-ucode", str(e.exception))
952
953     def testMicrocodeWithoutPtrInElf(self):
954         """Test that a U-Boot binary without the microcode symbol is detected"""
955         # ELF file without a '_dt_ucode_base_size' symbol
956         try:
957             with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
958                 TestFunctional._MakeInputFile('u-boot', fd.read())
959
960             with self.assertRaises(ValueError) as e:
961                 self._RunPackUbootSingleMicrocode()
962             self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
963                     "_dt_ucode_base_size symbol in u-boot", str(e.exception))
964
965         finally:
966             # Put the original file back
967             with open(self.TestFile('u_boot_ucode_ptr')) as fd:
968                 TestFunctional._MakeInputFile('u-boot', fd.read())
969
970     def testMicrocodeNotInImage(self):
971         """Test that microcode must be placed within the image"""
972         with self.assertRaises(ValueError) as e:
973             self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
974         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
975                 "pointer _dt_ucode_base_size at fffffe14 is outside the "
976                 "section ranging from 00000000 to 0000002e", str(e.exception))
977
978     def testWithoutMicrocode(self):
979         """Test that we can cope with an image without microcode (e.g. qemu)"""
980         with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
981             TestFunctional._MakeInputFile('u-boot', fd.read())
982         data, dtb, _, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
983
984         # Now check the device tree has no microcode
985         self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
986         second = data[len(U_BOOT_NODTB_DATA):]
987
988         fdt_len = self.GetFdtLen(second)
989         self.assertEqual(dtb, second[:fdt_len])
990
991         used_len = len(U_BOOT_NODTB_DATA) + fdt_len
992         third = data[used_len:]
993         self.assertEqual(chr(0) * (0x200 - used_len), third)
994
995     def testUnknownPosSize(self):
996         """Test that microcode must be placed within the image"""
997         with self.assertRaises(ValueError) as e:
998             self._DoReadFile('41_unknown_pos_size.dts', True)
999         self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1000                 "entry 'invalid-entry'", str(e.exception))
1001
1002     def testPackFsp(self):
1003         """Test that an image with a FSP binary can be created"""
1004         data = self._DoReadFile('42_intel-fsp.dts')
1005         self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1006
1007     def testPackCmc(self):
1008         """Test that an image with a CMC binary can be created"""
1009         data = self._DoReadFile('43_intel-cmc.dts')
1010         self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1011
1012     def testPackVbt(self):
1013         """Test that an image with a VBT binary can be created"""
1014         data = self._DoReadFile('46_intel-vbt.dts')
1015         self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1016
1017     def testSplBssPad(self):
1018         """Test that we can pad SPL's BSS with zeros"""
1019         # ELF file with a '__bss_size' symbol
1020         with open(self.TestFile('bss_data')) as fd:
1021             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1022         data = self._DoReadFile('47_spl_bss_pad.dts')
1023         self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
1024
1025     def testSplBssPadMissing(self):
1026         """Test that a missing symbol is detected"""
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             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()