1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # To run a single test, change to this directory, and:
7 # python -m unittest func_test.TestFunctional.testHelp
9 from __future__ import print_function
12 from optparse import OptionParser
33 # Contents of test files, corresponding to different entry types
35 U_BOOT_IMG_DATA = b'img'
36 U_BOOT_SPL_DATA = b'56780123456789abcde'
37 U_BOOT_TPL_DATA = b'tpl'
41 U_BOOT_DTB_DATA = b'udtb'
42 U_BOOT_SPL_DTB_DATA = b'spldtb'
43 U_BOOT_TPL_DTB_DATA = b'tpldtb'
44 X86_START16_DATA = b'start16'
45 X86_START16_SPL_DATA = b'start16spl'
46 X86_START16_TPL_DATA = b'start16tpl'
47 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
48 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
49 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
50 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
58 CROS_EC_RW_DATA = b'ecrw'
62 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
63 b"sorry you're alive\n")
64 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
65 REFCODE_DATA = b'refcode'
68 class TestFunctional(unittest.TestCase):
69 """Functional tests for binman
71 Most of these use a sample .dts file to build an image and then check
72 that it looks correct. The sample files are in the test/ subdirectory
75 For each entry type a very small test file is created using fixed
76 string contents. This makes it easy to test that things look right, and
79 In some cases a 'real' file must be used - these are also supplied in
87 # Handle the case where argv[0] is 'python'
88 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
89 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
91 # Create a temporary directory for input files
92 self._indir = tempfile.mkdtemp(prefix='binmant.')
94 # Create some test files
95 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
96 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
97 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
98 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
99 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
100 TestFunctional._MakeInputFile('me.bin', ME_DATA)
101 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
103 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
104 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
105 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
106 X86_START16_SPL_DATA)
107 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
108 X86_START16_TPL_DATA)
109 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
110 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
111 U_BOOT_SPL_NODTB_DATA)
112 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
113 U_BOOT_TPL_NODTB_DATA)
114 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
115 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
116 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
117 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
118 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
119 TestFunctional._MakeInputDir('devkeys')
120 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
121 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
123 # ELF file with a '_dt_ucode_base_size' symbol
124 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
125 TestFunctional._MakeInputFile('u-boot', fd.read())
127 # Intel flash descriptor file
128 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
129 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
131 shutil.copytree(self.TestFile('files'),
132 os.path.join(self._indir, 'files'))
134 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
137 def tearDownClass(self):
138 """Remove the temporary input directory and its contents"""
139 if self.preserve_indir:
140 print('Preserving input dir: %s' % self._indir)
143 shutil.rmtree(self._indir)
147 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
149 """Accept arguments controlling test execution
152 preserve_indir: Preserve the shared input directory used by all
154 preserve_outdir: Preserve the output directories used by tests. Each
155 test has its own, so this is normally only useful when running a
157 toolpath: ist of paths to use for tools
159 cls.preserve_indir = preserve_indir
160 cls.preserve_outdirs = preserve_outdirs
161 cls.toolpath = toolpath
164 # Enable this to turn on debugging output
165 # tout.Init(tout.DEBUG)
166 command.test_result = None
169 """Remove the temporary output directory"""
170 if self.preserve_outdirs:
171 print('Preserving output dir: %s' % tools.outdir)
173 tools._FinaliseForTest()
176 def _ResetDtbs(self):
177 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
178 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
179 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
181 def _GetVerbosity(self):
182 """Check if verbosity should be enabled
185 list containing either:
186 - Verbosity flag (e.g. '-v2') if it is present on the cmd line
187 - nothing if the flag is not present
189 for arg in sys.argv[1:]:
190 if arg.startswith('-v'):
194 def _RunBinman(self, *args, **kwargs):
195 """Run binman using the command line
198 Arguments to pass, as a list of strings
199 kwargs: Arguments to pass to Command.RunPipe()
201 result = command.RunPipe([[self._binman_pathname] + list(args)],
202 capture=True, capture_stderr=True, raise_on_error=False)
203 if result.return_code and kwargs.get('raise_on_error', True):
204 raise Exception("Error running '%s': %s" % (' '.join(args),
205 result.stdout + result.stderr))
208 def _DoBinman(self, *args):
209 """Run binman using directly (in the same process)
212 Arguments to pass, as a list of strings
214 Return value (0 for success)
219 (options, args) = cmdline.ParseArgs(args)
220 options.pager = 'binman-invalid-pager'
221 options.build_dir = self._indir
223 # For testing, you can force an increase in verbosity here
224 # options.verbosity = tout.DEBUG
225 return control.Binman(options, args)
227 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
228 entry_args=None, images=None, use_real_dtb=False,
230 """Run binman with a given test file
233 fname: Device-tree source filename to use (e.g. 005_simple.dts)
234 debug: True to enable debugging output
235 map: True to output map files for the images
236 update_dtb: Update the offset and size of each entry in the device
237 tree before packing it into the image
238 entry_args: Dict of entry args to supply to binman
240 value: value of that arg
241 images: List of image names to build
243 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
251 args.append('--fake-dtb')
252 if verbosity is not None:
253 args.append('-v%d' % verbosity)
255 args += self._GetVerbosity()
257 for arg, value in entry_args.items():
258 args.append('-a%s=%s' % (arg, value))
261 args += ['-i', image]
263 for path in self.toolpath:
264 args += ['--toolpath', path]
265 return self._DoBinman(*args)
267 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
268 """Set up a new test device-tree file
270 The given file is compiled and set up as the device tree to be used
274 fname: Filename of .dts file to read
275 outfile: Output filename for compiled device-tree binary
278 Contents of device-tree binary
280 tools.PrepareOutputDir(None)
281 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
282 with open(dtb, 'rb') as fd:
284 TestFunctional._MakeInputFile(outfile, data)
285 tools.FinaliseOutputDir()
288 def _GetDtbContentsForSplTpl(self, dtb_data, name):
289 """Create a version of the main DTB for SPL or SPL
291 For testing we don't actually have different versions of the DTB. With
292 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
293 we don't normally have any unwanted nodes.
295 We still want the DTBs for SPL and TPL to be different though, since
296 otherwise it is confusing to know which one we are looking at. So add
297 an 'spl' or 'tpl' property to the top-level node.
299 dtb = fdt.Fdt.FromData(dtb_data)
301 dtb.GetNode('/binman').AddZeroProp(name)
302 dtb.Sync(auto_resize=True)
304 return dtb.GetContents()
306 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
307 update_dtb=False, entry_args=None, reset_dtbs=True):
308 """Run binman and return the resulting image
310 This runs binman with a given test file and then reads the resulting
311 output file. It is a shortcut function since most tests need to do
314 Raises an assertion failure if binman returns a non-zero exit code.
317 fname: Device-tree source filename to use (e.g. 005_simple.dts)
318 use_real_dtb: True to use the test file as the contents of
319 the u-boot-dtb entry. Normally this is not needed and the
320 test contents (the U_BOOT_DTB_DATA string) can be used.
321 But in some test we need the real contents.
322 map: True to output map files for the images
323 update_dtb: Update the offset and size of each entry in the device
324 tree before packing it into the image
328 Resulting image contents
330 Map data showing contents of image (or None if none)
331 Output device tree binary filename ('u-boot.dtb' path)
334 # Use the compiled test file as the u-boot-dtb input
336 dtb_data = self._SetupDtb(fname)
338 # For testing purposes, make a copy of the DT for SPL and TPL. Add
339 # a node indicating which it is, so aid verification.
340 for name in ['spl', 'tpl']:
341 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
342 outfile = os.path.join(self._indir, dtb_fname)
343 TestFunctional._MakeInputFile(dtb_fname,
344 self._GetDtbContentsForSplTpl(dtb_data, name))
347 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
348 entry_args=entry_args, use_real_dtb=use_real_dtb)
349 self.assertEqual(0, retcode)
350 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
352 # Find the (only) image, read it and return its contents
353 image = control.images['image']
354 image_fname = tools.GetOutputFilename('image.bin')
355 self.assertTrue(os.path.exists(image_fname))
357 map_fname = tools.GetOutputFilename('image.map')
358 with open(map_fname) as fd:
362 with open(image_fname, 'rb') as fd:
363 return fd.read(), dtb_data, map_data, out_dtb_fname
365 # Put the test file back
366 if reset_dtbs and use_real_dtb:
369 def _DoReadFile(self, fname, use_real_dtb=False):
370 """Helper function which discards the device-tree binary
373 fname: Device-tree source filename to use (e.g. 005_simple.dts)
374 use_real_dtb: True to use the test file as the contents of
375 the u-boot-dtb entry. Normally this is not needed and the
376 test contents (the U_BOOT_DTB_DATA string) can be used.
377 But in some test we need the real contents.
380 Resulting image contents
382 return self._DoReadFileDtb(fname, use_real_dtb)[0]
385 def _MakeInputFile(self, fname, contents):
386 """Create a new test input file, creating directories as needed
389 fname: Filename to create
390 contents: File contents to write in to the file
392 Full pathname of file created
394 pathname = os.path.join(self._indir, fname)
395 dirname = os.path.dirname(pathname)
396 if dirname and not os.path.exists(dirname):
398 with open(pathname, 'wb') as fd:
403 def _MakeInputDir(self, dirname):
404 """Create a new test input directory, creating directories as needed
407 dirname: Directory name to create
410 Full pathname of directory created
412 pathname = os.path.join(self._indir, dirname)
413 if not os.path.exists(pathname):
414 os.makedirs(pathname)
418 def _SetupSplElf(self, src_fname='bss_data'):
419 """Set up an ELF file with a '_dt_ucode_base_size' symbol
422 Filename of ELF file to use as SPL
424 with open(self.TestFile(src_fname), 'rb') as fd:
425 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
428 def TestFile(self, fname):
429 return os.path.join(self._binman_dir, 'test', fname)
431 def AssertInList(self, grep_list, target):
432 """Assert that at least one of a list of things is in a target
435 grep_list: List of strings to check
436 target: Target string
438 for grep in grep_list:
441 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
443 def CheckNoGaps(self, entries):
444 """Check that all entries fit together without gaps
447 entries: List of entries to check
450 for entry in entries.values():
451 self.assertEqual(offset, entry.offset)
454 def GetFdtLen(self, dtb):
455 """Get the totalsize field from a device-tree binary
458 dtb: Device-tree binary contents
461 Total size of device-tree binary, from the header
463 return struct.unpack('>L', dtb[4:8])[0]
465 def _GetPropTree(self, dtb, prop_names):
466 def AddNode(node, path):
468 path += '/' + node.name
469 for subnode in node.subnodes:
470 for prop in subnode.props.values():
471 if prop.name in prop_names:
472 prop_path = path + '/' + subnode.name + ':' + prop.name
473 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
475 AddNode(subnode, path)
478 AddNode(dtb.GetRoot(), '')
482 """Test a basic run with valid args"""
483 result = self._RunBinman('-h')
485 def testFullHelp(self):
486 """Test that the full help is displayed with -H"""
487 result = self._RunBinman('-H')
488 help_file = os.path.join(self._binman_dir, 'README')
489 # Remove possible extraneous strings
490 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
491 gothelp = result.stdout.replace(extra, '')
492 self.assertEqual(len(gothelp), os.path.getsize(help_file))
493 self.assertEqual(0, len(result.stderr))
494 self.assertEqual(0, result.return_code)
496 def testFullHelpInternal(self):
497 """Test that the full help is displayed with -H"""
499 command.test_result = command.CommandResult()
500 result = self._DoBinman('-H')
501 help_file = os.path.join(self._binman_dir, 'README')
503 command.test_result = None
506 """Test that the basic help is displayed with -h"""
507 result = self._RunBinman('-h')
508 self.assertTrue(len(result.stdout) > 200)
509 self.assertEqual(0, len(result.stderr))
510 self.assertEqual(0, result.return_code)
513 """Test that we can run it with a specific board"""
514 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
515 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
516 result = self._DoBinman('-b', 'sandbox')
517 self.assertEqual(0, result)
519 def testNeedBoard(self):
520 """Test that we get an error when no board ius supplied"""
521 with self.assertRaises(ValueError) as e:
522 result = self._DoBinman()
523 self.assertIn("Must provide a board to process (use -b <board>)",
526 def testMissingDt(self):
527 """Test that an invalid device-tree file generates an error"""
528 with self.assertRaises(Exception) as e:
529 self._RunBinman('-d', 'missing_file')
530 # We get one error from libfdt, and a different one from fdtget.
531 self.AssertInList(["Couldn't open blob from 'missing_file'",
532 'No such file or directory'], str(e.exception))
534 def testBrokenDt(self):
535 """Test that an invalid device-tree source file generates an error
537 Since this is a source file it should be compiled and the error
538 will come from the device-tree compiler (dtc).
540 with self.assertRaises(Exception) as e:
541 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
542 self.assertIn("FATAL ERROR: Unable to parse input tree",
545 def testMissingNode(self):
546 """Test that a device tree without a 'binman' node generates an error"""
547 with self.assertRaises(Exception) as e:
548 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
549 self.assertIn("does not have a 'binman' node", str(e.exception))
552 """Test that an empty binman node works OK (i.e. does nothing)"""
553 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
554 self.assertEqual(0, len(result.stderr))
555 self.assertEqual(0, result.return_code)
557 def testInvalidEntry(self):
558 """Test that an invalid entry is flagged"""
559 with self.assertRaises(Exception) as e:
560 result = self._RunBinman('-d',
561 self.TestFile('004_invalid_entry.dts'))
562 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
563 "'/binman/not-a-valid-type'", str(e.exception))
565 def testSimple(self):
566 """Test a simple binman with a single file"""
567 data = self._DoReadFile('005_simple.dts')
568 self.assertEqual(U_BOOT_DATA, data)
570 def testSimpleDebug(self):
571 """Test a simple binman run with debugging enabled"""
572 data = self._DoTestFile('005_simple.dts', debug=True)
575 """Test that we can handle creating two images
577 This also tests image padding.
579 retcode = self._DoTestFile('006_dual_image.dts')
580 self.assertEqual(0, retcode)
582 image = control.images['image1']
583 self.assertEqual(len(U_BOOT_DATA), image._size)
584 fname = tools.GetOutputFilename('image1.bin')
585 self.assertTrue(os.path.exists(fname))
586 with open(fname, 'rb') as fd:
588 self.assertEqual(U_BOOT_DATA, data)
590 image = control.images['image2']
591 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
592 fname = tools.GetOutputFilename('image2.bin')
593 self.assertTrue(os.path.exists(fname))
594 with open(fname, 'rb') as fd:
596 self.assertEqual(U_BOOT_DATA, data[3:7])
597 self.assertEqual(tools.GetBytes(0, 3), data[:3])
598 self.assertEqual(tools.GetBytes(0, 5), data[7:])
600 def testBadAlign(self):
601 """Test that an invalid alignment value is detected"""
602 with self.assertRaises(ValueError) as e:
603 self._DoTestFile('007_bad_align.dts')
604 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
605 "of two", str(e.exception))
607 def testPackSimple(self):
608 """Test that packing works as expected"""
609 retcode = self._DoTestFile('008_pack.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))
617 self.assertIn('u-boot', entries)
618 entry = entries['u-boot']
619 self.assertEqual(0, entry.offset)
620 self.assertEqual(len(U_BOOT_DATA), entry.size)
622 # Second u-boot, aligned to 16-byte boundary
623 self.assertIn('u-boot-align', entries)
624 entry = entries['u-boot-align']
625 self.assertEqual(16, entry.offset)
626 self.assertEqual(len(U_BOOT_DATA), entry.size)
628 # Third u-boot, size 23 bytes
629 self.assertIn('u-boot-size', entries)
630 entry = entries['u-boot-size']
631 self.assertEqual(20, entry.offset)
632 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
633 self.assertEqual(23, entry.size)
635 # Fourth u-boot, placed immediate after the above
636 self.assertIn('u-boot-next', entries)
637 entry = entries['u-boot-next']
638 self.assertEqual(43, entry.offset)
639 self.assertEqual(len(U_BOOT_DATA), entry.size)
641 # Fifth u-boot, placed at a fixed offset
642 self.assertIn('u-boot-fixed', entries)
643 entry = entries['u-boot-fixed']
644 self.assertEqual(61, entry.offset)
645 self.assertEqual(len(U_BOOT_DATA), entry.size)
647 self.assertEqual(65, image._size)
649 def testPackExtra(self):
650 """Test that extra packing feature works as expected"""
651 retcode = self._DoTestFile('009_pack_extra.dts')
653 self.assertEqual(0, retcode)
654 self.assertIn('image', control.images)
655 image = control.images['image']
656 entries = image.GetEntries()
657 self.assertEqual(5, len(entries))
659 # First u-boot with padding before and after
660 self.assertIn('u-boot', entries)
661 entry = entries['u-boot']
662 self.assertEqual(0, entry.offset)
663 self.assertEqual(3, entry.pad_before)
664 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
666 # Second u-boot has an aligned size, but it has no effect
667 self.assertIn('u-boot-align-size-nop', entries)
668 entry = entries['u-boot-align-size-nop']
669 self.assertEqual(12, entry.offset)
670 self.assertEqual(4, entry.size)
672 # Third u-boot has an aligned size too
673 self.assertIn('u-boot-align-size', entries)
674 entry = entries['u-boot-align-size']
675 self.assertEqual(16, entry.offset)
676 self.assertEqual(32, entry.size)
678 # Fourth u-boot has an aligned end
679 self.assertIn('u-boot-align-end', entries)
680 entry = entries['u-boot-align-end']
681 self.assertEqual(48, entry.offset)
682 self.assertEqual(16, entry.size)
684 # Fifth u-boot immediately afterwards
685 self.assertIn('u-boot-align-both', entries)
686 entry = entries['u-boot-align-both']
687 self.assertEqual(64, entry.offset)
688 self.assertEqual(64, entry.size)
690 self.CheckNoGaps(entries)
691 self.assertEqual(128, image._size)
693 def testPackAlignPowerOf2(self):
694 """Test that invalid entry alignment is detected"""
695 with self.assertRaises(ValueError) as e:
696 self._DoTestFile('010_pack_align_power2.dts')
697 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
698 "of two", str(e.exception))
700 def testPackAlignSizePowerOf2(self):
701 """Test that invalid entry size alignment is detected"""
702 with self.assertRaises(ValueError) as e:
703 self._DoTestFile('011_pack_align_size_power2.dts')
704 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
705 "power of two", str(e.exception))
707 def testPackInvalidAlign(self):
708 """Test detection of an offset that does not match its alignment"""
709 with self.assertRaises(ValueError) as e:
710 self._DoTestFile('012_pack_inv_align.dts')
711 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
712 "align 0x4 (4)", str(e.exception))
714 def testPackInvalidSizeAlign(self):
715 """Test that invalid entry size alignment is detected"""
716 with self.assertRaises(ValueError) as e:
717 self._DoTestFile('013_pack_inv_size_align.dts')
718 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
719 "align-size 0x4 (4)", str(e.exception))
721 def testPackOverlap(self):
722 """Test that overlapping regions are detected"""
723 with self.assertRaises(ValueError) as e:
724 self._DoTestFile('014_pack_overlap.dts')
725 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
726 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
729 def testPackEntryOverflow(self):
730 """Test that entries that overflow their size are detected"""
731 with self.assertRaises(ValueError) as e:
732 self._DoTestFile('015_pack_overflow.dts')
733 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
734 "but entry size is 0x3 (3)", str(e.exception))
736 def testPackImageOverflow(self):
737 """Test that entries which overflow the image size are detected"""
738 with self.assertRaises(ValueError) as e:
739 self._DoTestFile('016_pack_image_overflow.dts')
740 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
741 "size 0x3 (3)", str(e.exception))
743 def testPackImageSize(self):
744 """Test that the image size can be set"""
745 retcode = self._DoTestFile('017_pack_image_size.dts')
746 self.assertEqual(0, retcode)
747 self.assertIn('image', control.images)
748 image = control.images['image']
749 self.assertEqual(7, image._size)
751 def testPackImageSizeAlign(self):
752 """Test that image size alignemnt works as expected"""
753 retcode = self._DoTestFile('018_pack_image_align.dts')
754 self.assertEqual(0, retcode)
755 self.assertIn('image', control.images)
756 image = control.images['image']
757 self.assertEqual(16, image._size)
759 def testPackInvalidImageAlign(self):
760 """Test that invalid image alignment is detected"""
761 with self.assertRaises(ValueError) as e:
762 self._DoTestFile('019_pack_inv_image_align.dts')
763 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
764 "align-size 0x8 (8)", str(e.exception))
766 def testPackAlignPowerOf2(self):
767 """Test that invalid image alignment is detected"""
768 with self.assertRaises(ValueError) as e:
769 self._DoTestFile('020_pack_inv_image_align_power2.dts')
770 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
771 "two", str(e.exception))
773 def testImagePadByte(self):
774 """Test that the image pad byte can be specified"""
776 data = self._DoReadFile('021_image_pad.dts')
777 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
780 def testImageName(self):
781 """Test that image files can be named"""
782 retcode = self._DoTestFile('022_image_name.dts')
783 self.assertEqual(0, retcode)
784 image = control.images['image1']
785 fname = tools.GetOutputFilename('test-name')
786 self.assertTrue(os.path.exists(fname))
788 image = control.images['image2']
789 fname = tools.GetOutputFilename('test-name.xx')
790 self.assertTrue(os.path.exists(fname))
792 def testBlobFilename(self):
793 """Test that generic blobs can be provided by filename"""
794 data = self._DoReadFile('023_blob.dts')
795 self.assertEqual(BLOB_DATA, data)
797 def testPackSorted(self):
798 """Test that entries can be sorted"""
800 data = self._DoReadFile('024_sorted.dts')
801 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
802 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
804 def testPackZeroOffset(self):
805 """Test that an entry at offset 0 is not given a new offset"""
806 with self.assertRaises(ValueError) as e:
807 self._DoTestFile('025_pack_zero_size.dts')
808 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
809 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
812 def testPackUbootDtb(self):
813 """Test that a device tree can be added to U-Boot"""
814 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
815 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
817 def testPackX86RomNoSize(self):
818 """Test that the end-at-4gb property requires a size property"""
819 with self.assertRaises(ValueError) as e:
820 self._DoTestFile('027_pack_4gb_no_size.dts')
821 self.assertIn("Section '/binman': Section size must be provided when "
822 "using end-at-4gb", str(e.exception))
824 def test4gbAndSkipAtStartTogether(self):
825 """Test that the end-at-4gb and skip-at-size property can't be used
827 with self.assertRaises(ValueError) as e:
828 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
829 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
830 "'skip-at-start'", str(e.exception))
832 def testPackX86RomOutside(self):
833 """Test that the end-at-4gb property checks for offset boundaries"""
834 with self.assertRaises(ValueError) as e:
835 self._DoTestFile('028_pack_4gb_outside.dts')
836 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
837 "the section starting at 0xffffffe0 (4294967264)",
840 def testPackX86Rom(self):
841 """Test that a basic x86 ROM can be created"""
843 data = self._DoReadFile('029_x86-rom.dts')
844 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
845 tools.GetBytes(0, 2), data)
847 def testPackX86RomMeNoDesc(self):
848 """Test that an invalid Intel descriptor entry is detected"""
849 TestFunctional._MakeInputFile('descriptor.bin', b'')
850 with self.assertRaises(ValueError) as e:
851 self._DoTestFile('031_x86-rom-me.dts')
852 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
855 def testPackX86RomBadDesc(self):
856 """Test that the Intel requires a descriptor entry"""
857 with self.assertRaises(ValueError) as e:
858 self._DoTestFile('030_x86-rom-me-no-desc.dts')
859 self.assertIn("Node '/binman/intel-me': No offset set with "
860 "offset-unset: should another entry provide this correct "
861 "offset?", str(e.exception))
863 def testPackX86RomMe(self):
864 """Test that an x86 ROM with an ME region can be created"""
865 data = self._DoReadFile('031_x86-rom-me.dts')
866 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
868 def testPackVga(self):
869 """Test that an image with a VGA binary can be created"""
870 data = self._DoReadFile('032_intel-vga.dts')
871 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
873 def testPackStart16(self):
874 """Test that an image with an x86 start16 region can be created"""
875 data = self._DoReadFile('033_x86-start16.dts')
876 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
878 def testPackPowerpcMpc85xxBootpgResetvec(self):
879 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
881 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
882 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
884 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
885 """Handle running a test for insertion of microcode
888 dts_fname: Name of test .dts file
889 nodtb_data: Data that we expect in the first section
890 ucode_second: True if the microsecond entry is second instead of
895 Contents of first region (U-Boot or SPL)
896 Offset and size components of microcode pointer, as inserted
897 in the above (two 4-byte words)
899 data = self._DoReadFile(dts_fname, True)
901 # Now check the device tree has no microcode
903 ucode_content = data[len(nodtb_data):]
904 ucode_pos = len(nodtb_data)
905 dtb_with_ucode = ucode_content[16:]
906 fdt_len = self.GetFdtLen(dtb_with_ucode)
908 dtb_with_ucode = data[len(nodtb_data):]
909 fdt_len = self.GetFdtLen(dtb_with_ucode)
910 ucode_content = dtb_with_ucode[fdt_len:]
911 ucode_pos = len(nodtb_data) + fdt_len
912 fname = tools.GetOutputFilename('test.dtb')
913 with open(fname, 'wb') as fd:
914 fd.write(dtb_with_ucode)
915 dtb = fdt.FdtScan(fname)
916 ucode = dtb.GetNode('/microcode')
917 self.assertTrue(ucode)
918 for node in ucode.subnodes:
919 self.assertFalse(node.props.get('data'))
921 # Check that the microcode appears immediately after the Fdt
922 # This matches the concatenation of the data properties in
923 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
924 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
926 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
928 # Check that the microcode pointer was inserted. It should match the
929 # expected offset and size
930 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
932 u_boot = data[:len(nodtb_data)]
933 return u_boot, pos_and_size
935 def testPackUbootMicrocode(self):
936 """Test that x86 microcode can be handled correctly
938 We expect to see the following in the image, in order:
939 u-boot-nodtb.bin with a microcode pointer inserted at the correct
941 u-boot.dtb with the microcode removed
944 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
946 self.assertEqual(b'nodtb with microcode' + pos_and_size +
947 b' somewhere in here', first)
949 def _RunPackUbootSingleMicrocode(self):
950 """Test that x86 microcode can be handled correctly
952 We expect to see the following in the image, in order:
953 u-boot-nodtb.bin with a microcode pointer inserted at the correct
955 u-boot.dtb with the microcode
956 an empty microcode region
958 # We need the libfdt library to run this test since only that allows
959 # finding the offset of a property. This is required by
960 # Entry_u_boot_dtb_with_ucode.ObtainContents().
961 data = self._DoReadFile('035_x86_single_ucode.dts', True)
963 second = data[len(U_BOOT_NODTB_DATA):]
965 fdt_len = self.GetFdtLen(second)
966 third = second[fdt_len:]
967 second = second[:fdt_len]
969 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
970 self.assertIn(ucode_data, second)
971 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
973 # Check that the microcode pointer was inserted. It should match the
974 # expected offset and size
975 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
977 first = data[:len(U_BOOT_NODTB_DATA)]
978 self.assertEqual(b'nodtb with microcode' + pos_and_size +
979 b' somewhere in here', first)
981 def testPackUbootSingleMicrocode(self):
982 """Test that x86 microcode can be handled correctly with fdt_normal.
984 self._RunPackUbootSingleMicrocode()
986 def testUBootImg(self):
987 """Test that u-boot.img can be put in a file"""
988 data = self._DoReadFile('036_u_boot_img.dts')
989 self.assertEqual(U_BOOT_IMG_DATA, data)
991 def testNoMicrocode(self):
992 """Test that a missing microcode region is detected"""
993 with self.assertRaises(ValueError) as e:
994 self._DoReadFile('037_x86_no_ucode.dts', True)
995 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
996 "node found in ", str(e.exception))
998 def testMicrocodeWithoutNode(self):
999 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1000 with self.assertRaises(ValueError) as e:
1001 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1002 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1003 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1005 def testMicrocodeWithoutNode2(self):
1006 """Test that a missing u-boot-ucode node is detected"""
1007 with self.assertRaises(ValueError) as e:
1008 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1009 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1010 "microcode region u-boot-ucode", str(e.exception))
1012 def testMicrocodeWithoutPtrInElf(self):
1013 """Test that a U-Boot binary without the microcode symbol is detected"""
1014 # ELF file without a '_dt_ucode_base_size' symbol
1016 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1017 TestFunctional._MakeInputFile('u-boot', fd.read())
1019 with self.assertRaises(ValueError) as e:
1020 self._RunPackUbootSingleMicrocode()
1021 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1022 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1025 # Put the original file back
1026 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1027 TestFunctional._MakeInputFile('u-boot', fd.read())
1029 def testMicrocodeNotInImage(self):
1030 """Test that microcode must be placed within the image"""
1031 with self.assertRaises(ValueError) as e:
1032 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1033 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1034 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1035 "section ranging from 00000000 to 0000002e", str(e.exception))
1037 def testWithoutMicrocode(self):
1038 """Test that we can cope with an image without microcode (e.g. qemu)"""
1039 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1040 TestFunctional._MakeInputFile('u-boot', fd.read())
1041 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1043 # Now check the device tree has no microcode
1044 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1045 second = data[len(U_BOOT_NODTB_DATA):]
1047 fdt_len = self.GetFdtLen(second)
1048 self.assertEqual(dtb, second[:fdt_len])
1050 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1051 third = data[used_len:]
1052 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1054 def testUnknownPosSize(self):
1055 """Test that microcode must be placed within the image"""
1056 with self.assertRaises(ValueError) as e:
1057 self._DoReadFile('041_unknown_pos_size.dts', True)
1058 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1059 "entry 'invalid-entry'", str(e.exception))
1061 def testPackFsp(self):
1062 """Test that an image with a FSP binary can be created"""
1063 data = self._DoReadFile('042_intel-fsp.dts')
1064 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1066 def testPackCmc(self):
1067 """Test that an image with a CMC binary can be created"""
1068 data = self._DoReadFile('043_intel-cmc.dts')
1069 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1071 def testPackVbt(self):
1072 """Test that an image with a VBT binary can be created"""
1073 data = self._DoReadFile('046_intel-vbt.dts')
1074 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1076 def testSplBssPad(self):
1077 """Test that we can pad SPL's BSS with zeros"""
1078 # ELF file with a '__bss_size' symbol
1080 data = self._DoReadFile('047_spl_bss_pad.dts')
1081 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1084 def testSplBssPadMissing(self):
1085 """Test that a missing symbol is detected"""
1086 self._SetupSplElf('u_boot_ucode_ptr')
1087 with self.assertRaises(ValueError) as e:
1088 self._DoReadFile('047_spl_bss_pad.dts')
1089 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1092 def testPackStart16Spl(self):
1093 """Test that an image with an x86 start16 SPL region can be created"""
1094 data = self._DoReadFile('048_x86-start16-spl.dts')
1095 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1097 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1098 """Helper function for microcode tests
1100 We expect to see the following in the image, in order:
1101 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1103 u-boot.dtb with the microcode removed
1107 dts: Device tree file to use for test
1108 ucode_second: True if the microsecond entry is second instead of
1111 self._SetupSplElf('u_boot_ucode_ptr')
1112 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1113 ucode_second=ucode_second)
1114 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1115 b'ter somewhere in here', first)
1117 def testPackUbootSplMicrocode(self):
1118 """Test that x86 microcode can be handled correctly in SPL"""
1119 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1121 def testPackUbootSplMicrocodeReorder(self):
1122 """Test that order doesn't matter for microcode entries
1124 This is the same as testPackUbootSplMicrocode but when we process the
1125 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1126 entry, so we reply on binman to try later.
1128 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1131 def testPackMrc(self):
1132 """Test that an image with an MRC binary can be created"""
1133 data = self._DoReadFile('050_intel_mrc.dts')
1134 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1136 def testSplDtb(self):
1137 """Test that an image with spl/u-boot-spl.dtb can be created"""
1138 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1139 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1141 def testSplNoDtb(self):
1142 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1143 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1144 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1146 def testSymbols(self):
1147 """Test binman can assign symbols embedded in U-Boot"""
1148 elf_fname = self.TestFile('u_boot_binman_syms')
1149 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1150 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1151 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1153 self._SetupSplElf('u_boot_binman_syms')
1154 data = self._DoReadFile('053_symbols.dts')
1155 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1156 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1157 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1158 U_BOOT_SPL_DATA[16:])
1159 self.assertEqual(expected, data)
1161 def testPackUnitAddress(self):
1162 """Test that we support multiple binaries with the same name"""
1163 data = self._DoReadFile('054_unit_address.dts')
1164 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1166 def testSections(self):
1167 """Basic test of sections"""
1168 data = self._DoReadFile('055_sections.dts')
1169 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1170 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1171 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1172 self.assertEqual(expected, data)
1175 """Tests outputting a map of the images"""
1176 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1177 self.assertEqual('''ImagePos Offset Size Name
1178 00000000 00000000 00000028 main-section
1179 00000000 00000000 00000010 section@0
1180 00000000 00000000 00000004 u-boot
1181 00000010 00000010 00000010 section@1
1182 00000010 00000000 00000004 u-boot
1183 00000020 00000020 00000004 section@2
1184 00000020 00000000 00000004 u-boot
1187 def testNamePrefix(self):
1188 """Tests that name prefixes are used"""
1189 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1190 self.assertEqual('''ImagePos Offset Size Name
1191 00000000 00000000 00000028 main-section
1192 00000000 00000000 00000010 section@0
1193 00000000 00000000 00000004 ro-u-boot
1194 00000010 00000010 00000010 section@1
1195 00000010 00000000 00000004 rw-u-boot
1198 def testUnknownContents(self):
1199 """Test that obtaining the contents works as expected"""
1200 with self.assertRaises(ValueError) as e:
1201 self._DoReadFile('057_unknown_contents.dts', True)
1202 self.assertIn("Section '/binman': Internal error: Could not complete "
1203 "processing of contents: remaining [<_testing.Entry__testing ",
1206 def testBadChangeSize(self):
1207 """Test that trying to change the size of an entry fails"""
1208 with self.assertRaises(ValueError) as e:
1209 self._DoReadFile('059_change_size.dts', True)
1210 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1211 '2 to 1', str(e.exception))
1213 def testUpdateFdt(self):
1214 """Test that we can update the device tree with offset/size info"""
1215 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1217 dtb = fdt.Fdt(out_dtb_fname)
1219 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
1223 '_testing:offset': 32,
1225 '_testing:image-pos': 32,
1226 'section@0/u-boot:offset': 0,
1227 'section@0/u-boot:size': len(U_BOOT_DATA),
1228 'section@0/u-boot:image-pos': 0,
1229 'section@0:offset': 0,
1230 'section@0:size': 16,
1231 'section@0:image-pos': 0,
1233 'section@1/u-boot:offset': 0,
1234 'section@1/u-boot:size': len(U_BOOT_DATA),
1235 'section@1/u-boot:image-pos': 16,
1236 'section@1:offset': 16,
1237 'section@1:size': 16,
1238 'section@1:image-pos': 16,
1242 def testUpdateFdtBad(self):
1243 """Test that we detect when ProcessFdt never completes"""
1244 with self.assertRaises(ValueError) as e:
1245 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1246 self.assertIn('Could not complete processing of Fdt: remaining '
1247 '[<_testing.Entry__testing', str(e.exception))
1249 def testEntryArgs(self):
1250 """Test passing arguments to entries from the command line"""
1252 'test-str-arg': 'test1',
1253 'test-int-arg': '456',
1255 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1256 self.assertIn('image', control.images)
1257 entry = control.images['image'].GetEntries()['_testing']
1258 self.assertEqual('test0', entry.test_str_fdt)
1259 self.assertEqual('test1', entry.test_str_arg)
1260 self.assertEqual(123, entry.test_int_fdt)
1261 self.assertEqual(456, entry.test_int_arg)
1263 def testEntryArgsMissing(self):
1264 """Test missing arguments and properties"""
1266 'test-int-arg': '456',
1268 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1269 entry = control.images['image'].GetEntries()['_testing']
1270 self.assertEqual('test0', entry.test_str_fdt)
1271 self.assertEqual(None, entry.test_str_arg)
1272 self.assertEqual(None, entry.test_int_fdt)
1273 self.assertEqual(456, entry.test_int_arg)
1275 def testEntryArgsRequired(self):
1276 """Test missing arguments and properties"""
1278 'test-int-arg': '456',
1280 with self.assertRaises(ValueError) as e:
1281 self._DoReadFileDtb('064_entry_args_required.dts')
1282 self.assertIn("Node '/binman/_testing': Missing required "
1283 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1286 def testEntryArgsInvalidFormat(self):
1287 """Test that an invalid entry-argument format is detected"""
1288 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
1289 with self.assertRaises(ValueError) as e:
1290 self._DoBinman(*args)
1291 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1293 def testEntryArgsInvalidInteger(self):
1294 """Test that an invalid entry-argument integer is detected"""
1296 'test-int-arg': 'abc',
1298 with self.assertRaises(ValueError) as e:
1299 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1300 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1301 "'test-int-arg' (value 'abc') to integer",
1304 def testEntryArgsInvalidDatatype(self):
1305 """Test that an invalid entry-argument datatype is detected
1307 This test could be written in entry_test.py except that it needs
1308 access to control.entry_args, which seems more than that module should
1312 'test-bad-datatype-arg': '12',
1314 with self.assertRaises(ValueError) as e:
1315 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1316 entry_args=entry_args)
1317 self.assertIn('GetArg() internal error: Unknown data type ',
1321 """Test for a text entry type"""
1323 'test-id': TEXT_DATA,
1324 'test-id2': TEXT_DATA2,
1325 'test-id3': TEXT_DATA3,
1327 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1328 entry_args=entry_args)
1329 expected = (tools.ToBytes(TEXT_DATA) +
1330 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1331 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1332 b'some text' + b'more text')
1333 self.assertEqual(expected, data)
1335 def testEntryDocs(self):
1336 """Test for creation of entry documentation"""
1337 with test_util.capture_sys_output() as (stdout, stderr):
1338 control.WriteEntryDocs(binman.GetEntryModules())
1339 self.assertTrue(len(stdout.getvalue()) > 0)
1341 def testEntryDocsMissing(self):
1342 """Test handling of missing entry documentation"""
1343 with self.assertRaises(ValueError) as e:
1344 with test_util.capture_sys_output() as (stdout, stderr):
1345 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1346 self.assertIn('Documentation is missing for modules: u_boot',
1350 """Basic test of generation of a flashrom fmap"""
1351 data = self._DoReadFile('067_fmap.dts')
1352 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1353 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1354 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1355 self.assertEqual(expected, data[:32])
1356 self.assertEqual(b'__FMAP__', fhdr.signature)
1357 self.assertEqual(1, fhdr.ver_major)
1358 self.assertEqual(0, fhdr.ver_minor)
1359 self.assertEqual(0, fhdr.base)
1360 self.assertEqual(16 + 16 +
1361 fmap_util.FMAP_HEADER_LEN +
1362 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1363 self.assertEqual(b'FMAP', fhdr.name)
1364 self.assertEqual(3, fhdr.nareas)
1365 for fentry in fentries:
1366 self.assertEqual(0, fentry.flags)
1368 self.assertEqual(0, fentries[0].offset)
1369 self.assertEqual(4, fentries[0].size)
1370 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1372 self.assertEqual(16, fentries[1].offset)
1373 self.assertEqual(4, fentries[1].size)
1374 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1376 self.assertEqual(32, fentries[2].offset)
1377 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1378 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1379 self.assertEqual(b'FMAP', fentries[2].name)
1381 def testBlobNamedByArg(self):
1382 """Test we can add a blob with the filename coming from an entry arg"""
1384 'cros-ec-rw-path': 'ecrw.bin',
1386 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1387 entry_args=entry_args)
1390 """Test for an fill entry type"""
1391 data = self._DoReadFile('069_fill.dts')
1392 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1393 self.assertEqual(expected, data)
1395 def testFillNoSize(self):
1396 """Test for an fill entry type with no size"""
1397 with self.assertRaises(ValueError) as e:
1398 self._DoReadFile('070_fill_no_size.dts')
1399 self.assertIn("'fill' entry must have a size property",
1402 def _HandleGbbCommand(self, pipe_list):
1403 """Fake calls to the futility utility"""
1404 if pipe_list[0][0] == 'futility':
1405 fname = pipe_list[0][-1]
1406 # Append our GBB data to the file, which will happen every time the
1407 # futility command is called.
1408 with open(fname, 'ab') as fd:
1410 return command.CommandResult()
1413 """Test for the Chromium OS Google Binary Block"""
1414 command.test_result = self._HandleGbbCommand
1416 'keydir': 'devkeys',
1417 'bmpblk': 'bmpblk.bin',
1419 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1422 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1423 tools.GetBytes(0, 0x2180 - 16))
1424 self.assertEqual(expected, data)
1426 def testGbbTooSmall(self):
1427 """Test for the Chromium OS Google Binary Block being large enough"""
1428 with self.assertRaises(ValueError) as e:
1429 self._DoReadFileDtb('072_gbb_too_small.dts')
1430 self.assertIn("Node '/binman/gbb': GBB is too small",
1433 def testGbbNoSize(self):
1434 """Test for the Chromium OS Google Binary Block having a size"""
1435 with self.assertRaises(ValueError) as e:
1436 self._DoReadFileDtb('073_gbb_no_size.dts')
1437 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1440 def _HandleVblockCommand(self, pipe_list):
1441 """Fake calls to the futility utility"""
1442 if pipe_list[0][0] == 'futility':
1443 fname = pipe_list[0][3]
1444 with open(fname, 'wb') as fd:
1445 fd.write(VBLOCK_DATA)
1446 return command.CommandResult()
1448 def testVblock(self):
1449 """Test for the Chromium OS Verified Boot Block"""
1450 command.test_result = self._HandleVblockCommand
1452 'keydir': 'devkeys',
1454 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1455 entry_args=entry_args)
1456 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1457 self.assertEqual(expected, data)
1459 def testVblockNoContent(self):
1460 """Test we detect a vblock which has no content to sign"""
1461 with self.assertRaises(ValueError) as e:
1462 self._DoReadFile('075_vblock_no_content.dts')
1463 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1464 'property', str(e.exception))
1466 def testVblockBadPhandle(self):
1467 """Test that we detect a vblock with an invalid phandle in contents"""
1468 with self.assertRaises(ValueError) as e:
1469 self._DoReadFile('076_vblock_bad_phandle.dts')
1470 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1471 '1000', str(e.exception))
1473 def testVblockBadEntry(self):
1474 """Test that we detect an entry that points to a non-entry"""
1475 with self.assertRaises(ValueError) as e:
1476 self._DoReadFile('077_vblock_bad_entry.dts')
1477 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1478 "'other'", str(e.exception))
1481 """Test that an image with TPL and ots device tree can be created"""
1482 # ELF file with a '__bss_size' symbol
1483 with open(self.TestFile('bss_data'), 'rb') as fd:
1484 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1485 data = self._DoReadFile('078_u_boot_tpl.dts')
1486 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1488 def testUsesPos(self):
1489 """Test that the 'pos' property cannot be used anymore"""
1490 with self.assertRaises(ValueError) as e:
1491 data = self._DoReadFile('079_uses_pos.dts')
1492 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1493 "'pos'", str(e.exception))
1495 def testFillZero(self):
1496 """Test for an fill entry type with a size of 0"""
1497 data = self._DoReadFile('080_fill_empty.dts')
1498 self.assertEqual(tools.GetBytes(0, 16), data)
1500 def testTextMissing(self):
1501 """Test for a text entry type where there is no text"""
1502 with self.assertRaises(ValueError) as e:
1503 self._DoReadFileDtb('066_text.dts',)
1504 self.assertIn("Node '/binman/text': No value provided for text label "
1505 "'test-id'", str(e.exception))
1507 def testPackStart16Tpl(self):
1508 """Test that an image with an x86 start16 TPL region can be created"""
1509 data = self._DoReadFile('081_x86-start16-tpl.dts')
1510 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1512 def testSelectImage(self):
1513 """Test that we can select which images to build"""
1514 expected = 'Skipping images: image1'
1516 # We should only get the expected message in verbose mode
1517 for verbosity in (0, 2):
1518 with test_util.capture_sys_output() as (stdout, stderr):
1519 retcode = self._DoTestFile('006_dual_image.dts',
1520 verbosity=verbosity,
1522 self.assertEqual(0, retcode)
1524 self.assertIn(expected, stdout.getvalue())
1526 self.assertNotIn(expected, stdout.getvalue())
1528 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1529 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1531 def testUpdateFdtAll(self):
1532 """Test that all device trees are updated with offset/size info"""
1533 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1534 use_real_dtb=True, update_dtb=True)
1537 'section:image-pos': 0,
1538 'u-boot-tpl-dtb:size': 513,
1539 'u-boot-spl-dtb:size': 513,
1540 'u-boot-spl-dtb:offset': 493,
1542 'section/u-boot-dtb:image-pos': 0,
1543 'u-boot-spl-dtb:image-pos': 493,
1544 'section/u-boot-dtb:size': 493,
1545 'u-boot-tpl-dtb:image-pos': 1006,
1546 'section/u-boot-dtb:offset': 0,
1547 'section:size': 493,
1549 'section:offset': 0,
1550 'u-boot-tpl-dtb:offset': 1006,
1554 # We expect three device-tree files in the output, one after the other.
1555 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1556 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1557 # main U-Boot tree. All three should have the same postions and offset.
1559 for item in ['', 'spl', 'tpl']:
1560 dtb = fdt.Fdt.FromData(data[start:])
1562 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1564 expected = dict(base_expected)
1567 self.assertEqual(expected, props)
1568 start += dtb._fdt_obj.totalsize()
1570 def testUpdateFdtOutput(self):
1571 """Test that output DTB files are updated"""
1573 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1574 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1576 # Unfortunately, compiling a source file always results in a file
1577 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1578 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1579 # binman as a file called u-boot.dtb. To fix this, copy the file
1580 # over to the expected place.
1581 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1582 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1584 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1585 'tpl/u-boot-tpl.dtb.out']:
1586 dtb = fdt.Fdt.FromData(data[start:])
1587 size = dtb._fdt_obj.totalsize()
1588 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1589 outdata = tools.ReadFile(pathname)
1590 name = os.path.split(fname)[0]
1593 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1595 orig_indata = dtb_data
1596 self.assertNotEqual(outdata, orig_indata,
1597 "Expected output file '%s' be updated" % pathname)
1598 self.assertEqual(outdata, data[start:start + size],
1599 "Expected output file '%s' to match output image" %
1605 def _decompress(self, data):
1606 return tools.Decompress(data, 'lz4')
1608 def testCompress(self):
1609 """Test compression of blobs"""
1610 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1611 use_real_dtb=True, update_dtb=True)
1612 dtb = fdt.Fdt(out_dtb_fname)
1614 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1615 orig = self._decompress(data)
1616 self.assertEquals(COMPRESS_DATA, orig)
1618 'blob:uncomp-size': len(COMPRESS_DATA),
1619 'blob:size': len(data),
1622 self.assertEqual(expected, props)
1624 def testFiles(self):
1625 """Test bringing in multiple files"""
1626 data = self._DoReadFile('084_files.dts')
1627 self.assertEqual(FILES_DATA, data)
1629 def testFilesCompress(self):
1630 """Test bringing in multiple files and compressing them"""
1631 data = self._DoReadFile('085_files_compress.dts')
1633 image = control.images['image']
1634 entries = image.GetEntries()
1635 files = entries['files']
1636 entries = files._section._entries
1639 for i in range(1, 3):
1641 start = entries[key].image_pos
1642 len = entries[key].size
1643 chunk = data[start:start + len]
1644 orig += self._decompress(chunk)
1646 self.assertEqual(FILES_DATA, orig)
1648 def testFilesMissing(self):
1649 """Test missing files"""
1650 with self.assertRaises(ValueError) as e:
1651 data = self._DoReadFile('086_files_none.dts')
1652 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1653 'no files', str(e.exception))
1655 def testFilesNoPattern(self):
1656 """Test missing files"""
1657 with self.assertRaises(ValueError) as e:
1658 data = self._DoReadFile('087_files_no_pattern.dts')
1659 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1662 def testExpandSize(self):
1663 """Test an expanding entry"""
1664 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1666 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1667 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1668 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1669 tools.GetBytes(ord('d'), 8))
1670 self.assertEqual(expect, data)
1671 self.assertEqual('''ImagePos Offset Size Name
1672 00000000 00000000 00000028 main-section
1673 00000000 00000000 00000008 fill
1674 00000008 00000008 00000004 u-boot
1675 0000000c 0000000c 00000004 section
1676 0000000c 00000000 00000003 intel-mrc
1677 00000010 00000010 00000004 u-boot2
1678 00000014 00000014 0000000c section2
1679 00000014 00000000 00000008 fill
1680 0000001c 00000008 00000004 u-boot
1681 00000020 00000020 00000008 fill2
1684 def testExpandSizeBad(self):
1685 """Test an expanding entry which fails to provide contents"""
1686 with test_util.capture_sys_output() as (stdout, stderr):
1687 with self.assertRaises(ValueError) as e:
1688 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1689 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1690 'expanding entry', str(e.exception))
1693 """Test hashing of the contents of an entry"""
1694 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1695 use_real_dtb=True, update_dtb=True)
1696 dtb = fdt.Fdt(out_dtb_fname)
1698 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1699 m = hashlib.sha256()
1700 m.update(U_BOOT_DATA)
1701 self.assertEqual(m.digest(), b''.join(hash_node.value))
1703 def testHashNoAlgo(self):
1704 with self.assertRaises(ValueError) as e:
1705 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1706 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1707 'hash node', str(e.exception))
1709 def testHashBadAlgo(self):
1710 with self.assertRaises(ValueError) as e:
1711 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1712 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1715 def testHashSection(self):
1716 """Test hashing of the contents of an entry"""
1717 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1718 use_real_dtb=True, update_dtb=True)
1719 dtb = fdt.Fdt(out_dtb_fname)
1721 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1722 m = hashlib.sha256()
1723 m.update(U_BOOT_DATA)
1724 m.update(tools.GetBytes(ord('a'), 16))
1725 self.assertEqual(m.digest(), b''.join(hash_node.value))
1727 def testPackUBootTplMicrocode(self):
1728 """Test that x86 microcode can be handled correctly in TPL
1730 We expect to see the following in the image, in order:
1731 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1733 u-boot-tpl.dtb with the microcode removed
1736 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1737 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1738 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1739 U_BOOT_TPL_NODTB_DATA)
1740 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1741 b'ter somewhere in here', first)
1743 def testFmapX86(self):
1744 """Basic test of generation of a flashrom fmap"""
1745 data = self._DoReadFile('094_fmap_x86.dts')
1746 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1747 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1748 self.assertEqual(expected, data[:32])
1749 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1751 self.assertEqual(0x100, fhdr.image_size)
1753 self.assertEqual(0, fentries[0].offset)
1754 self.assertEqual(4, fentries[0].size)
1755 self.assertEqual(b'U_BOOT', fentries[0].name)
1757 self.assertEqual(4, fentries[1].offset)
1758 self.assertEqual(3, fentries[1].size)
1759 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1761 self.assertEqual(32, fentries[2].offset)
1762 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1763 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1764 self.assertEqual(b'FMAP', fentries[2].name)
1766 def testFmapX86Section(self):
1767 """Basic test of generation of a flashrom fmap"""
1768 data = self._DoReadFile('095_fmap_x86_section.dts')
1769 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1770 self.assertEqual(expected, data[:32])
1771 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1773 self.assertEqual(0x100, fhdr.image_size)
1775 self.assertEqual(0, fentries[0].offset)
1776 self.assertEqual(4, fentries[0].size)
1777 self.assertEqual(b'U_BOOT', fentries[0].name)
1779 self.assertEqual(4, fentries[1].offset)
1780 self.assertEqual(3, fentries[1].size)
1781 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1783 self.assertEqual(36, fentries[2].offset)
1784 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1785 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1786 self.assertEqual(b'FMAP', fentries[2].name)
1789 """Basic test of ELF entries"""
1791 with open(self.TestFile('bss_data'), 'rb') as fd:
1792 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1793 with open(self.TestFile('bss_data'), 'rb') as fd:
1794 TestFunctional._MakeInputFile('-boot', fd.read())
1795 data = self._DoReadFile('096_elf.dts')
1797 def testElfStrip(self):
1798 """Basic test of ELF entries"""
1800 with open(self.TestFile('bss_data'), 'rb') as fd:
1801 TestFunctional._MakeInputFile('-boot', fd.read())
1802 data = self._DoReadFile('097_elf_strip.dts')
1804 def testPackOverlapMap(self):
1805 """Test that overlapping regions are detected"""
1806 with test_util.capture_sys_output() as (stdout, stderr):
1807 with self.assertRaises(ValueError) as e:
1808 self._DoTestFile('014_pack_overlap.dts', map=True)
1809 map_fname = tools.GetOutputFilename('image.map')
1810 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1813 # We should not get an inmage, but there should be a map file
1814 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1815 self.assertTrue(os.path.exists(map_fname))
1816 map_data = tools.ReadFile(map_fname, binary=False)
1817 self.assertEqual('''ImagePos Offset Size Name
1818 <none> 00000000 00000007 main-section
1819 <none> 00000000 00000004 u-boot
1820 <none> 00000003 00000004 u-boot-align
1823 def testPackRefCode(self):
1824 """Test that an image with an Intel Reference code binary works"""
1825 data = self._DoReadFile('100_intel_refcode.dts')
1826 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1828 def testSectionOffset(self):
1829 """Tests use of a section with an offset"""
1830 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1832 self.assertEqual('''ImagePos Offset Size Name
1833 00000000 00000000 00000038 main-section
1834 00000004 00000004 00000010 section@0
1835 00000004 00000000 00000004 u-boot
1836 00000018 00000018 00000010 section@1
1837 00000018 00000000 00000004 u-boot
1838 0000002c 0000002c 00000004 section@2
1839 0000002c 00000000 00000004 u-boot
1841 self.assertEqual(data,
1842 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1843 tools.GetBytes(0x21, 12) +
1844 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1845 tools.GetBytes(0x61, 12) +
1846 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1847 tools.GetBytes(0x26, 8))
1850 if __name__ == "__main__":