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