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
9 from optparse import OptionParser
30 # Contents of test files, corresponding to different entry types
32 U_BOOT_IMG_DATA = 'img'
33 U_BOOT_SPL_DATA = '56780123456789abcde'
34 U_BOOT_TPL_DATA = 'tpl'
38 U_BOOT_DTB_DATA = 'udtb'
39 U_BOOT_SPL_DTB_DATA = 'spldtb'
40 U_BOOT_TPL_DTB_DATA = 'tpldtb'
41 X86_START16_DATA = 'start16'
42 X86_START16_SPL_DATA = 'start16spl'
43 X86_START16_TPL_DATA = 'start16tpl'
44 U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
45 U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
53 CROS_EC_RW_DATA = 'ecrw'
59 class TestFunctional(unittest.TestCase):
60 """Functional tests for binman
62 Most of these use a sample .dts file to build an image and then check
63 that it looks correct. The sample files are in the test/ subdirectory
66 For each entry type a very small test file is created using fixed
67 string contents. This makes it easy to test that things look right, and
70 In some cases a 'real' file must be used - these are also supplied in
78 # Handle the case where argv[0] is 'python'
79 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
80 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
82 # Create a temporary directory for input files
83 self._indir = tempfile.mkdtemp(prefix='binmant.')
85 # Create some test files
86 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
87 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
88 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
89 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
90 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
91 TestFunctional._MakeInputFile('me.bin', ME_DATA)
92 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
94 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
95 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
97 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
99 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
100 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
101 U_BOOT_SPL_NODTB_DATA)
102 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
103 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
104 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
105 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
106 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
107 TestFunctional._MakeInputDir('devkeys')
108 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
109 self._output_setup = False
111 # ELF file with a '_dt_ucode_base_size' symbol
112 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
113 TestFunctional._MakeInputFile('u-boot', fd.read())
115 # Intel flash descriptor file
116 with open(self.TestFile('descriptor.bin')) as fd:
117 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
120 def tearDownClass(self):
121 """Remove the temporary input directory and its contents"""
123 shutil.rmtree(self._indir)
127 # Enable this to turn on debugging output
128 # tout.Init(tout.DEBUG)
129 command.test_result = None
132 """Remove the temporary output directory"""
133 tools._FinaliseForTest()
136 def _ResetDtbs(self):
137 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
138 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
139 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
141 def _RunBinman(self, *args, **kwargs):
142 """Run binman using the command line
145 Arguments to pass, as a list of strings
146 kwargs: Arguments to pass to Command.RunPipe()
148 result = command.RunPipe([[self._binman_pathname] + list(args)],
149 capture=True, capture_stderr=True, raise_on_error=False)
150 if result.return_code and kwargs.get('raise_on_error', True):
151 raise Exception("Error running '%s': %s" % (' '.join(args),
152 result.stdout + result.stderr))
155 def _DoBinman(self, *args):
156 """Run binman using directly (in the same process)
159 Arguments to pass, as a list of strings
161 Return value (0 for success)
166 (options, args) = cmdline.ParseArgs(args)
167 options.pager = 'binman-invalid-pager'
168 options.build_dir = self._indir
170 # For testing, you can force an increase in verbosity here
171 # options.verbosity = tout.DEBUG
172 return control.Binman(options, args)
174 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
175 entry_args=None, images=None, use_real_dtb=False):
176 """Run binman with a given test file
179 fname: Device-tree source filename to use (e.g. 05_simple.dts)
180 debug: True to enable debugging output
181 map: True to output map files for the images
182 update_dtb: Update the offset and size of each entry in the device
183 tree before packing it into the image
184 entry_args: Dict of entry args to supply to binman
186 value: value of that arg
187 images: List of image names to build
189 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
197 args.append('--fake-dtb')
199 for arg, value in entry_args.iteritems():
200 args.append('-a%s=%s' % (arg, value))
203 args += ['-i', image]
204 return self._DoBinman(*args)
206 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
207 """Set up a new test device-tree file
209 The given file is compiled and set up as the device tree to be used
213 fname: Filename of .dts file to read
214 outfile: Output filename for compiled device-tree binary
217 Contents of device-tree binary
219 if not self._output_setup:
220 tools.PrepareOutputDir(self._indir, True)
221 self._output_setup = True
222 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
223 with open(dtb) as fd:
225 TestFunctional._MakeInputFile(outfile, data)
228 def _GetDtbContentsForSplTpl(self, dtb_data, name):
229 """Create a version of the main DTB for SPL or SPL
231 For testing we don't actually have different versions of the DTB. With
232 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
233 we don't normally have any unwanted nodes.
235 We still want the DTBs for SPL and TPL to be different though, since
236 otherwise it is confusing to know which one we are looking at. So add
237 an 'spl' or 'tpl' property to the top-level node.
239 dtb = fdt.Fdt.FromData(dtb_data)
241 dtb.GetNode('/binman').AddZeroProp(name)
242 dtb.Sync(auto_resize=True)
244 return dtb.GetContents()
246 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
247 update_dtb=False, entry_args=None, reset_dtbs=True):
248 """Run binman and return the resulting image
250 This runs binman with a given test file and then reads the resulting
251 output file. It is a shortcut function since most tests need to do
254 Raises an assertion failure if binman returns a non-zero exit code.
257 fname: Device-tree source filename to use (e.g. 05_simple.dts)
258 use_real_dtb: True to use the test file as the contents of
259 the u-boot-dtb entry. Normally this is not needed and the
260 test contents (the U_BOOT_DTB_DATA string) can be used.
261 But in some test we need the real contents.
262 map: True to output map files for the images
263 update_dtb: Update the offset and size of each entry in the device
264 tree before packing it into the image
268 Resulting image contents
270 Map data showing contents of image (or None if none)
271 Output device tree binary filename ('u-boot.dtb' path)
274 # Use the compiled test file as the u-boot-dtb input
276 dtb_data = self._SetupDtb(fname)
277 infile = os.path.join(self._indir, 'u-boot.dtb')
279 # For testing purposes, make a copy of the DT for SPL and TPL. Add
280 # a node indicating which it is, so aid verification.
281 for name in ['spl', 'tpl']:
282 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
283 outfile = os.path.join(self._indir, dtb_fname)
284 TestFunctional._MakeInputFile(dtb_fname,
285 self._GetDtbContentsForSplTpl(dtb_data, name))
288 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
289 entry_args=entry_args, use_real_dtb=use_real_dtb)
290 self.assertEqual(0, retcode)
291 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
293 # Find the (only) image, read it and return its contents
294 image = control.images['image']
295 image_fname = tools.GetOutputFilename('image.bin')
296 self.assertTrue(os.path.exists(image_fname))
298 map_fname = tools.GetOutputFilename('image.map')
299 with open(map_fname) as fd:
303 with open(image_fname) as fd:
304 return fd.read(), dtb_data, map_data, out_dtb_fname
306 # Put the test file back
307 if reset_dtbs and use_real_dtb:
310 def _DoReadFile(self, fname, use_real_dtb=False):
311 """Helper function which discards the device-tree binary
314 fname: Device-tree source filename to use (e.g. 05_simple.dts)
315 use_real_dtb: True to use the test file as the contents of
316 the u-boot-dtb entry. Normally this is not needed and the
317 test contents (the U_BOOT_DTB_DATA string) can be used.
318 But in some test we need the real contents.
321 Resulting image contents
323 return self._DoReadFileDtb(fname, use_real_dtb)[0]
326 def _MakeInputFile(self, fname, contents):
327 """Create a new test input file, creating directories as needed
330 fname: Filename to create
331 contents: File contents to write in to the file
333 Full pathname of file created
335 pathname = os.path.join(self._indir, fname)
336 dirname = os.path.dirname(pathname)
337 if dirname and not os.path.exists(dirname):
339 with open(pathname, 'wb') as fd:
344 def _MakeInputDir(self, dirname):
345 """Create a new test input directory, creating directories as needed
348 dirname: Directory name to create
351 Full pathname of directory created
353 pathname = os.path.join(self._indir, dirname)
354 if not os.path.exists(pathname):
355 os.makedirs(pathname)
359 def TestFile(self, fname):
360 return os.path.join(self._binman_dir, 'test', fname)
362 def AssertInList(self, grep_list, target):
363 """Assert that at least one of a list of things is in a target
366 grep_list: List of strings to check
367 target: Target string
369 for grep in grep_list:
372 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
374 def CheckNoGaps(self, entries):
375 """Check that all entries fit together without gaps
378 entries: List of entries to check
381 for entry in entries.values():
382 self.assertEqual(offset, entry.offset)
385 def GetFdtLen(self, dtb):
386 """Get the totalsize field from a device-tree binary
389 dtb: Device-tree binary contents
392 Total size of device-tree binary, from the header
394 return struct.unpack('>L', dtb[4:8])[0]
396 def _GetPropTree(self, dtb, prop_names):
397 def AddNode(node, path):
399 path += '/' + node.name
400 for subnode in node.subnodes:
401 for prop in subnode.props.values():
402 if prop.name in prop_names:
403 prop_path = path + '/' + subnode.name + ':' + prop.name
404 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
406 AddNode(subnode, path)
409 AddNode(dtb.GetRoot(), '')
413 """Test a basic run with valid args"""
414 result = self._RunBinman('-h')
416 def testFullHelp(self):
417 """Test that the full help is displayed with -H"""
418 result = self._RunBinman('-H')
419 help_file = os.path.join(self._binman_dir, 'README')
420 # Remove possible extraneous strings
421 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
422 gothelp = result.stdout.replace(extra, '')
423 self.assertEqual(len(gothelp), os.path.getsize(help_file))
424 self.assertEqual(0, len(result.stderr))
425 self.assertEqual(0, result.return_code)
427 def testFullHelpInternal(self):
428 """Test that the full help is displayed with -H"""
430 command.test_result = command.CommandResult()
431 result = self._DoBinman('-H')
432 help_file = os.path.join(self._binman_dir, 'README')
434 command.test_result = None
437 """Test that the basic help is displayed with -h"""
438 result = self._RunBinman('-h')
439 self.assertTrue(len(result.stdout) > 200)
440 self.assertEqual(0, len(result.stderr))
441 self.assertEqual(0, result.return_code)
444 """Test that we can run it with a specific board"""
445 self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
446 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
447 result = self._DoBinman('-b', 'sandbox')
448 self.assertEqual(0, result)
450 def testNeedBoard(self):
451 """Test that we get an error when no board ius supplied"""
452 with self.assertRaises(ValueError) as e:
453 result = self._DoBinman()
454 self.assertIn("Must provide a board to process (use -b <board>)",
457 def testMissingDt(self):
458 """Test that an invalid device-tree file generates an error"""
459 with self.assertRaises(Exception) as e:
460 self._RunBinman('-d', 'missing_file')
461 # We get one error from libfdt, and a different one from fdtget.
462 self.AssertInList(["Couldn't open blob from 'missing_file'",
463 'No such file or directory'], str(e.exception))
465 def testBrokenDt(self):
466 """Test that an invalid device-tree source file generates an error
468 Since this is a source file it should be compiled and the error
469 will come from the device-tree compiler (dtc).
471 with self.assertRaises(Exception) as e:
472 self._RunBinman('-d', self.TestFile('01_invalid.dts'))
473 self.assertIn("FATAL ERROR: Unable to parse input tree",
476 def testMissingNode(self):
477 """Test that a device tree without a 'binman' node generates an error"""
478 with self.assertRaises(Exception) as e:
479 self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
480 self.assertIn("does not have a 'binman' node", str(e.exception))
483 """Test that an empty binman node works OK (i.e. does nothing)"""
484 result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
485 self.assertEqual(0, len(result.stderr))
486 self.assertEqual(0, result.return_code)
488 def testInvalidEntry(self):
489 """Test that an invalid entry is flagged"""
490 with self.assertRaises(Exception) as e:
491 result = self._RunBinman('-d',
492 self.TestFile('04_invalid_entry.dts'))
493 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
494 "'/binman/not-a-valid-type'", str(e.exception))
496 def testSimple(self):
497 """Test a simple binman with a single file"""
498 data = self._DoReadFile('05_simple.dts')
499 self.assertEqual(U_BOOT_DATA, data)
501 def testSimpleDebug(self):
502 """Test a simple binman run with debugging enabled"""
503 data = self._DoTestFile('05_simple.dts', debug=True)
506 """Test that we can handle creating two images
508 This also tests image padding.
510 retcode = self._DoTestFile('06_dual_image.dts')
511 self.assertEqual(0, retcode)
513 image = control.images['image1']
514 self.assertEqual(len(U_BOOT_DATA), image._size)
515 fname = tools.GetOutputFilename('image1.bin')
516 self.assertTrue(os.path.exists(fname))
517 with open(fname) as fd:
519 self.assertEqual(U_BOOT_DATA, data)
521 image = control.images['image2']
522 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
523 fname = tools.GetOutputFilename('image2.bin')
524 self.assertTrue(os.path.exists(fname))
525 with open(fname) as fd:
527 self.assertEqual(U_BOOT_DATA, data[3:7])
528 self.assertEqual(chr(0) * 3, data[:3])
529 self.assertEqual(chr(0) * 5, data[7:])
531 def testBadAlign(self):
532 """Test that an invalid alignment value is detected"""
533 with self.assertRaises(ValueError) as e:
534 self._DoTestFile('07_bad_align.dts')
535 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
536 "of two", str(e.exception))
538 def testPackSimple(self):
539 """Test that packing works as expected"""
540 retcode = self._DoTestFile('08_pack.dts')
541 self.assertEqual(0, retcode)
542 self.assertIn('image', control.images)
543 image = control.images['image']
544 entries = image.GetEntries()
545 self.assertEqual(5, len(entries))
548 self.assertIn('u-boot', entries)
549 entry = entries['u-boot']
550 self.assertEqual(0, entry.offset)
551 self.assertEqual(len(U_BOOT_DATA), entry.size)
553 # Second u-boot, aligned to 16-byte boundary
554 self.assertIn('u-boot-align', entries)
555 entry = entries['u-boot-align']
556 self.assertEqual(16, entry.offset)
557 self.assertEqual(len(U_BOOT_DATA), entry.size)
559 # Third u-boot, size 23 bytes
560 self.assertIn('u-boot-size', entries)
561 entry = entries['u-boot-size']
562 self.assertEqual(20, entry.offset)
563 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
564 self.assertEqual(23, entry.size)
566 # Fourth u-boot, placed immediate after the above
567 self.assertIn('u-boot-next', entries)
568 entry = entries['u-boot-next']
569 self.assertEqual(43, entry.offset)
570 self.assertEqual(len(U_BOOT_DATA), entry.size)
572 # Fifth u-boot, placed at a fixed offset
573 self.assertIn('u-boot-fixed', entries)
574 entry = entries['u-boot-fixed']
575 self.assertEqual(61, entry.offset)
576 self.assertEqual(len(U_BOOT_DATA), entry.size)
578 self.assertEqual(65, image._size)
580 def testPackExtra(self):
581 """Test that extra packing feature works as expected"""
582 retcode = self._DoTestFile('09_pack_extra.dts')
584 self.assertEqual(0, retcode)
585 self.assertIn('image', control.images)
586 image = control.images['image']
587 entries = image.GetEntries()
588 self.assertEqual(5, len(entries))
590 # First u-boot with padding before and after
591 self.assertIn('u-boot', entries)
592 entry = entries['u-boot']
593 self.assertEqual(0, entry.offset)
594 self.assertEqual(3, entry.pad_before)
595 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
597 # Second u-boot has an aligned size, but it has no effect
598 self.assertIn('u-boot-align-size-nop', entries)
599 entry = entries['u-boot-align-size-nop']
600 self.assertEqual(12, entry.offset)
601 self.assertEqual(4, entry.size)
603 # Third u-boot has an aligned size too
604 self.assertIn('u-boot-align-size', entries)
605 entry = entries['u-boot-align-size']
606 self.assertEqual(16, entry.offset)
607 self.assertEqual(32, entry.size)
609 # Fourth u-boot has an aligned end
610 self.assertIn('u-boot-align-end', entries)
611 entry = entries['u-boot-align-end']
612 self.assertEqual(48, entry.offset)
613 self.assertEqual(16, entry.size)
615 # Fifth u-boot immediately afterwards
616 self.assertIn('u-boot-align-both', entries)
617 entry = entries['u-boot-align-both']
618 self.assertEqual(64, entry.offset)
619 self.assertEqual(64, entry.size)
621 self.CheckNoGaps(entries)
622 self.assertEqual(128, image._size)
624 def testPackAlignPowerOf2(self):
625 """Test that invalid entry alignment is detected"""
626 with self.assertRaises(ValueError) as e:
627 self._DoTestFile('10_pack_align_power2.dts')
628 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
629 "of two", str(e.exception))
631 def testPackAlignSizePowerOf2(self):
632 """Test that invalid entry size alignment is detected"""
633 with self.assertRaises(ValueError) as e:
634 self._DoTestFile('11_pack_align_size_power2.dts')
635 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
636 "power of two", str(e.exception))
638 def testPackInvalidAlign(self):
639 """Test detection of an offset that does not match its alignment"""
640 with self.assertRaises(ValueError) as e:
641 self._DoTestFile('12_pack_inv_align.dts')
642 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
643 "align 0x4 (4)", str(e.exception))
645 def testPackInvalidSizeAlign(self):
646 """Test that invalid entry size alignment is detected"""
647 with self.assertRaises(ValueError) as e:
648 self._DoTestFile('13_pack_inv_size_align.dts')
649 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
650 "align-size 0x4 (4)", str(e.exception))
652 def testPackOverlap(self):
653 """Test that overlapping regions are detected"""
654 with self.assertRaises(ValueError) as e:
655 self._DoTestFile('14_pack_overlap.dts')
656 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
657 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
660 def testPackEntryOverflow(self):
661 """Test that entries that overflow their size are detected"""
662 with self.assertRaises(ValueError) as e:
663 self._DoTestFile('15_pack_overflow.dts')
664 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
665 "but entry size is 0x3 (3)", str(e.exception))
667 def testPackImageOverflow(self):
668 """Test that entries which overflow the image size are detected"""
669 with self.assertRaises(ValueError) as e:
670 self._DoTestFile('16_pack_image_overflow.dts')
671 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
672 "size 0x3 (3)", str(e.exception))
674 def testPackImageSize(self):
675 """Test that the image size can be set"""
676 retcode = self._DoTestFile('17_pack_image_size.dts')
677 self.assertEqual(0, retcode)
678 self.assertIn('image', control.images)
679 image = control.images['image']
680 self.assertEqual(7, image._size)
682 def testPackImageSizeAlign(self):
683 """Test that image size alignemnt works as expected"""
684 retcode = self._DoTestFile('18_pack_image_align.dts')
685 self.assertEqual(0, retcode)
686 self.assertIn('image', control.images)
687 image = control.images['image']
688 self.assertEqual(16, image._size)
690 def testPackInvalidImageAlign(self):
691 """Test that invalid image alignment is detected"""
692 with self.assertRaises(ValueError) as e:
693 self._DoTestFile('19_pack_inv_image_align.dts')
694 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
695 "align-size 0x8 (8)", str(e.exception))
697 def testPackAlignPowerOf2(self):
698 """Test that invalid image alignment is detected"""
699 with self.assertRaises(ValueError) as e:
700 self._DoTestFile('20_pack_inv_image_align_power2.dts')
701 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
702 "two", str(e.exception))
704 def testImagePadByte(self):
705 """Test that the image pad byte can be specified"""
706 with open(self.TestFile('bss_data')) as fd:
707 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
708 data = self._DoReadFile('21_image_pad.dts')
709 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
711 def testImageName(self):
712 """Test that image files can be named"""
713 retcode = self._DoTestFile('22_image_name.dts')
714 self.assertEqual(0, retcode)
715 image = control.images['image1']
716 fname = tools.GetOutputFilename('test-name')
717 self.assertTrue(os.path.exists(fname))
719 image = control.images['image2']
720 fname = tools.GetOutputFilename('test-name.xx')
721 self.assertTrue(os.path.exists(fname))
723 def testBlobFilename(self):
724 """Test that generic blobs can be provided by filename"""
725 data = self._DoReadFile('23_blob.dts')
726 self.assertEqual(BLOB_DATA, data)
728 def testPackSorted(self):
729 """Test that entries can be sorted"""
730 data = self._DoReadFile('24_sorted.dts')
731 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
734 def testPackZeroOffset(self):
735 """Test that an entry at offset 0 is not given a new offset"""
736 with self.assertRaises(ValueError) as e:
737 self._DoTestFile('25_pack_zero_size.dts')
738 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
739 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
742 def testPackUbootDtb(self):
743 """Test that a device tree can be added to U-Boot"""
744 data = self._DoReadFile('26_pack_u_boot_dtb.dts')
745 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
747 def testPackX86RomNoSize(self):
748 """Test that the end-at-4gb property requires a size property"""
749 with self.assertRaises(ValueError) as e:
750 self._DoTestFile('27_pack_4gb_no_size.dts')
751 self.assertIn("Section '/binman': Section size must be provided when "
752 "using end-at-4gb", str(e.exception))
754 def testPackX86RomOutside(self):
755 """Test that the end-at-4gb property checks for offset boundaries"""
756 with self.assertRaises(ValueError) as e:
757 self._DoTestFile('28_pack_4gb_outside.dts')
758 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
759 "the section starting at 0xffffffe0 (4294967264)",
762 def testPackX86Rom(self):
763 """Test that a basic x86 ROM can be created"""
764 data = self._DoReadFile('29_x86-rom.dts')
765 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
768 def testPackX86RomMeNoDesc(self):
769 """Test that an invalid Intel descriptor entry is detected"""
770 TestFunctional._MakeInputFile('descriptor.bin', '')
771 with self.assertRaises(ValueError) as e:
772 self._DoTestFile('31_x86-rom-me.dts')
773 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
774 "signature", str(e.exception))
776 def testPackX86RomBadDesc(self):
777 """Test that the Intel requires a descriptor entry"""
778 with self.assertRaises(ValueError) as e:
779 self._DoTestFile('30_x86-rom-me-no-desc.dts')
780 self.assertIn("Node '/binman/intel-me': No offset set with "
781 "offset-unset: should another entry provide this correct "
782 "offset?", str(e.exception))
784 def testPackX86RomMe(self):
785 """Test that an x86 ROM with an ME region can be created"""
786 data = self._DoReadFile('31_x86-rom-me.dts')
787 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
789 def testPackVga(self):
790 """Test that an image with a VGA binary can be created"""
791 data = self._DoReadFile('32_intel-vga.dts')
792 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
794 def testPackStart16(self):
795 """Test that an image with an x86 start16 region can be created"""
796 data = self._DoReadFile('33_x86-start16.dts')
797 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
799 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
800 """Handle running a test for insertion of microcode
803 dts_fname: Name of test .dts file
804 nodtb_data: Data that we expect in the first section
805 ucode_second: True if the microsecond entry is second instead of
810 Contents of first region (U-Boot or SPL)
811 Offset and size components of microcode pointer, as inserted
812 in the above (two 4-byte words)
814 data = self._DoReadFile(dts_fname, True)
816 # Now check the device tree has no microcode
818 ucode_content = data[len(nodtb_data):]
819 ucode_pos = len(nodtb_data)
820 dtb_with_ucode = ucode_content[16:]
821 fdt_len = self.GetFdtLen(dtb_with_ucode)
823 dtb_with_ucode = data[len(nodtb_data):]
824 fdt_len = self.GetFdtLen(dtb_with_ucode)
825 ucode_content = dtb_with_ucode[fdt_len:]
826 ucode_pos = len(nodtb_data) + fdt_len
827 fname = tools.GetOutputFilename('test.dtb')
828 with open(fname, 'wb') as fd:
829 fd.write(dtb_with_ucode)
830 dtb = fdt.FdtScan(fname)
831 ucode = dtb.GetNode('/microcode')
832 self.assertTrue(ucode)
833 for node in ucode.subnodes:
834 self.assertFalse(node.props.get('data'))
836 # Check that the microcode appears immediately after the Fdt
837 # This matches the concatenation of the data properties in
838 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
839 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
841 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
843 # Check that the microcode pointer was inserted. It should match the
844 # expected offset and size
845 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
847 u_boot = data[:len(nodtb_data)]
848 return u_boot, pos_and_size
850 def testPackUbootMicrocode(self):
851 """Test that x86 microcode can be handled correctly
853 We expect to see the following in the image, in order:
854 u-boot-nodtb.bin with a microcode pointer inserted at the correct
856 u-boot.dtb with the microcode removed
859 first, pos_and_size = self._RunMicrocodeTest('34_x86_ucode.dts',
861 self.assertEqual('nodtb with microcode' + pos_and_size +
862 ' somewhere in here', first)
864 def _RunPackUbootSingleMicrocode(self):
865 """Test that x86 microcode can be handled correctly
867 We expect to see the following in the image, in order:
868 u-boot-nodtb.bin with a microcode pointer inserted at the correct
870 u-boot.dtb with the microcode
871 an empty microcode region
873 # We need the libfdt library to run this test since only that allows
874 # finding the offset of a property. This is required by
875 # Entry_u_boot_dtb_with_ucode.ObtainContents().
876 data = self._DoReadFile('35_x86_single_ucode.dts', True)
878 second = data[len(U_BOOT_NODTB_DATA):]
880 fdt_len = self.GetFdtLen(second)
881 third = second[fdt_len:]
882 second = second[:fdt_len]
884 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
885 self.assertIn(ucode_data, second)
886 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
888 # Check that the microcode pointer was inserted. It should match the
889 # expected offset and size
890 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
892 first = data[:len(U_BOOT_NODTB_DATA)]
893 self.assertEqual('nodtb with microcode' + pos_and_size +
894 ' somewhere in here', first)
896 def testPackUbootSingleMicrocode(self):
897 """Test that x86 microcode can be handled correctly with fdt_normal.
899 self._RunPackUbootSingleMicrocode()
901 def testUBootImg(self):
902 """Test that u-boot.img can be put in a file"""
903 data = self._DoReadFile('36_u_boot_img.dts')
904 self.assertEqual(U_BOOT_IMG_DATA, data)
906 def testNoMicrocode(self):
907 """Test that a missing microcode region is detected"""
908 with self.assertRaises(ValueError) as e:
909 self._DoReadFile('37_x86_no_ucode.dts', True)
910 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
911 "node found in ", str(e.exception))
913 def testMicrocodeWithoutNode(self):
914 """Test that a missing u-boot-dtb-with-ucode node is detected"""
915 with self.assertRaises(ValueError) as e:
916 self._DoReadFile('38_x86_ucode_missing_node.dts', True)
917 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
918 "microcode region u-boot-dtb-with-ucode", str(e.exception))
920 def testMicrocodeWithoutNode2(self):
921 """Test that a missing u-boot-ucode node is detected"""
922 with self.assertRaises(ValueError) as e:
923 self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
924 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
925 "microcode region u-boot-ucode", str(e.exception))
927 def testMicrocodeWithoutPtrInElf(self):
928 """Test that a U-Boot binary without the microcode symbol is detected"""
929 # ELF file without a '_dt_ucode_base_size' symbol
931 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
932 TestFunctional._MakeInputFile('u-boot', fd.read())
934 with self.assertRaises(ValueError) as e:
935 self._RunPackUbootSingleMicrocode()
936 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
937 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
940 # Put the original file back
941 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
942 TestFunctional._MakeInputFile('u-boot', fd.read())
944 def testMicrocodeNotInImage(self):
945 """Test that microcode must be placed within the image"""
946 with self.assertRaises(ValueError) as e:
947 self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
948 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
949 "pointer _dt_ucode_base_size at fffffe14 is outside the "
950 "section ranging from 00000000 to 0000002e", str(e.exception))
952 def testWithoutMicrocode(self):
953 """Test that we can cope with an image without microcode (e.g. qemu)"""
954 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
955 TestFunctional._MakeInputFile('u-boot', fd.read())
956 data, dtb, _, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
958 # Now check the device tree has no microcode
959 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
960 second = data[len(U_BOOT_NODTB_DATA):]
962 fdt_len = self.GetFdtLen(second)
963 self.assertEqual(dtb, second[:fdt_len])
965 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
966 third = data[used_len:]
967 self.assertEqual(chr(0) * (0x200 - used_len), third)
969 def testUnknownPosSize(self):
970 """Test that microcode must be placed within the image"""
971 with self.assertRaises(ValueError) as e:
972 self._DoReadFile('41_unknown_pos_size.dts', True)
973 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
974 "entry 'invalid-entry'", str(e.exception))
976 def testPackFsp(self):
977 """Test that an image with a FSP binary can be created"""
978 data = self._DoReadFile('42_intel-fsp.dts')
979 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
981 def testPackCmc(self):
982 """Test that an image with a CMC binary can be created"""
983 data = self._DoReadFile('43_intel-cmc.dts')
984 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
986 def testPackVbt(self):
987 """Test that an image with a VBT binary can be created"""
988 data = self._DoReadFile('46_intel-vbt.dts')
989 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
991 def testSplBssPad(self):
992 """Test that we can pad SPL's BSS with zeros"""
993 # ELF file with a '__bss_size' symbol
994 with open(self.TestFile('bss_data')) as fd:
995 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
996 data = self._DoReadFile('47_spl_bss_pad.dts')
997 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
999 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1000 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1001 with self.assertRaises(ValueError) as e:
1002 data = self._DoReadFile('47_spl_bss_pad.dts')
1003 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1006 def testPackStart16Spl(self):
1007 """Test that an image with an x86 start16 SPL region can be created"""
1008 data = self._DoReadFile('48_x86-start16-spl.dts')
1009 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1011 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1012 """Helper function for microcode tests
1014 We expect to see the following in the image, in order:
1015 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1017 u-boot.dtb with the microcode removed
1021 dts: Device tree file to use for test
1022 ucode_second: True if the microsecond entry is second instead of
1025 # ELF file with a '_dt_ucode_base_size' symbol
1026 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1027 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1028 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1029 ucode_second=ucode_second)
1030 self.assertEqual('splnodtb with microc' + pos_and_size +
1031 'ter somewhere in here', first)
1033 def testPackUbootSplMicrocode(self):
1034 """Test that x86 microcode can be handled correctly in SPL"""
1035 self._PackUbootSplMicrocode('49_x86_ucode_spl.dts')
1037 def testPackUbootSplMicrocodeReorder(self):
1038 """Test that order doesn't matter for microcode entries
1040 This is the same as testPackUbootSplMicrocode but when we process the
1041 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1042 entry, so we reply on binman to try later.
1044 self._PackUbootSplMicrocode('58_x86_ucode_spl_needs_retry.dts',
1047 def testPackMrc(self):
1048 """Test that an image with an MRC binary can be created"""
1049 data = self._DoReadFile('50_intel_mrc.dts')
1050 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1052 def testSplDtb(self):
1053 """Test that an image with spl/u-boot-spl.dtb can be created"""
1054 data = self._DoReadFile('51_u_boot_spl_dtb.dts')
1055 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1057 def testSplNoDtb(self):
1058 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1059 data = self._DoReadFile('52_u_boot_spl_nodtb.dts')
1060 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1062 def testSymbols(self):
1063 """Test binman can assign symbols embedded in U-Boot"""
1064 elf_fname = self.TestFile('u_boot_binman_syms')
1065 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1066 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1067 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1069 with open(self.TestFile('u_boot_binman_syms')) as fd:
1070 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1071 data = self._DoReadFile('53_symbols.dts')
1072 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1073 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1075 sym_values + U_BOOT_SPL_DATA[16:])
1076 self.assertEqual(expected, data)
1078 def testPackUnitAddress(self):
1079 """Test that we support multiple binaries with the same name"""
1080 data = self._DoReadFile('54_unit_address.dts')
1081 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1083 def testSections(self):
1084 """Basic test of sections"""
1085 data = self._DoReadFile('55_sections.dts')
1086 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1087 U_BOOT_DATA + '&' * 4)
1088 self.assertEqual(expected, data)
1091 """Tests outputting a map of the images"""
1092 _, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
1093 self.assertEqual('''ImagePos Offset Size Name
1094 00000000 00000000 00000028 main-section
1095 00000000 00000000 00000010 section@0
1096 00000000 00000000 00000004 u-boot
1097 00000010 00000010 00000010 section@1
1098 00000010 00000000 00000004 u-boot
1099 00000020 00000020 00000004 section@2
1100 00000020 00000000 00000004 u-boot
1103 def testNamePrefix(self):
1104 """Tests that name prefixes are used"""
1105 _, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
1106 self.assertEqual('''ImagePos Offset Size Name
1107 00000000 00000000 00000028 main-section
1108 00000000 00000000 00000010 section@0
1109 00000000 00000000 00000004 ro-u-boot
1110 00000010 00000010 00000010 section@1
1111 00000010 00000000 00000004 rw-u-boot
1114 def testUnknownContents(self):
1115 """Test that obtaining the contents works as expected"""
1116 with self.assertRaises(ValueError) as e:
1117 self._DoReadFile('57_unknown_contents.dts', True)
1118 self.assertIn("Section '/binman': Internal error: Could not complete "
1119 "processing of contents: remaining [<_testing.Entry__testing ",
1122 def testBadChangeSize(self):
1123 """Test that trying to change the size of an entry fails"""
1124 with self.assertRaises(ValueError) as e:
1125 self._DoReadFile('59_change_size.dts', True)
1126 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1127 '2 to 1', str(e.exception))
1129 def testUpdateFdt(self):
1130 """Test that we can update the device tree with offset/size info"""
1131 _, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
1133 dtb = fdt.Fdt(out_dtb_fname)
1135 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
1139 '_testing:offset': 32,
1141 '_testing:image-pos': 32,
1142 'section@0/u-boot:offset': 0,
1143 'section@0/u-boot:size': len(U_BOOT_DATA),
1144 'section@0/u-boot:image-pos': 0,
1145 'section@0:offset': 0,
1146 'section@0:size': 16,
1147 'section@0:image-pos': 0,
1149 'section@1/u-boot:offset': 0,
1150 'section@1/u-boot:size': len(U_BOOT_DATA),
1151 'section@1/u-boot:image-pos': 16,
1152 'section@1:offset': 16,
1153 'section@1:size': 16,
1154 'section@1:image-pos': 16,
1158 def testUpdateFdtBad(self):
1159 """Test that we detect when ProcessFdt never completes"""
1160 with self.assertRaises(ValueError) as e:
1161 self._DoReadFileDtb('61_fdt_update_bad.dts', update_dtb=True)
1162 self.assertIn('Could not complete processing of Fdt: remaining '
1163 '[<_testing.Entry__testing', str(e.exception))
1165 def testEntryArgs(self):
1166 """Test passing arguments to entries from the command line"""
1168 'test-str-arg': 'test1',
1169 'test-int-arg': '456',
1171 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1172 self.assertIn('image', control.images)
1173 entry = control.images['image'].GetEntries()['_testing']
1174 self.assertEqual('test0', entry.test_str_fdt)
1175 self.assertEqual('test1', entry.test_str_arg)
1176 self.assertEqual(123, entry.test_int_fdt)
1177 self.assertEqual(456, entry.test_int_arg)
1179 def testEntryArgsMissing(self):
1180 """Test missing arguments and properties"""
1182 'test-int-arg': '456',
1184 self._DoReadFileDtb('63_entry_args_missing.dts', entry_args=entry_args)
1185 entry = control.images['image'].GetEntries()['_testing']
1186 self.assertEqual('test0', entry.test_str_fdt)
1187 self.assertEqual(None, entry.test_str_arg)
1188 self.assertEqual(None, entry.test_int_fdt)
1189 self.assertEqual(456, entry.test_int_arg)
1191 def testEntryArgsRequired(self):
1192 """Test missing arguments and properties"""
1194 'test-int-arg': '456',
1196 with self.assertRaises(ValueError) as e:
1197 self._DoReadFileDtb('64_entry_args_required.dts')
1198 self.assertIn("Node '/binman/_testing': Missing required "
1199 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1202 def testEntryArgsInvalidFormat(self):
1203 """Test that an invalid entry-argument format is detected"""
1204 args = ['-d', self.TestFile('64_entry_args_required.dts'), '-ano-value']
1205 with self.assertRaises(ValueError) as e:
1206 self._DoBinman(*args)
1207 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1209 def testEntryArgsInvalidInteger(self):
1210 """Test that an invalid entry-argument integer is detected"""
1212 'test-int-arg': 'abc',
1214 with self.assertRaises(ValueError) as e:
1215 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1216 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1217 "'test-int-arg' (value 'abc') to integer",
1220 def testEntryArgsInvalidDatatype(self):
1221 """Test that an invalid entry-argument datatype is detected
1223 This test could be written in entry_test.py except that it needs
1224 access to control.entry_args, which seems more than that module should
1228 'test-bad-datatype-arg': '12',
1230 with self.assertRaises(ValueError) as e:
1231 self._DoReadFileDtb('65_entry_args_unknown_datatype.dts',
1232 entry_args=entry_args)
1233 self.assertIn('GetArg() internal error: Unknown data type ',
1237 """Test for a text entry type"""
1239 'test-id': TEXT_DATA,
1240 'test-id2': TEXT_DATA2,
1241 'test-id3': TEXT_DATA3,
1243 data, _, _, _ = self._DoReadFileDtb('66_text.dts',
1244 entry_args=entry_args)
1245 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1246 TEXT_DATA3 + 'some text')
1247 self.assertEqual(expected, data)
1249 def testEntryDocs(self):
1250 """Test for creation of entry documentation"""
1251 with test_util.capture_sys_output() as (stdout, stderr):
1252 control.WriteEntryDocs(binman.GetEntryModules())
1253 self.assertTrue(len(stdout.getvalue()) > 0)
1255 def testEntryDocsMissing(self):
1256 """Test handling of missing entry documentation"""
1257 with self.assertRaises(ValueError) as e:
1258 with test_util.capture_sys_output() as (stdout, stderr):
1259 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1260 self.assertIn('Documentation is missing for modules: u_boot',
1264 """Basic test of generation of a flashrom fmap"""
1265 data = self._DoReadFile('67_fmap.dts')
1266 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1267 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1268 self.assertEqual(expected, data[:32])
1269 self.assertEqual('__FMAP__', fhdr.signature)
1270 self.assertEqual(1, fhdr.ver_major)
1271 self.assertEqual(0, fhdr.ver_minor)
1272 self.assertEqual(0, fhdr.base)
1273 self.assertEqual(16 + 16 +
1274 fmap_util.FMAP_HEADER_LEN +
1275 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1276 self.assertEqual('FMAP', fhdr.name)
1277 self.assertEqual(3, fhdr.nareas)
1278 for fentry in fentries:
1279 self.assertEqual(0, fentry.flags)
1281 self.assertEqual(0, fentries[0].offset)
1282 self.assertEqual(4, fentries[0].size)
1283 self.assertEqual('RO_U_BOOT', fentries[0].name)
1285 self.assertEqual(16, fentries[1].offset)
1286 self.assertEqual(4, fentries[1].size)
1287 self.assertEqual('RW_U_BOOT', fentries[1].name)
1289 self.assertEqual(32, fentries[2].offset)
1290 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1291 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1292 self.assertEqual('FMAP', fentries[2].name)
1294 def testBlobNamedByArg(self):
1295 """Test we can add a blob with the filename coming from an entry arg"""
1297 'cros-ec-rw-path': 'ecrw.bin',
1299 data, _, _, _ = self._DoReadFileDtb('68_blob_named_by_arg.dts',
1300 entry_args=entry_args)
1303 """Test for an fill entry type"""
1304 data = self._DoReadFile('69_fill.dts')
1305 expected = 8 * chr(0xff) + 8 * chr(0)
1306 self.assertEqual(expected, data)
1308 def testFillNoSize(self):
1309 """Test for an fill entry type with no size"""
1310 with self.assertRaises(ValueError) as e:
1311 self._DoReadFile('70_fill_no_size.dts')
1312 self.assertIn("'fill' entry must have a size property",
1315 def _HandleGbbCommand(self, pipe_list):
1316 """Fake calls to the futility utility"""
1317 if pipe_list[0][0] == 'futility':
1318 fname = pipe_list[0][-1]
1319 # Append our GBB data to the file, which will happen every time the
1320 # futility command is called.
1321 with open(fname, 'a') as fd:
1323 return command.CommandResult()
1326 """Test for the Chromium OS Google Binary Block"""
1327 command.test_result = self._HandleGbbCommand
1329 'keydir': 'devkeys',
1330 'bmpblk': 'bmpblk.bin',
1332 data, _, _, _ = self._DoReadFileDtb('71_gbb.dts', entry_args=entry_args)
1335 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1336 self.assertEqual(expected, data)
1338 def testGbbTooSmall(self):
1339 """Test for the Chromium OS Google Binary Block being large enough"""
1340 with self.assertRaises(ValueError) as e:
1341 self._DoReadFileDtb('72_gbb_too_small.dts')
1342 self.assertIn("Node '/binman/gbb': GBB is too small",
1345 def testGbbNoSize(self):
1346 """Test for the Chromium OS Google Binary Block having a size"""
1347 with self.assertRaises(ValueError) as e:
1348 self._DoReadFileDtb('73_gbb_no_size.dts')
1349 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1352 def _HandleVblockCommand(self, pipe_list):
1353 """Fake calls to the futility utility"""
1354 if pipe_list[0][0] == 'futility':
1355 fname = pipe_list[0][3]
1356 with open(fname, 'wb') as fd:
1357 fd.write(VBLOCK_DATA)
1358 return command.CommandResult()
1360 def testVblock(self):
1361 """Test for the Chromium OS Verified Boot Block"""
1362 command.test_result = self._HandleVblockCommand
1364 'keydir': 'devkeys',
1366 data, _, _, _ = self._DoReadFileDtb('74_vblock.dts',
1367 entry_args=entry_args)
1368 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1369 self.assertEqual(expected, data)
1371 def testVblockNoContent(self):
1372 """Test we detect a vblock which has no content to sign"""
1373 with self.assertRaises(ValueError) as e:
1374 self._DoReadFile('75_vblock_no_content.dts')
1375 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1376 'property', str(e.exception))
1378 def testVblockBadPhandle(self):
1379 """Test that we detect a vblock with an invalid phandle in contents"""
1380 with self.assertRaises(ValueError) as e:
1381 self._DoReadFile('76_vblock_bad_phandle.dts')
1382 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1383 '1000', str(e.exception))
1385 def testVblockBadEntry(self):
1386 """Test that we detect an entry that points to a non-entry"""
1387 with self.assertRaises(ValueError) as e:
1388 self._DoReadFile('77_vblock_bad_entry.dts')
1389 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1390 "'other'", str(e.exception))
1393 """Test that an image with TPL and ots device tree can be created"""
1394 # ELF file with a '__bss_size' symbol
1395 with open(self.TestFile('bss_data')) as fd:
1396 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1397 data = self._DoReadFile('78_u_boot_tpl.dts')
1398 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1400 def testUsesPos(self):
1401 """Test that the 'pos' property cannot be used anymore"""
1402 with self.assertRaises(ValueError) as e:
1403 data = self._DoReadFile('79_uses_pos.dts')
1404 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1405 "'pos'", str(e.exception))
1407 def testFillZero(self):
1408 """Test for an fill entry type with a size of 0"""
1409 data = self._DoReadFile('80_fill_empty.dts')
1410 self.assertEqual(chr(0) * 16, data)
1412 def testTextMissing(self):
1413 """Test for a text entry type where there is no text"""
1414 with self.assertRaises(ValueError) as e:
1415 self._DoReadFileDtb('66_text.dts',)
1416 self.assertIn("Node '/binman/text': No value provided for text label "
1417 "'test-id'", str(e.exception))
1419 def testPackStart16Tpl(self):
1420 """Test that an image with an x86 start16 TPL region can be created"""
1421 data = self._DoReadFile('81_x86-start16-tpl.dts')
1422 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1424 def testSelectImage(self):
1425 """Test that we can select which images to build"""
1426 with test_util.capture_sys_output() as (stdout, stderr):
1427 retcode = self._DoTestFile('06_dual_image.dts', images=['image2'])
1428 self.assertEqual(0, retcode)
1429 self.assertIn('Skipping images: image1', stdout.getvalue())
1431 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1432 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1434 def testUpdateFdtAll(self):
1435 """Test that all device trees are updated with offset/size info"""
1436 data, _, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1437 use_real_dtb=True, update_dtb=True)
1440 'section:image-pos': 0,
1441 'u-boot-tpl-dtb:size': 513,
1442 'u-boot-spl-dtb:size': 513,
1443 'u-boot-spl-dtb:offset': 493,
1445 'section/u-boot-dtb:image-pos': 0,
1446 'u-boot-spl-dtb:image-pos': 493,
1447 'section/u-boot-dtb:size': 493,
1448 'u-boot-tpl-dtb:image-pos': 1006,
1449 'section/u-boot-dtb:offset': 0,
1450 'section:size': 493,
1452 'section:offset': 0,
1453 'u-boot-tpl-dtb:offset': 1006,
1457 # We expect three device-tree files in the output, one after the other.
1458 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1459 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1460 # main U-Boot tree. All three should have the same postions and offset.
1462 for item in ['', 'spl', 'tpl']:
1463 dtb = fdt.Fdt.FromData(data[start:])
1465 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1467 expected = dict(base_expected)
1470 self.assertEqual(expected, props)
1471 start += dtb._fdt_obj.totalsize()
1473 def testUpdateFdtOutput(self):
1474 """Test that output DTB files are updated"""
1476 data, dtb_data, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1477 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1479 # Unfortunately, compiling a source file always results in a file
1480 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1481 # source file (e.g. test/75_fdt_update_all.dts) thus does not enter
1482 # binman as a file called u-boot.dtb. To fix this, copy the file
1483 # over to the expected place.
1484 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1485 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1487 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1488 'tpl/u-boot-tpl.dtb.out']:
1489 dtb = fdt.Fdt.FromData(data[start:])
1490 size = dtb._fdt_obj.totalsize()
1491 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1492 outdata = tools.ReadFile(pathname)
1493 name = os.path.split(fname)[0]
1496 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1498 orig_indata = dtb_data
1499 self.assertNotEqual(outdata, orig_indata,
1500 "Expected output file '%s' be updated" % pathname)
1501 self.assertEqual(outdata, data[start:start + size],
1502 "Expected output file '%s' to match output image" %
1509 if __name__ == "__main__":