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
27 from etype import fdtmap
28 from etype import image_header
33 from image import Image
38 # Contents of test files, corresponding to different entry types
40 U_BOOT_IMG_DATA = b'img'
41 U_BOOT_SPL_DATA = b'56780123456789abcde'
42 U_BOOT_TPL_DATA = b'tpl'
46 U_BOOT_DTB_DATA = b'udtb'
47 U_BOOT_SPL_DTB_DATA = b'spldtb'
48 U_BOOT_TPL_DTB_DATA = b'tpldtb'
49 X86_START16_DATA = b'start16'
50 X86_START16_SPL_DATA = b'start16spl'
51 X86_START16_TPL_DATA = b'start16tpl'
52 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
53 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
54 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
55 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
63 CROS_EC_RW_DATA = b'ecrw'
67 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
68 b"sorry you're alive\n")
69 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
70 REFCODE_DATA = b'refcode'
72 # The expected size for the device tree in some tests
73 EXTRACT_DTB_SIZE = 0x3c9
75 # Properties expected to be in the device tree when update_dtb is used
76 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
78 # Extra properties expected to be in the device tree when allow-repack is used
79 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
82 class TestFunctional(unittest.TestCase):
83 """Functional tests for binman
85 Most of these use a sample .dts file to build an image and then check
86 that it looks correct. The sample files are in the test/ subdirectory
89 For each entry type a very small test file is created using fixed
90 string contents. This makes it easy to test that things look right, and
93 In some cases a 'real' file must be used - these are also supplied in
101 # Handle the case where argv[0] is 'python'
102 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
103 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
105 # Create a temporary directory for input files
106 self._indir = tempfile.mkdtemp(prefix='binmant.')
108 # Create some test files
109 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
110 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
111 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
112 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
113 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
114 TestFunctional._MakeInputFile('me.bin', ME_DATA)
115 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
117 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
118 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
119 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
120 X86_START16_SPL_DATA)
121 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
122 X86_START16_TPL_DATA)
123 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
124 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
125 U_BOOT_SPL_NODTB_DATA)
126 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
127 U_BOOT_TPL_NODTB_DATA)
128 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
129 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
130 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
131 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
132 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
133 TestFunctional._MakeInputDir('devkeys')
134 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
135 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
137 # ELF file with a '_dt_ucode_base_size' symbol
138 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
139 TestFunctional._MakeInputFile('u-boot', fd.read())
141 # Intel flash descriptor file
142 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
143 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
145 shutil.copytree(self.TestFile('files'),
146 os.path.join(self._indir, 'files'))
148 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
150 # Travis-CI may have an old lz4
153 tools.Run('lz4', '--no-frame-crc', '-c',
154 os.path.join(self._indir, 'u-boot.bin'))
156 self.have_lz4 = False
159 def tearDownClass(self):
160 """Remove the temporary input directory and its contents"""
161 if self.preserve_indir:
162 print('Preserving input dir: %s' % self._indir)
165 shutil.rmtree(self._indir)
169 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
170 toolpath=None, verbosity=None):
171 """Accept arguments controlling test execution
174 preserve_indir: Preserve the shared input directory used by all
176 preserve_outdir: Preserve the output directories used by tests. Each
177 test has its own, so this is normally only useful when running a
179 toolpath: ist of paths to use for tools
181 cls.preserve_indir = preserve_indir
182 cls.preserve_outdirs = preserve_outdirs
183 cls.toolpath = toolpath
184 cls.verbosity = verbosity
187 if not self.have_lz4:
188 self.skipTest('lz4 --no-frame-crc not available')
191 # Enable this to turn on debugging output
192 # tout.Init(tout.DEBUG)
193 command.test_result = None
196 """Remove the temporary output directory"""
197 if self.preserve_outdirs:
198 print('Preserving output dir: %s' % tools.outdir)
200 tools._FinaliseForTest()
203 def _ResetDtbs(self):
204 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
205 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
206 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
208 def _RunBinman(self, *args, **kwargs):
209 """Run binman using the command line
212 Arguments to pass, as a list of strings
213 kwargs: Arguments to pass to Command.RunPipe()
215 result = command.RunPipe([[self._binman_pathname] + list(args)],
216 capture=True, capture_stderr=True, raise_on_error=False)
217 if result.return_code and kwargs.get('raise_on_error', True):
218 raise Exception("Error running '%s': %s" % (' '.join(args),
219 result.stdout + result.stderr))
222 def _DoBinman(self, *argv):
223 """Run binman using directly (in the same process)
226 Arguments to pass, as a list of strings
228 Return value (0 for success)
231 args = cmdline.ParseArgs(argv)
232 args.pager = 'binman-invalid-pager'
233 args.build_dir = self._indir
235 # For testing, you can force an increase in verbosity here
236 # args.verbosity = tout.DEBUG
237 return control.Binman(args)
239 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
240 entry_args=None, images=None, use_real_dtb=False,
242 """Run binman with a given test file
245 fname: Device-tree source filename to use (e.g. 005_simple.dts)
246 debug: True to enable debugging output
247 map: True to output map files for the images
248 update_dtb: Update the offset and size of each entry in the device
249 tree before packing it into the image
250 entry_args: Dict of entry args to supply to binman
252 value: value of that arg
253 images: List of image names to build
258 if verbosity is not None:
259 args.append('-v%d' % verbosity)
261 args.append('-v%d' % self.verbosity)
263 for path in self.toolpath:
264 args += ['--toolpath', path]
265 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
271 args.append('--fake-dtb')
273 for arg, value in entry_args.items():
274 args.append('-a%s=%s' % (arg, value))
277 args += ['-i', image]
278 return self._DoBinman(*args)
280 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
281 """Set up a new test device-tree file
283 The given file is compiled and set up as the device tree to be used
287 fname: Filename of .dts file to read
288 outfile: Output filename for compiled device-tree binary
291 Contents of device-tree binary
293 tmpdir = tempfile.mkdtemp(prefix='binmant.')
294 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
295 with open(dtb, 'rb') as fd:
297 TestFunctional._MakeInputFile(outfile, data)
298 shutil.rmtree(tmpdir)
301 def _GetDtbContentsForSplTpl(self, dtb_data, name):
302 """Create a version of the main DTB for SPL or SPL
304 For testing we don't actually have different versions of the DTB. With
305 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
306 we don't normally have any unwanted nodes.
308 We still want the DTBs for SPL and TPL to be different though, since
309 otherwise it is confusing to know which one we are looking at. So add
310 an 'spl' or 'tpl' property to the top-level node.
312 dtb = fdt.Fdt.FromData(dtb_data)
314 dtb.GetNode('/binman').AddZeroProp(name)
315 dtb.Sync(auto_resize=True)
317 return dtb.GetContents()
319 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
320 update_dtb=False, entry_args=None, reset_dtbs=True):
321 """Run binman and return the resulting image
323 This runs binman with a given test file and then reads the resulting
324 output file. It is a shortcut function since most tests need to do
327 Raises an assertion failure if binman returns a non-zero exit code.
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.
335 map: True to output map files for the images
336 update_dtb: Update the offset and size of each entry in the device
337 tree before packing it into the image
341 Resulting image contents
343 Map data showing contents of image (or None if none)
344 Output device tree binary filename ('u-boot.dtb' path)
347 # Use the compiled test file as the u-boot-dtb input
349 dtb_data = self._SetupDtb(fname)
351 # For testing purposes, make a copy of the DT for SPL and TPL. Add
352 # a node indicating which it is, so aid verification.
353 for name in ['spl', 'tpl']:
354 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
355 outfile = os.path.join(self._indir, dtb_fname)
356 TestFunctional._MakeInputFile(dtb_fname,
357 self._GetDtbContentsForSplTpl(dtb_data, name))
360 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
361 entry_args=entry_args, use_real_dtb=use_real_dtb)
362 self.assertEqual(0, retcode)
363 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
365 # Find the (only) image, read it and return its contents
366 image = control.images['image']
367 image_fname = tools.GetOutputFilename('image.bin')
368 self.assertTrue(os.path.exists(image_fname))
370 map_fname = tools.GetOutputFilename('image.map')
371 with open(map_fname) as fd:
375 with open(image_fname, 'rb') as fd:
376 return fd.read(), dtb_data, map_data, out_dtb_fname
378 # Put the test file back
379 if reset_dtbs and use_real_dtb:
382 def _DoReadFileRealDtb(self, fname):
383 """Run binman with a real .dtb file and return the resulting data
386 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
389 Resulting image contents
391 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
393 def _DoReadFile(self, fname, use_real_dtb=False):
394 """Helper function which discards the device-tree binary
397 fname: Device-tree source filename to use (e.g. 005_simple.dts)
398 use_real_dtb: True to use the test file as the contents of
399 the u-boot-dtb entry. Normally this is not needed and the
400 test contents (the U_BOOT_DTB_DATA string) can be used.
401 But in some test we need the real contents.
404 Resulting image contents
406 return self._DoReadFileDtb(fname, use_real_dtb)[0]
409 def _MakeInputFile(self, fname, contents):
410 """Create a new test input file, creating directories as needed
413 fname: Filename to create
414 contents: File contents to write in to the file
416 Full pathname of file created
418 pathname = os.path.join(self._indir, fname)
419 dirname = os.path.dirname(pathname)
420 if dirname and not os.path.exists(dirname):
422 with open(pathname, 'wb') as fd:
427 def _MakeInputDir(self, dirname):
428 """Create a new test input directory, creating directories as needed
431 dirname: Directory name to create
434 Full pathname of directory created
436 pathname = os.path.join(self._indir, dirname)
437 if not os.path.exists(pathname):
438 os.makedirs(pathname)
442 def _SetupSplElf(self, src_fname='bss_data'):
443 """Set up an ELF file with a '_dt_ucode_base_size' symbol
446 Filename of ELF file to use as SPL
448 with open(self.TestFile(src_fname), 'rb') as fd:
449 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
452 def TestFile(self, fname):
453 return os.path.join(self._binman_dir, 'test', fname)
455 def AssertInList(self, grep_list, target):
456 """Assert that at least one of a list of things is in a target
459 grep_list: List of strings to check
460 target: Target string
462 for grep in grep_list:
465 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
467 def CheckNoGaps(self, entries):
468 """Check that all entries fit together without gaps
471 entries: List of entries to check
474 for entry in entries.values():
475 self.assertEqual(offset, entry.offset)
478 def GetFdtLen(self, dtb):
479 """Get the totalsize field from a device-tree binary
482 dtb: Device-tree binary contents
485 Total size of device-tree binary, from the header
487 return struct.unpack('>L', dtb[4:8])[0]
489 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
490 def AddNode(node, path):
492 path += '/' + node.name
493 for prop in node.props.values():
494 if prop.name in prop_names:
495 prop_path = path + ':' + prop.name
496 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
498 for subnode in node.subnodes:
499 AddNode(subnode, path)
502 AddNode(dtb.GetRoot(), '')
506 """Test a basic run with valid args"""
507 result = self._RunBinman('-h')
509 def testFullHelp(self):
510 """Test that the full help is displayed with -H"""
511 result = self._RunBinman('-H')
512 help_file = os.path.join(self._binman_dir, 'README')
513 # Remove possible extraneous strings
514 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
515 gothelp = result.stdout.replace(extra, '')
516 self.assertEqual(len(gothelp), os.path.getsize(help_file))
517 self.assertEqual(0, len(result.stderr))
518 self.assertEqual(0, result.return_code)
520 def testFullHelpInternal(self):
521 """Test that the full help is displayed with -H"""
523 command.test_result = command.CommandResult()
524 result = self._DoBinman('-H')
525 help_file = os.path.join(self._binman_dir, 'README')
527 command.test_result = None
530 """Test that the basic help is displayed with -h"""
531 result = self._RunBinman('-h')
532 self.assertTrue(len(result.stdout) > 200)
533 self.assertEqual(0, len(result.stderr))
534 self.assertEqual(0, result.return_code)
537 """Test that we can run it with a specific board"""
538 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
539 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
540 result = self._DoBinman('build', '-b', 'sandbox')
541 self.assertEqual(0, result)
543 def testNeedBoard(self):
544 """Test that we get an error when no board ius supplied"""
545 with self.assertRaises(ValueError) as e:
546 result = self._DoBinman('build')
547 self.assertIn("Must provide a board to process (use -b <board>)",
550 def testMissingDt(self):
551 """Test that an invalid device-tree file generates an error"""
552 with self.assertRaises(Exception) as e:
553 self._RunBinman('build', '-d', 'missing_file')
554 # We get one error from libfdt, and a different one from fdtget.
555 self.AssertInList(["Couldn't open blob from 'missing_file'",
556 'No such file or directory'], str(e.exception))
558 def testBrokenDt(self):
559 """Test that an invalid device-tree source file generates an error
561 Since this is a source file it should be compiled and the error
562 will come from the device-tree compiler (dtc).
564 with self.assertRaises(Exception) as e:
565 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
566 self.assertIn("FATAL ERROR: Unable to parse input tree",
569 def testMissingNode(self):
570 """Test that a device tree without a 'binman' node generates an error"""
571 with self.assertRaises(Exception) as e:
572 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
573 self.assertIn("does not have a 'binman' node", str(e.exception))
576 """Test that an empty binman node works OK (i.e. does nothing)"""
577 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
578 self.assertEqual(0, len(result.stderr))
579 self.assertEqual(0, result.return_code)
581 def testInvalidEntry(self):
582 """Test that an invalid entry is flagged"""
583 with self.assertRaises(Exception) as e:
584 result = self._RunBinman('build', '-d',
585 self.TestFile('004_invalid_entry.dts'))
586 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
587 "'/binman/not-a-valid-type'", str(e.exception))
589 def testSimple(self):
590 """Test a simple binman with a single file"""
591 data = self._DoReadFile('005_simple.dts')
592 self.assertEqual(U_BOOT_DATA, data)
594 def testSimpleDebug(self):
595 """Test a simple binman run with debugging enabled"""
596 self._DoTestFile('005_simple.dts', debug=True)
599 """Test that we can handle creating two images
601 This also tests image padding.
603 retcode = self._DoTestFile('006_dual_image.dts')
604 self.assertEqual(0, retcode)
606 image = control.images['image1']
607 self.assertEqual(len(U_BOOT_DATA), image.size)
608 fname = tools.GetOutputFilename('image1.bin')
609 self.assertTrue(os.path.exists(fname))
610 with open(fname, 'rb') as fd:
612 self.assertEqual(U_BOOT_DATA, data)
614 image = control.images['image2']
615 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
616 fname = tools.GetOutputFilename('image2.bin')
617 self.assertTrue(os.path.exists(fname))
618 with open(fname, 'rb') as fd:
620 self.assertEqual(U_BOOT_DATA, data[3:7])
621 self.assertEqual(tools.GetBytes(0, 3), data[:3])
622 self.assertEqual(tools.GetBytes(0, 5), data[7:])
624 def testBadAlign(self):
625 """Test that an invalid alignment value is detected"""
626 with self.assertRaises(ValueError) as e:
627 self._DoTestFile('007_bad_align.dts')
628 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
629 "of two", str(e.exception))
631 def testPackSimple(self):
632 """Test that packing works as expected"""
633 retcode = self._DoTestFile('008_pack.dts')
634 self.assertEqual(0, retcode)
635 self.assertIn('image', control.images)
636 image = control.images['image']
637 entries = image.GetEntries()
638 self.assertEqual(5, len(entries))
641 self.assertIn('u-boot', entries)
642 entry = entries['u-boot']
643 self.assertEqual(0, entry.offset)
644 self.assertEqual(len(U_BOOT_DATA), entry.size)
646 # Second u-boot, aligned to 16-byte boundary
647 self.assertIn('u-boot-align', entries)
648 entry = entries['u-boot-align']
649 self.assertEqual(16, entry.offset)
650 self.assertEqual(len(U_BOOT_DATA), entry.size)
652 # Third u-boot, size 23 bytes
653 self.assertIn('u-boot-size', entries)
654 entry = entries['u-boot-size']
655 self.assertEqual(20, entry.offset)
656 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
657 self.assertEqual(23, entry.size)
659 # Fourth u-boot, placed immediate after the above
660 self.assertIn('u-boot-next', entries)
661 entry = entries['u-boot-next']
662 self.assertEqual(43, entry.offset)
663 self.assertEqual(len(U_BOOT_DATA), entry.size)
665 # Fifth u-boot, placed at a fixed offset
666 self.assertIn('u-boot-fixed', entries)
667 entry = entries['u-boot-fixed']
668 self.assertEqual(61, entry.offset)
669 self.assertEqual(len(U_BOOT_DATA), entry.size)
671 self.assertEqual(65, image.size)
673 def testPackExtra(self):
674 """Test that extra packing feature works as expected"""
675 retcode = self._DoTestFile('009_pack_extra.dts')
677 self.assertEqual(0, retcode)
678 self.assertIn('image', control.images)
679 image = control.images['image']
680 entries = image.GetEntries()
681 self.assertEqual(5, len(entries))
683 # First u-boot with padding before and after
684 self.assertIn('u-boot', entries)
685 entry = entries['u-boot']
686 self.assertEqual(0, entry.offset)
687 self.assertEqual(3, entry.pad_before)
688 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
690 # Second u-boot has an aligned size, but it has no effect
691 self.assertIn('u-boot-align-size-nop', entries)
692 entry = entries['u-boot-align-size-nop']
693 self.assertEqual(12, entry.offset)
694 self.assertEqual(4, entry.size)
696 # Third u-boot has an aligned size too
697 self.assertIn('u-boot-align-size', entries)
698 entry = entries['u-boot-align-size']
699 self.assertEqual(16, entry.offset)
700 self.assertEqual(32, entry.size)
702 # Fourth u-boot has an aligned end
703 self.assertIn('u-boot-align-end', entries)
704 entry = entries['u-boot-align-end']
705 self.assertEqual(48, entry.offset)
706 self.assertEqual(16, entry.size)
708 # Fifth u-boot immediately afterwards
709 self.assertIn('u-boot-align-both', entries)
710 entry = entries['u-boot-align-both']
711 self.assertEqual(64, entry.offset)
712 self.assertEqual(64, entry.size)
714 self.CheckNoGaps(entries)
715 self.assertEqual(128, image.size)
717 def testPackAlignPowerOf2(self):
718 """Test that invalid entry alignment is detected"""
719 with self.assertRaises(ValueError) as e:
720 self._DoTestFile('010_pack_align_power2.dts')
721 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
722 "of two", str(e.exception))
724 def testPackAlignSizePowerOf2(self):
725 """Test that invalid entry size alignment is detected"""
726 with self.assertRaises(ValueError) as e:
727 self._DoTestFile('011_pack_align_size_power2.dts')
728 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
729 "power of two", str(e.exception))
731 def testPackInvalidAlign(self):
732 """Test detection of an offset that does not match its alignment"""
733 with self.assertRaises(ValueError) as e:
734 self._DoTestFile('012_pack_inv_align.dts')
735 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
736 "align 0x4 (4)", str(e.exception))
738 def testPackInvalidSizeAlign(self):
739 """Test that invalid entry size alignment is detected"""
740 with self.assertRaises(ValueError) as e:
741 self._DoTestFile('013_pack_inv_size_align.dts')
742 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
743 "align-size 0x4 (4)", str(e.exception))
745 def testPackOverlap(self):
746 """Test that overlapping regions are detected"""
747 with self.assertRaises(ValueError) as e:
748 self._DoTestFile('014_pack_overlap.dts')
749 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
750 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
753 def testPackEntryOverflow(self):
754 """Test that entries that overflow their size are detected"""
755 with self.assertRaises(ValueError) as e:
756 self._DoTestFile('015_pack_overflow.dts')
757 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
758 "but entry size is 0x3 (3)", str(e.exception))
760 def testPackImageOverflow(self):
761 """Test that entries which overflow the image size are detected"""
762 with self.assertRaises(ValueError) as e:
763 self._DoTestFile('016_pack_image_overflow.dts')
764 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
765 "size 0x3 (3)", str(e.exception))
767 def testPackImageSize(self):
768 """Test that the image size can be set"""
769 retcode = self._DoTestFile('017_pack_image_size.dts')
770 self.assertEqual(0, retcode)
771 self.assertIn('image', control.images)
772 image = control.images['image']
773 self.assertEqual(7, image.size)
775 def testPackImageSizeAlign(self):
776 """Test that image size alignemnt works as expected"""
777 retcode = self._DoTestFile('018_pack_image_align.dts')
778 self.assertEqual(0, retcode)
779 self.assertIn('image', control.images)
780 image = control.images['image']
781 self.assertEqual(16, image.size)
783 def testPackInvalidImageAlign(self):
784 """Test that invalid image alignment is detected"""
785 with self.assertRaises(ValueError) as e:
786 self._DoTestFile('019_pack_inv_image_align.dts')
787 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
788 "align-size 0x8 (8)", str(e.exception))
790 def testPackAlignPowerOf2(self):
791 """Test that invalid image alignment is detected"""
792 with self.assertRaises(ValueError) as e:
793 self._DoTestFile('020_pack_inv_image_align_power2.dts')
794 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
795 "two", str(e.exception))
797 def testImagePadByte(self):
798 """Test that the image pad byte can be specified"""
800 data = self._DoReadFile('021_image_pad.dts')
801 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
804 def testImageName(self):
805 """Test that image files can be named"""
806 retcode = self._DoTestFile('022_image_name.dts')
807 self.assertEqual(0, retcode)
808 image = control.images['image1']
809 fname = tools.GetOutputFilename('test-name')
810 self.assertTrue(os.path.exists(fname))
812 image = control.images['image2']
813 fname = tools.GetOutputFilename('test-name.xx')
814 self.assertTrue(os.path.exists(fname))
816 def testBlobFilename(self):
817 """Test that generic blobs can be provided by filename"""
818 data = self._DoReadFile('023_blob.dts')
819 self.assertEqual(BLOB_DATA, data)
821 def testPackSorted(self):
822 """Test that entries can be sorted"""
824 data = self._DoReadFile('024_sorted.dts')
825 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
826 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
828 def testPackZeroOffset(self):
829 """Test that an entry at offset 0 is not given a new offset"""
830 with self.assertRaises(ValueError) as e:
831 self._DoTestFile('025_pack_zero_size.dts')
832 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
833 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
836 def testPackUbootDtb(self):
837 """Test that a device tree can be added to U-Boot"""
838 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
839 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
841 def testPackX86RomNoSize(self):
842 """Test that the end-at-4gb property requires a size property"""
843 with self.assertRaises(ValueError) as e:
844 self._DoTestFile('027_pack_4gb_no_size.dts')
845 self.assertIn("Image '/binman': Section size must be provided when "
846 "using end-at-4gb", str(e.exception))
848 def test4gbAndSkipAtStartTogether(self):
849 """Test that the end-at-4gb and skip-at-size property can't be used
851 with self.assertRaises(ValueError) as e:
852 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
853 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
854 "'skip-at-start'", str(e.exception))
856 def testPackX86RomOutside(self):
857 """Test that the end-at-4gb property checks for offset boundaries"""
858 with self.assertRaises(ValueError) as e:
859 self._DoTestFile('028_pack_4gb_outside.dts')
860 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
861 "the section starting at 0xffffffe0 (4294967264)",
864 def testPackX86Rom(self):
865 """Test that a basic x86 ROM can be created"""
867 data = self._DoReadFile('029_x86-rom.dts')
868 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
869 tools.GetBytes(0, 2), data)
871 def testPackX86RomMeNoDesc(self):
872 """Test that an invalid Intel descriptor entry is detected"""
873 TestFunctional._MakeInputFile('descriptor.bin', b'')
874 with self.assertRaises(ValueError) as e:
875 self._DoTestFile('031_x86-rom-me.dts')
876 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
879 def testPackX86RomBadDesc(self):
880 """Test that the Intel requires a descriptor entry"""
881 with self.assertRaises(ValueError) as e:
882 self._DoTestFile('030_x86-rom-me-no-desc.dts')
883 self.assertIn("Node '/binman/intel-me': No offset set with "
884 "offset-unset: should another entry provide this correct "
885 "offset?", str(e.exception))
887 def testPackX86RomMe(self):
888 """Test that an x86 ROM with an ME region can be created"""
889 data = self._DoReadFile('031_x86-rom-me.dts')
890 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
891 if data[:0x1000] != expected_desc:
892 self.fail('Expected descriptor binary at start of image')
893 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
895 def testPackVga(self):
896 """Test that an image with a VGA binary can be created"""
897 data = self._DoReadFile('032_intel-vga.dts')
898 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
900 def testPackStart16(self):
901 """Test that an image with an x86 start16 region can be created"""
902 data = self._DoReadFile('033_x86-start16.dts')
903 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
905 def testPackPowerpcMpc85xxBootpgResetvec(self):
906 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
908 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
909 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
911 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
912 """Handle running a test for insertion of microcode
915 dts_fname: Name of test .dts file
916 nodtb_data: Data that we expect in the first section
917 ucode_second: True if the microsecond entry is second instead of
922 Contents of first region (U-Boot or SPL)
923 Offset and size components of microcode pointer, as inserted
924 in the above (two 4-byte words)
926 data = self._DoReadFile(dts_fname, True)
928 # Now check the device tree has no microcode
930 ucode_content = data[len(nodtb_data):]
931 ucode_pos = len(nodtb_data)
932 dtb_with_ucode = ucode_content[16:]
933 fdt_len = self.GetFdtLen(dtb_with_ucode)
935 dtb_with_ucode = data[len(nodtb_data):]
936 fdt_len = self.GetFdtLen(dtb_with_ucode)
937 ucode_content = dtb_with_ucode[fdt_len:]
938 ucode_pos = len(nodtb_data) + fdt_len
939 fname = tools.GetOutputFilename('test.dtb')
940 with open(fname, 'wb') as fd:
941 fd.write(dtb_with_ucode)
942 dtb = fdt.FdtScan(fname)
943 ucode = dtb.GetNode('/microcode')
944 self.assertTrue(ucode)
945 for node in ucode.subnodes:
946 self.assertFalse(node.props.get('data'))
948 # Check that the microcode appears immediately after the Fdt
949 # This matches the concatenation of the data properties in
950 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
951 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
953 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
955 # Check that the microcode pointer was inserted. It should match the
956 # expected offset and size
957 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
959 u_boot = data[:len(nodtb_data)]
960 return u_boot, pos_and_size
962 def testPackUbootMicrocode(self):
963 """Test that x86 microcode can be handled correctly
965 We expect to see the following in the image, in order:
966 u-boot-nodtb.bin with a microcode pointer inserted at the correct
968 u-boot.dtb with the microcode removed
971 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
973 self.assertEqual(b'nodtb with microcode' + pos_and_size +
974 b' somewhere in here', first)
976 def _RunPackUbootSingleMicrocode(self):
977 """Test that x86 microcode can be handled correctly
979 We expect to see the following in the image, in order:
980 u-boot-nodtb.bin with a microcode pointer inserted at the correct
982 u-boot.dtb with the microcode
983 an empty microcode region
985 # We need the libfdt library to run this test since only that allows
986 # finding the offset of a property. This is required by
987 # Entry_u_boot_dtb_with_ucode.ObtainContents().
988 data = self._DoReadFile('035_x86_single_ucode.dts', True)
990 second = data[len(U_BOOT_NODTB_DATA):]
992 fdt_len = self.GetFdtLen(second)
993 third = second[fdt_len:]
994 second = second[:fdt_len]
996 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
997 self.assertIn(ucode_data, second)
998 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1000 # Check that the microcode pointer was inserted. It should match the
1001 # expected offset and size
1002 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1004 first = data[:len(U_BOOT_NODTB_DATA)]
1005 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1006 b' somewhere in here', first)
1008 def testPackUbootSingleMicrocode(self):
1009 """Test that x86 microcode can be handled correctly with fdt_normal.
1011 self._RunPackUbootSingleMicrocode()
1013 def testUBootImg(self):
1014 """Test that u-boot.img can be put in a file"""
1015 data = self._DoReadFile('036_u_boot_img.dts')
1016 self.assertEqual(U_BOOT_IMG_DATA, data)
1018 def testNoMicrocode(self):
1019 """Test that a missing microcode region is detected"""
1020 with self.assertRaises(ValueError) as e:
1021 self._DoReadFile('037_x86_no_ucode.dts', True)
1022 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1023 "node found in ", str(e.exception))
1025 def testMicrocodeWithoutNode(self):
1026 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1027 with self.assertRaises(ValueError) as e:
1028 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1029 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1030 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1032 def testMicrocodeWithoutNode2(self):
1033 """Test that a missing u-boot-ucode node is detected"""
1034 with self.assertRaises(ValueError) as e:
1035 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1036 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1037 "microcode region u-boot-ucode", str(e.exception))
1039 def testMicrocodeWithoutPtrInElf(self):
1040 """Test that a U-Boot binary without the microcode symbol is detected"""
1041 # ELF file without a '_dt_ucode_base_size' symbol
1043 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1044 TestFunctional._MakeInputFile('u-boot', fd.read())
1046 with self.assertRaises(ValueError) as e:
1047 self._RunPackUbootSingleMicrocode()
1048 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1049 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1052 # Put the original file back
1053 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1054 TestFunctional._MakeInputFile('u-boot', fd.read())
1056 def testMicrocodeNotInImage(self):
1057 """Test that microcode must be placed within the image"""
1058 with self.assertRaises(ValueError) as e:
1059 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1060 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1061 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1062 "section ranging from 00000000 to 0000002e", str(e.exception))
1064 def testWithoutMicrocode(self):
1065 """Test that we can cope with an image without microcode (e.g. qemu)"""
1066 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1067 TestFunctional._MakeInputFile('u-boot', fd.read())
1068 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1070 # Now check the device tree has no microcode
1071 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1072 second = data[len(U_BOOT_NODTB_DATA):]
1074 fdt_len = self.GetFdtLen(second)
1075 self.assertEqual(dtb, second[:fdt_len])
1077 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1078 third = data[used_len:]
1079 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1081 def testUnknownPosSize(self):
1082 """Test that microcode must be placed within the image"""
1083 with self.assertRaises(ValueError) as e:
1084 self._DoReadFile('041_unknown_pos_size.dts', True)
1085 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1086 "entry 'invalid-entry'", str(e.exception))
1088 def testPackFsp(self):
1089 """Test that an image with a FSP binary can be created"""
1090 data = self._DoReadFile('042_intel-fsp.dts')
1091 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1093 def testPackCmc(self):
1094 """Test that an image with a CMC binary can be created"""
1095 data = self._DoReadFile('043_intel-cmc.dts')
1096 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1098 def testPackVbt(self):
1099 """Test that an image with a VBT binary can be created"""
1100 data = self._DoReadFile('046_intel-vbt.dts')
1101 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1103 def testSplBssPad(self):
1104 """Test that we can pad SPL's BSS with zeros"""
1105 # ELF file with a '__bss_size' symbol
1107 data = self._DoReadFile('047_spl_bss_pad.dts')
1108 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1111 def testSplBssPadMissing(self):
1112 """Test that a missing symbol is detected"""
1113 self._SetupSplElf('u_boot_ucode_ptr')
1114 with self.assertRaises(ValueError) as e:
1115 self._DoReadFile('047_spl_bss_pad.dts')
1116 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1119 def testPackStart16Spl(self):
1120 """Test that an image with an x86 start16 SPL region can be created"""
1121 data = self._DoReadFile('048_x86-start16-spl.dts')
1122 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1124 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1125 """Helper function for microcode tests
1127 We expect to see the following in the image, in order:
1128 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1130 u-boot.dtb with the microcode removed
1134 dts: Device tree file to use for test
1135 ucode_second: True if the microsecond entry is second instead of
1138 self._SetupSplElf('u_boot_ucode_ptr')
1139 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1140 ucode_second=ucode_second)
1141 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1142 b'ter somewhere in here', first)
1144 def testPackUbootSplMicrocode(self):
1145 """Test that x86 microcode can be handled correctly in SPL"""
1146 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1148 def testPackUbootSplMicrocodeReorder(self):
1149 """Test that order doesn't matter for microcode entries
1151 This is the same as testPackUbootSplMicrocode but when we process the
1152 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1153 entry, so we reply on binman to try later.
1155 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1158 def testPackMrc(self):
1159 """Test that an image with an MRC binary can be created"""
1160 data = self._DoReadFile('050_intel_mrc.dts')
1161 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1163 def testSplDtb(self):
1164 """Test that an image with spl/u-boot-spl.dtb can be created"""
1165 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1166 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1168 def testSplNoDtb(self):
1169 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1170 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1171 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1173 def testSymbols(self):
1174 """Test binman can assign symbols embedded in U-Boot"""
1175 elf_fname = self.TestFile('u_boot_binman_syms')
1176 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1177 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1178 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1180 self._SetupSplElf('u_boot_binman_syms')
1181 data = self._DoReadFile('053_symbols.dts')
1182 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1183 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1184 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1185 U_BOOT_SPL_DATA[16:])
1186 self.assertEqual(expected, data)
1188 def testPackUnitAddress(self):
1189 """Test that we support multiple binaries with the same name"""
1190 data = self._DoReadFile('054_unit_address.dts')
1191 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1193 def testSections(self):
1194 """Basic test of sections"""
1195 data = self._DoReadFile('055_sections.dts')
1196 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1197 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1198 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1199 self.assertEqual(expected, data)
1202 """Tests outputting a map of the images"""
1203 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1204 self.assertEqual('''ImagePos Offset Size Name
1205 00000000 00000000 00000028 main-section
1206 00000000 00000000 00000010 section@0
1207 00000000 00000000 00000004 u-boot
1208 00000010 00000010 00000010 section@1
1209 00000010 00000000 00000004 u-boot
1210 00000020 00000020 00000004 section@2
1211 00000020 00000000 00000004 u-boot
1214 def testNamePrefix(self):
1215 """Tests that name prefixes are used"""
1216 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1217 self.assertEqual('''ImagePos Offset Size Name
1218 00000000 00000000 00000028 main-section
1219 00000000 00000000 00000010 section@0
1220 00000000 00000000 00000004 ro-u-boot
1221 00000010 00000010 00000010 section@1
1222 00000010 00000000 00000004 rw-u-boot
1225 def testUnknownContents(self):
1226 """Test that obtaining the contents works as expected"""
1227 with self.assertRaises(ValueError) as e:
1228 self._DoReadFile('057_unknown_contents.dts', True)
1229 self.assertIn("Image '/binman': Internal error: Could not complete "
1230 "processing of contents: remaining [<_testing.Entry__testing ",
1233 def testBadChangeSize(self):
1234 """Test that trying to change the size of an entry fails"""
1236 state.SetAllowEntryExpansion(False)
1237 with self.assertRaises(ValueError) as e:
1238 self._DoReadFile('059_change_size.dts', True)
1239 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1242 state.SetAllowEntryExpansion(True)
1244 def testUpdateFdt(self):
1245 """Test that we can update the device tree with offset/size info"""
1246 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1248 dtb = fdt.Fdt(out_dtb_fname)
1250 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1254 '_testing:offset': 32,
1256 '_testing:image-pos': 32,
1257 'section@0/u-boot:offset': 0,
1258 'section@0/u-boot:size': len(U_BOOT_DATA),
1259 'section@0/u-boot:image-pos': 0,
1260 'section@0:offset': 0,
1261 'section@0:size': 16,
1262 'section@0:image-pos': 0,
1264 'section@1/u-boot:offset': 0,
1265 'section@1/u-boot:size': len(U_BOOT_DATA),
1266 'section@1/u-boot:image-pos': 16,
1267 'section@1:offset': 16,
1268 'section@1:size': 16,
1269 'section@1:image-pos': 16,
1273 def testUpdateFdtBad(self):
1274 """Test that we detect when ProcessFdt never completes"""
1275 with self.assertRaises(ValueError) as e:
1276 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1277 self.assertIn('Could not complete processing of Fdt: remaining '
1278 '[<_testing.Entry__testing', str(e.exception))
1280 def testEntryArgs(self):
1281 """Test passing arguments to entries from the command line"""
1283 'test-str-arg': 'test1',
1284 'test-int-arg': '456',
1286 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1287 self.assertIn('image', control.images)
1288 entry = control.images['image'].GetEntries()['_testing']
1289 self.assertEqual('test0', entry.test_str_fdt)
1290 self.assertEqual('test1', entry.test_str_arg)
1291 self.assertEqual(123, entry.test_int_fdt)
1292 self.assertEqual(456, entry.test_int_arg)
1294 def testEntryArgsMissing(self):
1295 """Test missing arguments and properties"""
1297 'test-int-arg': '456',
1299 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1300 entry = control.images['image'].GetEntries()['_testing']
1301 self.assertEqual('test0', entry.test_str_fdt)
1302 self.assertEqual(None, entry.test_str_arg)
1303 self.assertEqual(None, entry.test_int_fdt)
1304 self.assertEqual(456, entry.test_int_arg)
1306 def testEntryArgsRequired(self):
1307 """Test missing arguments and properties"""
1309 'test-int-arg': '456',
1311 with self.assertRaises(ValueError) as e:
1312 self._DoReadFileDtb('064_entry_args_required.dts')
1313 self.assertIn("Node '/binman/_testing': Missing required "
1314 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1317 def testEntryArgsInvalidFormat(self):
1318 """Test that an invalid entry-argument format is detected"""
1319 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1321 with self.assertRaises(ValueError) as e:
1322 self._DoBinman(*args)
1323 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1325 def testEntryArgsInvalidInteger(self):
1326 """Test that an invalid entry-argument integer is detected"""
1328 'test-int-arg': 'abc',
1330 with self.assertRaises(ValueError) as e:
1331 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1332 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1333 "'test-int-arg' (value 'abc') to integer",
1336 def testEntryArgsInvalidDatatype(self):
1337 """Test that an invalid entry-argument datatype is detected
1339 This test could be written in entry_test.py except that it needs
1340 access to control.entry_args, which seems more than that module should
1344 'test-bad-datatype-arg': '12',
1346 with self.assertRaises(ValueError) as e:
1347 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1348 entry_args=entry_args)
1349 self.assertIn('GetArg() internal error: Unknown data type ',
1353 """Test for a text entry type"""
1355 'test-id': TEXT_DATA,
1356 'test-id2': TEXT_DATA2,
1357 'test-id3': TEXT_DATA3,
1359 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1360 entry_args=entry_args)
1361 expected = (tools.ToBytes(TEXT_DATA) +
1362 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1363 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1364 b'some text' + b'more text')
1365 self.assertEqual(expected, data)
1367 def testEntryDocs(self):
1368 """Test for creation of entry documentation"""
1369 with test_util.capture_sys_output() as (stdout, stderr):
1370 control.WriteEntryDocs(binman.GetEntryModules())
1371 self.assertTrue(len(stdout.getvalue()) > 0)
1373 def testEntryDocsMissing(self):
1374 """Test handling of missing entry documentation"""
1375 with self.assertRaises(ValueError) as e:
1376 with test_util.capture_sys_output() as (stdout, stderr):
1377 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1378 self.assertIn('Documentation is missing for modules: u_boot',
1382 """Basic test of generation of a flashrom fmap"""
1383 data = self._DoReadFile('067_fmap.dts')
1384 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1385 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1386 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1387 self.assertEqual(expected, data[:32])
1388 self.assertEqual(b'__FMAP__', fhdr.signature)
1389 self.assertEqual(1, fhdr.ver_major)
1390 self.assertEqual(0, fhdr.ver_minor)
1391 self.assertEqual(0, fhdr.base)
1392 self.assertEqual(16 + 16 +
1393 fmap_util.FMAP_HEADER_LEN +
1394 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1395 self.assertEqual(b'FMAP', fhdr.name)
1396 self.assertEqual(3, fhdr.nareas)
1397 for fentry in fentries:
1398 self.assertEqual(0, fentry.flags)
1400 self.assertEqual(0, fentries[0].offset)
1401 self.assertEqual(4, fentries[0].size)
1402 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1404 self.assertEqual(16, fentries[1].offset)
1405 self.assertEqual(4, fentries[1].size)
1406 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1408 self.assertEqual(32, fentries[2].offset)
1409 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1410 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1411 self.assertEqual(b'FMAP', fentries[2].name)
1413 def testBlobNamedByArg(self):
1414 """Test we can add a blob with the filename coming from an entry arg"""
1416 'cros-ec-rw-path': 'ecrw.bin',
1418 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1419 entry_args=entry_args)
1422 """Test for an fill entry type"""
1423 data = self._DoReadFile('069_fill.dts')
1424 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1425 self.assertEqual(expected, data)
1427 def testFillNoSize(self):
1428 """Test for an fill entry type with no size"""
1429 with self.assertRaises(ValueError) as e:
1430 self._DoReadFile('070_fill_no_size.dts')
1431 self.assertIn("'fill' entry must have a size property",
1434 def _HandleGbbCommand(self, pipe_list):
1435 """Fake calls to the futility utility"""
1436 if pipe_list[0][0] == 'futility':
1437 fname = pipe_list[0][-1]
1438 # Append our GBB data to the file, which will happen every time the
1439 # futility command is called.
1440 with open(fname, 'ab') as fd:
1442 return command.CommandResult()
1445 """Test for the Chromium OS Google Binary Block"""
1446 command.test_result = self._HandleGbbCommand
1448 'keydir': 'devkeys',
1449 'bmpblk': 'bmpblk.bin',
1451 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1454 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1455 tools.GetBytes(0, 0x2180 - 16))
1456 self.assertEqual(expected, data)
1458 def testGbbTooSmall(self):
1459 """Test for the Chromium OS Google Binary Block being large enough"""
1460 with self.assertRaises(ValueError) as e:
1461 self._DoReadFileDtb('072_gbb_too_small.dts')
1462 self.assertIn("Node '/binman/gbb': GBB is too small",
1465 def testGbbNoSize(self):
1466 """Test for the Chromium OS Google Binary Block having a size"""
1467 with self.assertRaises(ValueError) as e:
1468 self._DoReadFileDtb('073_gbb_no_size.dts')
1469 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1472 def _HandleVblockCommand(self, pipe_list):
1473 """Fake calls to the futility utility"""
1474 if pipe_list[0][0] == 'futility':
1475 fname = pipe_list[0][3]
1476 with open(fname, 'wb') as fd:
1477 fd.write(VBLOCK_DATA)
1478 return command.CommandResult()
1480 def testVblock(self):
1481 """Test for the Chromium OS Verified Boot Block"""
1482 command.test_result = self._HandleVblockCommand
1484 'keydir': 'devkeys',
1486 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1487 entry_args=entry_args)
1488 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1489 self.assertEqual(expected, data)
1491 def testVblockNoContent(self):
1492 """Test we detect a vblock which has no content to sign"""
1493 with self.assertRaises(ValueError) as e:
1494 self._DoReadFile('075_vblock_no_content.dts')
1495 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1496 'property', str(e.exception))
1498 def testVblockBadPhandle(self):
1499 """Test that we detect a vblock with an invalid phandle in contents"""
1500 with self.assertRaises(ValueError) as e:
1501 self._DoReadFile('076_vblock_bad_phandle.dts')
1502 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1503 '1000', str(e.exception))
1505 def testVblockBadEntry(self):
1506 """Test that we detect an entry that points to a non-entry"""
1507 with self.assertRaises(ValueError) as e:
1508 self._DoReadFile('077_vblock_bad_entry.dts')
1509 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1510 "'other'", str(e.exception))
1513 """Test that an image with TPL and ots device tree can be created"""
1514 # ELF file with a '__bss_size' symbol
1515 with open(self.TestFile('bss_data'), 'rb') as fd:
1516 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1517 data = self._DoReadFile('078_u_boot_tpl.dts')
1518 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1520 def testUsesPos(self):
1521 """Test that the 'pos' property cannot be used anymore"""
1522 with self.assertRaises(ValueError) as e:
1523 data = self._DoReadFile('079_uses_pos.dts')
1524 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1525 "'pos'", str(e.exception))
1527 def testFillZero(self):
1528 """Test for an fill entry type with a size of 0"""
1529 data = self._DoReadFile('080_fill_empty.dts')
1530 self.assertEqual(tools.GetBytes(0, 16), data)
1532 def testTextMissing(self):
1533 """Test for a text entry type where there is no text"""
1534 with self.assertRaises(ValueError) as e:
1535 self._DoReadFileDtb('066_text.dts',)
1536 self.assertIn("Node '/binman/text': No value provided for text label "
1537 "'test-id'", str(e.exception))
1539 def testPackStart16Tpl(self):
1540 """Test that an image with an x86 start16 TPL region can be created"""
1541 data = self._DoReadFile('081_x86-start16-tpl.dts')
1542 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1544 def testSelectImage(self):
1545 """Test that we can select which images to build"""
1546 expected = 'Skipping images: image1'
1548 # We should only get the expected message in verbose mode
1549 for verbosity in (0, 2):
1550 with test_util.capture_sys_output() as (stdout, stderr):
1551 retcode = self._DoTestFile('006_dual_image.dts',
1552 verbosity=verbosity,
1554 self.assertEqual(0, retcode)
1556 self.assertIn(expected, stdout.getvalue())
1558 self.assertNotIn(expected, stdout.getvalue())
1560 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1561 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1563 def testUpdateFdtAll(self):
1564 """Test that all device trees are updated with offset/size info"""
1565 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1568 'section:image-pos': 0,
1569 'u-boot-tpl-dtb:size': 513,
1570 'u-boot-spl-dtb:size': 513,
1571 'u-boot-spl-dtb:offset': 493,
1573 'section/u-boot-dtb:image-pos': 0,
1574 'u-boot-spl-dtb:image-pos': 493,
1575 'section/u-boot-dtb:size': 493,
1576 'u-boot-tpl-dtb:image-pos': 1006,
1577 'section/u-boot-dtb:offset': 0,
1578 'section:size': 493,
1580 'section:offset': 0,
1581 'u-boot-tpl-dtb:offset': 1006,
1585 # We expect three device-tree files in the output, one after the other.
1586 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1587 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1588 # main U-Boot tree. All three should have the same postions and offset.
1590 for item in ['', 'spl', 'tpl']:
1591 dtb = fdt.Fdt.FromData(data[start:])
1593 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1595 expected = dict(base_expected)
1598 self.assertEqual(expected, props)
1599 start += dtb._fdt_obj.totalsize()
1601 def testUpdateFdtOutput(self):
1602 """Test that output DTB files are updated"""
1604 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1605 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1607 # Unfortunately, compiling a source file always results in a file
1608 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1609 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1610 # binman as a file called u-boot.dtb. To fix this, copy the file
1611 # over to the expected place.
1612 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1613 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1615 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1616 'tpl/u-boot-tpl.dtb.out']:
1617 dtb = fdt.Fdt.FromData(data[start:])
1618 size = dtb._fdt_obj.totalsize()
1619 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1620 outdata = tools.ReadFile(pathname)
1621 name = os.path.split(fname)[0]
1624 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1626 orig_indata = dtb_data
1627 self.assertNotEqual(outdata, orig_indata,
1628 "Expected output file '%s' be updated" % pathname)
1629 self.assertEqual(outdata, data[start:start + size],
1630 "Expected output file '%s' to match output image" %
1636 def _decompress(self, data):
1637 return tools.Decompress(data, 'lz4')
1639 def testCompress(self):
1640 """Test compression of blobs"""
1642 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1643 use_real_dtb=True, update_dtb=True)
1644 dtb = fdt.Fdt(out_dtb_fname)
1646 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1647 orig = self._decompress(data)
1648 self.assertEquals(COMPRESS_DATA, orig)
1650 'blob:uncomp-size': len(COMPRESS_DATA),
1651 'blob:size': len(data),
1654 self.assertEqual(expected, props)
1656 def testFiles(self):
1657 """Test bringing in multiple files"""
1658 data = self._DoReadFile('084_files.dts')
1659 self.assertEqual(FILES_DATA, data)
1661 def testFilesCompress(self):
1662 """Test bringing in multiple files and compressing them"""
1664 data = self._DoReadFile('085_files_compress.dts')
1666 image = control.images['image']
1667 entries = image.GetEntries()
1668 files = entries['files']
1669 entries = files._entries
1672 for i in range(1, 3):
1674 start = entries[key].image_pos
1675 len = entries[key].size
1676 chunk = data[start:start + len]
1677 orig += self._decompress(chunk)
1679 self.assertEqual(FILES_DATA, orig)
1681 def testFilesMissing(self):
1682 """Test missing files"""
1683 with self.assertRaises(ValueError) as e:
1684 data = self._DoReadFile('086_files_none.dts')
1685 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1686 'no files', str(e.exception))
1688 def testFilesNoPattern(self):
1689 """Test missing files"""
1690 with self.assertRaises(ValueError) as e:
1691 data = self._DoReadFile('087_files_no_pattern.dts')
1692 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1695 def testExpandSize(self):
1696 """Test an expanding entry"""
1697 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1699 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1700 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1701 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1702 tools.GetBytes(ord('d'), 8))
1703 self.assertEqual(expect, data)
1704 self.assertEqual('''ImagePos Offset Size Name
1705 00000000 00000000 00000028 main-section
1706 00000000 00000000 00000008 fill
1707 00000008 00000008 00000004 u-boot
1708 0000000c 0000000c 00000004 section
1709 0000000c 00000000 00000003 intel-mrc
1710 00000010 00000010 00000004 u-boot2
1711 00000014 00000014 0000000c section2
1712 00000014 00000000 00000008 fill
1713 0000001c 00000008 00000004 u-boot
1714 00000020 00000020 00000008 fill2
1717 def testExpandSizeBad(self):
1718 """Test an expanding entry which fails to provide contents"""
1719 with test_util.capture_sys_output() as (stdout, stderr):
1720 with self.assertRaises(ValueError) as e:
1721 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1722 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1723 'expanding entry', str(e.exception))
1726 """Test hashing of the contents of an entry"""
1727 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1728 use_real_dtb=True, update_dtb=True)
1729 dtb = fdt.Fdt(out_dtb_fname)
1731 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1732 m = hashlib.sha256()
1733 m.update(U_BOOT_DATA)
1734 self.assertEqual(m.digest(), b''.join(hash_node.value))
1736 def testHashNoAlgo(self):
1737 with self.assertRaises(ValueError) as e:
1738 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1739 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1740 'hash node', str(e.exception))
1742 def testHashBadAlgo(self):
1743 with self.assertRaises(ValueError) as e:
1744 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1745 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1748 def testHashSection(self):
1749 """Test hashing of the contents of an entry"""
1750 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1751 use_real_dtb=True, update_dtb=True)
1752 dtb = fdt.Fdt(out_dtb_fname)
1754 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1755 m = hashlib.sha256()
1756 m.update(U_BOOT_DATA)
1757 m.update(tools.GetBytes(ord('a'), 16))
1758 self.assertEqual(m.digest(), b''.join(hash_node.value))
1760 def testPackUBootTplMicrocode(self):
1761 """Test that x86 microcode can be handled correctly in TPL
1763 We expect to see the following in the image, in order:
1764 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1766 u-boot-tpl.dtb with the microcode removed
1769 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1770 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1771 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1772 U_BOOT_TPL_NODTB_DATA)
1773 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1774 b'ter somewhere in here', first)
1776 def testFmapX86(self):
1777 """Basic test of generation of a flashrom fmap"""
1778 data = self._DoReadFile('094_fmap_x86.dts')
1779 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1780 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1781 self.assertEqual(expected, data[:32])
1782 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1784 self.assertEqual(0x100, fhdr.image_size)
1786 self.assertEqual(0, fentries[0].offset)
1787 self.assertEqual(4, fentries[0].size)
1788 self.assertEqual(b'U_BOOT', fentries[0].name)
1790 self.assertEqual(4, fentries[1].offset)
1791 self.assertEqual(3, fentries[1].size)
1792 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1794 self.assertEqual(32, fentries[2].offset)
1795 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1796 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1797 self.assertEqual(b'FMAP', fentries[2].name)
1799 def testFmapX86Section(self):
1800 """Basic test of generation of a flashrom fmap"""
1801 data = self._DoReadFile('095_fmap_x86_section.dts')
1802 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1803 self.assertEqual(expected, data[:32])
1804 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1806 self.assertEqual(0x100, fhdr.image_size)
1808 self.assertEqual(0, fentries[0].offset)
1809 self.assertEqual(4, fentries[0].size)
1810 self.assertEqual(b'U_BOOT', fentries[0].name)
1812 self.assertEqual(4, fentries[1].offset)
1813 self.assertEqual(3, fentries[1].size)
1814 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1816 self.assertEqual(36, fentries[2].offset)
1817 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1818 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1819 self.assertEqual(b'FMAP', fentries[2].name)
1822 """Basic test of ELF entries"""
1824 with open(self.TestFile('bss_data'), 'rb') as fd:
1825 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1826 with open(self.TestFile('bss_data'), 'rb') as fd:
1827 TestFunctional._MakeInputFile('-boot', fd.read())
1828 data = self._DoReadFile('096_elf.dts')
1830 def testElfStrip(self):
1831 """Basic test of ELF entries"""
1833 with open(self.TestFile('bss_data'), 'rb') as fd:
1834 TestFunctional._MakeInputFile('-boot', fd.read())
1835 data = self._DoReadFile('097_elf_strip.dts')
1837 def testPackOverlapMap(self):
1838 """Test that overlapping regions are detected"""
1839 with test_util.capture_sys_output() as (stdout, stderr):
1840 with self.assertRaises(ValueError) as e:
1841 self._DoTestFile('014_pack_overlap.dts', map=True)
1842 map_fname = tools.GetOutputFilename('image.map')
1843 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1846 # We should not get an inmage, but there should be a map file
1847 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1848 self.assertTrue(os.path.exists(map_fname))
1849 map_data = tools.ReadFile(map_fname, binary=False)
1850 self.assertEqual('''ImagePos Offset Size Name
1851 <none> 00000000 00000007 main-section
1852 <none> 00000000 00000004 u-boot
1853 <none> 00000003 00000004 u-boot-align
1856 def testPackRefCode(self):
1857 """Test that an image with an Intel Reference code binary works"""
1858 data = self._DoReadFile('100_intel_refcode.dts')
1859 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1861 def testSectionOffset(self):
1862 """Tests use of a section with an offset"""
1863 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1865 self.assertEqual('''ImagePos Offset Size Name
1866 00000000 00000000 00000038 main-section
1867 00000004 00000004 00000010 section@0
1868 00000004 00000000 00000004 u-boot
1869 00000018 00000018 00000010 section@1
1870 00000018 00000000 00000004 u-boot
1871 0000002c 0000002c 00000004 section@2
1872 0000002c 00000000 00000004 u-boot
1874 self.assertEqual(data,
1875 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1876 tools.GetBytes(0x21, 12) +
1877 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1878 tools.GetBytes(0x61, 12) +
1879 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1880 tools.GetBytes(0x26, 8))
1882 def testCbfsRaw(self):
1883 """Test base handling of a Coreboot Filesystem (CBFS)
1885 The exact contents of the CBFS is verified by similar tests in
1886 cbfs_util_test.py. The tests here merely check that the files added to
1887 the CBFS can be found in the final image.
1889 data = self._DoReadFile('102_cbfs_raw.dts')
1892 cbfs = cbfs_util.CbfsReader(data)
1893 self.assertEqual(size, cbfs.rom_size)
1895 self.assertIn('u-boot-dtb', cbfs.files)
1896 cfile = cbfs.files['u-boot-dtb']
1897 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1899 def testCbfsArch(self):
1900 """Test on non-x86 architecture"""
1901 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1904 cbfs = cbfs_util.CbfsReader(data)
1905 self.assertEqual(size, cbfs.rom_size)
1907 self.assertIn('u-boot-dtb', cbfs.files)
1908 cfile = cbfs.files['u-boot-dtb']
1909 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1911 def testCbfsStage(self):
1912 """Tests handling of a Coreboot Filesystem (CBFS)"""
1913 if not elf.ELF_TOOLS:
1914 self.skipTest('Python elftools not available')
1915 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1916 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1919 data = self._DoReadFile('104_cbfs_stage.dts')
1920 cbfs = cbfs_util.CbfsReader(data)
1921 self.assertEqual(size, cbfs.rom_size)
1923 self.assertIn('u-boot', cbfs.files)
1924 cfile = cbfs.files['u-boot']
1925 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1927 def testCbfsRawCompress(self):
1928 """Test handling of compressing raw files"""
1930 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1933 cbfs = cbfs_util.CbfsReader(data)
1934 self.assertIn('u-boot', cbfs.files)
1935 cfile = cbfs.files['u-boot']
1936 self.assertEqual(COMPRESS_DATA, cfile.data)
1938 def testCbfsBadArch(self):
1939 """Test handling of a bad architecture"""
1940 with self.assertRaises(ValueError) as e:
1941 self._DoReadFile('106_cbfs_bad_arch.dts')
1942 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1944 def testCbfsNoSize(self):
1945 """Test handling of a missing size property"""
1946 with self.assertRaises(ValueError) as e:
1947 self._DoReadFile('107_cbfs_no_size.dts')
1948 self.assertIn('entry must have a size property', str(e.exception))
1950 def testCbfsNoCOntents(self):
1951 """Test handling of a CBFS entry which does not provide contentsy"""
1952 with self.assertRaises(ValueError) as e:
1953 self._DoReadFile('108_cbfs_no_contents.dts')
1954 self.assertIn('Could not complete processing of contents',
1957 def testCbfsBadCompress(self):
1958 """Test handling of a bad architecture"""
1959 with self.assertRaises(ValueError) as e:
1960 self._DoReadFile('109_cbfs_bad_compress.dts')
1961 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1964 def testCbfsNamedEntries(self):
1965 """Test handling of named entries"""
1966 data = self._DoReadFile('110_cbfs_name.dts')
1968 cbfs = cbfs_util.CbfsReader(data)
1969 self.assertIn('FRED', cbfs.files)
1970 cfile1 = cbfs.files['FRED']
1971 self.assertEqual(U_BOOT_DATA, cfile1.data)
1973 self.assertIn('hello', cbfs.files)
1974 cfile2 = cbfs.files['hello']
1975 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1977 def _SetupIfwi(self, fname):
1978 """Set up to run an IFWI test
1981 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1985 # Intel Integrated Firmware Image (IFWI) file
1986 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1988 TestFunctional._MakeInputFile(fname,data)
1990 def _CheckIfwi(self, data):
1991 """Check that an image with an IFWI contains the correct output
1994 data: Conents of output file
1996 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1997 if data[:0x1000] != expected_desc:
1998 self.fail('Expected descriptor binary at start of image')
2000 # We expect to find the TPL wil in subpart IBBP entry IBBL
2001 image_fname = tools.GetOutputFilename('image.bin')
2002 tpl_fname = tools.GetOutputFilename('tpl.out')
2003 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2004 subpart='IBBP', entry_name='IBBL')
2006 tpl_data = tools.ReadFile(tpl_fname)
2007 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2009 def testPackX86RomIfwi(self):
2010 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2011 self._SetupIfwi('fitimage.bin')
2012 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2013 self._CheckIfwi(data)
2015 def testPackX86RomIfwiNoDesc(self):
2016 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2017 self._SetupIfwi('ifwi.bin')
2018 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2019 self._CheckIfwi(data)
2021 def testPackX86RomIfwiNoData(self):
2022 """Test that an x86 ROM with IFWI handles missing data"""
2023 self._SetupIfwi('ifwi.bin')
2024 with self.assertRaises(ValueError) as e:
2025 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2026 self.assertIn('Could not complete processing of contents',
2029 def testCbfsOffset(self):
2030 """Test a CBFS with files at particular offsets
2032 Like all CFBS tests, this is just checking the logic that calls
2033 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2035 data = self._DoReadFile('114_cbfs_offset.dts')
2038 cbfs = cbfs_util.CbfsReader(data)
2039 self.assertEqual(size, cbfs.rom_size)
2041 self.assertIn('u-boot', cbfs.files)
2042 cfile = cbfs.files['u-boot']
2043 self.assertEqual(U_BOOT_DATA, cfile.data)
2044 self.assertEqual(0x40, cfile.cbfs_offset)
2046 self.assertIn('u-boot-dtb', cbfs.files)
2047 cfile2 = cbfs.files['u-boot-dtb']
2048 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2049 self.assertEqual(0x140, cfile2.cbfs_offset)
2051 def testFdtmap(self):
2052 """Test an FDT map can be inserted in the image"""
2053 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2054 fdtmap_data = data[len(U_BOOT_DATA):]
2055 magic = fdtmap_data[:8]
2056 self.assertEqual('_FDTMAP_', magic)
2057 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2059 fdt_data = fdtmap_data[16:]
2060 dtb = fdt.Fdt.FromData(fdt_data)
2062 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2067 'u-boot:size': len(U_BOOT_DATA),
2068 'u-boot:image-pos': 0,
2069 'fdtmap:image-pos': 4,
2071 'fdtmap:size': len(fdtmap_data),
2075 def testFdtmapNoMatch(self):
2076 """Check handling of an FDT map when the section cannot be found"""
2077 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2079 # Mangle the section name, which should cause a mismatch between the
2080 # correct FDT path and the one expected by the section
2081 image = control.images['image']
2082 image._node.path += '-suffix'
2083 entries = image.GetEntries()
2084 fdtmap = entries['fdtmap']
2085 with self.assertRaises(ValueError) as e:
2087 self.assertIn("Cannot locate node for path '/binman-suffix'",
2090 def testFdtmapHeader(self):
2091 """Test an FDT map and image header can be inserted in the image"""
2092 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2093 fdtmap_pos = len(U_BOOT_DATA)
2094 fdtmap_data = data[fdtmap_pos:]
2095 fdt_data = fdtmap_data[16:]
2096 dtb = fdt.Fdt.FromData(fdt_data)
2097 fdt_size = dtb.GetFdtObj().totalsize()
2098 hdr_data = data[-8:]
2099 self.assertEqual('BinM', hdr_data[:4])
2100 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2101 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2103 def testFdtmapHeaderStart(self):
2104 """Test an image header can be inserted at the image start"""
2105 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2106 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2108 self.assertEqual('BinM', hdr_data[:4])
2109 offset = struct.unpack('<I', hdr_data[4:])[0]
2110 self.assertEqual(fdtmap_pos, offset)
2112 def testFdtmapHeaderPos(self):
2113 """Test an image header can be inserted at a chosen position"""
2114 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2115 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2116 hdr_data = data[0x80:0x88]
2117 self.assertEqual('BinM', hdr_data[:4])
2118 offset = struct.unpack('<I', hdr_data[4:])[0]
2119 self.assertEqual(fdtmap_pos, offset)
2121 def testHeaderMissingFdtmap(self):
2122 """Test an image header requires an fdtmap"""
2123 with self.assertRaises(ValueError) as e:
2124 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2125 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2128 def testHeaderNoLocation(self):
2129 """Test an image header with a no specified location is detected"""
2130 with self.assertRaises(ValueError) as e:
2131 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2132 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2135 def testEntryExpand(self):
2136 """Test expanding an entry after it is packed"""
2137 data = self._DoReadFile('121_entry_expand.dts')
2138 self.assertEqual(b'aaa', data[:3])
2139 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2140 self.assertEqual(b'aaa', data[-3:])
2142 def testEntryExpandBad(self):
2143 """Test expanding an entry after it is packed, twice"""
2144 with self.assertRaises(ValueError) as e:
2145 self._DoReadFile('122_entry_expand_twice.dts')
2146 self.assertIn("Image '/binman': Entries changed size after packing",
2149 def testEntryExpandSection(self):
2150 """Test expanding an entry within a section after it is packed"""
2151 data = self._DoReadFile('123_entry_expand_section.dts')
2152 self.assertEqual(b'aaa', data[:3])
2153 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2154 self.assertEqual(b'aaa', data[-3:])
2156 def testCompressDtb(self):
2157 """Test that compress of device-tree files is supported"""
2159 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2160 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2161 comp_data = data[len(U_BOOT_DATA):]
2162 orig = self._decompress(comp_data)
2163 dtb = fdt.Fdt.FromData(orig)
2165 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2167 'u-boot:size': len(U_BOOT_DATA),
2168 'u-boot-dtb:uncomp-size': len(orig),
2169 'u-boot-dtb:size': len(comp_data),
2172 self.assertEqual(expected, props)
2174 def testCbfsUpdateFdt(self):
2175 """Test that we can update the device tree with CBFS offset/size info"""
2177 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2179 dtb = fdt.Fdt(out_dtb_fname)
2181 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2182 del props['cbfs/u-boot:size']
2188 'cbfs:size': len(data),
2189 'cbfs:image-pos': 0,
2190 'cbfs/u-boot:offset': 0x38,
2191 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2192 'cbfs/u-boot:image-pos': 0x38,
2193 'cbfs/u-boot-dtb:offset': 0xb8,
2194 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2195 'cbfs/u-boot-dtb:image-pos': 0xb8,
2198 def testCbfsBadType(self):
2199 """Test an image header with a no specified location is detected"""
2200 with self.assertRaises(ValueError) as e:
2201 self._DoReadFile('126_cbfs_bad_type.dts')
2202 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2205 """Test listing the files in an image"""
2207 data = self._DoReadFile('127_list.dts')
2208 image = control.images['image']
2209 entries = image.BuildEntryList()
2210 self.assertEqual(7, len(entries))
2213 self.assertEqual(0, ent.indent)
2214 self.assertEqual('main-section', ent.name)
2215 self.assertEqual('section', ent.etype)
2216 self.assertEqual(len(data), ent.size)
2217 self.assertEqual(0, ent.image_pos)
2218 self.assertEqual(None, ent.uncomp_size)
2219 self.assertEqual(0, ent.offset)
2222 self.assertEqual(1, ent.indent)
2223 self.assertEqual('u-boot', ent.name)
2224 self.assertEqual('u-boot', ent.etype)
2225 self.assertEqual(len(U_BOOT_DATA), ent.size)
2226 self.assertEqual(0, ent.image_pos)
2227 self.assertEqual(None, ent.uncomp_size)
2228 self.assertEqual(0, ent.offset)
2231 self.assertEqual(1, ent.indent)
2232 self.assertEqual('section', ent.name)
2233 self.assertEqual('section', ent.etype)
2234 section_size = ent.size
2235 self.assertEqual(0x100, ent.image_pos)
2236 self.assertEqual(None, ent.uncomp_size)
2237 self.assertEqual(0x100, ent.offset)
2240 self.assertEqual(2, ent.indent)
2241 self.assertEqual('cbfs', ent.name)
2242 self.assertEqual('cbfs', ent.etype)
2243 self.assertEqual(0x400, ent.size)
2244 self.assertEqual(0x100, ent.image_pos)
2245 self.assertEqual(None, ent.uncomp_size)
2246 self.assertEqual(0, ent.offset)
2249 self.assertEqual(3, ent.indent)
2250 self.assertEqual('u-boot', ent.name)
2251 self.assertEqual('u-boot', ent.etype)
2252 self.assertEqual(len(U_BOOT_DATA), ent.size)
2253 self.assertEqual(0x138, ent.image_pos)
2254 self.assertEqual(None, ent.uncomp_size)
2255 self.assertEqual(0x38, ent.offset)
2258 self.assertEqual(3, ent.indent)
2259 self.assertEqual('u-boot-dtb', ent.name)
2260 self.assertEqual('text', ent.etype)
2261 self.assertGreater(len(COMPRESS_DATA), ent.size)
2262 self.assertEqual(0x178, ent.image_pos)
2263 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2264 self.assertEqual(0x78, ent.offset)
2267 self.assertEqual(2, ent.indent)
2268 self.assertEqual('u-boot-dtb', ent.name)
2269 self.assertEqual('u-boot-dtb', ent.etype)
2270 self.assertEqual(0x500, ent.image_pos)
2271 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2273 # Compressing this data expands it since headers are added
2274 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2275 self.assertEqual(0x400, ent.offset)
2277 self.assertEqual(len(data), 0x100 + section_size)
2278 self.assertEqual(section_size, 0x400 + dtb_size)
2280 def testFindFdtmap(self):
2281 """Test locating an FDT map in an image"""
2283 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2284 image = control.images['image']
2285 entries = image.GetEntries()
2286 entry = entries['fdtmap']
2287 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2289 def testFindFdtmapMissing(self):
2290 """Test failing to locate an FDP map"""
2291 data = self._DoReadFile('005_simple.dts')
2292 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2294 def testFindImageHeader(self):
2295 """Test locating a image header"""
2297 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2298 image = control.images['image']
2299 entries = image.GetEntries()
2300 entry = entries['fdtmap']
2301 # The header should point to the FDT map
2302 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2304 def testFindImageHeaderStart(self):
2305 """Test locating a image header located at the start of an image"""
2306 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2307 image = control.images['image']
2308 entries = image.GetEntries()
2309 entry = entries['fdtmap']
2310 # The header should point to the FDT map
2311 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2313 def testFindImageHeaderMissing(self):
2314 """Test failing to locate an image header"""
2315 data = self._DoReadFile('005_simple.dts')
2316 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2318 def testReadImage(self):
2319 """Test reading an image and accessing its FDT map"""
2321 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2322 image_fname = tools.GetOutputFilename('image.bin')
2323 orig_image = control.images['image']
2324 image = Image.FromFile(image_fname)
2325 self.assertEqual(orig_image.GetEntries().keys(),
2326 image.GetEntries().keys())
2328 orig_entry = orig_image.GetEntries()['fdtmap']
2329 entry = image.GetEntries()['fdtmap']
2330 self.assertEquals(orig_entry.offset, entry.offset)
2331 self.assertEquals(orig_entry.size, entry.size)
2332 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2334 def testReadImageNoHeader(self):
2335 """Test accessing an image's FDT map without an image header"""
2337 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2338 image_fname = tools.GetOutputFilename('image.bin')
2339 image = Image.FromFile(image_fname)
2340 self.assertTrue(isinstance(image, Image))
2341 self.assertEqual('image', image.image_name[-5:])
2343 def testReadImageFail(self):
2344 """Test failing to read an image image's FDT map"""
2345 self._DoReadFile('005_simple.dts')
2346 image_fname = tools.GetOutputFilename('image.bin')
2347 with self.assertRaises(ValueError) as e:
2348 image = Image.FromFile(image_fname)
2349 self.assertIn("Cannot find FDT map in image", str(e.exception))
2351 def testListCmd(self):
2352 """Test listing the files in an image using an Fdtmap"""
2354 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2356 # lz4 compression size differs depending on the version
2357 image = control.images['image']
2358 entries = image.GetEntries()
2359 section_size = entries['section'].size
2360 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2361 fdtmap_offset = entries['fdtmap'].offset
2363 image_fname = tools.GetOutputFilename('image.bin')
2364 with test_util.capture_sys_output() as (stdout, stderr):
2365 self._DoBinman('ls', '-i', image_fname)
2366 lines = stdout.getvalue().splitlines()
2368 'Name Image-pos Size Entry-type Offset Uncomp-size',
2369 '----------------------------------------------------------------------',
2370 'main-section 0 c00 section 0',
2371 ' u-boot 0 4 u-boot 0',
2372 ' section 100 %x section 100' % section_size,
2373 ' cbfs 100 400 cbfs 0',
2374 ' u-boot 138 4 u-boot 38',
2375 ' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2376 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2377 ' fdtmap %x 3b4 fdtmap %x' %
2378 (fdtmap_offset, fdtmap_offset),
2379 ' image-header bf8 8 image-header bf8',
2381 self.assertEqual(expected, lines)
2383 def testListCmdFail(self):
2384 """Test failing to list an image"""
2385 self._DoReadFile('005_simple.dts')
2386 image_fname = tools.GetOutputFilename('image.bin')
2387 with self.assertRaises(ValueError) as e:
2388 self._DoBinman('ls', '-i', image_fname)
2389 self.assertIn("Cannot find FDT map in image", str(e.exception))
2391 def _RunListCmd(self, paths, expected):
2392 """List out entries and check the result
2395 paths: List of paths to pass to the list command
2396 expected: Expected list of filenames to be returned, in order
2399 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2400 image_fname = tools.GetOutputFilename('image.bin')
2401 image = Image.FromFile(image_fname)
2402 lines = image.GetListEntries(paths)[1]
2403 files = [line[0].strip() for line in lines[1:]]
2404 self.assertEqual(expected, files)
2406 def testListCmdSection(self):
2407 """Test listing the files in a section"""
2408 self._RunListCmd(['section'],
2409 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2411 def testListCmdFile(self):
2412 """Test listing a particular file"""
2413 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2415 def testListCmdWildcard(self):
2416 """Test listing a wildcarded file"""
2417 self._RunListCmd(['*boot*'],
2418 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2420 def testListCmdWildcardMulti(self):
2421 """Test listing a wildcarded file"""
2422 self._RunListCmd(['*cb*', '*head*'],
2423 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2425 def testListCmdEmpty(self):
2426 """Test listing a wildcarded file"""
2427 self._RunListCmd(['nothing'], [])
2429 def testListCmdPath(self):
2430 """Test listing the files in a sub-entry of a section"""
2431 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2433 def _RunExtractCmd(self, entry_name, decomp=True):
2434 """Extract an entry from an image
2437 entry_name: Entry name to extract
2438 decomp: True to decompress the data if compressed, False to leave
2439 it in its raw uncompressed format
2445 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2446 image_fname = tools.GetOutputFilename('image.bin')
2447 return control.ReadEntry(image_fname, entry_name, decomp)
2449 def testExtractSimple(self):
2450 """Test extracting a single file"""
2451 data = self._RunExtractCmd('u-boot')
2452 self.assertEqual(U_BOOT_DATA, data)
2454 def testExtractSection(self):
2455 """Test extracting the files in a section"""
2456 data = self._RunExtractCmd('section')
2457 cbfs_data = data[:0x400]
2458 cbfs = cbfs_util.CbfsReader(cbfs_data)
2459 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2460 dtb_data = data[0x400:]
2461 dtb = self._decompress(dtb_data)
2462 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2464 def testExtractCompressed(self):
2465 """Test extracting compressed data"""
2466 data = self._RunExtractCmd('section/u-boot-dtb')
2467 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2469 def testExtractRaw(self):
2470 """Test extracting compressed data without decompressing it"""
2471 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2472 dtb = self._decompress(data)
2473 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2475 def testExtractCbfs(self):
2476 """Test extracting CBFS data"""
2477 data = self._RunExtractCmd('section/cbfs/u-boot')
2478 self.assertEqual(U_BOOT_DATA, data)
2480 def testExtractCbfsCompressed(self):
2481 """Test extracting CBFS compressed data"""
2482 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2483 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2485 def testExtractCbfsRaw(self):
2486 """Test extracting CBFS compressed data without decompressing it"""
2487 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2488 dtb = tools.Decompress(data, 'lzma', with_header=False)
2489 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2491 def testExtractBadEntry(self):
2492 """Test extracting a bad section path"""
2493 with self.assertRaises(ValueError) as e:
2494 self._RunExtractCmd('section/does-not-exist')
2495 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2498 def testExtractMissingFile(self):
2499 """Test extracting file that does not exist"""
2500 with self.assertRaises(IOError) as e:
2501 control.ReadEntry('missing-file', 'name')
2503 def testExtractBadFile(self):
2504 """Test extracting an invalid file"""
2505 fname = os.path.join(self._indir, 'badfile')
2506 tools.WriteFile(fname, b'')
2507 with self.assertRaises(ValueError) as e:
2508 control.ReadEntry(fname, 'name')
2510 def testExtractCmd(self):
2511 """Test extracting a file fron an image on the command line"""
2513 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2514 image_fname = tools.GetOutputFilename('image.bin')
2515 fname = os.path.join(self._indir, 'output.extact')
2516 with test_util.capture_sys_output() as (stdout, stderr):
2517 self._DoBinman('extract', '-i', image_fname, 'u-boot', '-f', fname)
2518 data = tools.ReadFile(fname)
2519 self.assertEqual(U_BOOT_DATA, data)
2521 def testExtractOneEntry(self):
2522 """Test extracting a single entry fron an image """
2524 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2525 image_fname = tools.GetOutputFilename('image.bin')
2526 fname = os.path.join(self._indir, 'output.extact')
2527 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2528 data = tools.ReadFile(fname)
2529 self.assertEqual(U_BOOT_DATA, data)
2531 def _CheckExtractOutput(self, decomp):
2532 """Helper to test file output with and without decompression
2535 decomp: True to decompress entry data, False to output it raw
2537 def _CheckPresent(entry_path, expect_data, expect_size=None):
2538 """Check and remove expected file
2540 This checks the data/size of a file and removes the file both from
2541 the outfiles set and from the output directory. Once all files are
2542 processed, both the set and directory should be empty.
2545 entry_path: Entry path
2546 expect_data: Data to expect in file, or None to skip check
2547 expect_size: Size of data to expect in file, or None to skip
2549 path = os.path.join(outdir, entry_path)
2550 data = tools.ReadFile(path)
2553 self.assertEqual(expect_data, data)
2555 self.assertEqual(expect_size, len(data))
2556 outfiles.remove(path)
2558 def _CheckDirPresent(name):
2559 """Remove expected directory
2561 This gives an error if the directory does not exist as expected
2564 name: Name of directory to remove
2566 path = os.path.join(outdir, name)
2569 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2570 image_fname = tools.GetOutputFilename('image.bin')
2571 outdir = os.path.join(self._indir, 'extract')
2572 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2574 # Create a set of all file that were output (should be 9)
2576 for root, dirs, files in os.walk(outdir):
2577 outfiles |= set([os.path.join(root, fname) for fname in files])
2578 self.assertEqual(9, len(outfiles))
2579 self.assertEqual(9, len(einfos))
2581 image = control.images['image']
2582 entries = image.GetEntries()
2584 # Check the 9 files in various ways
2585 section = entries['section']
2586 section_entries = section.GetEntries()
2587 cbfs_entries = section_entries['cbfs'].GetEntries()
2588 _CheckPresent('u-boot', U_BOOT_DATA)
2589 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2590 dtb_len = EXTRACT_DTB_SIZE
2592 dtb_len = cbfs_entries['u-boot-dtb'].size
2593 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2595 dtb_len = section_entries['u-boot-dtb'].size
2596 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2598 fdtmap = entries['fdtmap']
2599 _CheckPresent('fdtmap', fdtmap.data)
2600 hdr = entries['image-header']
2601 _CheckPresent('image-header', hdr.data)
2603 _CheckPresent('section/root', section.data)
2604 cbfs = section_entries['cbfs']
2605 _CheckPresent('section/cbfs/root', cbfs.data)
2606 data = tools.ReadFile(image_fname)
2607 _CheckPresent('root', data)
2609 # There should be no files left. Remove all the directories to check.
2610 # If there are any files/dirs remaining, one of these checks will fail.
2611 self.assertEqual(0, len(outfiles))
2612 _CheckDirPresent('section/cbfs')
2613 _CheckDirPresent('section')
2614 _CheckDirPresent('')
2615 self.assertFalse(os.path.exists(outdir))
2617 def testExtractAllEntries(self):
2618 """Test extracting all entries"""
2620 self._CheckExtractOutput(decomp=True)
2622 def testExtractAllEntriesRaw(self):
2623 """Test extracting all entries without decompressing them"""
2625 self._CheckExtractOutput(decomp=False)
2627 def testExtractSelectedEntries(self):
2628 """Test extracting some entries"""
2630 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2631 image_fname = tools.GetOutputFilename('image.bin')
2632 outdir = os.path.join(self._indir, 'extract')
2633 einfos = control.ExtractEntries(image_fname, None, outdir,
2636 # File output is tested by testExtractAllEntries(), so just check that
2637 # the expected entries are selected
2638 names = [einfo.name for einfo in einfos]
2639 self.assertEqual(names,
2640 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2642 def testExtractNoEntryPaths(self):
2643 """Test extracting some entries"""
2645 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2646 image_fname = tools.GetOutputFilename('image.bin')
2647 with self.assertRaises(ValueError) as e:
2648 control.ExtractEntries(image_fname, 'fname', None, [])
2649 self.assertIn('Must specify an entry path to write with -o',
2652 def testExtractTooManyEntryPaths(self):
2653 """Test extracting some entries"""
2655 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2656 image_fname = tools.GetOutputFilename('image.bin')
2657 with self.assertRaises(ValueError) as e:
2658 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2659 self.assertIn('Must specify exactly one entry path to write with -o',
2662 def testPackAlignSection(self):
2663 """Test that sections can have alignment"""
2664 self._DoReadFile('131_pack_align_section.dts')
2666 self.assertIn('image', control.images)
2667 image = control.images['image']
2668 entries = image.GetEntries()
2669 self.assertEqual(3, len(entries))
2672 self.assertIn('u-boot', entries)
2673 entry = entries['u-boot']
2674 self.assertEqual(0, entry.offset)
2675 self.assertEqual(0, entry.image_pos)
2676 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2677 self.assertEqual(len(U_BOOT_DATA), entry.size)
2680 self.assertIn('section0', entries)
2681 section0 = entries['section0']
2682 self.assertEqual(0x10, section0.offset)
2683 self.assertEqual(0x10, section0.image_pos)
2684 self.assertEqual(len(U_BOOT_DATA), section0.size)
2687 section_entries = section0.GetEntries()
2688 self.assertIn('u-boot', section_entries)
2689 entry = section_entries['u-boot']
2690 self.assertEqual(0, entry.offset)
2691 self.assertEqual(0x10, entry.image_pos)
2692 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2693 self.assertEqual(len(U_BOOT_DATA), entry.size)
2696 self.assertIn('section1', entries)
2697 section1 = entries['section1']
2698 self.assertEqual(0x14, section1.offset)
2699 self.assertEqual(0x14, section1.image_pos)
2700 self.assertEqual(0x20, section1.size)
2703 section_entries = section1.GetEntries()
2704 self.assertIn('u-boot', section_entries)
2705 entry = section_entries['u-boot']
2706 self.assertEqual(0, entry.offset)
2707 self.assertEqual(0x14, entry.image_pos)
2708 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2709 self.assertEqual(len(U_BOOT_DATA), entry.size)
2712 self.assertIn('section2', section_entries)
2713 section2 = section_entries['section2']
2714 self.assertEqual(0x4, section2.offset)
2715 self.assertEqual(0x18, section2.image_pos)
2716 self.assertEqual(4, section2.size)
2719 section_entries = section2.GetEntries()
2720 self.assertIn('u-boot', section_entries)
2721 entry = section_entries['u-boot']
2722 self.assertEqual(0, entry.offset)
2723 self.assertEqual(0x18, entry.image_pos)
2724 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2725 self.assertEqual(len(U_BOOT_DATA), entry.size)
2727 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2728 dts='132_replace.dts'):
2729 """Replace an entry in an image
2731 This writes the entry data to update it, then opens the updated file and
2732 returns the value that it now finds there.
2735 entry_name: Entry name to replace
2736 data: Data to replace it with
2737 decomp: True to compress the data if needed, False if data is
2738 already compressed so should be used as is
2739 allow_resize: True to allow entries to change size, False to raise
2745 data from fdtmap (excluding header)
2746 Image object that was modified
2748 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2751 self.assertIn('image', control.images)
2752 image = control.images['image']
2753 entries = image.GetEntries()
2754 orig_dtb_data = entries['u-boot-dtb'].data
2755 orig_fdtmap_data = entries['fdtmap'].data
2757 image_fname = tools.GetOutputFilename('image.bin')
2758 updated_fname = tools.GetOutputFilename('image-updated.bin')
2759 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2760 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2762 data = control.ReadEntry(updated_fname, entry_name, decomp)
2764 # The DT data should not change unless resized:
2765 if not allow_resize:
2766 new_dtb_data = entries['u-boot-dtb'].data
2767 self.assertEqual(new_dtb_data, orig_dtb_data)
2768 new_fdtmap_data = entries['fdtmap'].data
2769 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2771 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2773 def testReplaceSimple(self):
2774 """Test replacing a single file"""
2775 expected = b'x' * len(U_BOOT_DATA)
2776 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2778 self.assertEqual(expected, data)
2780 # Test that the state looks right. There should be an FDT for the fdtmap
2781 # that we jsut read back in, and it should match what we find in the
2782 # 'control' tables. Checking for an FDT that does not exist should
2784 path, fdtmap = state.GetFdtContents('fdtmap')
2785 self.assertIsNotNone(path)
2786 self.assertEqual(expected_fdtmap, fdtmap)
2788 dtb = state.GetFdtForEtype('fdtmap')
2789 self.assertEqual(dtb.GetContents(), fdtmap)
2791 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2792 self.assertIsNone(missing_path)
2793 self.assertIsNone(missing_fdtmap)
2795 missing_dtb = state.GetFdtForEtype('missing')
2796 self.assertIsNone(missing_dtb)
2798 self.assertEqual('/binman', state.fdt_path_prefix)
2800 def testReplaceResizeFail(self):
2801 """Test replacing a file by something larger"""
2802 expected = U_BOOT_DATA + b'x'
2803 with self.assertRaises(ValueError) as e:
2804 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2805 dts='139_replace_repack.dts')
2806 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2809 def testReplaceMulti(self):
2810 """Test replacing entry data where multiple images are generated"""
2811 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2813 expected = b'x' * len(U_BOOT_DATA)
2814 updated_fname = tools.GetOutputFilename('image-updated.bin')
2815 tools.WriteFile(updated_fname, data)
2816 entry_name = 'u-boot'
2817 control.WriteEntry(updated_fname, entry_name, expected,
2819 data = control.ReadEntry(updated_fname, entry_name)
2820 self.assertEqual(expected, data)
2822 # Check the state looks right.
2823 self.assertEqual('/binman/image', state.fdt_path_prefix)
2825 # Now check we can write the first image
2826 image_fname = tools.GetOutputFilename('first-image.bin')
2827 updated_fname = tools.GetOutputFilename('first-updated.bin')
2828 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2829 entry_name = 'u-boot'
2830 control.WriteEntry(updated_fname, entry_name, expected,
2832 data = control.ReadEntry(updated_fname, entry_name)
2833 self.assertEqual(expected, data)
2835 # Check the state looks right.
2836 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2838 def testUpdateFdtAllRepack(self):
2839 """Test that all device trees are updated with offset/size info"""
2840 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2841 SECTION_SIZE = 0x300
2846 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2848 'section:offset': 0,
2849 'section:size': SECTION_SIZE,
2850 'section:image-pos': 0,
2851 'section/u-boot-dtb:offset': 4,
2852 'section/u-boot-dtb:size': 636,
2853 'section/u-boot-dtb:image-pos': 4,
2854 'u-boot-spl-dtb:offset': SECTION_SIZE,
2855 'u-boot-spl-dtb:size': DTB_SIZE,
2856 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2857 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2858 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2859 'u-boot-tpl-dtb:size': DTB_SIZE,
2860 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2861 'fdtmap:size': FDTMAP_SIZE,
2862 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2865 'section:orig-size': SECTION_SIZE,
2866 'section/u-boot-dtb:orig-offset': 4,
2869 # We expect three device-tree files in the output, with the first one
2870 # within a fixed-size section.
2871 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2872 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2873 # main U-Boot tree. All three should have the same positions and offset
2874 # except that the main tree should include the main_expected properties
2876 for item in ['', 'spl', 'tpl', None]:
2878 start += 16 # Move past fdtmap header
2879 dtb = fdt.Fdt.FromData(data[start:])
2881 props = self._GetPropTree(dtb,
2882 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2883 prefix='/' if item is None else '/binman/')
2884 expected = dict(base_expected)
2888 # Main DTB and fdtdec should include the 'orig-' properties
2889 expected.update(main_expected)
2890 # Helpful for debugging:
2891 #for prop in sorted(props):
2892 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2893 self.assertEqual(expected, props)
2895 start = SECTION_SIZE
2897 start += dtb._fdt_obj.totalsize()
2899 def testFdtmapHeaderMiddle(self):
2900 """Test an FDT map in the middle of an image when it should be at end"""
2901 with self.assertRaises(ValueError) as e:
2902 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2903 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2906 def testFdtmapHeaderStartBad(self):
2907 """Test an FDT map in middle of an image when it should be at start"""
2908 with self.assertRaises(ValueError) as e:
2909 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2910 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2913 def testFdtmapHeaderEndBad(self):
2914 """Test an FDT map at the start of an image when it should be at end"""
2915 with self.assertRaises(ValueError) as e:
2916 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2917 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2920 def testFdtmapHeaderNoSize(self):
2921 """Test an image header at the end of an image with undefined size"""
2922 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2924 def testReplaceResize(self):
2925 """Test replacing a single file in an entry with a larger file"""
2926 expected = U_BOOT_DATA + b'x'
2927 data, _, image = self._RunReplaceCmd('u-boot', expected,
2928 dts='139_replace_repack.dts')
2929 self.assertEqual(expected, data)
2931 entries = image.GetEntries()
2932 dtb_data = entries['u-boot-dtb'].data
2933 dtb = fdt.Fdt.FromData(dtb_data)
2936 # The u-boot section should now be larger in the dtb
2937 node = dtb.GetNode('/binman/u-boot')
2938 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
2940 # Same for the fdtmap
2941 fdata = entries['fdtmap'].data
2942 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
2944 fnode = fdtb.GetNode('/u-boot')
2945 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
2947 def testReplaceResizeNoRepack(self):
2948 """Test replacing an entry with a larger file when not allowed"""
2949 expected = U_BOOT_DATA + b'x'
2950 with self.assertRaises(ValueError) as e:
2951 self._RunReplaceCmd('u-boot', expected)
2952 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
2955 def testEntryShrink(self):
2956 """Test contracting an entry after it is packed"""
2958 state.SetAllowEntryContraction(True)
2959 data = self._DoReadFileDtb('140_entry_shrink.dts',
2962 state.SetAllowEntryContraction(False)
2963 self.assertEqual(b'a', data[:1])
2964 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
2965 self.assertEqual(b'a', data[-1:])
2967 def testEntryShrinkFail(self):
2968 """Test not being allowed to contract an entry after it is packed"""
2969 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
2971 # In this case there is a spare byte at the end of the data. The size of
2972 # the contents is only 1 byte but we still have the size before it
2974 self.assertEqual(b'a\0', data[:2])
2975 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2976 self.assertEqual(b'a\0', data[-2:])
2978 def testDescriptorOffset(self):
2979 """Test that the Intel descriptor is always placed at at the start"""
2980 data = self._DoReadFileDtb('141_descriptor_offset.dts')
2981 image = control.images['image']
2982 entries = image.GetEntries()
2983 desc = entries['intel-descriptor']
2984 self.assertEqual(0xff800000, desc.offset);
2985 self.assertEqual(0xff800000, desc.image_pos);
2987 def testReplaceCbfs(self):
2988 """Test replacing a single file in CBFS without changing the size"""
2990 expected = b'x' * len(U_BOOT_DATA)
2991 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
2992 updated_fname = tools.GetOutputFilename('image-updated.bin')
2993 tools.WriteFile(updated_fname, data)
2994 entry_name = 'section/cbfs/u-boot'
2995 control.WriteEntry(updated_fname, entry_name, expected,
2997 data = control.ReadEntry(updated_fname, entry_name)
2998 self.assertEqual(expected, data)
3000 def testReplaceResizeCbfs(self):
3001 """Test replacing a single file in CBFS with one of a different size"""
3003 expected = U_BOOT_DATA + b'x'
3004 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3005 updated_fname = tools.GetOutputFilename('image-updated.bin')
3006 tools.WriteFile(updated_fname, data)
3007 entry_name = 'section/cbfs/u-boot'
3008 control.WriteEntry(updated_fname, entry_name, expected,
3010 data = control.ReadEntry(updated_fname, entry_name)
3011 self.assertEqual(expected, data)
3014 if __name__ == "__main__":