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