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 = b'img'
34 U_BOOT_SPL_DATA = b'56780123456789abcde'
35 U_BOOT_TPL_DATA = b'tpl'
39 U_BOOT_DTB_DATA = b'udtb'
40 U_BOOT_SPL_DTB_DATA = b'spldtb'
41 U_BOOT_TPL_DTB_DATA = b'tpldtb'
42 X86_START16_DATA = b'start16'
43 X86_START16_SPL_DATA = b'start16spl'
44 X86_START16_TPL_DATA = b'start16tpl'
45 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
46 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
47 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
48 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
56 CROS_EC_RW_DATA = b'ecrw'
60 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
61 b"sorry you're alive\n")
62 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
63 REFCODE_DATA = b'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: '%s' 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(tools.GetBytes(0, 3), data[:3])
555 self.assertEqual(tools.GetBytes(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 + tools.GetBytes(0xff, 1) +
737 def testImageName(self):
738 """Test that image files can be named"""
739 retcode = self._DoTestFile('022_image_name.dts')
740 self.assertEqual(0, retcode)
741 image = control.images['image1']
742 fname = tools.GetOutputFilename('test-name')
743 self.assertTrue(os.path.exists(fname))
745 image = control.images['image2']
746 fname = tools.GetOutputFilename('test-name.xx')
747 self.assertTrue(os.path.exists(fname))
749 def testBlobFilename(self):
750 """Test that generic blobs can be provided by filename"""
751 data = self._DoReadFile('023_blob.dts')
752 self.assertEqual(BLOB_DATA, data)
754 def testPackSorted(self):
755 """Test that entries can be sorted"""
757 data = self._DoReadFile('024_sorted.dts')
758 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
759 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
761 def testPackZeroOffset(self):
762 """Test that an entry at offset 0 is not given a new offset"""
763 with self.assertRaises(ValueError) as e:
764 self._DoTestFile('025_pack_zero_size.dts')
765 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
766 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
769 def testPackUbootDtb(self):
770 """Test that a device tree can be added to U-Boot"""
771 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
772 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
774 def testPackX86RomNoSize(self):
775 """Test that the end-at-4gb property requires a size property"""
776 with self.assertRaises(ValueError) as e:
777 self._DoTestFile('027_pack_4gb_no_size.dts')
778 self.assertIn("Section '/binman': Section size must be provided when "
779 "using end-at-4gb", str(e.exception))
781 def test4gbAndSkipAtStartTogether(self):
782 """Test that the end-at-4gb and skip-at-size property can't be used
784 with self.assertRaises(ValueError) as e:
785 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
786 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
787 "'skip-at-start'", str(e.exception))
789 def testPackX86RomOutside(self):
790 """Test that the end-at-4gb property checks for offset boundaries"""
791 with self.assertRaises(ValueError) as e:
792 self._DoTestFile('028_pack_4gb_outside.dts')
793 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
794 "the section starting at 0xffffffe0 (4294967264)",
797 def testPackX86Rom(self):
798 """Test that a basic x86 ROM can be created"""
800 data = self._DoReadFile('029_x86-rom.dts')
801 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
802 tools.GetBytes(0, 2), data)
804 def testPackX86RomMeNoDesc(self):
805 """Test that an invalid Intel descriptor entry is detected"""
806 TestFunctional._MakeInputFile('descriptor.bin', b'')
807 with self.assertRaises(ValueError) as e:
808 self._DoTestFile('031_x86-rom-me.dts')
809 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
812 def testPackX86RomBadDesc(self):
813 """Test that the Intel requires a descriptor entry"""
814 with self.assertRaises(ValueError) as e:
815 self._DoTestFile('030_x86-rom-me-no-desc.dts')
816 self.assertIn("Node '/binman/intel-me': No offset set with "
817 "offset-unset: should another entry provide this correct "
818 "offset?", str(e.exception))
820 def testPackX86RomMe(self):
821 """Test that an x86 ROM with an ME region can be created"""
822 data = self._DoReadFile('031_x86-rom-me.dts')
823 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
825 def testPackVga(self):
826 """Test that an image with a VGA binary can be created"""
827 data = self._DoReadFile('032_intel-vga.dts')
828 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
830 def testPackStart16(self):
831 """Test that an image with an x86 start16 region can be created"""
832 data = self._DoReadFile('033_x86-start16.dts')
833 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
835 def testPackPowerpcMpc85xxBootpgResetvec(self):
836 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
838 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
839 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
841 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
842 """Handle running a test for insertion of microcode
845 dts_fname: Name of test .dts file
846 nodtb_data: Data that we expect in the first section
847 ucode_second: True if the microsecond entry is second instead of
852 Contents of first region (U-Boot or SPL)
853 Offset and size components of microcode pointer, as inserted
854 in the above (two 4-byte words)
856 data = self._DoReadFile(dts_fname, True)
858 # Now check the device tree has no microcode
860 ucode_content = data[len(nodtb_data):]
861 ucode_pos = len(nodtb_data)
862 dtb_with_ucode = ucode_content[16:]
863 fdt_len = self.GetFdtLen(dtb_with_ucode)
865 dtb_with_ucode = data[len(nodtb_data):]
866 fdt_len = self.GetFdtLen(dtb_with_ucode)
867 ucode_content = dtb_with_ucode[fdt_len:]
868 ucode_pos = len(nodtb_data) + fdt_len
869 fname = tools.GetOutputFilename('test.dtb')
870 with open(fname, 'wb') as fd:
871 fd.write(dtb_with_ucode)
872 dtb = fdt.FdtScan(fname)
873 ucode = dtb.GetNode('/microcode')
874 self.assertTrue(ucode)
875 for node in ucode.subnodes:
876 self.assertFalse(node.props.get('data'))
878 # Check that the microcode appears immediately after the Fdt
879 # This matches the concatenation of the data properties in
880 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
881 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
883 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
885 # Check that the microcode pointer was inserted. It should match the
886 # expected offset and size
887 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
889 u_boot = data[:len(nodtb_data)]
890 return u_boot, pos_and_size
892 def testPackUbootMicrocode(self):
893 """Test that x86 microcode can be handled correctly
895 We expect to see the following in the image, in order:
896 u-boot-nodtb.bin with a microcode pointer inserted at the correct
898 u-boot.dtb with the microcode removed
901 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
903 self.assertEqual(b'nodtb with microcode' + pos_and_size +
904 b' somewhere in here', first)
906 def _RunPackUbootSingleMicrocode(self):
907 """Test that x86 microcode can be handled correctly
909 We expect to see the following in the image, in order:
910 u-boot-nodtb.bin with a microcode pointer inserted at the correct
912 u-boot.dtb with the microcode
913 an empty microcode region
915 # We need the libfdt library to run this test since only that allows
916 # finding the offset of a property. This is required by
917 # Entry_u_boot_dtb_with_ucode.ObtainContents().
918 data = self._DoReadFile('035_x86_single_ucode.dts', True)
920 second = data[len(U_BOOT_NODTB_DATA):]
922 fdt_len = self.GetFdtLen(second)
923 third = second[fdt_len:]
924 second = second[:fdt_len]
926 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
927 self.assertIn(ucode_data, second)
928 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
930 # Check that the microcode pointer was inserted. It should match the
931 # expected offset and size
932 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
934 first = data[:len(U_BOOT_NODTB_DATA)]
935 self.assertEqual(b'nodtb with microcode' + pos_and_size +
936 b' somewhere in here', first)
938 def testPackUbootSingleMicrocode(self):
939 """Test that x86 microcode can be handled correctly with fdt_normal.
941 self._RunPackUbootSingleMicrocode()
943 def testUBootImg(self):
944 """Test that u-boot.img can be put in a file"""
945 data = self._DoReadFile('036_u_boot_img.dts')
946 self.assertEqual(U_BOOT_IMG_DATA, data)
948 def testNoMicrocode(self):
949 """Test that a missing microcode region is detected"""
950 with self.assertRaises(ValueError) as e:
951 self._DoReadFile('037_x86_no_ucode.dts', True)
952 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
953 "node found in ", str(e.exception))
955 def testMicrocodeWithoutNode(self):
956 """Test that a missing u-boot-dtb-with-ucode node is detected"""
957 with self.assertRaises(ValueError) as e:
958 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
959 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
960 "microcode region u-boot-dtb-with-ucode", str(e.exception))
962 def testMicrocodeWithoutNode2(self):
963 """Test that a missing u-boot-ucode node is detected"""
964 with self.assertRaises(ValueError) as e:
965 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
966 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
967 "microcode region u-boot-ucode", str(e.exception))
969 def testMicrocodeWithoutPtrInElf(self):
970 """Test that a U-Boot binary without the microcode symbol is detected"""
971 # ELF file without a '_dt_ucode_base_size' symbol
973 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
974 TestFunctional._MakeInputFile('u-boot', fd.read())
976 with self.assertRaises(ValueError) as e:
977 self._RunPackUbootSingleMicrocode()
978 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
979 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
982 # Put the original file back
983 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
984 TestFunctional._MakeInputFile('u-boot', fd.read())
986 def testMicrocodeNotInImage(self):
987 """Test that microcode must be placed within the image"""
988 with self.assertRaises(ValueError) as e:
989 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
990 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
991 "pointer _dt_ucode_base_size at fffffe14 is outside the "
992 "section ranging from 00000000 to 0000002e", str(e.exception))
994 def testWithoutMicrocode(self):
995 """Test that we can cope with an image without microcode (e.g. qemu)"""
996 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
997 TestFunctional._MakeInputFile('u-boot', fd.read())
998 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1000 # Now check the device tree has no microcode
1001 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1002 second = data[len(U_BOOT_NODTB_DATA):]
1004 fdt_len = self.GetFdtLen(second)
1005 self.assertEqual(dtb, second[:fdt_len])
1007 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1008 third = data[used_len:]
1009 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1011 def testUnknownPosSize(self):
1012 """Test that microcode must be placed within the image"""
1013 with self.assertRaises(ValueError) as e:
1014 self._DoReadFile('041_unknown_pos_size.dts', True)
1015 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1016 "entry 'invalid-entry'", str(e.exception))
1018 def testPackFsp(self):
1019 """Test that an image with a FSP binary can be created"""
1020 data = self._DoReadFile('042_intel-fsp.dts')
1021 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1023 def testPackCmc(self):
1024 """Test that an image with a CMC binary can be created"""
1025 data = self._DoReadFile('043_intel-cmc.dts')
1026 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1028 def testPackVbt(self):
1029 """Test that an image with a VBT binary can be created"""
1030 data = self._DoReadFile('046_intel-vbt.dts')
1031 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1033 def testSplBssPad(self):
1034 """Test that we can pad SPL's BSS with zeros"""
1035 # ELF file with a '__bss_size' symbol
1037 data = self._DoReadFile('047_spl_bss_pad.dts')
1038 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1041 def testSplBssPadMissing(self):
1042 """Test that a missing symbol is detected"""
1043 self._SetupSplElf('u_boot_ucode_ptr')
1044 with self.assertRaises(ValueError) as e:
1045 self._DoReadFile('047_spl_bss_pad.dts')
1046 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1049 def testPackStart16Spl(self):
1050 """Test that an image with an x86 start16 SPL region can be created"""
1051 data = self._DoReadFile('048_x86-start16-spl.dts')
1052 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1054 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1055 """Helper function for microcode tests
1057 We expect to see the following in the image, in order:
1058 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1060 u-boot.dtb with the microcode removed
1064 dts: Device tree file to use for test
1065 ucode_second: True if the microsecond entry is second instead of
1068 self._SetupSplElf('u_boot_ucode_ptr')
1069 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1070 ucode_second=ucode_second)
1071 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1072 b'ter somewhere in here', first)
1074 def testPackUbootSplMicrocode(self):
1075 """Test that x86 microcode can be handled correctly in SPL"""
1076 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1078 def testPackUbootSplMicrocodeReorder(self):
1079 """Test that order doesn't matter for microcode entries
1081 This is the same as testPackUbootSplMicrocode but when we process the
1082 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1083 entry, so we reply on binman to try later.
1085 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1088 def testPackMrc(self):
1089 """Test that an image with an MRC binary can be created"""
1090 data = self._DoReadFile('050_intel_mrc.dts')
1091 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1093 def testSplDtb(self):
1094 """Test that an image with spl/u-boot-spl.dtb can be created"""
1095 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1096 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1098 def testSplNoDtb(self):
1099 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1100 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1101 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1103 def testSymbols(self):
1104 """Test binman can assign symbols embedded in U-Boot"""
1105 elf_fname = self.TestFile('u_boot_binman_syms')
1106 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1107 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1108 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1110 self._SetupSplElf('u_boot_binman_syms')
1111 data = self._DoReadFile('053_symbols.dts')
1112 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1113 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1114 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1115 U_BOOT_SPL_DATA[16:])
1116 self.assertEqual(expected, data)
1118 def testPackUnitAddress(self):
1119 """Test that we support multiple binaries with the same name"""
1120 data = self._DoReadFile('054_unit_address.dts')
1121 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1123 def testSections(self):
1124 """Basic test of sections"""
1125 data = self._DoReadFile('055_sections.dts')
1126 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1127 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1128 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1129 self.assertEqual(expected, data)
1132 """Tests outputting a map of the images"""
1133 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1134 self.assertEqual('''ImagePos Offset Size Name
1135 00000000 00000000 00000028 main-section
1136 00000000 00000000 00000010 section@0
1137 00000000 00000000 00000004 u-boot
1138 00000010 00000010 00000010 section@1
1139 00000010 00000000 00000004 u-boot
1140 00000020 00000020 00000004 section@2
1141 00000020 00000000 00000004 u-boot
1144 def testNamePrefix(self):
1145 """Tests that name prefixes are used"""
1146 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1147 self.assertEqual('''ImagePos Offset Size Name
1148 00000000 00000000 00000028 main-section
1149 00000000 00000000 00000010 section@0
1150 00000000 00000000 00000004 ro-u-boot
1151 00000010 00000010 00000010 section@1
1152 00000010 00000000 00000004 rw-u-boot
1155 def testUnknownContents(self):
1156 """Test that obtaining the contents works as expected"""
1157 with self.assertRaises(ValueError) as e:
1158 self._DoReadFile('057_unknown_contents.dts', True)
1159 self.assertIn("Section '/binman': Internal error: Could not complete "
1160 "processing of contents: remaining [<_testing.Entry__testing ",
1163 def testBadChangeSize(self):
1164 """Test that trying to change the size of an entry fails"""
1165 with self.assertRaises(ValueError) as e:
1166 self._DoReadFile('059_change_size.dts', True)
1167 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1168 '2 to 1', str(e.exception))
1170 def testUpdateFdt(self):
1171 """Test that we can update the device tree with offset/size info"""
1172 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1174 dtb = fdt.Fdt(out_dtb_fname)
1176 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
1180 '_testing:offset': 32,
1182 '_testing:image-pos': 32,
1183 'section@0/u-boot:offset': 0,
1184 'section@0/u-boot:size': len(U_BOOT_DATA),
1185 'section@0/u-boot:image-pos': 0,
1186 'section@0:offset': 0,
1187 'section@0:size': 16,
1188 'section@0:image-pos': 0,
1190 'section@1/u-boot:offset': 0,
1191 'section@1/u-boot:size': len(U_BOOT_DATA),
1192 'section@1/u-boot:image-pos': 16,
1193 'section@1:offset': 16,
1194 'section@1:size': 16,
1195 'section@1:image-pos': 16,
1199 def testUpdateFdtBad(self):
1200 """Test that we detect when ProcessFdt never completes"""
1201 with self.assertRaises(ValueError) as e:
1202 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1203 self.assertIn('Could not complete processing of Fdt: remaining '
1204 '[<_testing.Entry__testing', str(e.exception))
1206 def testEntryArgs(self):
1207 """Test passing arguments to entries from the command line"""
1209 'test-str-arg': 'test1',
1210 'test-int-arg': '456',
1212 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1213 self.assertIn('image', control.images)
1214 entry = control.images['image'].GetEntries()['_testing']
1215 self.assertEqual('test0', entry.test_str_fdt)
1216 self.assertEqual('test1', entry.test_str_arg)
1217 self.assertEqual(123, entry.test_int_fdt)
1218 self.assertEqual(456, entry.test_int_arg)
1220 def testEntryArgsMissing(self):
1221 """Test missing arguments and properties"""
1223 'test-int-arg': '456',
1225 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1226 entry = control.images['image'].GetEntries()['_testing']
1227 self.assertEqual('test0', entry.test_str_fdt)
1228 self.assertEqual(None, entry.test_str_arg)
1229 self.assertEqual(None, entry.test_int_fdt)
1230 self.assertEqual(456, entry.test_int_arg)
1232 def testEntryArgsRequired(self):
1233 """Test missing arguments and properties"""
1235 'test-int-arg': '456',
1237 with self.assertRaises(ValueError) as e:
1238 self._DoReadFileDtb('064_entry_args_required.dts')
1239 self.assertIn("Node '/binman/_testing': Missing required "
1240 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1243 def testEntryArgsInvalidFormat(self):
1244 """Test that an invalid entry-argument format is detected"""
1245 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
1246 with self.assertRaises(ValueError) as e:
1247 self._DoBinman(*args)
1248 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1250 def testEntryArgsInvalidInteger(self):
1251 """Test that an invalid entry-argument integer is detected"""
1253 'test-int-arg': 'abc',
1255 with self.assertRaises(ValueError) as e:
1256 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1257 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1258 "'test-int-arg' (value 'abc') to integer",
1261 def testEntryArgsInvalidDatatype(self):
1262 """Test that an invalid entry-argument datatype is detected
1264 This test could be written in entry_test.py except that it needs
1265 access to control.entry_args, which seems more than that module should
1269 'test-bad-datatype-arg': '12',
1271 with self.assertRaises(ValueError) as e:
1272 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1273 entry_args=entry_args)
1274 self.assertIn('GetArg() internal error: Unknown data type ',
1278 """Test for a text entry type"""
1280 'test-id': TEXT_DATA,
1281 'test-id2': TEXT_DATA2,
1282 'test-id3': TEXT_DATA3,
1284 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1285 entry_args=entry_args)
1286 expected = (tools.ToBytes(TEXT_DATA) +
1287 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1288 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1289 b'some text' + b'more text')
1290 self.assertEqual(expected, data)
1292 def testEntryDocs(self):
1293 """Test for creation of entry documentation"""
1294 with test_util.capture_sys_output() as (stdout, stderr):
1295 control.WriteEntryDocs(binman.GetEntryModules())
1296 self.assertTrue(len(stdout.getvalue()) > 0)
1298 def testEntryDocsMissing(self):
1299 """Test handling of missing entry documentation"""
1300 with self.assertRaises(ValueError) as e:
1301 with test_util.capture_sys_output() as (stdout, stderr):
1302 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1303 self.assertIn('Documentation is missing for modules: u_boot',
1307 """Basic test of generation of a flashrom fmap"""
1308 data = self._DoReadFile('067_fmap.dts')
1309 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1310 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1311 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1312 self.assertEqual(expected, data[:32])
1313 self.assertEqual(b'__FMAP__', fhdr.signature)
1314 self.assertEqual(1, fhdr.ver_major)
1315 self.assertEqual(0, fhdr.ver_minor)
1316 self.assertEqual(0, fhdr.base)
1317 self.assertEqual(16 + 16 +
1318 fmap_util.FMAP_HEADER_LEN +
1319 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1320 self.assertEqual(b'FMAP', fhdr.name)
1321 self.assertEqual(3, fhdr.nareas)
1322 for fentry in fentries:
1323 self.assertEqual(0, fentry.flags)
1325 self.assertEqual(0, fentries[0].offset)
1326 self.assertEqual(4, fentries[0].size)
1327 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1329 self.assertEqual(16, fentries[1].offset)
1330 self.assertEqual(4, fentries[1].size)
1331 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1333 self.assertEqual(32, fentries[2].offset)
1334 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1335 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1336 self.assertEqual(b'FMAP', fentries[2].name)
1338 def testBlobNamedByArg(self):
1339 """Test we can add a blob with the filename coming from an entry arg"""
1341 'cros-ec-rw-path': 'ecrw.bin',
1343 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1344 entry_args=entry_args)
1347 """Test for an fill entry type"""
1348 data = self._DoReadFile('069_fill.dts')
1349 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1350 self.assertEqual(expected, data)
1352 def testFillNoSize(self):
1353 """Test for an fill entry type with no size"""
1354 with self.assertRaises(ValueError) as e:
1355 self._DoReadFile('070_fill_no_size.dts')
1356 self.assertIn("'fill' entry must have a size property",
1359 def _HandleGbbCommand(self, pipe_list):
1360 """Fake calls to the futility utility"""
1361 if pipe_list[0][0] == 'futility':
1362 fname = pipe_list[0][-1]
1363 # Append our GBB data to the file, which will happen every time the
1364 # futility command is called.
1365 with open(fname, 'ab') as fd:
1367 return command.CommandResult()
1370 """Test for the Chromium OS Google Binary Block"""
1371 command.test_result = self._HandleGbbCommand
1373 'keydir': 'devkeys',
1374 'bmpblk': 'bmpblk.bin',
1376 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1379 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1380 tools.GetBytes(0, 0x2180 - 16))
1381 self.assertEqual(expected, data)
1383 def testGbbTooSmall(self):
1384 """Test for the Chromium OS Google Binary Block being large enough"""
1385 with self.assertRaises(ValueError) as e:
1386 self._DoReadFileDtb('072_gbb_too_small.dts')
1387 self.assertIn("Node '/binman/gbb': GBB is too small",
1390 def testGbbNoSize(self):
1391 """Test for the Chromium OS Google Binary Block having a size"""
1392 with self.assertRaises(ValueError) as e:
1393 self._DoReadFileDtb('073_gbb_no_size.dts')
1394 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1397 def _HandleVblockCommand(self, pipe_list):
1398 """Fake calls to the futility utility"""
1399 if pipe_list[0][0] == 'futility':
1400 fname = pipe_list[0][3]
1401 with open(fname, 'wb') as fd:
1402 fd.write(VBLOCK_DATA)
1403 return command.CommandResult()
1405 def testVblock(self):
1406 """Test for the Chromium OS Verified Boot Block"""
1407 command.test_result = self._HandleVblockCommand
1409 'keydir': 'devkeys',
1411 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1412 entry_args=entry_args)
1413 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1414 self.assertEqual(expected, data)
1416 def testVblockNoContent(self):
1417 """Test we detect a vblock which has no content to sign"""
1418 with self.assertRaises(ValueError) as e:
1419 self._DoReadFile('075_vblock_no_content.dts')
1420 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1421 'property', str(e.exception))
1423 def testVblockBadPhandle(self):
1424 """Test that we detect a vblock with an invalid phandle in contents"""
1425 with self.assertRaises(ValueError) as e:
1426 self._DoReadFile('076_vblock_bad_phandle.dts')
1427 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1428 '1000', str(e.exception))
1430 def testVblockBadEntry(self):
1431 """Test that we detect an entry that points to a non-entry"""
1432 with self.assertRaises(ValueError) as e:
1433 self._DoReadFile('077_vblock_bad_entry.dts')
1434 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1435 "'other'", str(e.exception))
1438 """Test that an image with TPL and ots device tree can be created"""
1439 # ELF file with a '__bss_size' symbol
1440 with open(self.TestFile('bss_data'), 'rb') as fd:
1441 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1442 data = self._DoReadFile('078_u_boot_tpl.dts')
1443 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1445 def testUsesPos(self):
1446 """Test that the 'pos' property cannot be used anymore"""
1447 with self.assertRaises(ValueError) as e:
1448 data = self._DoReadFile('079_uses_pos.dts')
1449 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1450 "'pos'", str(e.exception))
1452 def testFillZero(self):
1453 """Test for an fill entry type with a size of 0"""
1454 data = self._DoReadFile('080_fill_empty.dts')
1455 self.assertEqual(tools.GetBytes(0, 16), data)
1457 def testTextMissing(self):
1458 """Test for a text entry type where there is no text"""
1459 with self.assertRaises(ValueError) as e:
1460 self._DoReadFileDtb('066_text.dts',)
1461 self.assertIn("Node '/binman/text': No value provided for text label "
1462 "'test-id'", str(e.exception))
1464 def testPackStart16Tpl(self):
1465 """Test that an image with an x86 start16 TPL region can be created"""
1466 data = self._DoReadFile('081_x86-start16-tpl.dts')
1467 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1469 def testSelectImage(self):
1470 """Test that we can select which images to build"""
1471 expected = 'Skipping images: image1'
1473 # We should only get the expected message in verbose mode
1474 for verbosity in (None, 2):
1475 with test_util.capture_sys_output() as (stdout, stderr):
1476 retcode = self._DoTestFile('006_dual_image.dts',
1477 verbosity=verbosity,
1479 self.assertEqual(0, retcode)
1481 self.assertIn(expected, stdout.getvalue())
1483 self.assertNotIn(expected, stdout.getvalue())
1485 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1486 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1488 def testUpdateFdtAll(self):
1489 """Test that all device trees are updated with offset/size info"""
1490 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1491 use_real_dtb=True, update_dtb=True)
1494 'section:image-pos': 0,
1495 'u-boot-tpl-dtb:size': 513,
1496 'u-boot-spl-dtb:size': 513,
1497 'u-boot-spl-dtb:offset': 493,
1499 'section/u-boot-dtb:image-pos': 0,
1500 'u-boot-spl-dtb:image-pos': 493,
1501 'section/u-boot-dtb:size': 493,
1502 'u-boot-tpl-dtb:image-pos': 1006,
1503 'section/u-boot-dtb:offset': 0,
1504 'section:size': 493,
1506 'section:offset': 0,
1507 'u-boot-tpl-dtb:offset': 1006,
1511 # We expect three device-tree files in the output, one after the other.
1512 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1513 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1514 # main U-Boot tree. All three should have the same postions and offset.
1516 for item in ['', 'spl', 'tpl']:
1517 dtb = fdt.Fdt.FromData(data[start:])
1519 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1521 expected = dict(base_expected)
1524 self.assertEqual(expected, props)
1525 start += dtb._fdt_obj.totalsize()
1527 def testUpdateFdtOutput(self):
1528 """Test that output DTB files are updated"""
1530 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1531 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1533 # Unfortunately, compiling a source file always results in a file
1534 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1535 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1536 # binman as a file called u-boot.dtb. To fix this, copy the file
1537 # over to the expected place.
1538 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1539 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1541 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1542 'tpl/u-boot-tpl.dtb.out']:
1543 dtb = fdt.Fdt.FromData(data[start:])
1544 size = dtb._fdt_obj.totalsize()
1545 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1546 outdata = tools.ReadFile(pathname)
1547 name = os.path.split(fname)[0]
1550 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1552 orig_indata = dtb_data
1553 self.assertNotEqual(outdata, orig_indata,
1554 "Expected output file '%s' be updated" % pathname)
1555 self.assertEqual(outdata, data[start:start + size],
1556 "Expected output file '%s' to match output image" %
1562 def _decompress(self, data):
1563 return tools.Decompress(data, 'lz4')
1565 def testCompress(self):
1566 """Test compression of blobs"""
1567 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1568 use_real_dtb=True, update_dtb=True)
1569 dtb = fdt.Fdt(out_dtb_fname)
1571 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1572 orig = self._decompress(data)
1573 self.assertEquals(COMPRESS_DATA, orig)
1575 'blob:uncomp-size': len(COMPRESS_DATA),
1576 'blob:size': len(data),
1579 self.assertEqual(expected, props)
1581 def testFiles(self):
1582 """Test bringing in multiple files"""
1583 data = self._DoReadFile('084_files.dts')
1584 self.assertEqual(FILES_DATA, data)
1586 def testFilesCompress(self):
1587 """Test bringing in multiple files and compressing them"""
1588 data = self._DoReadFile('085_files_compress.dts')
1590 image = control.images['image']
1591 entries = image.GetEntries()
1592 files = entries['files']
1593 entries = files._section._entries
1596 for i in range(1, 3):
1598 start = entries[key].image_pos
1599 len = entries[key].size
1600 chunk = data[start:start + len]
1601 orig += self._decompress(chunk)
1603 self.assertEqual(FILES_DATA, orig)
1605 def testFilesMissing(self):
1606 """Test missing files"""
1607 with self.assertRaises(ValueError) as e:
1608 data = self._DoReadFile('086_files_none.dts')
1609 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1610 'no files', str(e.exception))
1612 def testFilesNoPattern(self):
1613 """Test missing files"""
1614 with self.assertRaises(ValueError) as e:
1615 data = self._DoReadFile('087_files_no_pattern.dts')
1616 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1619 def testExpandSize(self):
1620 """Test an expanding entry"""
1621 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1623 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1624 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1625 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1626 tools.GetBytes(ord('d'), 8))
1627 self.assertEqual(expect, data)
1628 self.assertEqual('''ImagePos Offset Size Name
1629 00000000 00000000 00000028 main-section
1630 00000000 00000000 00000008 fill
1631 00000008 00000008 00000004 u-boot
1632 0000000c 0000000c 00000004 section
1633 0000000c 00000000 00000003 intel-mrc
1634 00000010 00000010 00000004 u-boot2
1635 00000014 00000014 0000000c section2
1636 00000014 00000000 00000008 fill
1637 0000001c 00000008 00000004 u-boot
1638 00000020 00000020 00000008 fill2
1641 def testExpandSizeBad(self):
1642 """Test an expanding entry which fails to provide contents"""
1643 with test_util.capture_sys_output() as (stdout, stderr):
1644 with self.assertRaises(ValueError) as e:
1645 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1646 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1647 'expanding entry', str(e.exception))
1650 """Test hashing of the contents of an entry"""
1651 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1652 use_real_dtb=True, update_dtb=True)
1653 dtb = fdt.Fdt(out_dtb_fname)
1655 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1656 m = hashlib.sha256()
1657 m.update(U_BOOT_DATA)
1658 self.assertEqual(m.digest(), b''.join(hash_node.value))
1660 def testHashNoAlgo(self):
1661 with self.assertRaises(ValueError) as e:
1662 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1663 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1664 'hash node', str(e.exception))
1666 def testHashBadAlgo(self):
1667 with self.assertRaises(ValueError) as e:
1668 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1669 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1672 def testHashSection(self):
1673 """Test hashing of the contents of an entry"""
1674 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1675 use_real_dtb=True, update_dtb=True)
1676 dtb = fdt.Fdt(out_dtb_fname)
1678 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1679 m = hashlib.sha256()
1680 m.update(U_BOOT_DATA)
1681 m.update(tools.GetBytes(ord('a'), 16))
1682 self.assertEqual(m.digest(), b''.join(hash_node.value))
1684 def testPackUBootTplMicrocode(self):
1685 """Test that x86 microcode can be handled correctly in TPL
1687 We expect to see the following in the image, in order:
1688 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1690 u-boot-tpl.dtb with the microcode removed
1693 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1694 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1695 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1696 U_BOOT_TPL_NODTB_DATA)
1697 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1698 b'ter somewhere in here', first)
1700 def testFmapX86(self):
1701 """Basic test of generation of a flashrom fmap"""
1702 data = self._DoReadFile('094_fmap_x86.dts')
1703 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1704 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1705 self.assertEqual(expected, data[:32])
1706 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1708 self.assertEqual(0x100, fhdr.image_size)
1710 self.assertEqual(0, fentries[0].offset)
1711 self.assertEqual(4, fentries[0].size)
1712 self.assertEqual(b'U_BOOT', fentries[0].name)
1714 self.assertEqual(4, fentries[1].offset)
1715 self.assertEqual(3, fentries[1].size)
1716 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1718 self.assertEqual(32, fentries[2].offset)
1719 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1720 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1721 self.assertEqual(b'FMAP', fentries[2].name)
1723 def testFmapX86Section(self):
1724 """Basic test of generation of a flashrom fmap"""
1725 data = self._DoReadFile('095_fmap_x86_section.dts')
1726 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1727 self.assertEqual(expected, data[:32])
1728 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1730 self.assertEqual(0x100, fhdr.image_size)
1732 self.assertEqual(0, fentries[0].offset)
1733 self.assertEqual(4, fentries[0].size)
1734 self.assertEqual(b'U_BOOT', fentries[0].name)
1736 self.assertEqual(4, fentries[1].offset)
1737 self.assertEqual(3, fentries[1].size)
1738 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1740 self.assertEqual(36, fentries[2].offset)
1741 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1742 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1743 self.assertEqual(b'FMAP', fentries[2].name)
1746 """Basic test of ELF entries"""
1748 with open(self.TestFile('bss_data'), 'rb') as fd:
1749 TestFunctional._MakeInputFile('-boot', fd.read())
1750 data = self._DoReadFile('096_elf.dts')
1752 def testElfStrip(self):
1753 """Basic test of ELF entries"""
1755 with open(self.TestFile('bss_data'), 'rb') as fd:
1756 TestFunctional._MakeInputFile('-boot', fd.read())
1757 data = self._DoReadFile('097_elf_strip.dts')
1759 def testPackOverlapMap(self):
1760 """Test that overlapping regions are detected"""
1761 with test_util.capture_sys_output() as (stdout, stderr):
1762 with self.assertRaises(ValueError) as e:
1763 self._DoTestFile('014_pack_overlap.dts', map=True)
1764 map_fname = tools.GetOutputFilename('image.map')
1765 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1768 # We should not get an inmage, but there should be a map file
1769 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1770 self.assertTrue(os.path.exists(map_fname))
1771 map_data = tools.ReadFile(map_fname, binary=False)
1772 self.assertEqual('''ImagePos Offset Size Name
1773 <none> 00000000 00000007 main-section
1774 <none> 00000000 00000004 u-boot
1775 <none> 00000003 00000004 u-boot-align
1778 def testPackRefCode(self):
1779 """Test that an image with an Intel Reference code binary works"""
1780 data = self._DoReadFile('100_intel_refcode.dts')
1781 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1783 def testSectionOffset(self):
1784 """Tests use of a section with an offset"""
1785 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1787 self.assertEqual('''ImagePos Offset Size Name
1788 00000000 00000000 00000038 main-section
1789 00000004 00000004 00000010 section@0
1790 00000004 00000000 00000004 u-boot
1791 00000018 00000018 00000010 section@1
1792 00000018 00000000 00000004 u-boot
1793 0000002c 0000002c 00000004 section@2
1794 0000002c 00000000 00000004 u-boot
1796 self.assertEqual(data,
1797 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1798 tools.GetBytes(0x21, 12) +
1799 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1800 tools.GetBytes(0x61, 12) +
1801 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1802 tools.GetBytes(0x26, 8))
1805 if __name__ == "__main__":