bd4de4e28711d25689d910339c1a4ff793c05c3f
[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 from optparse import OptionParser
10 import os
11 import shutil
12 import struct
13 import sys
14 import tempfile
15 import unittest
16
17 import binman
18 import cmdline
19 import command
20 import control
21 import elf
22 import fdt
23 import fdt_util
24 import fmap_util
25 import test_util
26 import tools
27 import tout
28
29 # Contents of test files, corresponding to different entry types
30 U_BOOT_DATA           = '1234'
31 U_BOOT_IMG_DATA       = 'img'
32 U_BOOT_SPL_DATA       = '56780123456789abcde'
33 BLOB_DATA             = '89'
34 ME_DATA               = '0abcd'
35 VGA_DATA              = 'vga'
36 U_BOOT_DTB_DATA       = 'udtb'
37 U_BOOT_SPL_DTB_DATA   = 'spldtb'
38 X86_START16_DATA      = 'start16'
39 X86_START16_SPL_DATA  = 'start16spl'
40 U_BOOT_NODTB_DATA     = 'nodtb with microcode pointer somewhere in here'
41 U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
42 FSP_DATA              = 'fsp'
43 CMC_DATA              = 'cmc'
44 VBT_DATA              = 'vbt'
45 MRC_DATA              = 'mrc'
46 TEXT_DATA             = 'text'
47 TEXT_DATA2            = 'text2'
48 TEXT_DATA3            = 'text3'
49
50 class TestFunctional(unittest.TestCase):
51     """Functional tests for binman
52
53     Most of these use a sample .dts file to build an image and then check
54     that it looks correct. The sample files are in the test/ subdirectory
55     and are numbered.
56
57     For each entry type a very small test file is created using fixed
58     string contents. This makes it easy to test that things look right, and
59     debug problems.
60
61     In some cases a 'real' file must be used - these are also supplied in
62     the test/ diurectory.
63     """
64     @classmethod
65     def setUpClass(self):
66         global entry
67         import entry
68
69         # Handle the case where argv[0] is 'python'
70         self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
71         self._binman_pathname = os.path.join(self._binman_dir, 'binman')
72
73         # Create a temporary directory for input files
74         self._indir = tempfile.mkdtemp(prefix='binmant.')
75
76         # Create some test files
77         TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
78         TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
79         TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
80         TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
81         TestFunctional._MakeInputFile('me.bin', ME_DATA)
82         TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
83         TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
84         TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
85         TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
86         TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
87                                       X86_START16_SPL_DATA)
88         TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
89         TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
90                                       U_BOOT_SPL_NODTB_DATA)
91         TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
92         TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
93         TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
94         TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
95         self._output_setup = False
96
97         # ELF file with a '_dt_ucode_base_size' symbol
98         with open(self.TestFile('u_boot_ucode_ptr')) as fd:
99             TestFunctional._MakeInputFile('u-boot', fd.read())
100
101         # Intel flash descriptor file
102         with open(self.TestFile('descriptor.bin')) as fd:
103             TestFunctional._MakeInputFile('descriptor.bin', fd.read())
104
105     @classmethod
106     def tearDownClass(self):
107         """Remove the temporary input directory and its contents"""
108         if self._indir:
109             shutil.rmtree(self._indir)
110         self._indir = None
111
112     def setUp(self):
113         # Enable this to turn on debugging output
114         # tout.Init(tout.DEBUG)
115         command.test_result = None
116
117     def tearDown(self):
118         """Remove the temporary output directory"""
119         tools._FinaliseForTest()
120
121     def _RunBinman(self, *args, **kwargs):
122         """Run binman using the command line
123
124         Args:
125             Arguments to pass, as a list of strings
126             kwargs: Arguments to pass to Command.RunPipe()
127         """
128         result = command.RunPipe([[self._binman_pathname] + list(args)],
129                 capture=True, capture_stderr=True, raise_on_error=False)
130         if result.return_code and kwargs.get('raise_on_error', True):
131             raise Exception("Error running '%s': %s" % (' '.join(args),
132                             result.stdout + result.stderr))
133         return result
134
135     def _DoBinman(self, *args):
136         """Run binman using directly (in the same process)
137
138         Args:
139             Arguments to pass, as a list of strings
140         Returns:
141             Return value (0 for success)
142         """
143         args = list(args)
144         if '-D' in sys.argv:
145             args = args + ['-D']
146         (options, args) = cmdline.ParseArgs(args)
147         options.pager = 'binman-invalid-pager'
148         options.build_dir = self._indir
149
150         # For testing, you can force an increase in verbosity here
151         # options.verbosity = tout.DEBUG
152         return control.Binman(options, args)
153
154     def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
155                     entry_args=None):
156         """Run binman with a given test file
157
158         Args:
159             fname: Device-tree source filename to use (e.g. 05_simple.dts)
160             debug: True to enable debugging output
161             map: True to output map files for the images
162             update_dtb: Update the offset and size of each entry in the device
163                 tree before packing it into the image
164         """
165         args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
166         if debug:
167             args.append('-D')
168         if map:
169             args.append('-m')
170         if update_dtb:
171             args.append('-up')
172         if entry_args:
173             for arg, value in entry_args.iteritems():
174                 args.append('-a%s=%s' % (arg, value))
175         return self._DoBinman(*args)
176
177     def _SetupDtb(self, fname, outfile='u-boot.dtb'):
178         """Set up a new test device-tree file
179
180         The given file is compiled and set up as the device tree to be used
181         for ths test.
182
183         Args:
184             fname: Filename of .dts file to read
185             outfile: Output filename for compiled device-tree binary
186
187         Returns:
188             Contents of device-tree binary
189         """
190         if not self._output_setup:
191             tools.PrepareOutputDir(self._indir, True)
192             self._output_setup = True
193         dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
194         with open(dtb) as fd:
195             data = fd.read()
196             TestFunctional._MakeInputFile(outfile, data)
197             return data
198
199     def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
200                        update_dtb=False, entry_args=None):
201         """Run binman and return the resulting image
202
203         This runs binman with a given test file and then reads the resulting
204         output file. It is a shortcut function since most tests need to do
205         these steps.
206
207         Raises an assertion failure if binman returns a non-zero exit code.
208
209         Args:
210             fname: Device-tree source filename to use (e.g. 05_simple.dts)
211             use_real_dtb: True to use the test file as the contents of
212                 the u-boot-dtb entry. Normally this is not needed and the
213                 test contents (the U_BOOT_DTB_DATA string) can be used.
214                 But in some test we need the real contents.
215             map: True to output map files for the images
216             update_dtb: Update the offset and size of each entry in the device
217                 tree before packing it into the image
218
219         Returns:
220             Tuple:
221                 Resulting image contents
222                 Device tree contents
223                 Map data showing contents of image (or None if none)
224                 Output device tree binary filename ('u-boot.dtb' path)
225         """
226         dtb_data = None
227         # Use the compiled test file as the u-boot-dtb input
228         if use_real_dtb:
229             dtb_data = self._SetupDtb(fname)
230
231         try:
232             retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
233                                        entry_args=entry_args)
234             self.assertEqual(0, retcode)
235             out_dtb_fname = control.GetFdtPath('u-boot.dtb')
236
237             # Find the (only) image, read it and return its contents
238             image = control.images['image']
239             image_fname = tools.GetOutputFilename('image.bin')
240             self.assertTrue(os.path.exists(image_fname))
241             if map:
242                 map_fname = tools.GetOutputFilename('image.map')
243                 with open(map_fname) as fd:
244                     map_data = fd.read()
245             else:
246                 map_data = None
247             with open(image_fname) as fd:
248                 return fd.read(), dtb_data, map_data, out_dtb_fname
249         finally:
250             # Put the test file back
251             if use_real_dtb:
252                 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
253
254     def _DoReadFile(self, fname, use_real_dtb=False):
255         """Helper function which discards the device-tree binary
256
257         Args:
258             fname: Device-tree source filename to use (e.g. 05_simple.dts)
259             use_real_dtb: True to use the test file as the contents of
260                 the u-boot-dtb entry. Normally this is not needed and the
261                 test contents (the U_BOOT_DTB_DATA string) can be used.
262                 But in some test we need the real contents.
263
264         Returns:
265             Resulting image contents
266         """
267         return self._DoReadFileDtb(fname, use_real_dtb)[0]
268
269     @classmethod
270     def _MakeInputFile(self, fname, contents):
271         """Create a new test input file, creating directories as needed
272
273         Args:
274             fname: Filename to create
275             contents: File contents to write in to the file
276         Returns:
277             Full pathname of file created
278         """
279         pathname = os.path.join(self._indir, fname)
280         dirname = os.path.dirname(pathname)
281         if dirname and not os.path.exists(dirname):
282             os.makedirs(dirname)
283         with open(pathname, 'wb') as fd:
284             fd.write(contents)
285         return pathname
286
287     @classmethod
288     def TestFile(self, fname):
289         return os.path.join(self._binman_dir, 'test', fname)
290
291     def AssertInList(self, grep_list, target):
292         """Assert that at least one of a list of things is in a target
293
294         Args:
295             grep_list: List of strings to check
296             target: Target string
297         """
298         for grep in grep_list:
299             if grep in target:
300                 return
301         self.fail("Error: '%' not found in '%s'" % (grep_list, target))
302
303     def CheckNoGaps(self, entries):
304         """Check that all entries fit together without gaps
305
306         Args:
307             entries: List of entries to check
308         """
309         offset = 0
310         for entry in entries.values():
311             self.assertEqual(offset, entry.offset)
312             offset += entry.size
313
314     def GetFdtLen(self, dtb):
315         """Get the totalsize field from a device-tree binary
316
317         Args:
318             dtb: Device-tree binary contents
319
320         Returns:
321             Total size of device-tree binary, from the header
322         """
323         return struct.unpack('>L', dtb[4:8])[0]
324
325     def _GetPropTree(self, dtb_data, node_names):
326         def AddNode(node, path):
327             if node.name != '/':
328                 path += '/' + node.name
329             for subnode in node.subnodes:
330                 for prop in subnode.props.values():
331                     if prop.name in node_names:
332                         prop_path = path + '/' + subnode.name + ':' + prop.name
333                         tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
334                             prop.value)
335                 AddNode(subnode, path)
336
337         tree = {}
338         dtb = fdt.Fdt(dtb_data)
339         dtb.Scan()
340         AddNode(dtb.GetRoot(), '')
341         return tree
342
343     def testRun(self):
344         """Test a basic run with valid args"""
345         result = self._RunBinman('-h')
346
347     def testFullHelp(self):
348         """Test that the full help is displayed with -H"""
349         result = self._RunBinman('-H')
350         help_file = os.path.join(self._binman_dir, 'README')
351         # Remove possible extraneous strings
352         extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
353         gothelp = result.stdout.replace(extra, '')
354         self.assertEqual(len(gothelp), os.path.getsize(help_file))
355         self.assertEqual(0, len(result.stderr))
356         self.assertEqual(0, result.return_code)
357
358     def testFullHelpInternal(self):
359         """Test that the full help is displayed with -H"""
360         try:
361             command.test_result = command.CommandResult()
362             result = self._DoBinman('-H')
363             help_file = os.path.join(self._binman_dir, 'README')
364         finally:
365             command.test_result = None
366
367     def testHelp(self):
368         """Test that the basic help is displayed with -h"""
369         result = self._RunBinman('-h')
370         self.assertTrue(len(result.stdout) > 200)
371         self.assertEqual(0, len(result.stderr))
372         self.assertEqual(0, result.return_code)
373
374     def testBoard(self):
375         """Test that we can run it with a specific board"""
376         self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
377         TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
378         result = self._DoBinman('-b', 'sandbox')
379         self.assertEqual(0, result)
380
381     def testNeedBoard(self):
382         """Test that we get an error when no board ius supplied"""
383         with self.assertRaises(ValueError) as e:
384             result = self._DoBinman()
385         self.assertIn("Must provide a board to process (use -b <board>)",
386                 str(e.exception))
387
388     def testMissingDt(self):
389         """Test that an invalid device-tree file generates an error"""
390         with self.assertRaises(Exception) as e:
391             self._RunBinman('-d', 'missing_file')
392         # We get one error from libfdt, and a different one from fdtget.
393         self.AssertInList(["Couldn't open blob from 'missing_file'",
394                            'No such file or directory'], str(e.exception))
395
396     def testBrokenDt(self):
397         """Test that an invalid device-tree source file generates an error
398
399         Since this is a source file it should be compiled and the error
400         will come from the device-tree compiler (dtc).
401         """
402         with self.assertRaises(Exception) as e:
403             self._RunBinman('-d', self.TestFile('01_invalid.dts'))
404         self.assertIn("FATAL ERROR: Unable to parse input tree",
405                 str(e.exception))
406
407     def testMissingNode(self):
408         """Test that a device tree without a 'binman' node generates an error"""
409         with self.assertRaises(Exception) as e:
410             self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
411         self.assertIn("does not have a 'binman' node", str(e.exception))
412
413     def testEmpty(self):
414         """Test that an empty binman node works OK (i.e. does nothing)"""
415         result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
416         self.assertEqual(0, len(result.stderr))
417         self.assertEqual(0, result.return_code)
418
419     def testInvalidEntry(self):
420         """Test that an invalid entry is flagged"""
421         with self.assertRaises(Exception) as e:
422             result = self._RunBinman('-d',
423                                      self.TestFile('04_invalid_entry.dts'))
424         self.assertIn("Unknown entry type 'not-a-valid-type' in node "
425                 "'/binman/not-a-valid-type'", str(e.exception))
426
427     def testSimple(self):
428         """Test a simple binman with a single file"""
429         data = self._DoReadFile('05_simple.dts')
430         self.assertEqual(U_BOOT_DATA, data)
431
432     def testSimpleDebug(self):
433         """Test a simple binman run with debugging enabled"""
434         data = self._DoTestFile('05_simple.dts', debug=True)
435
436     def testDual(self):
437         """Test that we can handle creating two images
438
439         This also tests image padding.
440         """
441         retcode = self._DoTestFile('06_dual_image.dts')
442         self.assertEqual(0, retcode)
443
444         image = control.images['image1']
445         self.assertEqual(len(U_BOOT_DATA), image._size)
446         fname = tools.GetOutputFilename('image1.bin')
447         self.assertTrue(os.path.exists(fname))
448         with open(fname) as fd:
449             data = fd.read()
450             self.assertEqual(U_BOOT_DATA, data)
451
452         image = control.images['image2']
453         self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
454         fname = tools.GetOutputFilename('image2.bin')
455         self.assertTrue(os.path.exists(fname))
456         with open(fname) as fd:
457             data = fd.read()
458             self.assertEqual(U_BOOT_DATA, data[3:7])
459             self.assertEqual(chr(0) * 3, data[:3])
460             self.assertEqual(chr(0) * 5, data[7:])
461
462     def testBadAlign(self):
463         """Test that an invalid alignment value is detected"""
464         with self.assertRaises(ValueError) as e:
465             self._DoTestFile('07_bad_align.dts')
466         self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
467                       "of two", str(e.exception))
468
469     def testPackSimple(self):
470         """Test that packing works as expected"""
471         retcode = self._DoTestFile('08_pack.dts')
472         self.assertEqual(0, retcode)
473         self.assertIn('image', control.images)
474         image = control.images['image']
475         entries = image.GetEntries()
476         self.assertEqual(5, len(entries))
477
478         # First u-boot
479         self.assertIn('u-boot', entries)
480         entry = entries['u-boot']
481         self.assertEqual(0, entry.offset)
482         self.assertEqual(len(U_BOOT_DATA), entry.size)
483
484         # Second u-boot, aligned to 16-byte boundary
485         self.assertIn('u-boot-align', entries)
486         entry = entries['u-boot-align']
487         self.assertEqual(16, entry.offset)
488         self.assertEqual(len(U_BOOT_DATA), entry.size)
489
490         # Third u-boot, size 23 bytes
491         self.assertIn('u-boot-size', entries)
492         entry = entries['u-boot-size']
493         self.assertEqual(20, entry.offset)
494         self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
495         self.assertEqual(23, entry.size)
496
497         # Fourth u-boot, placed immediate after the above
498         self.assertIn('u-boot-next', entries)
499         entry = entries['u-boot-next']
500         self.assertEqual(43, entry.offset)
501         self.assertEqual(len(U_BOOT_DATA), entry.size)
502
503         # Fifth u-boot, placed at a fixed offset
504         self.assertIn('u-boot-fixed', entries)
505         entry = entries['u-boot-fixed']
506         self.assertEqual(61, entry.offset)
507         self.assertEqual(len(U_BOOT_DATA), entry.size)
508
509         self.assertEqual(65, image._size)
510
511     def testPackExtra(self):
512         """Test that extra packing feature works as expected"""
513         retcode = self._DoTestFile('09_pack_extra.dts')
514
515         self.assertEqual(0, retcode)
516         self.assertIn('image', control.images)
517         image = control.images['image']
518         entries = image.GetEntries()
519         self.assertEqual(5, len(entries))
520
521         # First u-boot with padding before and after
522         self.assertIn('u-boot', entries)
523         entry = entries['u-boot']
524         self.assertEqual(0, entry.offset)
525         self.assertEqual(3, entry.pad_before)
526         self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
527
528         # Second u-boot has an aligned size, but it has no effect
529         self.assertIn('u-boot-align-size-nop', entries)
530         entry = entries['u-boot-align-size-nop']
531         self.assertEqual(12, entry.offset)
532         self.assertEqual(4, entry.size)
533
534         # Third u-boot has an aligned size too
535         self.assertIn('u-boot-align-size', entries)
536         entry = entries['u-boot-align-size']
537         self.assertEqual(16, entry.offset)
538         self.assertEqual(32, entry.size)
539
540         # Fourth u-boot has an aligned end
541         self.assertIn('u-boot-align-end', entries)
542         entry = entries['u-boot-align-end']
543         self.assertEqual(48, entry.offset)
544         self.assertEqual(16, entry.size)
545
546         # Fifth u-boot immediately afterwards
547         self.assertIn('u-boot-align-both', entries)
548         entry = entries['u-boot-align-both']
549         self.assertEqual(64, entry.offset)
550         self.assertEqual(64, entry.size)
551
552         self.CheckNoGaps(entries)
553         self.assertEqual(128, image._size)
554
555     def testPackAlignPowerOf2(self):
556         """Test that invalid entry alignment is detected"""
557         with self.assertRaises(ValueError) as e:
558             self._DoTestFile('10_pack_align_power2.dts')
559         self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
560                       "of two", str(e.exception))
561
562     def testPackAlignSizePowerOf2(self):
563         """Test that invalid entry size alignment is detected"""
564         with self.assertRaises(ValueError) as e:
565             self._DoTestFile('11_pack_align_size_power2.dts')
566         self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
567                       "power of two", str(e.exception))
568
569     def testPackInvalidAlign(self):
570         """Test detection of an offset that does not match its alignment"""
571         with self.assertRaises(ValueError) as e:
572             self._DoTestFile('12_pack_inv_align.dts')
573         self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
574                       "align 0x4 (4)", str(e.exception))
575
576     def testPackInvalidSizeAlign(self):
577         """Test that invalid entry size alignment is detected"""
578         with self.assertRaises(ValueError) as e:
579             self._DoTestFile('13_pack_inv_size_align.dts')
580         self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
581                       "align-size 0x4 (4)", str(e.exception))
582
583     def testPackOverlap(self):
584         """Test that overlapping regions are detected"""
585         with self.assertRaises(ValueError) as e:
586             self._DoTestFile('14_pack_overlap.dts')
587         self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
588                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
589                       str(e.exception))
590
591     def testPackEntryOverflow(self):
592         """Test that entries that overflow their size are detected"""
593         with self.assertRaises(ValueError) as e:
594             self._DoTestFile('15_pack_overflow.dts')
595         self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
596                       "but entry size is 0x3 (3)", str(e.exception))
597
598     def testPackImageOverflow(self):
599         """Test that entries which overflow the image size are detected"""
600         with self.assertRaises(ValueError) as e:
601             self._DoTestFile('16_pack_image_overflow.dts')
602         self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
603                       "size 0x3 (3)", str(e.exception))
604
605     def testPackImageSize(self):
606         """Test that the image size can be set"""
607         retcode = self._DoTestFile('17_pack_image_size.dts')
608         self.assertEqual(0, retcode)
609         self.assertIn('image', control.images)
610         image = control.images['image']
611         self.assertEqual(7, image._size)
612
613     def testPackImageSizeAlign(self):
614         """Test that image size alignemnt works as expected"""
615         retcode = self._DoTestFile('18_pack_image_align.dts')
616         self.assertEqual(0, retcode)
617         self.assertIn('image', control.images)
618         image = control.images['image']
619         self.assertEqual(16, image._size)
620
621     def testPackInvalidImageAlign(self):
622         """Test that invalid image alignment is detected"""
623         with self.assertRaises(ValueError) as e:
624             self._DoTestFile('19_pack_inv_image_align.dts')
625         self.assertIn("Section '/binman': Size 0x7 (7) does not match "
626                       "align-size 0x8 (8)", str(e.exception))
627
628     def testPackAlignPowerOf2(self):
629         """Test that invalid image alignment is detected"""
630         with self.assertRaises(ValueError) as e:
631             self._DoTestFile('20_pack_inv_image_align_power2.dts')
632         self.assertIn("Section '/binman': Alignment size 131 must be a power of "
633                       "two", str(e.exception))
634
635     def testImagePadByte(self):
636         """Test that the image pad byte can be specified"""
637         with open(self.TestFile('bss_data')) as fd:
638             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
639         data = self._DoReadFile('21_image_pad.dts')
640         self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
641
642     def testImageName(self):
643         """Test that image files can be named"""
644         retcode = self._DoTestFile('22_image_name.dts')
645         self.assertEqual(0, retcode)
646         image = control.images['image1']
647         fname = tools.GetOutputFilename('test-name')
648         self.assertTrue(os.path.exists(fname))
649
650         image = control.images['image2']
651         fname = tools.GetOutputFilename('test-name.xx')
652         self.assertTrue(os.path.exists(fname))
653
654     def testBlobFilename(self):
655         """Test that generic blobs can be provided by filename"""
656         data = self._DoReadFile('23_blob.dts')
657         self.assertEqual(BLOB_DATA, data)
658
659     def testPackSorted(self):
660         """Test that entries can be sorted"""
661         data = self._DoReadFile('24_sorted.dts')
662         self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
663                          U_BOOT_DATA, data)
664
665     def testPackZeroOffset(self):
666         """Test that an entry at offset 0 is not given a new offset"""
667         with self.assertRaises(ValueError) as e:
668             self._DoTestFile('25_pack_zero_size.dts')
669         self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
670                       "with previous entry '/binman/u-boot' ending at 0x4 (4)",
671                       str(e.exception))
672
673     def testPackUbootDtb(self):
674         """Test that a device tree can be added to U-Boot"""
675         data = self._DoReadFile('26_pack_u_boot_dtb.dts')
676         self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
677
678     def testPackX86RomNoSize(self):
679         """Test that the end-at-4gb property requires a size property"""
680         with self.assertRaises(ValueError) as e:
681             self._DoTestFile('27_pack_4gb_no_size.dts')
682         self.assertIn("Section '/binman': Section size must be provided when "
683                       "using end-at-4gb", str(e.exception))
684
685     def testPackX86RomOutside(self):
686         """Test that the end-at-4gb property checks for offset boundaries"""
687         with self.assertRaises(ValueError) as e:
688             self._DoTestFile('28_pack_4gb_outside.dts')
689         self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
690                       "the section starting at 0xffffffe0 (4294967264)",
691                       str(e.exception))
692
693     def testPackX86Rom(self):
694         """Test that a basic x86 ROM can be created"""
695         data = self._DoReadFile('29_x86-rom.dts')
696         self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
697                          chr(0) * 2, data)
698
699     def testPackX86RomMeNoDesc(self):
700         """Test that an invalid Intel descriptor entry is detected"""
701         TestFunctional._MakeInputFile('descriptor.bin', '')
702         with self.assertRaises(ValueError) as e:
703             self._DoTestFile('31_x86-rom-me.dts')
704         self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
705                       "signature", str(e.exception))
706
707     def testPackX86RomBadDesc(self):
708         """Test that the Intel requires a descriptor entry"""
709         with self.assertRaises(ValueError) as e:
710             self._DoTestFile('30_x86-rom-me-no-desc.dts')
711         self.assertIn("Node '/binman/intel-me': No offset set with "
712                       "offset-unset: should another entry provide this correct "
713                       "offset?", str(e.exception))
714
715     def testPackX86RomMe(self):
716         """Test that an x86 ROM with an ME region can be created"""
717         data = self._DoReadFile('31_x86-rom-me.dts')
718         self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
719
720     def testPackVga(self):
721         """Test that an image with a VGA binary can be created"""
722         data = self._DoReadFile('32_intel-vga.dts')
723         self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
724
725     def testPackStart16(self):
726         """Test that an image with an x86 start16 region can be created"""
727         data = self._DoReadFile('33_x86-start16.dts')
728         self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
729
730     def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
731         """Handle running a test for insertion of microcode
732
733         Args:
734             dts_fname: Name of test .dts file
735             nodtb_data: Data that we expect in the first section
736             ucode_second: True if the microsecond entry is second instead of
737                 third
738
739         Returns:
740             Tuple:
741                 Contents of first region (U-Boot or SPL)
742                 Offset and size components of microcode pointer, as inserted
743                     in the above (two 4-byte words)
744         """
745         data = self._DoReadFile(dts_fname, True)
746
747         # Now check the device tree has no microcode
748         if ucode_second:
749             ucode_content = data[len(nodtb_data):]
750             ucode_pos = len(nodtb_data)
751             dtb_with_ucode = ucode_content[16:]
752             fdt_len = self.GetFdtLen(dtb_with_ucode)
753         else:
754             dtb_with_ucode = data[len(nodtb_data):]
755             fdt_len = self.GetFdtLen(dtb_with_ucode)
756             ucode_content = dtb_with_ucode[fdt_len:]
757             ucode_pos = len(nodtb_data) + fdt_len
758         fname = tools.GetOutputFilename('test.dtb')
759         with open(fname, 'wb') as fd:
760             fd.write(dtb_with_ucode)
761         dtb = fdt.FdtScan(fname)
762         ucode = dtb.GetNode('/microcode')
763         self.assertTrue(ucode)
764         for node in ucode.subnodes:
765             self.assertFalse(node.props.get('data'))
766
767         # Check that the microcode appears immediately after the Fdt
768         # This matches the concatenation of the data properties in
769         # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
770         ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
771                                  0x78235609)
772         self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
773
774         # Check that the microcode pointer was inserted. It should match the
775         # expected offset and size
776         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
777                                    len(ucode_data))
778         u_boot = data[:len(nodtb_data)]
779         return u_boot, pos_and_size
780
781     def testPackUbootMicrocode(self):
782         """Test that x86 microcode can be handled correctly
783
784         We expect to see the following in the image, in order:
785             u-boot-nodtb.bin with a microcode pointer inserted at the correct
786                 place
787             u-boot.dtb with the microcode removed
788             the microcode
789         """
790         first, pos_and_size = self._RunMicrocodeTest('34_x86_ucode.dts',
791                                                      U_BOOT_NODTB_DATA)
792         self.assertEqual('nodtb with microcode' + pos_and_size +
793                          ' somewhere in here', first)
794
795     def _RunPackUbootSingleMicrocode(self):
796         """Test that x86 microcode can be handled correctly
797
798         We expect to see the following in the image, in order:
799             u-boot-nodtb.bin with a microcode pointer inserted at the correct
800                 place
801             u-boot.dtb with the microcode
802             an empty microcode region
803         """
804         # We need the libfdt library to run this test since only that allows
805         # finding the offset of a property. This is required by
806         # Entry_u_boot_dtb_with_ucode.ObtainContents().
807         data = self._DoReadFile('35_x86_single_ucode.dts', True)
808
809         second = data[len(U_BOOT_NODTB_DATA):]
810
811         fdt_len = self.GetFdtLen(second)
812         third = second[fdt_len:]
813         second = second[:fdt_len]
814
815         ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
816         self.assertIn(ucode_data, second)
817         ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
818
819         # Check that the microcode pointer was inserted. It should match the
820         # expected offset and size
821         pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
822                                    len(ucode_data))
823         first = data[:len(U_BOOT_NODTB_DATA)]
824         self.assertEqual('nodtb with microcode' + pos_and_size +
825                          ' somewhere in here', first)
826
827     def testPackUbootSingleMicrocode(self):
828         """Test that x86 microcode can be handled correctly with fdt_normal.
829         """
830         self._RunPackUbootSingleMicrocode()
831
832     def testUBootImg(self):
833         """Test that u-boot.img can be put in a file"""
834         data = self._DoReadFile('36_u_boot_img.dts')
835         self.assertEqual(U_BOOT_IMG_DATA, data)
836
837     def testNoMicrocode(self):
838         """Test that a missing microcode region is detected"""
839         with self.assertRaises(ValueError) as e:
840             self._DoReadFile('37_x86_no_ucode.dts', True)
841         self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
842                       "node found in ", str(e.exception))
843
844     def testMicrocodeWithoutNode(self):
845         """Test that a missing u-boot-dtb-with-ucode node is detected"""
846         with self.assertRaises(ValueError) as e:
847             self._DoReadFile('38_x86_ucode_missing_node.dts', True)
848         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
849                 "microcode region u-boot-dtb-with-ucode", str(e.exception))
850
851     def testMicrocodeWithoutNode2(self):
852         """Test that a missing u-boot-ucode node is detected"""
853         with self.assertRaises(ValueError) as e:
854             self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
855         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
856             "microcode region u-boot-ucode", str(e.exception))
857
858     def testMicrocodeWithoutPtrInElf(self):
859         """Test that a U-Boot binary without the microcode symbol is detected"""
860         # ELF file without a '_dt_ucode_base_size' symbol
861         try:
862             with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
863                 TestFunctional._MakeInputFile('u-boot', fd.read())
864
865             with self.assertRaises(ValueError) as e:
866                 self._RunPackUbootSingleMicrocode()
867             self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
868                     "_dt_ucode_base_size symbol in u-boot", str(e.exception))
869
870         finally:
871             # Put the original file back
872             with open(self.TestFile('u_boot_ucode_ptr')) as fd:
873                 TestFunctional._MakeInputFile('u-boot', fd.read())
874
875     def testMicrocodeNotInImage(self):
876         """Test that microcode must be placed within the image"""
877         with self.assertRaises(ValueError) as e:
878             self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
879         self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
880                 "pointer _dt_ucode_base_size at fffffe14 is outside the "
881                 "section ranging from 00000000 to 0000002e", str(e.exception))
882
883     def testWithoutMicrocode(self):
884         """Test that we can cope with an image without microcode (e.g. qemu)"""
885         with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
886             TestFunctional._MakeInputFile('u-boot', fd.read())
887         data, dtb, _, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
888
889         # Now check the device tree has no microcode
890         self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
891         second = data[len(U_BOOT_NODTB_DATA):]
892
893         fdt_len = self.GetFdtLen(second)
894         self.assertEqual(dtb, second[:fdt_len])
895
896         used_len = len(U_BOOT_NODTB_DATA) + fdt_len
897         third = data[used_len:]
898         self.assertEqual(chr(0) * (0x200 - used_len), third)
899
900     def testUnknownPosSize(self):
901         """Test that microcode must be placed within the image"""
902         with self.assertRaises(ValueError) as e:
903             self._DoReadFile('41_unknown_pos_size.dts', True)
904         self.assertIn("Section '/binman': Unable to set offset/size for unknown "
905                 "entry 'invalid-entry'", str(e.exception))
906
907     def testPackFsp(self):
908         """Test that an image with a FSP binary can be created"""
909         data = self._DoReadFile('42_intel-fsp.dts')
910         self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
911
912     def testPackCmc(self):
913         """Test that an image with a CMC binary can be created"""
914         data = self._DoReadFile('43_intel-cmc.dts')
915         self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
916
917     def testPackVbt(self):
918         """Test that an image with a VBT binary can be created"""
919         data = self._DoReadFile('46_intel-vbt.dts')
920         self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
921
922     def testSplBssPad(self):
923         """Test that we can pad SPL's BSS with zeros"""
924         # ELF file with a '__bss_size' symbol
925         with open(self.TestFile('bss_data')) as fd:
926             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
927         data = self._DoReadFile('47_spl_bss_pad.dts')
928         self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
929
930         with open(self.TestFile('u_boot_ucode_ptr')) as fd:
931             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
932         with self.assertRaises(ValueError) as e:
933             data = self._DoReadFile('47_spl_bss_pad.dts')
934         self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
935                       str(e.exception))
936
937     def testPackStart16Spl(self):
938         """Test that an image with an x86 start16 region can be created"""
939         data = self._DoReadFile('48_x86-start16-spl.dts')
940         self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
941
942     def _PackUbootSplMicrocode(self, dts, ucode_second=False):
943         """Helper function for microcode tests
944
945         We expect to see the following in the image, in order:
946             u-boot-spl-nodtb.bin with a microcode pointer inserted at the
947                 correct place
948             u-boot.dtb with the microcode removed
949             the microcode
950
951         Args:
952             dts: Device tree file to use for test
953             ucode_second: True if the microsecond entry is second instead of
954                 third
955         """
956         # ELF file with a '_dt_ucode_base_size' symbol
957         with open(self.TestFile('u_boot_ucode_ptr')) as fd:
958             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
959         first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
960                                                      ucode_second=ucode_second)
961         self.assertEqual('splnodtb with microc' + pos_and_size +
962                          'ter somewhere in here', first)
963
964     def testPackUbootSplMicrocode(self):
965         """Test that x86 microcode can be handled correctly in SPL"""
966         self._PackUbootSplMicrocode('49_x86_ucode_spl.dts')
967
968     def testPackUbootSplMicrocodeReorder(self):
969         """Test that order doesn't matter for microcode entries
970
971         This is the same as testPackUbootSplMicrocode but when we process the
972         u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
973         entry, so we reply on binman to try later.
974         """
975         self._PackUbootSplMicrocode('58_x86_ucode_spl_needs_retry.dts',
976                                     ucode_second=True)
977
978     def testPackMrc(self):
979         """Test that an image with an MRC binary can be created"""
980         data = self._DoReadFile('50_intel_mrc.dts')
981         self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
982
983     def testSplDtb(self):
984         """Test that an image with spl/u-boot-spl.dtb can be created"""
985         data = self._DoReadFile('51_u_boot_spl_dtb.dts')
986         self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
987
988     def testSplNoDtb(self):
989         """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
990         data = self._DoReadFile('52_u_boot_spl_nodtb.dts')
991         self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
992
993     def testSymbols(self):
994         """Test binman can assign symbols embedded in U-Boot"""
995         elf_fname = self.TestFile('u_boot_binman_syms')
996         syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
997         addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
998         self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
999
1000         with open(self.TestFile('u_boot_binman_syms')) as fd:
1001             TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1002         data = self._DoReadFile('53_symbols.dts')
1003         sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1004         expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1005                     U_BOOT_DATA +
1006                     sym_values + U_BOOT_SPL_DATA[16:])
1007         self.assertEqual(expected, data)
1008
1009     def testPackUnitAddress(self):
1010         """Test that we support multiple binaries with the same name"""
1011         data = self._DoReadFile('54_unit_address.dts')
1012         self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1013
1014     def testSections(self):
1015         """Basic test of sections"""
1016         data = self._DoReadFile('55_sections.dts')
1017         expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1018                     U_BOOT_DATA + '&' * 4)
1019         self.assertEqual(expected, data)
1020
1021     def testMap(self):
1022         """Tests outputting a map of the images"""
1023         _, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
1024         self.assertEqual('''  Offset      Size  Name
1025 00000000  00000028  main-section
1026  00000000  00000010  section@0
1027   00000000  00000004  u-boot
1028  00000010  00000010  section@1
1029   00000000  00000004  u-boot
1030  00000020  00000004  section@2
1031   00000000  00000004  u-boot
1032 ''', map_data)
1033
1034     def testNamePrefix(self):
1035         """Tests that name prefixes are used"""
1036         _, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
1037         self.assertEqual('''  Offset      Size  Name
1038 00000000  00000028  main-section
1039  00000000  00000010  section@0
1040   00000000  00000004  ro-u-boot
1041  00000010  00000010  section@1
1042   00000000  00000004  rw-u-boot
1043 ''', map_data)
1044
1045     def testUnknownContents(self):
1046         """Test that obtaining the contents works as expected"""
1047         with self.assertRaises(ValueError) as e:
1048             self._DoReadFile('57_unknown_contents.dts', True)
1049         self.assertIn("Section '/binman': Internal error: Could not complete "
1050                 "processing of contents: remaining [<_testing.Entry__testing ",
1051                 str(e.exception))
1052
1053     def testBadChangeSize(self):
1054         """Test that trying to change the size of an entry fails"""
1055         with self.assertRaises(ValueError) as e:
1056             self._DoReadFile('59_change_size.dts', True)
1057         self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1058                       '2 to 1', str(e.exception))
1059
1060     def testUpdateFdt(self):
1061         """Test that we can update the device tree with offset/size info"""
1062         _, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
1063                                                      update_dtb=True)
1064         props = self._GetPropTree(out_dtb_fname, ['offset', 'size',
1065                                                   'image-pos'])
1066         with open('/tmp/x.dtb', 'wb') as outf:
1067             with open(out_dtb_fname) as inf:
1068                 outf.write(inf.read())
1069         self.assertEqual({
1070             'image-pos': 0,
1071             'offset': 0,
1072             '_testing:offset': 32,
1073             '_testing:size': 1,
1074             '_testing:image-pos': 32,
1075             'section@0/u-boot:offset': 0,
1076             'section@0/u-boot:size': len(U_BOOT_DATA),
1077             'section@0/u-boot:image-pos': 0,
1078             'section@0:offset': 0,
1079             'section@0:size': 16,
1080             'section@0:image-pos': 0,
1081
1082             'section@1/u-boot:offset': 0,
1083             'section@1/u-boot:size': len(U_BOOT_DATA),
1084             'section@1/u-boot:image-pos': 16,
1085             'section@1:offset': 16,
1086             'section@1:size': 16,
1087             'section@1:image-pos': 16,
1088             'size': 40
1089         }, props)
1090
1091     def testUpdateFdtBad(self):
1092         """Test that we detect when ProcessFdt never completes"""
1093         with self.assertRaises(ValueError) as e:
1094             self._DoReadFileDtb('61_fdt_update_bad.dts', update_dtb=True)
1095         self.assertIn('Could not complete processing of Fdt: remaining '
1096                       '[<_testing.Entry__testing', str(e.exception))
1097
1098     def testEntryArgs(self):
1099         """Test passing arguments to entries from the command line"""
1100         entry_args = {
1101             'test-str-arg': 'test1',
1102             'test-int-arg': '456',
1103         }
1104         self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1105         self.assertIn('image', control.images)
1106         entry = control.images['image'].GetEntries()['_testing']
1107         self.assertEqual('test0', entry.test_str_fdt)
1108         self.assertEqual('test1', entry.test_str_arg)
1109         self.assertEqual(123, entry.test_int_fdt)
1110         self.assertEqual(456, entry.test_int_arg)
1111
1112     def testEntryArgsMissing(self):
1113         """Test missing arguments and properties"""
1114         entry_args = {
1115             'test-int-arg': '456',
1116         }
1117         self._DoReadFileDtb('63_entry_args_missing.dts', entry_args=entry_args)
1118         entry = control.images['image'].GetEntries()['_testing']
1119         self.assertEqual('test0', entry.test_str_fdt)
1120         self.assertEqual(None, entry.test_str_arg)
1121         self.assertEqual(None, entry.test_int_fdt)
1122         self.assertEqual(456, entry.test_int_arg)
1123
1124     def testEntryArgsRequired(self):
1125         """Test missing arguments and properties"""
1126         entry_args = {
1127             'test-int-arg': '456',
1128         }
1129         with self.assertRaises(ValueError) as e:
1130             self._DoReadFileDtb('64_entry_args_required.dts')
1131         self.assertIn("Node '/binman/_testing': Missing required "
1132             'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1133             str(e.exception))
1134
1135     def testEntryArgsInvalidFormat(self):
1136         """Test that an invalid entry-argument format is detected"""
1137         args = ['-d', self.TestFile('64_entry_args_required.dts'), '-ano-value']
1138         with self.assertRaises(ValueError) as e:
1139             self._DoBinman(*args)
1140         self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1141
1142     def testEntryArgsInvalidInteger(self):
1143         """Test that an invalid entry-argument integer is detected"""
1144         entry_args = {
1145             'test-int-arg': 'abc',
1146         }
1147         with self.assertRaises(ValueError) as e:
1148             self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1149         self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1150                       "'test-int-arg' (value 'abc') to integer",
1151             str(e.exception))
1152
1153     def testEntryArgsInvalidDatatype(self):
1154         """Test that an invalid entry-argument datatype is detected
1155
1156         This test could be written in entry_test.py except that it needs
1157         access to control.entry_args, which seems more than that module should
1158         be able to see.
1159         """
1160         entry_args = {
1161             'test-bad-datatype-arg': '12',
1162         }
1163         with self.assertRaises(ValueError) as e:
1164             self._DoReadFileDtb('65_entry_args_unknown_datatype.dts',
1165                                 entry_args=entry_args)
1166         self.assertIn('GetArg() internal error: Unknown data type ',
1167                       str(e.exception))
1168
1169     def testText(self):
1170         """Test for a text entry type"""
1171         entry_args = {
1172             'test-id': TEXT_DATA,
1173             'test-id2': TEXT_DATA2,
1174             'test-id3': TEXT_DATA3,
1175         }
1176         data, _, _, _ = self._DoReadFileDtb('66_text.dts',
1177                                             entry_args=entry_args)
1178         expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1179                     TEXT_DATA3 + 'some text')
1180         self.assertEqual(expected, data)
1181
1182     def testEntryDocs(self):
1183         """Test for creation of entry documentation"""
1184         with test_util.capture_sys_output() as (stdout, stderr):
1185             control.WriteEntryDocs(binman.GetEntryModules())
1186         self.assertTrue(len(stdout.getvalue()) > 0)
1187
1188     def testEntryDocsMissing(self):
1189         """Test handling of missing entry documentation"""
1190         with self.assertRaises(ValueError) as e:
1191             with test_util.capture_sys_output() as (stdout, stderr):
1192                 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1193         self.assertIn('Documentation is missing for modules: u_boot',
1194                       str(e.exception))
1195
1196     def testFmap(self):
1197         """Basic test of generation of a flashrom fmap"""
1198         data = self._DoReadFile('67_fmap.dts')
1199         fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1200         expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1201         self.assertEqual(expected, data[:32])
1202         self.assertEqual('__FMAP__', fhdr.signature)
1203         self.assertEqual(1, fhdr.ver_major)
1204         self.assertEqual(0, fhdr.ver_minor)
1205         self.assertEqual(0, fhdr.base)
1206         self.assertEqual(16 + 16 +
1207                          fmap_util.FMAP_HEADER_LEN +
1208                          fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1209         self.assertEqual('FMAP', fhdr.name)
1210         self.assertEqual(3, fhdr.nareas)
1211         for fentry in fentries:
1212             self.assertEqual(0, fentry.flags)
1213
1214         self.assertEqual(0, fentries[0].offset)
1215         self.assertEqual(4, fentries[0].size)
1216         self.assertEqual('RO_U_BOOT', fentries[0].name)
1217
1218         self.assertEqual(16, fentries[1].offset)
1219         self.assertEqual(4, fentries[1].size)
1220         self.assertEqual('RW_U_BOOT', fentries[1].name)
1221
1222         self.assertEqual(32, fentries[2].offset)
1223         self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1224                          fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1225         self.assertEqual('FMAP', fentries[2].name)
1226
1227
1228 if __name__ == "__main__":
1229     unittest.main()