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