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'), 'rb') as fd:
123 TestFunctional._MakeInputFile('u-boot', fd.read())
125 # Intel flash descriptor file
126 with open(self.TestFile('descriptor.bin'), 'rb') 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.items():
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, 'rb') 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)
295 # For testing purposes, make a copy of the DT for SPL and TPL. Add
296 # a node indicating which it is, so aid verification.
297 for name in ['spl', 'tpl']:
298 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
299 outfile = os.path.join(self._indir, dtb_fname)
300 TestFunctional._MakeInputFile(dtb_fname,
301 self._GetDtbContentsForSplTpl(dtb_data, name))
304 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
305 entry_args=entry_args, use_real_dtb=use_real_dtb)
306 self.assertEqual(0, retcode)
307 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
309 # Find the (only) image, read it and return its contents
310 image = control.images['image']
311 image_fname = tools.GetOutputFilename('image.bin')
312 self.assertTrue(os.path.exists(image_fname))
314 map_fname = tools.GetOutputFilename('image.map')
315 with open(map_fname) as fd:
319 with open(image_fname, 'rb') as fd:
320 return fd.read(), dtb_data, map_data, out_dtb_fname
322 # Put the test file back
323 if reset_dtbs and use_real_dtb:
326 def _DoReadFile(self, fname, use_real_dtb=False):
327 """Helper function which discards the device-tree binary
330 fname: Device-tree source filename to use (e.g. 005_simple.dts)
331 use_real_dtb: True to use the test file as the contents of
332 the u-boot-dtb entry. Normally this is not needed and the
333 test contents (the U_BOOT_DTB_DATA string) can be used.
334 But in some test we need the real contents.
337 Resulting image contents
339 return self._DoReadFileDtb(fname, use_real_dtb)[0]
342 def _MakeInputFile(self, fname, contents):
343 """Create a new test input file, creating directories as needed
346 fname: Filename to create
347 contents: File contents to write in to the file
349 Full pathname of file created
351 pathname = os.path.join(self._indir, fname)
352 dirname = os.path.dirname(pathname)
353 if dirname and not os.path.exists(dirname):
355 with open(pathname, 'wb') as fd:
360 def _MakeInputDir(self, dirname):
361 """Create a new test input directory, creating directories as needed
364 dirname: Directory name to create
367 Full pathname of directory created
369 pathname = os.path.join(self._indir, dirname)
370 if not os.path.exists(pathname):
371 os.makedirs(pathname)
375 def _SetupSplElf(self, src_fname='bss_data'):
376 """Set up an ELF file with a '_dt_ucode_base_size' symbol
379 Filename of ELF file to use as SPL
381 with open(self.TestFile(src_fname), 'rb') as fd:
382 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
385 def TestFile(self, fname):
386 return os.path.join(self._binman_dir, 'test', fname)
388 def AssertInList(self, grep_list, target):
389 """Assert that at least one of a list of things is in a target
392 grep_list: List of strings to check
393 target: Target string
395 for grep in grep_list:
398 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
400 def CheckNoGaps(self, entries):
401 """Check that all entries fit together without gaps
404 entries: List of entries to check
407 for entry in entries.values():
408 self.assertEqual(offset, entry.offset)
411 def GetFdtLen(self, dtb):
412 """Get the totalsize field from a device-tree binary
415 dtb: Device-tree binary contents
418 Total size of device-tree binary, from the header
420 return struct.unpack('>L', dtb[4:8])[0]
422 def _GetPropTree(self, dtb, prop_names):
423 def AddNode(node, path):
425 path += '/' + node.name
426 for subnode in node.subnodes:
427 for prop in subnode.props.values():
428 if prop.name in prop_names:
429 prop_path = path + '/' + subnode.name + ':' + prop.name
430 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
432 AddNode(subnode, path)
435 AddNode(dtb.GetRoot(), '')
439 """Test a basic run with valid args"""
440 result = self._RunBinman('-h')
442 def testFullHelp(self):
443 """Test that the full help is displayed with -H"""
444 result = self._RunBinman('-H')
445 help_file = os.path.join(self._binman_dir, 'README')
446 # Remove possible extraneous strings
447 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
448 gothelp = result.stdout.replace(extra, '')
449 self.assertEqual(len(gothelp), os.path.getsize(help_file))
450 self.assertEqual(0, len(result.stderr))
451 self.assertEqual(0, result.return_code)
453 def testFullHelpInternal(self):
454 """Test that the full help is displayed with -H"""
456 command.test_result = command.CommandResult()
457 result = self._DoBinman('-H')
458 help_file = os.path.join(self._binman_dir, 'README')
460 command.test_result = None
463 """Test that the basic help is displayed with -h"""
464 result = self._RunBinman('-h')
465 self.assertTrue(len(result.stdout) > 200)
466 self.assertEqual(0, len(result.stderr))
467 self.assertEqual(0, result.return_code)
470 """Test that we can run it with a specific board"""
471 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
472 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
473 result = self._DoBinman('-b', 'sandbox')
474 self.assertEqual(0, result)
476 def testNeedBoard(self):
477 """Test that we get an error when no board ius supplied"""
478 with self.assertRaises(ValueError) as e:
479 result = self._DoBinman()
480 self.assertIn("Must provide a board to process (use -b <board>)",
483 def testMissingDt(self):
484 """Test that an invalid device-tree file generates an error"""
485 with self.assertRaises(Exception) as e:
486 self._RunBinman('-d', 'missing_file')
487 # We get one error from libfdt, and a different one from fdtget.
488 self.AssertInList(["Couldn't open blob from 'missing_file'",
489 'No such file or directory'], str(e.exception))
491 def testBrokenDt(self):
492 """Test that an invalid device-tree source file generates an error
494 Since this is a source file it should be compiled and the error
495 will come from the device-tree compiler (dtc).
497 with self.assertRaises(Exception) as e:
498 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
499 self.assertIn("FATAL ERROR: Unable to parse input tree",
502 def testMissingNode(self):
503 """Test that a device tree without a 'binman' node generates an error"""
504 with self.assertRaises(Exception) as e:
505 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
506 self.assertIn("does not have a 'binman' node", str(e.exception))
509 """Test that an empty binman node works OK (i.e. does nothing)"""
510 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
511 self.assertEqual(0, len(result.stderr))
512 self.assertEqual(0, result.return_code)
514 def testInvalidEntry(self):
515 """Test that an invalid entry is flagged"""
516 with self.assertRaises(Exception) as e:
517 result = self._RunBinman('-d',
518 self.TestFile('004_invalid_entry.dts'))
519 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
520 "'/binman/not-a-valid-type'", str(e.exception))
522 def testSimple(self):
523 """Test a simple binman with a single file"""
524 data = self._DoReadFile('005_simple.dts')
525 self.assertEqual(U_BOOT_DATA, data)
527 def testSimpleDebug(self):
528 """Test a simple binman run with debugging enabled"""
529 data = self._DoTestFile('005_simple.dts', debug=True)
532 """Test that we can handle creating two images
534 This also tests image padding.
536 retcode = self._DoTestFile('006_dual_image.dts')
537 self.assertEqual(0, retcode)
539 image = control.images['image1']
540 self.assertEqual(len(U_BOOT_DATA), image._size)
541 fname = tools.GetOutputFilename('image1.bin')
542 self.assertTrue(os.path.exists(fname))
543 with open(fname, 'rb') as fd:
545 self.assertEqual(U_BOOT_DATA, data)
547 image = control.images['image2']
548 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
549 fname = tools.GetOutputFilename('image2.bin')
550 self.assertTrue(os.path.exists(fname))
551 with open(fname, 'rb') as fd:
553 self.assertEqual(U_BOOT_DATA, data[3:7])
554 self.assertEqual(chr(0) * 3, data[:3])
555 self.assertEqual(chr(0) * 5, data[7:])
557 def testBadAlign(self):
558 """Test that an invalid alignment value is detected"""
559 with self.assertRaises(ValueError) as e:
560 self._DoTestFile('007_bad_align.dts')
561 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
562 "of two", str(e.exception))
564 def testPackSimple(self):
565 """Test that packing works as expected"""
566 retcode = self._DoTestFile('008_pack.dts')
567 self.assertEqual(0, retcode)
568 self.assertIn('image', control.images)
569 image = control.images['image']
570 entries = image.GetEntries()
571 self.assertEqual(5, len(entries))
574 self.assertIn('u-boot', entries)
575 entry = entries['u-boot']
576 self.assertEqual(0, entry.offset)
577 self.assertEqual(len(U_BOOT_DATA), entry.size)
579 # Second u-boot, aligned to 16-byte boundary
580 self.assertIn('u-boot-align', entries)
581 entry = entries['u-boot-align']
582 self.assertEqual(16, entry.offset)
583 self.assertEqual(len(U_BOOT_DATA), entry.size)
585 # Third u-boot, size 23 bytes
586 self.assertIn('u-boot-size', entries)
587 entry = entries['u-boot-size']
588 self.assertEqual(20, entry.offset)
589 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
590 self.assertEqual(23, entry.size)
592 # Fourth u-boot, placed immediate after the above
593 self.assertIn('u-boot-next', entries)
594 entry = entries['u-boot-next']
595 self.assertEqual(43, entry.offset)
596 self.assertEqual(len(U_BOOT_DATA), entry.size)
598 # Fifth u-boot, placed at a fixed offset
599 self.assertIn('u-boot-fixed', entries)
600 entry = entries['u-boot-fixed']
601 self.assertEqual(61, entry.offset)
602 self.assertEqual(len(U_BOOT_DATA), entry.size)
604 self.assertEqual(65, image._size)
606 def testPackExtra(self):
607 """Test that extra packing feature works as expected"""
608 retcode = self._DoTestFile('009_pack_extra.dts')
610 self.assertEqual(0, retcode)
611 self.assertIn('image', control.images)
612 image = control.images['image']
613 entries = image.GetEntries()
614 self.assertEqual(5, len(entries))
616 # First u-boot with padding before and after
617 self.assertIn('u-boot', entries)
618 entry = entries['u-boot']
619 self.assertEqual(0, entry.offset)
620 self.assertEqual(3, entry.pad_before)
621 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
623 # Second u-boot has an aligned size, but it has no effect
624 self.assertIn('u-boot-align-size-nop', entries)
625 entry = entries['u-boot-align-size-nop']
626 self.assertEqual(12, entry.offset)
627 self.assertEqual(4, entry.size)
629 # Third u-boot has an aligned size too
630 self.assertIn('u-boot-align-size', entries)
631 entry = entries['u-boot-align-size']
632 self.assertEqual(16, entry.offset)
633 self.assertEqual(32, entry.size)
635 # Fourth u-boot has an aligned end
636 self.assertIn('u-boot-align-end', entries)
637 entry = entries['u-boot-align-end']
638 self.assertEqual(48, entry.offset)
639 self.assertEqual(16, entry.size)
641 # Fifth u-boot immediately afterwards
642 self.assertIn('u-boot-align-both', entries)
643 entry = entries['u-boot-align-both']
644 self.assertEqual(64, entry.offset)
645 self.assertEqual(64, entry.size)
647 self.CheckNoGaps(entries)
648 self.assertEqual(128, image._size)
650 def testPackAlignPowerOf2(self):
651 """Test that invalid entry alignment is detected"""
652 with self.assertRaises(ValueError) as e:
653 self._DoTestFile('010_pack_align_power2.dts')
654 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
655 "of two", str(e.exception))
657 def testPackAlignSizePowerOf2(self):
658 """Test that invalid entry size alignment is detected"""
659 with self.assertRaises(ValueError) as e:
660 self._DoTestFile('011_pack_align_size_power2.dts')
661 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
662 "power of two", str(e.exception))
664 def testPackInvalidAlign(self):
665 """Test detection of an offset that does not match its alignment"""
666 with self.assertRaises(ValueError) as e:
667 self._DoTestFile('012_pack_inv_align.dts')
668 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
669 "align 0x4 (4)", str(e.exception))
671 def testPackInvalidSizeAlign(self):
672 """Test that invalid entry size alignment is detected"""
673 with self.assertRaises(ValueError) as e:
674 self._DoTestFile('013_pack_inv_size_align.dts')
675 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
676 "align-size 0x4 (4)", str(e.exception))
678 def testPackOverlap(self):
679 """Test that overlapping regions are detected"""
680 with self.assertRaises(ValueError) as e:
681 self._DoTestFile('014_pack_overlap.dts')
682 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
683 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
686 def testPackEntryOverflow(self):
687 """Test that entries that overflow their size are detected"""
688 with self.assertRaises(ValueError) as e:
689 self._DoTestFile('015_pack_overflow.dts')
690 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
691 "but entry size is 0x3 (3)", str(e.exception))
693 def testPackImageOverflow(self):
694 """Test that entries which overflow the image size are detected"""
695 with self.assertRaises(ValueError) as e:
696 self._DoTestFile('016_pack_image_overflow.dts')
697 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
698 "size 0x3 (3)", str(e.exception))
700 def testPackImageSize(self):
701 """Test that the image size can be set"""
702 retcode = self._DoTestFile('017_pack_image_size.dts')
703 self.assertEqual(0, retcode)
704 self.assertIn('image', control.images)
705 image = control.images['image']
706 self.assertEqual(7, image._size)
708 def testPackImageSizeAlign(self):
709 """Test that image size alignemnt works as expected"""
710 retcode = self._DoTestFile('018_pack_image_align.dts')
711 self.assertEqual(0, retcode)
712 self.assertIn('image', control.images)
713 image = control.images['image']
714 self.assertEqual(16, image._size)
716 def testPackInvalidImageAlign(self):
717 """Test that invalid image alignment is detected"""
718 with self.assertRaises(ValueError) as e:
719 self._DoTestFile('019_pack_inv_image_align.dts')
720 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
721 "align-size 0x8 (8)", str(e.exception))
723 def testPackAlignPowerOf2(self):
724 """Test that invalid image alignment is detected"""
725 with self.assertRaises(ValueError) as e:
726 self._DoTestFile('020_pack_inv_image_align_power2.dts')
727 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
728 "two", str(e.exception))
730 def testImagePadByte(self):
731 """Test that the image pad byte can be specified"""
733 data = self._DoReadFile('021_image_pad.dts')
734 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
736 def testImageName(self):
737 """Test that image files can be named"""
738 retcode = self._DoTestFile('022_image_name.dts')
739 self.assertEqual(0, retcode)
740 image = control.images['image1']
741 fname = tools.GetOutputFilename('test-name')
742 self.assertTrue(os.path.exists(fname))
744 image = control.images['image2']
745 fname = tools.GetOutputFilename('test-name.xx')
746 self.assertTrue(os.path.exists(fname))
748 def testBlobFilename(self):
749 """Test that generic blobs can be provided by filename"""
750 data = self._DoReadFile('023_blob.dts')
751 self.assertEqual(BLOB_DATA, data)
753 def testPackSorted(self):
754 """Test that entries can be sorted"""
756 data = self._DoReadFile('024_sorted.dts')
757 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
760 def testPackZeroOffset(self):
761 """Test that an entry at offset 0 is not given a new offset"""
762 with self.assertRaises(ValueError) as e:
763 self._DoTestFile('025_pack_zero_size.dts')
764 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
765 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
768 def testPackUbootDtb(self):
769 """Test that a device tree can be added to U-Boot"""
770 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
771 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
773 def testPackX86RomNoSize(self):
774 """Test that the end-at-4gb property requires a size property"""
775 with self.assertRaises(ValueError) as e:
776 self._DoTestFile('027_pack_4gb_no_size.dts')
777 self.assertIn("Section '/binman': Section size must be provided when "
778 "using end-at-4gb", str(e.exception))
780 def test4gbAndSkipAtStartTogether(self):
781 """Test that the end-at-4gb and skip-at-size property can't be used
783 with self.assertRaises(ValueError) as e:
784 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
785 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
786 "'skip-at-start'", str(e.exception))
788 def testPackX86RomOutside(self):
789 """Test that the end-at-4gb property checks for offset boundaries"""
790 with self.assertRaises(ValueError) as e:
791 self._DoTestFile('028_pack_4gb_outside.dts')
792 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
793 "the section starting at 0xffffffe0 (4294967264)",
796 def testPackX86Rom(self):
797 """Test that a basic x86 ROM can be created"""
799 data = self._DoReadFile('029_x86-rom.dts')
800 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
803 def testPackX86RomMeNoDesc(self):
804 """Test that an invalid Intel descriptor entry is detected"""
805 TestFunctional._MakeInputFile('descriptor.bin', '')
806 with self.assertRaises(ValueError) as e:
807 self._DoTestFile('031_x86-rom-me.dts')
808 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
809 "signature", str(e.exception))
811 def testPackX86RomBadDesc(self):
812 """Test that the Intel requires a descriptor entry"""
813 with self.assertRaises(ValueError) as e:
814 self._DoTestFile('030_x86-rom-me-no-desc.dts')
815 self.assertIn("Node '/binman/intel-me': No offset set with "
816 "offset-unset: should another entry provide this correct "
817 "offset?", str(e.exception))
819 def testPackX86RomMe(self):
820 """Test that an x86 ROM with an ME region can be created"""
821 data = self._DoReadFile('031_x86-rom-me.dts')
822 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
824 def testPackVga(self):
825 """Test that an image with a VGA binary can be created"""
826 data = self._DoReadFile('032_intel-vga.dts')
827 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
829 def testPackStart16(self):
830 """Test that an image with an x86 start16 region can be created"""
831 data = self._DoReadFile('033_x86-start16.dts')
832 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
834 def testPackPowerpcMpc85xxBootpgResetvec(self):
835 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
837 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
838 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
840 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
841 """Handle running a test for insertion of microcode
844 dts_fname: Name of test .dts file
845 nodtb_data: Data that we expect in the first section
846 ucode_second: True if the microsecond entry is second instead of
851 Contents of first region (U-Boot or SPL)
852 Offset and size components of microcode pointer, as inserted
853 in the above (two 4-byte words)
855 data = self._DoReadFile(dts_fname, True)
857 # Now check the device tree has no microcode
859 ucode_content = data[len(nodtb_data):]
860 ucode_pos = len(nodtb_data)
861 dtb_with_ucode = ucode_content[16:]
862 fdt_len = self.GetFdtLen(dtb_with_ucode)
864 dtb_with_ucode = data[len(nodtb_data):]
865 fdt_len = self.GetFdtLen(dtb_with_ucode)
866 ucode_content = dtb_with_ucode[fdt_len:]
867 ucode_pos = len(nodtb_data) + fdt_len
868 fname = tools.GetOutputFilename('test.dtb')
869 with open(fname, 'wb') as fd:
870 fd.write(dtb_with_ucode)
871 dtb = fdt.FdtScan(fname)
872 ucode = dtb.GetNode('/microcode')
873 self.assertTrue(ucode)
874 for node in ucode.subnodes:
875 self.assertFalse(node.props.get('data'))
877 # Check that the microcode appears immediately after the Fdt
878 # This matches the concatenation of the data properties in
879 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
880 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
882 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
884 # Check that the microcode pointer was inserted. It should match the
885 # expected offset and size
886 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
888 u_boot = data[:len(nodtb_data)]
889 return u_boot, pos_and_size
891 def testPackUbootMicrocode(self):
892 """Test that x86 microcode can be handled correctly
894 We expect to see the following in the image, in order:
895 u-boot-nodtb.bin with a microcode pointer inserted at the correct
897 u-boot.dtb with the microcode removed
900 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
902 self.assertEqual('nodtb with microcode' + pos_and_size +
903 ' somewhere in here', first)
905 def _RunPackUbootSingleMicrocode(self):
906 """Test that x86 microcode can be handled correctly
908 We expect to see the following in the image, in order:
909 u-boot-nodtb.bin with a microcode pointer inserted at the correct
911 u-boot.dtb with the microcode
912 an empty microcode region
914 # We need the libfdt library to run this test since only that allows
915 # finding the offset of a property. This is required by
916 # Entry_u_boot_dtb_with_ucode.ObtainContents().
917 data = self._DoReadFile('035_x86_single_ucode.dts', True)
919 second = data[len(U_BOOT_NODTB_DATA):]
921 fdt_len = self.GetFdtLen(second)
922 third = second[fdt_len:]
923 second = second[:fdt_len]
925 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
926 self.assertIn(ucode_data, second)
927 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
929 # Check that the microcode pointer was inserted. It should match the
930 # expected offset and size
931 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
933 first = data[:len(U_BOOT_NODTB_DATA)]
934 self.assertEqual('nodtb with microcode' + pos_and_size +
935 ' somewhere in here', first)
937 def testPackUbootSingleMicrocode(self):
938 """Test that x86 microcode can be handled correctly with fdt_normal.
940 self._RunPackUbootSingleMicrocode()
942 def testUBootImg(self):
943 """Test that u-boot.img can be put in a file"""
944 data = self._DoReadFile('036_u_boot_img.dts')
945 self.assertEqual(U_BOOT_IMG_DATA, data)
947 def testNoMicrocode(self):
948 """Test that a missing microcode region is detected"""
949 with self.assertRaises(ValueError) as e:
950 self._DoReadFile('037_x86_no_ucode.dts', True)
951 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
952 "node found in ", str(e.exception))
954 def testMicrocodeWithoutNode(self):
955 """Test that a missing u-boot-dtb-with-ucode node is detected"""
956 with self.assertRaises(ValueError) as e:
957 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
958 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
959 "microcode region u-boot-dtb-with-ucode", str(e.exception))
961 def testMicrocodeWithoutNode2(self):
962 """Test that a missing u-boot-ucode node is detected"""
963 with self.assertRaises(ValueError) as e:
964 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
965 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
966 "microcode region u-boot-ucode", str(e.exception))
968 def testMicrocodeWithoutPtrInElf(self):
969 """Test that a U-Boot binary without the microcode symbol is detected"""
970 # ELF file without a '_dt_ucode_base_size' symbol
972 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
973 TestFunctional._MakeInputFile('u-boot', fd.read())
975 with self.assertRaises(ValueError) as e:
976 self._RunPackUbootSingleMicrocode()
977 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
978 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
981 # Put the original file back
982 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
983 TestFunctional._MakeInputFile('u-boot', fd.read())
985 def testMicrocodeNotInImage(self):
986 """Test that microcode must be placed within the image"""
987 with self.assertRaises(ValueError) as e:
988 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
989 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
990 "pointer _dt_ucode_base_size at fffffe14 is outside the "
991 "section ranging from 00000000 to 0000002e", str(e.exception))
993 def testWithoutMicrocode(self):
994 """Test that we can cope with an image without microcode (e.g. qemu)"""
995 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
996 TestFunctional._MakeInputFile('u-boot', fd.read())
997 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
999 # Now check the device tree has no microcode
1000 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1001 second = data[len(U_BOOT_NODTB_DATA):]
1003 fdt_len = self.GetFdtLen(second)
1004 self.assertEqual(dtb, second[:fdt_len])
1006 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1007 third = data[used_len:]
1008 self.assertEqual(chr(0) * (0x200 - used_len), third)
1010 def testUnknownPosSize(self):
1011 """Test that microcode must be placed within the image"""
1012 with self.assertRaises(ValueError) as e:
1013 self._DoReadFile('041_unknown_pos_size.dts', True)
1014 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1015 "entry 'invalid-entry'", str(e.exception))
1017 def testPackFsp(self):
1018 """Test that an image with a FSP binary can be created"""
1019 data = self._DoReadFile('042_intel-fsp.dts')
1020 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1022 def testPackCmc(self):
1023 """Test that an image with a CMC binary can be created"""
1024 data = self._DoReadFile('043_intel-cmc.dts')
1025 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1027 def testPackVbt(self):
1028 """Test that an image with a VBT binary can be created"""
1029 data = self._DoReadFile('046_intel-vbt.dts')
1030 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1032 def testSplBssPad(self):
1033 """Test that we can pad SPL's BSS with zeros"""
1034 # ELF file with a '__bss_size' symbol
1036 data = self._DoReadFile('047_spl_bss_pad.dts')
1037 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
1039 def testSplBssPadMissing(self):
1040 """Test that a missing symbol is detected"""
1041 self._SetupSplElf('u_boot_ucode_ptr')
1042 with self.assertRaises(ValueError) as e:
1043 self._DoReadFile('047_spl_bss_pad.dts')
1044 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1047 def testPackStart16Spl(self):
1048 """Test that an image with an x86 start16 SPL region can be created"""
1049 data = self._DoReadFile('048_x86-start16-spl.dts')
1050 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1052 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1053 """Helper function for microcode tests
1055 We expect to see the following in the image, in order:
1056 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1058 u-boot.dtb with the microcode removed
1062 dts: Device tree file to use for test
1063 ucode_second: True if the microsecond entry is second instead of
1066 self._SetupSplElf('u_boot_ucode_ptr')
1067 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1068 ucode_second=ucode_second)
1069 self.assertEqual('splnodtb with microc' + pos_and_size +
1070 'ter somewhere in here', first)
1072 def testPackUbootSplMicrocode(self):
1073 """Test that x86 microcode can be handled correctly in SPL"""
1074 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1076 def testPackUbootSplMicrocodeReorder(self):
1077 """Test that order doesn't matter for microcode entries
1079 This is the same as testPackUbootSplMicrocode but when we process the
1080 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1081 entry, so we reply on binman to try later.
1083 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1086 def testPackMrc(self):
1087 """Test that an image with an MRC binary can be created"""
1088 data = self._DoReadFile('050_intel_mrc.dts')
1089 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1091 def testSplDtb(self):
1092 """Test that an image with spl/u-boot-spl.dtb can be created"""
1093 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1094 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1096 def testSplNoDtb(self):
1097 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1098 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1099 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1101 def testSymbols(self):
1102 """Test binman can assign symbols embedded in U-Boot"""
1103 elf_fname = self.TestFile('u_boot_binman_syms')
1104 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1105 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1106 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1108 self._SetupSplElf('u_boot_binman_syms')
1109 data = self._DoReadFile('053_symbols.dts')
1110 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1111 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1113 sym_values + U_BOOT_SPL_DATA[16:])
1114 self.assertEqual(expected, data)
1116 def testPackUnitAddress(self):
1117 """Test that we support multiple binaries with the same name"""
1118 data = self._DoReadFile('054_unit_address.dts')
1119 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1121 def testSections(self):
1122 """Basic test of sections"""
1123 data = self._DoReadFile('055_sections.dts')
1124 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1125 U_BOOT_DATA + '&' * 4)
1126 self.assertEqual(expected, data)
1129 """Tests outputting a map of the images"""
1130 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1131 self.assertEqual('''ImagePos Offset Size Name
1132 00000000 00000000 00000028 main-section
1133 00000000 00000000 00000010 section@0
1134 00000000 00000000 00000004 u-boot
1135 00000010 00000010 00000010 section@1
1136 00000010 00000000 00000004 u-boot
1137 00000020 00000020 00000004 section@2
1138 00000020 00000000 00000004 u-boot
1141 def testNamePrefix(self):
1142 """Tests that name prefixes are used"""
1143 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1144 self.assertEqual('''ImagePos Offset Size Name
1145 00000000 00000000 00000028 main-section
1146 00000000 00000000 00000010 section@0
1147 00000000 00000000 00000004 ro-u-boot
1148 00000010 00000010 00000010 section@1
1149 00000010 00000000 00000004 rw-u-boot
1152 def testUnknownContents(self):
1153 """Test that obtaining the contents works as expected"""
1154 with self.assertRaises(ValueError) as e:
1155 self._DoReadFile('057_unknown_contents.dts', True)
1156 self.assertIn("Section '/binman': Internal error: Could not complete "
1157 "processing of contents: remaining [<_testing.Entry__testing ",
1160 def testBadChangeSize(self):
1161 """Test that trying to change the size of an entry fails"""
1162 with self.assertRaises(ValueError) as e:
1163 self._DoReadFile('059_change_size.dts', True)
1164 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1165 '2 to 1', str(e.exception))
1167 def testUpdateFdt(self):
1168 """Test that we can update the device tree with offset/size info"""
1169 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1171 dtb = fdt.Fdt(out_dtb_fname)
1173 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
1177 '_testing:offset': 32,
1179 '_testing:image-pos': 32,
1180 'section@0/u-boot:offset': 0,
1181 'section@0/u-boot:size': len(U_BOOT_DATA),
1182 'section@0/u-boot:image-pos': 0,
1183 'section@0:offset': 0,
1184 'section@0:size': 16,
1185 'section@0:image-pos': 0,
1187 'section@1/u-boot:offset': 0,
1188 'section@1/u-boot:size': len(U_BOOT_DATA),
1189 'section@1/u-boot:image-pos': 16,
1190 'section@1:offset': 16,
1191 'section@1:size': 16,
1192 'section@1:image-pos': 16,
1196 def testUpdateFdtBad(self):
1197 """Test that we detect when ProcessFdt never completes"""
1198 with self.assertRaises(ValueError) as e:
1199 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1200 self.assertIn('Could not complete processing of Fdt: remaining '
1201 '[<_testing.Entry__testing', str(e.exception))
1203 def testEntryArgs(self):
1204 """Test passing arguments to entries from the command line"""
1206 'test-str-arg': 'test1',
1207 'test-int-arg': '456',
1209 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1210 self.assertIn('image', control.images)
1211 entry = control.images['image'].GetEntries()['_testing']
1212 self.assertEqual('test0', entry.test_str_fdt)
1213 self.assertEqual('test1', entry.test_str_arg)
1214 self.assertEqual(123, entry.test_int_fdt)
1215 self.assertEqual(456, entry.test_int_arg)
1217 def testEntryArgsMissing(self):
1218 """Test missing arguments and properties"""
1220 'test-int-arg': '456',
1222 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1223 entry = control.images['image'].GetEntries()['_testing']
1224 self.assertEqual('test0', entry.test_str_fdt)
1225 self.assertEqual(None, entry.test_str_arg)
1226 self.assertEqual(None, entry.test_int_fdt)
1227 self.assertEqual(456, entry.test_int_arg)
1229 def testEntryArgsRequired(self):
1230 """Test missing arguments and properties"""
1232 'test-int-arg': '456',
1234 with self.assertRaises(ValueError) as e:
1235 self._DoReadFileDtb('064_entry_args_required.dts')
1236 self.assertIn("Node '/binman/_testing': Missing required "
1237 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1240 def testEntryArgsInvalidFormat(self):
1241 """Test that an invalid entry-argument format is detected"""
1242 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
1243 with self.assertRaises(ValueError) as e:
1244 self._DoBinman(*args)
1245 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1247 def testEntryArgsInvalidInteger(self):
1248 """Test that an invalid entry-argument integer is detected"""
1250 'test-int-arg': 'abc',
1252 with self.assertRaises(ValueError) as e:
1253 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1254 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1255 "'test-int-arg' (value 'abc') to integer",
1258 def testEntryArgsInvalidDatatype(self):
1259 """Test that an invalid entry-argument datatype is detected
1261 This test could be written in entry_test.py except that it needs
1262 access to control.entry_args, which seems more than that module should
1266 'test-bad-datatype-arg': '12',
1268 with self.assertRaises(ValueError) as e:
1269 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1270 entry_args=entry_args)
1271 self.assertIn('GetArg() internal error: Unknown data type ',
1275 """Test for a text entry type"""
1277 'test-id': TEXT_DATA,
1278 'test-id2': TEXT_DATA2,
1279 'test-id3': TEXT_DATA3,
1281 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1282 entry_args=entry_args)
1283 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1284 TEXT_DATA3 + 'some text')
1285 self.assertEqual(expected, data)
1287 def testEntryDocs(self):
1288 """Test for creation of entry documentation"""
1289 with test_util.capture_sys_output() as (stdout, stderr):
1290 control.WriteEntryDocs(binman.GetEntryModules())
1291 self.assertTrue(len(stdout.getvalue()) > 0)
1293 def testEntryDocsMissing(self):
1294 """Test handling of missing entry documentation"""
1295 with self.assertRaises(ValueError) as e:
1296 with test_util.capture_sys_output() as (stdout, stderr):
1297 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1298 self.assertIn('Documentation is missing for modules: u_boot',
1302 """Basic test of generation of a flashrom fmap"""
1303 data = self._DoReadFile('067_fmap.dts')
1304 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1305 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1306 self.assertEqual(expected, data[:32])
1307 self.assertEqual('__FMAP__', fhdr.signature)
1308 self.assertEqual(1, fhdr.ver_major)
1309 self.assertEqual(0, fhdr.ver_minor)
1310 self.assertEqual(0, fhdr.base)
1311 self.assertEqual(16 + 16 +
1312 fmap_util.FMAP_HEADER_LEN +
1313 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1314 self.assertEqual('FMAP', fhdr.name)
1315 self.assertEqual(3, fhdr.nareas)
1316 for fentry in fentries:
1317 self.assertEqual(0, fentry.flags)
1319 self.assertEqual(0, fentries[0].offset)
1320 self.assertEqual(4, fentries[0].size)
1321 self.assertEqual('RO_U_BOOT', fentries[0].name)
1323 self.assertEqual(16, fentries[1].offset)
1324 self.assertEqual(4, fentries[1].size)
1325 self.assertEqual('RW_U_BOOT', fentries[1].name)
1327 self.assertEqual(32, fentries[2].offset)
1328 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1329 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1330 self.assertEqual('FMAP', fentries[2].name)
1332 def testBlobNamedByArg(self):
1333 """Test we can add a blob with the filename coming from an entry arg"""
1335 'cros-ec-rw-path': 'ecrw.bin',
1337 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1338 entry_args=entry_args)
1341 """Test for an fill entry type"""
1342 data = self._DoReadFile('069_fill.dts')
1343 expected = 8 * chr(0xff) + 8 * chr(0)
1344 self.assertEqual(expected, data)
1346 def testFillNoSize(self):
1347 """Test for an fill entry type with no size"""
1348 with self.assertRaises(ValueError) as e:
1349 self._DoReadFile('070_fill_no_size.dts')
1350 self.assertIn("'fill' entry must have a size property",
1353 def _HandleGbbCommand(self, pipe_list):
1354 """Fake calls to the futility utility"""
1355 if pipe_list[0][0] == 'futility':
1356 fname = pipe_list[0][-1]
1357 # Append our GBB data to the file, which will happen every time the
1358 # futility command is called.
1359 with open(fname, 'ab') as fd:
1361 return command.CommandResult()
1364 """Test for the Chromium OS Google Binary Block"""
1365 command.test_result = self._HandleGbbCommand
1367 'keydir': 'devkeys',
1368 'bmpblk': 'bmpblk.bin',
1370 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1373 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1374 self.assertEqual(expected, data)
1376 def testGbbTooSmall(self):
1377 """Test for the Chromium OS Google Binary Block being large enough"""
1378 with self.assertRaises(ValueError) as e:
1379 self._DoReadFileDtb('072_gbb_too_small.dts')
1380 self.assertIn("Node '/binman/gbb': GBB is too small",
1383 def testGbbNoSize(self):
1384 """Test for the Chromium OS Google Binary Block having a size"""
1385 with self.assertRaises(ValueError) as e:
1386 self._DoReadFileDtb('073_gbb_no_size.dts')
1387 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1390 def _HandleVblockCommand(self, pipe_list):
1391 """Fake calls to the futility utility"""
1392 if pipe_list[0][0] == 'futility':
1393 fname = pipe_list[0][3]
1394 with open(fname, 'wb') as fd:
1395 fd.write(VBLOCK_DATA)
1396 return command.CommandResult()
1398 def testVblock(self):
1399 """Test for the Chromium OS Verified Boot Block"""
1400 command.test_result = self._HandleVblockCommand
1402 'keydir': 'devkeys',
1404 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1405 entry_args=entry_args)
1406 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1407 self.assertEqual(expected, data)
1409 def testVblockNoContent(self):
1410 """Test we detect a vblock which has no content to sign"""
1411 with self.assertRaises(ValueError) as e:
1412 self._DoReadFile('075_vblock_no_content.dts')
1413 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1414 'property', str(e.exception))
1416 def testVblockBadPhandle(self):
1417 """Test that we detect a vblock with an invalid phandle in contents"""
1418 with self.assertRaises(ValueError) as e:
1419 self._DoReadFile('076_vblock_bad_phandle.dts')
1420 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1421 '1000', str(e.exception))
1423 def testVblockBadEntry(self):
1424 """Test that we detect an entry that points to a non-entry"""
1425 with self.assertRaises(ValueError) as e:
1426 self._DoReadFile('077_vblock_bad_entry.dts')
1427 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1428 "'other'", str(e.exception))
1431 """Test that an image with TPL and ots device tree can be created"""
1432 # ELF file with a '__bss_size' symbol
1433 with open(self.TestFile('bss_data'), 'rb') as fd:
1434 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1435 data = self._DoReadFile('078_u_boot_tpl.dts')
1436 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1438 def testUsesPos(self):
1439 """Test that the 'pos' property cannot be used anymore"""
1440 with self.assertRaises(ValueError) as e:
1441 data = self._DoReadFile('079_uses_pos.dts')
1442 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1443 "'pos'", str(e.exception))
1445 def testFillZero(self):
1446 """Test for an fill entry type with a size of 0"""
1447 data = self._DoReadFile('080_fill_empty.dts')
1448 self.assertEqual(chr(0) * 16, data)
1450 def testTextMissing(self):
1451 """Test for a text entry type where there is no text"""
1452 with self.assertRaises(ValueError) as e:
1453 self._DoReadFileDtb('066_text.dts',)
1454 self.assertIn("Node '/binman/text': No value provided for text label "
1455 "'test-id'", str(e.exception))
1457 def testPackStart16Tpl(self):
1458 """Test that an image with an x86 start16 TPL region can be created"""
1459 data = self._DoReadFile('081_x86-start16-tpl.dts')
1460 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1462 def testSelectImage(self):
1463 """Test that we can select which images to build"""
1464 expected = 'Skipping images: image1'
1466 # We should only get the expected message in verbose mode
1467 for verbosity in (None, 2):
1468 with test_util.capture_sys_output() as (stdout, stderr):
1469 retcode = self._DoTestFile('006_dual_image.dts',
1470 verbosity=verbosity,
1472 self.assertEqual(0, retcode)
1474 self.assertIn(expected, stdout.getvalue())
1476 self.assertNotIn(expected, stdout.getvalue())
1478 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1479 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1481 def testUpdateFdtAll(self):
1482 """Test that all device trees are updated with offset/size info"""
1483 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1484 use_real_dtb=True, update_dtb=True)
1487 'section:image-pos': 0,
1488 'u-boot-tpl-dtb:size': 513,
1489 'u-boot-spl-dtb:size': 513,
1490 'u-boot-spl-dtb:offset': 493,
1492 'section/u-boot-dtb:image-pos': 0,
1493 'u-boot-spl-dtb:image-pos': 493,
1494 'section/u-boot-dtb:size': 493,
1495 'u-boot-tpl-dtb:image-pos': 1006,
1496 'section/u-boot-dtb:offset': 0,
1497 'section:size': 493,
1499 'section:offset': 0,
1500 'u-boot-tpl-dtb:offset': 1006,
1504 # We expect three device-tree files in the output, one after the other.
1505 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1506 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1507 # main U-Boot tree. All three should have the same postions and offset.
1509 for item in ['', 'spl', 'tpl']:
1510 dtb = fdt.Fdt.FromData(data[start:])
1512 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1514 expected = dict(base_expected)
1517 self.assertEqual(expected, props)
1518 start += dtb._fdt_obj.totalsize()
1520 def testUpdateFdtOutput(self):
1521 """Test that output DTB files are updated"""
1523 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1524 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1526 # Unfortunately, compiling a source file always results in a file
1527 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1528 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1529 # binman as a file called u-boot.dtb. To fix this, copy the file
1530 # over to the expected place.
1531 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1532 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1534 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1535 'tpl/u-boot-tpl.dtb.out']:
1536 dtb = fdt.Fdt.FromData(data[start:])
1537 size = dtb._fdt_obj.totalsize()
1538 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1539 outdata = tools.ReadFile(pathname)
1540 name = os.path.split(fname)[0]
1543 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1545 orig_indata = dtb_data
1546 self.assertNotEqual(outdata, orig_indata,
1547 "Expected output file '%s' be updated" % pathname)
1548 self.assertEqual(outdata, data[start:start + size],
1549 "Expected output file '%s' to match output image" %
1555 def _decompress(self, data):
1556 out = os.path.join(self._indir, 'lz4.tmp')
1557 with open(out, 'wb') as fd:
1559 return tools.Run('lz4', '-dc', out, binary=True)
1562 orig = lz4.frame.decompress(data)
1563 except AttributeError:
1564 orig = lz4.decompress(data)
1567 def testCompress(self):
1568 """Test compression of blobs"""
1569 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1570 use_real_dtb=True, update_dtb=True)
1571 dtb = fdt.Fdt(out_dtb_fname)
1573 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1574 orig = self._decompress(data)
1575 self.assertEquals(COMPRESS_DATA, orig)
1577 'blob:uncomp-size': len(COMPRESS_DATA),
1578 'blob:size': len(data),
1581 self.assertEqual(expected, props)
1583 def testFiles(self):
1584 """Test bringing in multiple files"""
1585 data = self._DoReadFile('084_files.dts')
1586 self.assertEqual(FILES_DATA, data)
1588 def testFilesCompress(self):
1589 """Test bringing in multiple files and compressing them"""
1590 data = self._DoReadFile('085_files_compress.dts')
1592 image = control.images['image']
1593 entries = image.GetEntries()
1594 files = entries['files']
1595 entries = files._section._entries
1598 for i in range(1, 3):
1600 start = entries[key].image_pos
1601 len = entries[key].size
1602 chunk = data[start:start + len]
1603 orig += self._decompress(chunk)
1605 self.assertEqual(FILES_DATA, orig)
1607 def testFilesMissing(self):
1608 """Test missing files"""
1609 with self.assertRaises(ValueError) as e:
1610 data = self._DoReadFile('086_files_none.dts')
1611 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1612 'no files', str(e.exception))
1614 def testFilesNoPattern(self):
1615 """Test missing files"""
1616 with self.assertRaises(ValueError) as e:
1617 data = self._DoReadFile('087_files_no_pattern.dts')
1618 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1621 def testExpandSize(self):
1622 """Test an expanding entry"""
1623 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1625 expect = ('a' * 8 + U_BOOT_DATA +
1626 MRC_DATA + 'b' * 1 + U_BOOT_DATA +
1627 'c' * 8 + U_BOOT_DATA +
1629 self.assertEqual(expect, data)
1630 self.assertEqual('''ImagePos Offset Size Name
1631 00000000 00000000 00000028 main-section
1632 00000000 00000000 00000008 fill
1633 00000008 00000008 00000004 u-boot
1634 0000000c 0000000c 00000004 section
1635 0000000c 00000000 00000003 intel-mrc
1636 00000010 00000010 00000004 u-boot2
1637 00000014 00000014 0000000c section2
1638 00000014 00000000 00000008 fill
1639 0000001c 00000008 00000004 u-boot
1640 00000020 00000020 00000008 fill2
1643 def testExpandSizeBad(self):
1644 """Test an expanding entry which fails to provide contents"""
1645 with test_util.capture_sys_output() as (stdout, stderr):
1646 with self.assertRaises(ValueError) as e:
1647 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1648 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1649 'expanding entry', str(e.exception))
1652 """Test hashing of the contents of an entry"""
1653 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1654 use_real_dtb=True, update_dtb=True)
1655 dtb = fdt.Fdt(out_dtb_fname)
1657 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1658 m = hashlib.sha256()
1659 m.update(U_BOOT_DATA)
1660 self.assertEqual(m.digest(), ''.join(hash_node.value))
1662 def testHashNoAlgo(self):
1663 with self.assertRaises(ValueError) as e:
1664 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1665 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1666 'hash node', str(e.exception))
1668 def testHashBadAlgo(self):
1669 with self.assertRaises(ValueError) as e:
1670 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1671 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1674 def testHashSection(self):
1675 """Test hashing of the contents of an entry"""
1676 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1677 use_real_dtb=True, update_dtb=True)
1678 dtb = fdt.Fdt(out_dtb_fname)
1680 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1681 m = hashlib.sha256()
1682 m.update(U_BOOT_DATA)
1684 self.assertEqual(m.digest(), ''.join(hash_node.value))
1686 def testPackUBootTplMicrocode(self):
1687 """Test that x86 microcode can be handled correctly in TPL
1689 We expect to see the following in the image, in order:
1690 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1692 u-boot-tpl.dtb with the microcode removed
1695 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1696 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1697 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1698 U_BOOT_TPL_NODTB_DATA)
1699 self.assertEqual('tplnodtb with microc' + pos_and_size +
1700 'ter somewhere in here', first)
1702 def testFmapX86(self):
1703 """Basic test of generation of a flashrom fmap"""
1704 data = self._DoReadFile('094_fmap_x86.dts')
1705 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1706 expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7)
1707 self.assertEqual(expected, data[:32])
1708 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1710 self.assertEqual(0x100, fhdr.image_size)
1712 self.assertEqual(0, fentries[0].offset)
1713 self.assertEqual(4, fentries[0].size)
1714 self.assertEqual('U_BOOT', fentries[0].name)
1716 self.assertEqual(4, fentries[1].offset)
1717 self.assertEqual(3, fentries[1].size)
1718 self.assertEqual('INTEL_MRC', fentries[1].name)
1720 self.assertEqual(32, fentries[2].offset)
1721 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1722 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1723 self.assertEqual('FMAP', fentries[2].name)
1725 def testFmapX86Section(self):
1726 """Basic test of generation of a flashrom fmap"""
1727 data = self._DoReadFile('095_fmap_x86_section.dts')
1728 expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7)
1729 self.assertEqual(expected, data[:32])
1730 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1732 self.assertEqual(0x100, fhdr.image_size)
1734 self.assertEqual(0, fentries[0].offset)
1735 self.assertEqual(4, fentries[0].size)
1736 self.assertEqual('U_BOOT', fentries[0].name)
1738 self.assertEqual(4, fentries[1].offset)
1739 self.assertEqual(3, fentries[1].size)
1740 self.assertEqual('INTEL_MRC', fentries[1].name)
1742 self.assertEqual(36, fentries[2].offset)
1743 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1744 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1745 self.assertEqual('FMAP', fentries[2].name)
1748 """Basic test of ELF entries"""
1750 with open(self.TestFile('bss_data'), 'rb') as fd:
1751 TestFunctional._MakeInputFile('-boot', fd.read())
1752 data = self._DoReadFile('096_elf.dts')
1754 def testElfStripg(self):
1755 """Basic test of ELF entries"""
1757 with open(self.TestFile('bss_data'), 'rb') as fd:
1758 TestFunctional._MakeInputFile('-boot', fd.read())
1759 data = self._DoReadFile('097_elf_strip.dts')
1761 def testPackOverlapMap(self):
1762 """Test that overlapping regions are detected"""
1763 with test_util.capture_sys_output() as (stdout, stderr):
1764 with self.assertRaises(ValueError) as e:
1765 self._DoTestFile('014_pack_overlap.dts', map=True)
1766 map_fname = tools.GetOutputFilename('image.map')
1767 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1770 # We should not get an inmage, but there should be a map file
1771 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1772 self.assertTrue(os.path.exists(map_fname))
1773 map_data = tools.ReadFile(map_fname)
1774 self.assertEqual('''ImagePos Offset Size Name
1775 <none> 00000000 00000007 main-section
1776 <none> 00000000 00000004 u-boot
1777 <none> 00000003 00000004 u-boot-align
1780 def testPacRefCode(self):
1781 """Test that an image with an Intel Reference code binary works"""
1782 data = self._DoReadFile('100_intel_refcode.dts')
1783 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1785 def testSectionOffset(self):
1786 """Tests use of a section with an offset"""
1787 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1789 self.assertEqual('''ImagePos Offset Size Name
1790 00000000 00000000 00000038 main-section
1791 00000004 00000004 00000010 section@0
1792 00000004 00000000 00000004 u-boot
1793 00000018 00000018 00000010 section@1
1794 00000018 00000000 00000004 u-boot
1795 0000002c 0000002c 00000004 section@2
1796 0000002c 00000000 00000004 u-boot
1798 self.assertEqual(data,
1799 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x21) +
1800 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x61) +
1801 4 * chr(0x26) + U_BOOT_DATA + 8 * chr(0x26))
1804 if __name__ == "__main__":