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