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')
190 def _CleanupOutputDir(self):
191 """Remove the temporary output directory"""
192 if self.preserve_outdirs:
193 print('Preserving output dir: %s' % tools.outdir)
195 tools._FinaliseForTest()
198 # Enable this to turn on debugging output
199 # tout.Init(tout.DEBUG)
200 command.test_result = None
203 """Remove the temporary output directory"""
204 self._CleanupOutputDir()
206 def _SetupImageInTmpdir(self):
207 """Set up the output image in a new temporary directory
209 This is used when an image has been generated in the output directory,
210 but we want to run binman again. This will create a new output
211 directory and fail to delete the original one.
213 This creates a new temporary directory, copies the image to it (with a
214 new name) and removes the old output directory.
218 Temporary directory to use
221 image_fname = tools.GetOutputFilename('image.bin')
222 tmpdir = tempfile.mkdtemp(prefix='binman.')
223 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
224 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
225 self._CleanupOutputDir()
226 return tmpdir, updated_fname
229 def _ResetDtbs(self):
230 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
231 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
232 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
234 def _RunBinman(self, *args, **kwargs):
235 """Run binman using the command line
238 Arguments to pass, as a list of strings
239 kwargs: Arguments to pass to Command.RunPipe()
241 result = command.RunPipe([[self._binman_pathname] + list(args)],
242 capture=True, capture_stderr=True, raise_on_error=False)
243 if result.return_code and kwargs.get('raise_on_error', True):
244 raise Exception("Error running '%s': %s" % (' '.join(args),
245 result.stdout + result.stderr))
248 def _DoBinman(self, *argv):
249 """Run binman using directly (in the same process)
252 Arguments to pass, as a list of strings
254 Return value (0 for success)
257 args = cmdline.ParseArgs(argv)
258 args.pager = 'binman-invalid-pager'
259 args.build_dir = self._indir
261 # For testing, you can force an increase in verbosity here
262 # args.verbosity = tout.DEBUG
263 return control.Binman(args)
265 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
266 entry_args=None, images=None, use_real_dtb=False,
268 """Run binman with a given test file
271 fname: Device-tree source filename to use (e.g. 005_simple.dts)
272 debug: True to enable debugging output
273 map: True to output map files for the images
274 update_dtb: Update the offset and size of each entry in the device
275 tree before packing it into the image
276 entry_args: Dict of entry args to supply to binman
278 value: value of that arg
279 images: List of image names to build
284 if verbosity is not None:
285 args.append('-v%d' % verbosity)
287 args.append('-v%d' % self.verbosity)
289 for path in self.toolpath:
290 args += ['--toolpath', path]
291 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
297 args.append('--fake-dtb')
299 for arg, value in entry_args.items():
300 args.append('-a%s=%s' % (arg, value))
303 args += ['-i', image]
304 return self._DoBinman(*args)
306 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
307 """Set up a new test device-tree file
309 The given file is compiled and set up as the device tree to be used
313 fname: Filename of .dts file to read
314 outfile: Output filename for compiled device-tree binary
317 Contents of device-tree binary
319 tmpdir = tempfile.mkdtemp(prefix='binmant.')
320 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
321 with open(dtb, 'rb') as fd:
323 TestFunctional._MakeInputFile(outfile, data)
324 shutil.rmtree(tmpdir)
327 def _GetDtbContentsForSplTpl(self, dtb_data, name):
328 """Create a version of the main DTB for SPL or SPL
330 For testing we don't actually have different versions of the DTB. With
331 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
332 we don't normally have any unwanted nodes.
334 We still want the DTBs for SPL and TPL to be different though, since
335 otherwise it is confusing to know which one we are looking at. So add
336 an 'spl' or 'tpl' property to the top-level node.
338 dtb = fdt.Fdt.FromData(dtb_data)
340 dtb.GetNode('/binman').AddZeroProp(name)
341 dtb.Sync(auto_resize=True)
343 return dtb.GetContents()
345 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
346 update_dtb=False, entry_args=None, reset_dtbs=True):
347 """Run binman and return the resulting image
349 This runs binman with a given test file and then reads the resulting
350 output file. It is a shortcut function since most tests need to do
353 Raises an assertion failure if binman returns a non-zero exit code.
356 fname: Device-tree source filename to use (e.g. 005_simple.dts)
357 use_real_dtb: True to use the test file as the contents of
358 the u-boot-dtb entry. Normally this is not needed and the
359 test contents (the U_BOOT_DTB_DATA string) can be used.
360 But in some test we need the real contents.
361 map: True to output map files for the images
362 update_dtb: Update the offset and size of each entry in the device
363 tree before packing it into the image
367 Resulting image contents
369 Map data showing contents of image (or None if none)
370 Output device tree binary filename ('u-boot.dtb' path)
373 # Use the compiled test file as the u-boot-dtb input
375 dtb_data = self._SetupDtb(fname)
377 # For testing purposes, make a copy of the DT for SPL and TPL. Add
378 # a node indicating which it is, so aid verification.
379 for name in ['spl', 'tpl']:
380 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
381 outfile = os.path.join(self._indir, dtb_fname)
382 TestFunctional._MakeInputFile(dtb_fname,
383 self._GetDtbContentsForSplTpl(dtb_data, name))
386 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
387 entry_args=entry_args, use_real_dtb=use_real_dtb)
388 self.assertEqual(0, retcode)
389 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
391 # Find the (only) image, read it and return its contents
392 image = control.images['image']
393 image_fname = tools.GetOutputFilename('image.bin')
394 self.assertTrue(os.path.exists(image_fname))
396 map_fname = tools.GetOutputFilename('image.map')
397 with open(map_fname) as fd:
401 with open(image_fname, 'rb') as fd:
402 return fd.read(), dtb_data, map_data, out_dtb_fname
404 # Put the test file back
405 if reset_dtbs and use_real_dtb:
408 def _DoReadFileRealDtb(self, fname):
409 """Run binman with a real .dtb file and return the resulting data
412 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
415 Resulting image contents
417 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
419 def _DoReadFile(self, fname, use_real_dtb=False):
420 """Helper function which discards the device-tree binary
423 fname: Device-tree source filename to use (e.g. 005_simple.dts)
424 use_real_dtb: True to use the test file as the contents of
425 the u-boot-dtb entry. Normally this is not needed and the
426 test contents (the U_BOOT_DTB_DATA string) can be used.
427 But in some test we need the real contents.
430 Resulting image contents
432 return self._DoReadFileDtb(fname, use_real_dtb)[0]
435 def _MakeInputFile(self, fname, contents):
436 """Create a new test input file, creating directories as needed
439 fname: Filename to create
440 contents: File contents to write in to the file
442 Full pathname of file created
444 pathname = os.path.join(self._indir, fname)
445 dirname = os.path.dirname(pathname)
446 if dirname and not os.path.exists(dirname):
448 with open(pathname, 'wb') as fd:
453 def _MakeInputDir(self, dirname):
454 """Create a new test input directory, creating directories as needed
457 dirname: Directory name to create
460 Full pathname of directory created
462 pathname = os.path.join(self._indir, dirname)
463 if not os.path.exists(pathname):
464 os.makedirs(pathname)
468 def _SetupSplElf(self, src_fname='bss_data'):
469 """Set up an ELF file with a '_dt_ucode_base_size' symbol
472 Filename of ELF file to use as SPL
474 with open(self.TestFile(src_fname), 'rb') as fd:
475 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
478 def TestFile(self, fname):
479 return os.path.join(self._binman_dir, 'test', fname)
481 def AssertInList(self, grep_list, target):
482 """Assert that at least one of a list of things is in a target
485 grep_list: List of strings to check
486 target: Target string
488 for grep in grep_list:
491 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
493 def CheckNoGaps(self, entries):
494 """Check that all entries fit together without gaps
497 entries: List of entries to check
500 for entry in entries.values():
501 self.assertEqual(offset, entry.offset)
504 def GetFdtLen(self, dtb):
505 """Get the totalsize field from a device-tree binary
508 dtb: Device-tree binary contents
511 Total size of device-tree binary, from the header
513 return struct.unpack('>L', dtb[4:8])[0]
515 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
516 def AddNode(node, path):
518 path += '/' + node.name
519 for prop in node.props.values():
520 if prop.name in prop_names:
521 prop_path = path + ':' + prop.name
522 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
524 for subnode in node.subnodes:
525 AddNode(subnode, path)
528 AddNode(dtb.GetRoot(), '')
532 """Test a basic run with valid args"""
533 result = self._RunBinman('-h')
535 def testFullHelp(self):
536 """Test that the full help is displayed with -H"""
537 result = self._RunBinman('-H')
538 help_file = os.path.join(self._binman_dir, 'README')
539 # Remove possible extraneous strings
540 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
541 gothelp = result.stdout.replace(extra, '')
542 self.assertEqual(len(gothelp), os.path.getsize(help_file))
543 self.assertEqual(0, len(result.stderr))
544 self.assertEqual(0, result.return_code)
546 def testFullHelpInternal(self):
547 """Test that the full help is displayed with -H"""
549 command.test_result = command.CommandResult()
550 result = self._DoBinman('-H')
551 help_file = os.path.join(self._binman_dir, 'README')
553 command.test_result = None
556 """Test that the basic help is displayed with -h"""
557 result = self._RunBinman('-h')
558 self.assertTrue(len(result.stdout) > 200)
559 self.assertEqual(0, len(result.stderr))
560 self.assertEqual(0, result.return_code)
563 """Test that we can run it with a specific board"""
564 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
565 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
566 result = self._DoBinman('build', '-b', 'sandbox')
567 self.assertEqual(0, result)
569 def testNeedBoard(self):
570 """Test that we get an error when no board ius supplied"""
571 with self.assertRaises(ValueError) as e:
572 result = self._DoBinman('build')
573 self.assertIn("Must provide a board to process (use -b <board>)",
576 def testMissingDt(self):
577 """Test that an invalid device-tree file generates an error"""
578 with self.assertRaises(Exception) as e:
579 self._RunBinman('build', '-d', 'missing_file')
580 # We get one error from libfdt, and a different one from fdtget.
581 self.AssertInList(["Couldn't open blob from 'missing_file'",
582 'No such file or directory'], str(e.exception))
584 def testBrokenDt(self):
585 """Test that an invalid device-tree source file generates an error
587 Since this is a source file it should be compiled and the error
588 will come from the device-tree compiler (dtc).
590 with self.assertRaises(Exception) as e:
591 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
592 self.assertIn("FATAL ERROR: Unable to parse input tree",
595 def testMissingNode(self):
596 """Test that a device tree without a 'binman' node generates an error"""
597 with self.assertRaises(Exception) as e:
598 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
599 self.assertIn("does not have a 'binman' node", str(e.exception))
602 """Test that an empty binman node works OK (i.e. does nothing)"""
603 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
604 self.assertEqual(0, len(result.stderr))
605 self.assertEqual(0, result.return_code)
607 def testInvalidEntry(self):
608 """Test that an invalid entry is flagged"""
609 with self.assertRaises(Exception) as e:
610 result = self._RunBinman('build', '-d',
611 self.TestFile('004_invalid_entry.dts'))
612 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
613 "'/binman/not-a-valid-type'", str(e.exception))
615 def testSimple(self):
616 """Test a simple binman with a single file"""
617 data = self._DoReadFile('005_simple.dts')
618 self.assertEqual(U_BOOT_DATA, data)
620 def testSimpleDebug(self):
621 """Test a simple binman run with debugging enabled"""
622 self._DoTestFile('005_simple.dts', debug=True)
625 """Test that we can handle creating two images
627 This also tests image padding.
629 retcode = self._DoTestFile('006_dual_image.dts')
630 self.assertEqual(0, retcode)
632 image = control.images['image1']
633 self.assertEqual(len(U_BOOT_DATA), image.size)
634 fname = tools.GetOutputFilename('image1.bin')
635 self.assertTrue(os.path.exists(fname))
636 with open(fname, 'rb') as fd:
638 self.assertEqual(U_BOOT_DATA, data)
640 image = control.images['image2']
641 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
642 fname = tools.GetOutputFilename('image2.bin')
643 self.assertTrue(os.path.exists(fname))
644 with open(fname, 'rb') as fd:
646 self.assertEqual(U_BOOT_DATA, data[3:7])
647 self.assertEqual(tools.GetBytes(0, 3), data[:3])
648 self.assertEqual(tools.GetBytes(0, 5), data[7:])
650 def testBadAlign(self):
651 """Test that an invalid alignment value is detected"""
652 with self.assertRaises(ValueError) as e:
653 self._DoTestFile('007_bad_align.dts')
654 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
655 "of two", str(e.exception))
657 def testPackSimple(self):
658 """Test that packing works as expected"""
659 retcode = self._DoTestFile('008_pack.dts')
660 self.assertEqual(0, retcode)
661 self.assertIn('image', control.images)
662 image = control.images['image']
663 entries = image.GetEntries()
664 self.assertEqual(5, len(entries))
667 self.assertIn('u-boot', entries)
668 entry = entries['u-boot']
669 self.assertEqual(0, entry.offset)
670 self.assertEqual(len(U_BOOT_DATA), entry.size)
672 # Second u-boot, aligned to 16-byte boundary
673 self.assertIn('u-boot-align', entries)
674 entry = entries['u-boot-align']
675 self.assertEqual(16, entry.offset)
676 self.assertEqual(len(U_BOOT_DATA), entry.size)
678 # Third u-boot, size 23 bytes
679 self.assertIn('u-boot-size', entries)
680 entry = entries['u-boot-size']
681 self.assertEqual(20, entry.offset)
682 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
683 self.assertEqual(23, entry.size)
685 # Fourth u-boot, placed immediate after the above
686 self.assertIn('u-boot-next', entries)
687 entry = entries['u-boot-next']
688 self.assertEqual(43, entry.offset)
689 self.assertEqual(len(U_BOOT_DATA), entry.size)
691 # Fifth u-boot, placed at a fixed offset
692 self.assertIn('u-boot-fixed', entries)
693 entry = entries['u-boot-fixed']
694 self.assertEqual(61, entry.offset)
695 self.assertEqual(len(U_BOOT_DATA), entry.size)
697 self.assertEqual(65, image.size)
699 def testPackExtra(self):
700 """Test that extra packing feature works as expected"""
701 retcode = self._DoTestFile('009_pack_extra.dts')
703 self.assertEqual(0, retcode)
704 self.assertIn('image', control.images)
705 image = control.images['image']
706 entries = image.GetEntries()
707 self.assertEqual(5, len(entries))
709 # First u-boot with padding before and after
710 self.assertIn('u-boot', entries)
711 entry = entries['u-boot']
712 self.assertEqual(0, entry.offset)
713 self.assertEqual(3, entry.pad_before)
714 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
716 # Second u-boot has an aligned size, but it has no effect
717 self.assertIn('u-boot-align-size-nop', entries)
718 entry = entries['u-boot-align-size-nop']
719 self.assertEqual(12, entry.offset)
720 self.assertEqual(4, entry.size)
722 # Third u-boot has an aligned size too
723 self.assertIn('u-boot-align-size', entries)
724 entry = entries['u-boot-align-size']
725 self.assertEqual(16, entry.offset)
726 self.assertEqual(32, entry.size)
728 # Fourth u-boot has an aligned end
729 self.assertIn('u-boot-align-end', entries)
730 entry = entries['u-boot-align-end']
731 self.assertEqual(48, entry.offset)
732 self.assertEqual(16, entry.size)
734 # Fifth u-boot immediately afterwards
735 self.assertIn('u-boot-align-both', entries)
736 entry = entries['u-boot-align-both']
737 self.assertEqual(64, entry.offset)
738 self.assertEqual(64, entry.size)
740 self.CheckNoGaps(entries)
741 self.assertEqual(128, image.size)
743 def testPackAlignPowerOf2(self):
744 """Test that invalid entry alignment is detected"""
745 with self.assertRaises(ValueError) as e:
746 self._DoTestFile('010_pack_align_power2.dts')
747 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
748 "of two", str(e.exception))
750 def testPackAlignSizePowerOf2(self):
751 """Test that invalid entry size alignment is detected"""
752 with self.assertRaises(ValueError) as e:
753 self._DoTestFile('011_pack_align_size_power2.dts')
754 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
755 "power of two", str(e.exception))
757 def testPackInvalidAlign(self):
758 """Test detection of an offset that does not match its alignment"""
759 with self.assertRaises(ValueError) as e:
760 self._DoTestFile('012_pack_inv_align.dts')
761 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
762 "align 0x4 (4)", str(e.exception))
764 def testPackInvalidSizeAlign(self):
765 """Test that invalid entry size alignment is detected"""
766 with self.assertRaises(ValueError) as e:
767 self._DoTestFile('013_pack_inv_size_align.dts')
768 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
769 "align-size 0x4 (4)", str(e.exception))
771 def testPackOverlap(self):
772 """Test that overlapping regions are detected"""
773 with self.assertRaises(ValueError) as e:
774 self._DoTestFile('014_pack_overlap.dts')
775 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
776 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
779 def testPackEntryOverflow(self):
780 """Test that entries that overflow their size are detected"""
781 with self.assertRaises(ValueError) as e:
782 self._DoTestFile('015_pack_overflow.dts')
783 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
784 "but entry size is 0x3 (3)", str(e.exception))
786 def testPackImageOverflow(self):
787 """Test that entries which overflow the image size are detected"""
788 with self.assertRaises(ValueError) as e:
789 self._DoTestFile('016_pack_image_overflow.dts')
790 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
791 "size 0x3 (3)", str(e.exception))
793 def testPackImageSize(self):
794 """Test that the image size can be set"""
795 retcode = self._DoTestFile('017_pack_image_size.dts')
796 self.assertEqual(0, retcode)
797 self.assertIn('image', control.images)
798 image = control.images['image']
799 self.assertEqual(7, image.size)
801 def testPackImageSizeAlign(self):
802 """Test that image size alignemnt works as expected"""
803 retcode = self._DoTestFile('018_pack_image_align.dts')
804 self.assertEqual(0, retcode)
805 self.assertIn('image', control.images)
806 image = control.images['image']
807 self.assertEqual(16, image.size)
809 def testPackInvalidImageAlign(self):
810 """Test that invalid image alignment is detected"""
811 with self.assertRaises(ValueError) as e:
812 self._DoTestFile('019_pack_inv_image_align.dts')
813 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
814 "align-size 0x8 (8)", str(e.exception))
816 def testPackAlignPowerOf2(self):
817 """Test that invalid image alignment is detected"""
818 with self.assertRaises(ValueError) as e:
819 self._DoTestFile('020_pack_inv_image_align_power2.dts')
820 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
821 "two", str(e.exception))
823 def testImagePadByte(self):
824 """Test that the image pad byte can be specified"""
826 data = self._DoReadFile('021_image_pad.dts')
827 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
830 def testImageName(self):
831 """Test that image files can be named"""
832 retcode = self._DoTestFile('022_image_name.dts')
833 self.assertEqual(0, retcode)
834 image = control.images['image1']
835 fname = tools.GetOutputFilename('test-name')
836 self.assertTrue(os.path.exists(fname))
838 image = control.images['image2']
839 fname = tools.GetOutputFilename('test-name.xx')
840 self.assertTrue(os.path.exists(fname))
842 def testBlobFilename(self):
843 """Test that generic blobs can be provided by filename"""
844 data = self._DoReadFile('023_blob.dts')
845 self.assertEqual(BLOB_DATA, data)
847 def testPackSorted(self):
848 """Test that entries can be sorted"""
850 data = self._DoReadFile('024_sorted.dts')
851 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
852 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
854 def testPackZeroOffset(self):
855 """Test that an entry at offset 0 is not given a new offset"""
856 with self.assertRaises(ValueError) as e:
857 self._DoTestFile('025_pack_zero_size.dts')
858 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
859 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
862 def testPackUbootDtb(self):
863 """Test that a device tree can be added to U-Boot"""
864 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
865 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
867 def testPackX86RomNoSize(self):
868 """Test that the end-at-4gb property requires a size property"""
869 with self.assertRaises(ValueError) as e:
870 self._DoTestFile('027_pack_4gb_no_size.dts')
871 self.assertIn("Image '/binman': Section size must be provided when "
872 "using end-at-4gb", str(e.exception))
874 def test4gbAndSkipAtStartTogether(self):
875 """Test that the end-at-4gb and skip-at-size property can't be used
877 with self.assertRaises(ValueError) as e:
878 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
879 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
880 "'skip-at-start'", str(e.exception))
882 def testPackX86RomOutside(self):
883 """Test that the end-at-4gb property checks for offset boundaries"""
884 with self.assertRaises(ValueError) as e:
885 self._DoTestFile('028_pack_4gb_outside.dts')
886 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
887 "the section starting at 0xffffffe0 (4294967264)",
890 def testPackX86Rom(self):
891 """Test that a basic x86 ROM can be created"""
893 data = self._DoReadFile('029_x86-rom.dts')
894 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
895 tools.GetBytes(0, 2), data)
897 def testPackX86RomMeNoDesc(self):
898 """Test that an invalid Intel descriptor entry is detected"""
899 TestFunctional._MakeInputFile('descriptor.bin', b'')
900 with self.assertRaises(ValueError) as e:
901 self._DoTestFile('031_x86-rom-me.dts')
902 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
905 def testPackX86RomBadDesc(self):
906 """Test that the Intel requires a descriptor entry"""
907 with self.assertRaises(ValueError) as e:
908 self._DoTestFile('030_x86-rom-me-no-desc.dts')
909 self.assertIn("Node '/binman/intel-me': No offset set with "
910 "offset-unset: should another entry provide this correct "
911 "offset?", str(e.exception))
913 def testPackX86RomMe(self):
914 """Test that an x86 ROM with an ME region can be created"""
915 data = self._DoReadFile('031_x86-rom-me.dts')
916 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
917 if data[:0x1000] != expected_desc:
918 self.fail('Expected descriptor binary at start of image')
919 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
921 def testPackVga(self):
922 """Test that an image with a VGA binary can be created"""
923 data = self._DoReadFile('032_intel-vga.dts')
924 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
926 def testPackStart16(self):
927 """Test that an image with an x86 start16 region can be created"""
928 data = self._DoReadFile('033_x86-start16.dts')
929 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
931 def testPackPowerpcMpc85xxBootpgResetvec(self):
932 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
934 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
935 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
937 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
938 """Handle running a test for insertion of microcode
941 dts_fname: Name of test .dts file
942 nodtb_data: Data that we expect in the first section
943 ucode_second: True if the microsecond entry is second instead of
948 Contents of first region (U-Boot or SPL)
949 Offset and size components of microcode pointer, as inserted
950 in the above (two 4-byte words)
952 data = self._DoReadFile(dts_fname, True)
954 # Now check the device tree has no microcode
956 ucode_content = data[len(nodtb_data):]
957 ucode_pos = len(nodtb_data)
958 dtb_with_ucode = ucode_content[16:]
959 fdt_len = self.GetFdtLen(dtb_with_ucode)
961 dtb_with_ucode = data[len(nodtb_data):]
962 fdt_len = self.GetFdtLen(dtb_with_ucode)
963 ucode_content = dtb_with_ucode[fdt_len:]
964 ucode_pos = len(nodtb_data) + fdt_len
965 fname = tools.GetOutputFilename('test.dtb')
966 with open(fname, 'wb') as fd:
967 fd.write(dtb_with_ucode)
968 dtb = fdt.FdtScan(fname)
969 ucode = dtb.GetNode('/microcode')
970 self.assertTrue(ucode)
971 for node in ucode.subnodes:
972 self.assertFalse(node.props.get('data'))
974 # Check that the microcode appears immediately after the Fdt
975 # This matches the concatenation of the data properties in
976 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
977 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
979 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
981 # Check that the microcode pointer was inserted. It should match the
982 # expected offset and size
983 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
985 u_boot = data[:len(nodtb_data)]
986 return u_boot, pos_and_size
988 def testPackUbootMicrocode(self):
989 """Test that x86 microcode can be handled correctly
991 We expect to see the following in the image, in order:
992 u-boot-nodtb.bin with a microcode pointer inserted at the correct
994 u-boot.dtb with the microcode removed
997 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
999 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1000 b' somewhere in here', first)
1002 def _RunPackUbootSingleMicrocode(self):
1003 """Test that x86 microcode can be handled correctly
1005 We expect to see the following in the image, in order:
1006 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1008 u-boot.dtb with the microcode
1009 an empty microcode region
1011 # We need the libfdt library to run this test since only that allows
1012 # finding the offset of a property. This is required by
1013 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1014 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1016 second = data[len(U_BOOT_NODTB_DATA):]
1018 fdt_len = self.GetFdtLen(second)
1019 third = second[fdt_len:]
1020 second = second[:fdt_len]
1022 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1023 self.assertIn(ucode_data, second)
1024 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1026 # Check that the microcode pointer was inserted. It should match the
1027 # expected offset and size
1028 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1030 first = data[:len(U_BOOT_NODTB_DATA)]
1031 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1032 b' somewhere in here', first)
1034 def testPackUbootSingleMicrocode(self):
1035 """Test that x86 microcode can be handled correctly with fdt_normal.
1037 self._RunPackUbootSingleMicrocode()
1039 def testUBootImg(self):
1040 """Test that u-boot.img can be put in a file"""
1041 data = self._DoReadFile('036_u_boot_img.dts')
1042 self.assertEqual(U_BOOT_IMG_DATA, data)
1044 def testNoMicrocode(self):
1045 """Test that a missing microcode region is detected"""
1046 with self.assertRaises(ValueError) as e:
1047 self._DoReadFile('037_x86_no_ucode.dts', True)
1048 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1049 "node found in ", str(e.exception))
1051 def testMicrocodeWithoutNode(self):
1052 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1053 with self.assertRaises(ValueError) as e:
1054 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1055 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1056 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1058 def testMicrocodeWithoutNode2(self):
1059 """Test that a missing u-boot-ucode node is detected"""
1060 with self.assertRaises(ValueError) as e:
1061 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1062 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1063 "microcode region u-boot-ucode", str(e.exception))
1065 def testMicrocodeWithoutPtrInElf(self):
1066 """Test that a U-Boot binary without the microcode symbol is detected"""
1067 # ELF file without a '_dt_ucode_base_size' symbol
1069 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1070 TestFunctional._MakeInputFile('u-boot', fd.read())
1072 with self.assertRaises(ValueError) as e:
1073 self._RunPackUbootSingleMicrocode()
1074 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1075 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1078 # Put the original file back
1079 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1080 TestFunctional._MakeInputFile('u-boot', fd.read())
1082 def testMicrocodeNotInImage(self):
1083 """Test that microcode must be placed within the image"""
1084 with self.assertRaises(ValueError) as e:
1085 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1086 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1087 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1088 "section ranging from 00000000 to 0000002e", str(e.exception))
1090 def testWithoutMicrocode(self):
1091 """Test that we can cope with an image without microcode (e.g. qemu)"""
1092 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1093 TestFunctional._MakeInputFile('u-boot', fd.read())
1094 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1096 # Now check the device tree has no microcode
1097 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1098 second = data[len(U_BOOT_NODTB_DATA):]
1100 fdt_len = self.GetFdtLen(second)
1101 self.assertEqual(dtb, second[:fdt_len])
1103 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1104 third = data[used_len:]
1105 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1107 def testUnknownPosSize(self):
1108 """Test that microcode must be placed within the image"""
1109 with self.assertRaises(ValueError) as e:
1110 self._DoReadFile('041_unknown_pos_size.dts', True)
1111 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1112 "entry 'invalid-entry'", str(e.exception))
1114 def testPackFsp(self):
1115 """Test that an image with a FSP binary can be created"""
1116 data = self._DoReadFile('042_intel-fsp.dts')
1117 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1119 def testPackCmc(self):
1120 """Test that an image with a CMC binary can be created"""
1121 data = self._DoReadFile('043_intel-cmc.dts')
1122 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1124 def testPackVbt(self):
1125 """Test that an image with a VBT binary can be created"""
1126 data = self._DoReadFile('046_intel-vbt.dts')
1127 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1129 def testSplBssPad(self):
1130 """Test that we can pad SPL's BSS with zeros"""
1131 # ELF file with a '__bss_size' symbol
1133 data = self._DoReadFile('047_spl_bss_pad.dts')
1134 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1137 def testSplBssPadMissing(self):
1138 """Test that a missing symbol is detected"""
1139 self._SetupSplElf('u_boot_ucode_ptr')
1140 with self.assertRaises(ValueError) as e:
1141 self._DoReadFile('047_spl_bss_pad.dts')
1142 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1145 def testPackStart16Spl(self):
1146 """Test that an image with an x86 start16 SPL region can be created"""
1147 data = self._DoReadFile('048_x86-start16-spl.dts')
1148 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1150 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1151 """Helper function for microcode tests
1153 We expect to see the following in the image, in order:
1154 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1156 u-boot.dtb with the microcode removed
1160 dts: Device tree file to use for test
1161 ucode_second: True if the microsecond entry is second instead of
1164 self._SetupSplElf('u_boot_ucode_ptr')
1165 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1166 ucode_second=ucode_second)
1167 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1168 b'ter somewhere in here', first)
1170 def testPackUbootSplMicrocode(self):
1171 """Test that x86 microcode can be handled correctly in SPL"""
1172 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1174 def testPackUbootSplMicrocodeReorder(self):
1175 """Test that order doesn't matter for microcode entries
1177 This is the same as testPackUbootSplMicrocode but when we process the
1178 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1179 entry, so we reply on binman to try later.
1181 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1184 def testPackMrc(self):
1185 """Test that an image with an MRC binary can be created"""
1186 data = self._DoReadFile('050_intel_mrc.dts')
1187 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1189 def testSplDtb(self):
1190 """Test that an image with spl/u-boot-spl.dtb can be created"""
1191 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1192 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1194 def testSplNoDtb(self):
1195 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1196 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1197 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1199 def testSymbols(self):
1200 """Test binman can assign symbols embedded in U-Boot"""
1201 elf_fname = self.TestFile('u_boot_binman_syms')
1202 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1203 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1204 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1206 self._SetupSplElf('u_boot_binman_syms')
1207 data = self._DoReadFile('053_symbols.dts')
1208 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1209 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1210 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1211 U_BOOT_SPL_DATA[16:])
1212 self.assertEqual(expected, data)
1214 def testPackUnitAddress(self):
1215 """Test that we support multiple binaries with the same name"""
1216 data = self._DoReadFile('054_unit_address.dts')
1217 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1219 def testSections(self):
1220 """Basic test of sections"""
1221 data = self._DoReadFile('055_sections.dts')
1222 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1223 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1224 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1225 self.assertEqual(expected, data)
1228 """Tests outputting a map of the images"""
1229 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1230 self.assertEqual('''ImagePos Offset Size Name
1231 00000000 00000000 00000028 main-section
1232 00000000 00000000 00000010 section@0
1233 00000000 00000000 00000004 u-boot
1234 00000010 00000010 00000010 section@1
1235 00000010 00000000 00000004 u-boot
1236 00000020 00000020 00000004 section@2
1237 00000020 00000000 00000004 u-boot
1240 def testNamePrefix(self):
1241 """Tests that name prefixes are used"""
1242 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1243 self.assertEqual('''ImagePos Offset Size Name
1244 00000000 00000000 00000028 main-section
1245 00000000 00000000 00000010 section@0
1246 00000000 00000000 00000004 ro-u-boot
1247 00000010 00000010 00000010 section@1
1248 00000010 00000000 00000004 rw-u-boot
1251 def testUnknownContents(self):
1252 """Test that obtaining the contents works as expected"""
1253 with self.assertRaises(ValueError) as e:
1254 self._DoReadFile('057_unknown_contents.dts', True)
1255 self.assertIn("Image '/binman': Internal error: Could not complete "
1256 "processing of contents: remaining [<_testing.Entry__testing ",
1259 def testBadChangeSize(self):
1260 """Test that trying to change the size of an entry fails"""
1262 state.SetAllowEntryExpansion(False)
1263 with self.assertRaises(ValueError) as e:
1264 self._DoReadFile('059_change_size.dts', True)
1265 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1268 state.SetAllowEntryExpansion(True)
1270 def testUpdateFdt(self):
1271 """Test that we can update the device tree with offset/size info"""
1272 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1274 dtb = fdt.Fdt(out_dtb_fname)
1276 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1280 '_testing:offset': 32,
1282 '_testing:image-pos': 32,
1283 'section@0/u-boot:offset': 0,
1284 'section@0/u-boot:size': len(U_BOOT_DATA),
1285 'section@0/u-boot:image-pos': 0,
1286 'section@0:offset': 0,
1287 'section@0:size': 16,
1288 'section@0:image-pos': 0,
1290 'section@1/u-boot:offset': 0,
1291 'section@1/u-boot:size': len(U_BOOT_DATA),
1292 'section@1/u-boot:image-pos': 16,
1293 'section@1:offset': 16,
1294 'section@1:size': 16,
1295 'section@1:image-pos': 16,
1299 def testUpdateFdtBad(self):
1300 """Test that we detect when ProcessFdt never completes"""
1301 with self.assertRaises(ValueError) as e:
1302 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1303 self.assertIn('Could not complete processing of Fdt: remaining '
1304 '[<_testing.Entry__testing', str(e.exception))
1306 def testEntryArgs(self):
1307 """Test passing arguments to entries from the command line"""
1309 'test-str-arg': 'test1',
1310 'test-int-arg': '456',
1312 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1313 self.assertIn('image', control.images)
1314 entry = control.images['image'].GetEntries()['_testing']
1315 self.assertEqual('test0', entry.test_str_fdt)
1316 self.assertEqual('test1', entry.test_str_arg)
1317 self.assertEqual(123, entry.test_int_fdt)
1318 self.assertEqual(456, entry.test_int_arg)
1320 def testEntryArgsMissing(self):
1321 """Test missing arguments and properties"""
1323 'test-int-arg': '456',
1325 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1326 entry = control.images['image'].GetEntries()['_testing']
1327 self.assertEqual('test0', entry.test_str_fdt)
1328 self.assertEqual(None, entry.test_str_arg)
1329 self.assertEqual(None, entry.test_int_fdt)
1330 self.assertEqual(456, entry.test_int_arg)
1332 def testEntryArgsRequired(self):
1333 """Test missing arguments and properties"""
1335 'test-int-arg': '456',
1337 with self.assertRaises(ValueError) as e:
1338 self._DoReadFileDtb('064_entry_args_required.dts')
1339 self.assertIn("Node '/binman/_testing': Missing required "
1340 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1343 def testEntryArgsInvalidFormat(self):
1344 """Test that an invalid entry-argument format is detected"""
1345 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1347 with self.assertRaises(ValueError) as e:
1348 self._DoBinman(*args)
1349 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1351 def testEntryArgsInvalidInteger(self):
1352 """Test that an invalid entry-argument integer is detected"""
1354 'test-int-arg': 'abc',
1356 with self.assertRaises(ValueError) as e:
1357 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1358 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1359 "'test-int-arg' (value 'abc') to integer",
1362 def testEntryArgsInvalidDatatype(self):
1363 """Test that an invalid entry-argument datatype is detected
1365 This test could be written in entry_test.py except that it needs
1366 access to control.entry_args, which seems more than that module should
1370 'test-bad-datatype-arg': '12',
1372 with self.assertRaises(ValueError) as e:
1373 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1374 entry_args=entry_args)
1375 self.assertIn('GetArg() internal error: Unknown data type ',
1379 """Test for a text entry type"""
1381 'test-id': TEXT_DATA,
1382 'test-id2': TEXT_DATA2,
1383 'test-id3': TEXT_DATA3,
1385 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1386 entry_args=entry_args)
1387 expected = (tools.ToBytes(TEXT_DATA) +
1388 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1389 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1390 b'some text' + b'more text')
1391 self.assertEqual(expected, data)
1393 def testEntryDocs(self):
1394 """Test for creation of entry documentation"""
1395 with test_util.capture_sys_output() as (stdout, stderr):
1396 control.WriteEntryDocs(binman.GetEntryModules())
1397 self.assertTrue(len(stdout.getvalue()) > 0)
1399 def testEntryDocsMissing(self):
1400 """Test handling of missing entry documentation"""
1401 with self.assertRaises(ValueError) as e:
1402 with test_util.capture_sys_output() as (stdout, stderr):
1403 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1404 self.assertIn('Documentation is missing for modules: u_boot',
1408 """Basic test of generation of a flashrom fmap"""
1409 data = self._DoReadFile('067_fmap.dts')
1410 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1411 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1412 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1413 self.assertEqual(expected, data[:32])
1414 self.assertEqual(b'__FMAP__', fhdr.signature)
1415 self.assertEqual(1, fhdr.ver_major)
1416 self.assertEqual(0, fhdr.ver_minor)
1417 self.assertEqual(0, fhdr.base)
1418 self.assertEqual(16 + 16 +
1419 fmap_util.FMAP_HEADER_LEN +
1420 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1421 self.assertEqual(b'FMAP', fhdr.name)
1422 self.assertEqual(3, fhdr.nareas)
1423 for fentry in fentries:
1424 self.assertEqual(0, fentry.flags)
1426 self.assertEqual(0, fentries[0].offset)
1427 self.assertEqual(4, fentries[0].size)
1428 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1430 self.assertEqual(16, fentries[1].offset)
1431 self.assertEqual(4, fentries[1].size)
1432 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1434 self.assertEqual(32, fentries[2].offset)
1435 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1436 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1437 self.assertEqual(b'FMAP', fentries[2].name)
1439 def testBlobNamedByArg(self):
1440 """Test we can add a blob with the filename coming from an entry arg"""
1442 'cros-ec-rw-path': 'ecrw.bin',
1444 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1445 entry_args=entry_args)
1448 """Test for an fill entry type"""
1449 data = self._DoReadFile('069_fill.dts')
1450 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1451 self.assertEqual(expected, data)
1453 def testFillNoSize(self):
1454 """Test for an fill entry type with no size"""
1455 with self.assertRaises(ValueError) as e:
1456 self._DoReadFile('070_fill_no_size.dts')
1457 self.assertIn("'fill' entry must have a size property",
1460 def _HandleGbbCommand(self, pipe_list):
1461 """Fake calls to the futility utility"""
1462 if pipe_list[0][0] == 'futility':
1463 fname = pipe_list[0][-1]
1464 # Append our GBB data to the file, which will happen every time the
1465 # futility command is called.
1466 with open(fname, 'ab') as fd:
1468 return command.CommandResult()
1471 """Test for the Chromium OS Google Binary Block"""
1472 command.test_result = self._HandleGbbCommand
1474 'keydir': 'devkeys',
1475 'bmpblk': 'bmpblk.bin',
1477 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1480 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1481 tools.GetBytes(0, 0x2180 - 16))
1482 self.assertEqual(expected, data)
1484 def testGbbTooSmall(self):
1485 """Test for the Chromium OS Google Binary Block being large enough"""
1486 with self.assertRaises(ValueError) as e:
1487 self._DoReadFileDtb('072_gbb_too_small.dts')
1488 self.assertIn("Node '/binman/gbb': GBB is too small",
1491 def testGbbNoSize(self):
1492 """Test for the Chromium OS Google Binary Block having a size"""
1493 with self.assertRaises(ValueError) as e:
1494 self._DoReadFileDtb('073_gbb_no_size.dts')
1495 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1498 def _HandleVblockCommand(self, pipe_list):
1499 """Fake calls to the futility utility"""
1500 if pipe_list[0][0] == 'futility':
1501 fname = pipe_list[0][3]
1502 with open(fname, 'wb') as fd:
1503 fd.write(VBLOCK_DATA)
1504 return command.CommandResult()
1506 def testVblock(self):
1507 """Test for the Chromium OS Verified Boot Block"""
1508 command.test_result = self._HandleVblockCommand
1510 'keydir': 'devkeys',
1512 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1513 entry_args=entry_args)
1514 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1515 self.assertEqual(expected, data)
1517 def testVblockNoContent(self):
1518 """Test we detect a vblock which has no content to sign"""
1519 with self.assertRaises(ValueError) as e:
1520 self._DoReadFile('075_vblock_no_content.dts')
1521 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1522 'property', str(e.exception))
1524 def testVblockBadPhandle(self):
1525 """Test that we detect a vblock with an invalid phandle in contents"""
1526 with self.assertRaises(ValueError) as e:
1527 self._DoReadFile('076_vblock_bad_phandle.dts')
1528 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1529 '1000', str(e.exception))
1531 def testVblockBadEntry(self):
1532 """Test that we detect an entry that points to a non-entry"""
1533 with self.assertRaises(ValueError) as e:
1534 self._DoReadFile('077_vblock_bad_entry.dts')
1535 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1536 "'other'", str(e.exception))
1539 """Test that an image with TPL and ots device tree can be created"""
1540 # ELF file with a '__bss_size' symbol
1541 with open(self.TestFile('bss_data'), 'rb') as fd:
1542 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1543 data = self._DoReadFile('078_u_boot_tpl.dts')
1544 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1546 def testUsesPos(self):
1547 """Test that the 'pos' property cannot be used anymore"""
1548 with self.assertRaises(ValueError) as e:
1549 data = self._DoReadFile('079_uses_pos.dts')
1550 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1551 "'pos'", str(e.exception))
1553 def testFillZero(self):
1554 """Test for an fill entry type with a size of 0"""
1555 data = self._DoReadFile('080_fill_empty.dts')
1556 self.assertEqual(tools.GetBytes(0, 16), data)
1558 def testTextMissing(self):
1559 """Test for a text entry type where there is no text"""
1560 with self.assertRaises(ValueError) as e:
1561 self._DoReadFileDtb('066_text.dts',)
1562 self.assertIn("Node '/binman/text': No value provided for text label "
1563 "'test-id'", str(e.exception))
1565 def testPackStart16Tpl(self):
1566 """Test that an image with an x86 start16 TPL region can be created"""
1567 data = self._DoReadFile('081_x86-start16-tpl.dts')
1568 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1570 def testSelectImage(self):
1571 """Test that we can select which images to build"""
1572 expected = 'Skipping images: image1'
1574 # We should only get the expected message in verbose mode
1575 for verbosity in (0, 2):
1576 with test_util.capture_sys_output() as (stdout, stderr):
1577 retcode = self._DoTestFile('006_dual_image.dts',
1578 verbosity=verbosity,
1580 self.assertEqual(0, retcode)
1582 self.assertIn(expected, stdout.getvalue())
1584 self.assertNotIn(expected, stdout.getvalue())
1586 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1587 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1588 self._CleanupOutputDir()
1590 def testUpdateFdtAll(self):
1591 """Test that all device trees are updated with offset/size info"""
1592 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1595 'section:image-pos': 0,
1596 'u-boot-tpl-dtb:size': 513,
1597 'u-boot-spl-dtb:size': 513,
1598 'u-boot-spl-dtb:offset': 493,
1600 'section/u-boot-dtb:image-pos': 0,
1601 'u-boot-spl-dtb:image-pos': 493,
1602 'section/u-boot-dtb:size': 493,
1603 'u-boot-tpl-dtb:image-pos': 1006,
1604 'section/u-boot-dtb:offset': 0,
1605 'section:size': 493,
1607 'section:offset': 0,
1608 'u-boot-tpl-dtb:offset': 1006,
1612 # We expect three device-tree files in the output, one after the other.
1613 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1614 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1615 # main U-Boot tree. All three should have the same postions and offset.
1617 for item in ['', 'spl', 'tpl']:
1618 dtb = fdt.Fdt.FromData(data[start:])
1620 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1622 expected = dict(base_expected)
1625 self.assertEqual(expected, props)
1626 start += dtb._fdt_obj.totalsize()
1628 def testUpdateFdtOutput(self):
1629 """Test that output DTB files are updated"""
1631 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1632 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1634 # Unfortunately, compiling a source file always results in a file
1635 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1636 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1637 # binman as a file called u-boot.dtb. To fix this, copy the file
1638 # over to the expected place.
1639 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1640 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1642 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1643 'tpl/u-boot-tpl.dtb.out']:
1644 dtb = fdt.Fdt.FromData(data[start:])
1645 size = dtb._fdt_obj.totalsize()
1646 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1647 outdata = tools.ReadFile(pathname)
1648 name = os.path.split(fname)[0]
1651 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1653 orig_indata = dtb_data
1654 self.assertNotEqual(outdata, orig_indata,
1655 "Expected output file '%s' be updated" % pathname)
1656 self.assertEqual(outdata, data[start:start + size],
1657 "Expected output file '%s' to match output image" %
1663 def _decompress(self, data):
1664 return tools.Decompress(data, 'lz4')
1666 def testCompress(self):
1667 """Test compression of blobs"""
1669 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1670 use_real_dtb=True, update_dtb=True)
1671 dtb = fdt.Fdt(out_dtb_fname)
1673 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1674 orig = self._decompress(data)
1675 self.assertEquals(COMPRESS_DATA, orig)
1677 'blob:uncomp-size': len(COMPRESS_DATA),
1678 'blob:size': len(data),
1681 self.assertEqual(expected, props)
1683 def testFiles(self):
1684 """Test bringing in multiple files"""
1685 data = self._DoReadFile('084_files.dts')
1686 self.assertEqual(FILES_DATA, data)
1688 def testFilesCompress(self):
1689 """Test bringing in multiple files and compressing them"""
1691 data = self._DoReadFile('085_files_compress.dts')
1693 image = control.images['image']
1694 entries = image.GetEntries()
1695 files = entries['files']
1696 entries = files._entries
1699 for i in range(1, 3):
1701 start = entries[key].image_pos
1702 len = entries[key].size
1703 chunk = data[start:start + len]
1704 orig += self._decompress(chunk)
1706 self.assertEqual(FILES_DATA, orig)
1708 def testFilesMissing(self):
1709 """Test missing files"""
1710 with self.assertRaises(ValueError) as e:
1711 data = self._DoReadFile('086_files_none.dts')
1712 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1713 'no files', str(e.exception))
1715 def testFilesNoPattern(self):
1716 """Test missing files"""
1717 with self.assertRaises(ValueError) as e:
1718 data = self._DoReadFile('087_files_no_pattern.dts')
1719 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1722 def testExpandSize(self):
1723 """Test an expanding entry"""
1724 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1726 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1727 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1728 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1729 tools.GetBytes(ord('d'), 8))
1730 self.assertEqual(expect, data)
1731 self.assertEqual('''ImagePos Offset Size Name
1732 00000000 00000000 00000028 main-section
1733 00000000 00000000 00000008 fill
1734 00000008 00000008 00000004 u-boot
1735 0000000c 0000000c 00000004 section
1736 0000000c 00000000 00000003 intel-mrc
1737 00000010 00000010 00000004 u-boot2
1738 00000014 00000014 0000000c section2
1739 00000014 00000000 00000008 fill
1740 0000001c 00000008 00000004 u-boot
1741 00000020 00000020 00000008 fill2
1744 def testExpandSizeBad(self):
1745 """Test an expanding entry which fails to provide contents"""
1746 with test_util.capture_sys_output() as (stdout, stderr):
1747 with self.assertRaises(ValueError) as e:
1748 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1749 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1750 'expanding entry', str(e.exception))
1753 """Test hashing of the contents of an entry"""
1754 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1755 use_real_dtb=True, update_dtb=True)
1756 dtb = fdt.Fdt(out_dtb_fname)
1758 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1759 m = hashlib.sha256()
1760 m.update(U_BOOT_DATA)
1761 self.assertEqual(m.digest(), b''.join(hash_node.value))
1763 def testHashNoAlgo(self):
1764 with self.assertRaises(ValueError) as e:
1765 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1766 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1767 'hash node', str(e.exception))
1769 def testHashBadAlgo(self):
1770 with self.assertRaises(ValueError) as e:
1771 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1772 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1775 def testHashSection(self):
1776 """Test hashing of the contents of an entry"""
1777 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1778 use_real_dtb=True, update_dtb=True)
1779 dtb = fdt.Fdt(out_dtb_fname)
1781 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1782 m = hashlib.sha256()
1783 m.update(U_BOOT_DATA)
1784 m.update(tools.GetBytes(ord('a'), 16))
1785 self.assertEqual(m.digest(), b''.join(hash_node.value))
1787 def testPackUBootTplMicrocode(self):
1788 """Test that x86 microcode can be handled correctly in TPL
1790 We expect to see the following in the image, in order:
1791 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1793 u-boot-tpl.dtb with the microcode removed
1796 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1797 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1798 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1799 U_BOOT_TPL_NODTB_DATA)
1800 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1801 b'ter somewhere in here', first)
1803 def testFmapX86(self):
1804 """Basic test of generation of a flashrom fmap"""
1805 data = self._DoReadFile('094_fmap_x86.dts')
1806 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1807 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1808 self.assertEqual(expected, data[:32])
1809 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1811 self.assertEqual(0x100, fhdr.image_size)
1813 self.assertEqual(0, fentries[0].offset)
1814 self.assertEqual(4, fentries[0].size)
1815 self.assertEqual(b'U_BOOT', fentries[0].name)
1817 self.assertEqual(4, fentries[1].offset)
1818 self.assertEqual(3, fentries[1].size)
1819 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1821 self.assertEqual(32, fentries[2].offset)
1822 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1823 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1824 self.assertEqual(b'FMAP', fentries[2].name)
1826 def testFmapX86Section(self):
1827 """Basic test of generation of a flashrom fmap"""
1828 data = self._DoReadFile('095_fmap_x86_section.dts')
1829 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1830 self.assertEqual(expected, data[:32])
1831 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1833 self.assertEqual(0x100, fhdr.image_size)
1835 self.assertEqual(0, fentries[0].offset)
1836 self.assertEqual(4, fentries[0].size)
1837 self.assertEqual(b'U_BOOT', fentries[0].name)
1839 self.assertEqual(4, fentries[1].offset)
1840 self.assertEqual(3, fentries[1].size)
1841 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1843 self.assertEqual(36, fentries[2].offset)
1844 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1845 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1846 self.assertEqual(b'FMAP', fentries[2].name)
1849 """Basic test of ELF entries"""
1851 with open(self.TestFile('bss_data'), 'rb') as fd:
1852 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1853 with open(self.TestFile('bss_data'), 'rb') as fd:
1854 TestFunctional._MakeInputFile('-boot', fd.read())
1855 data = self._DoReadFile('096_elf.dts')
1857 def testElfStrip(self):
1858 """Basic test of ELF entries"""
1860 with open(self.TestFile('bss_data'), 'rb') as fd:
1861 TestFunctional._MakeInputFile('-boot', fd.read())
1862 data = self._DoReadFile('097_elf_strip.dts')
1864 def testPackOverlapMap(self):
1865 """Test that overlapping regions are detected"""
1866 with test_util.capture_sys_output() as (stdout, stderr):
1867 with self.assertRaises(ValueError) as e:
1868 self._DoTestFile('014_pack_overlap.dts', map=True)
1869 map_fname = tools.GetOutputFilename('image.map')
1870 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1873 # We should not get an inmage, but there should be a map file
1874 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1875 self.assertTrue(os.path.exists(map_fname))
1876 map_data = tools.ReadFile(map_fname, binary=False)
1877 self.assertEqual('''ImagePos Offset Size Name
1878 <none> 00000000 00000007 main-section
1879 <none> 00000000 00000004 u-boot
1880 <none> 00000003 00000004 u-boot-align
1883 def testPackRefCode(self):
1884 """Test that an image with an Intel Reference code binary works"""
1885 data = self._DoReadFile('100_intel_refcode.dts')
1886 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1888 def testSectionOffset(self):
1889 """Tests use of a section with an offset"""
1890 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1892 self.assertEqual('''ImagePos Offset Size Name
1893 00000000 00000000 00000038 main-section
1894 00000004 00000004 00000010 section@0
1895 00000004 00000000 00000004 u-boot
1896 00000018 00000018 00000010 section@1
1897 00000018 00000000 00000004 u-boot
1898 0000002c 0000002c 00000004 section@2
1899 0000002c 00000000 00000004 u-boot
1901 self.assertEqual(data,
1902 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1903 tools.GetBytes(0x21, 12) +
1904 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1905 tools.GetBytes(0x61, 12) +
1906 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1907 tools.GetBytes(0x26, 8))
1909 def testCbfsRaw(self):
1910 """Test base handling of a Coreboot Filesystem (CBFS)
1912 The exact contents of the CBFS is verified by similar tests in
1913 cbfs_util_test.py. The tests here merely check that the files added to
1914 the CBFS can be found in the final image.
1916 data = self._DoReadFile('102_cbfs_raw.dts')
1919 cbfs = cbfs_util.CbfsReader(data)
1920 self.assertEqual(size, cbfs.rom_size)
1922 self.assertIn('u-boot-dtb', cbfs.files)
1923 cfile = cbfs.files['u-boot-dtb']
1924 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1926 def testCbfsArch(self):
1927 """Test on non-x86 architecture"""
1928 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1931 cbfs = cbfs_util.CbfsReader(data)
1932 self.assertEqual(size, cbfs.rom_size)
1934 self.assertIn('u-boot-dtb', cbfs.files)
1935 cfile = cbfs.files['u-boot-dtb']
1936 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1938 def testCbfsStage(self):
1939 """Tests handling of a Coreboot Filesystem (CBFS)"""
1940 if not elf.ELF_TOOLS:
1941 self.skipTest('Python elftools not available')
1942 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1943 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1946 data = self._DoReadFile('104_cbfs_stage.dts')
1947 cbfs = cbfs_util.CbfsReader(data)
1948 self.assertEqual(size, cbfs.rom_size)
1950 self.assertIn('u-boot', cbfs.files)
1951 cfile = cbfs.files['u-boot']
1952 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1954 def testCbfsRawCompress(self):
1955 """Test handling of compressing raw files"""
1957 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1960 cbfs = cbfs_util.CbfsReader(data)
1961 self.assertIn('u-boot', cbfs.files)
1962 cfile = cbfs.files['u-boot']
1963 self.assertEqual(COMPRESS_DATA, cfile.data)
1965 def testCbfsBadArch(self):
1966 """Test handling of a bad architecture"""
1967 with self.assertRaises(ValueError) as e:
1968 self._DoReadFile('106_cbfs_bad_arch.dts')
1969 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1971 def testCbfsNoSize(self):
1972 """Test handling of a missing size property"""
1973 with self.assertRaises(ValueError) as e:
1974 self._DoReadFile('107_cbfs_no_size.dts')
1975 self.assertIn('entry must have a size property', str(e.exception))
1977 def testCbfsNoCOntents(self):
1978 """Test handling of a CBFS entry which does not provide contentsy"""
1979 with self.assertRaises(ValueError) as e:
1980 self._DoReadFile('108_cbfs_no_contents.dts')
1981 self.assertIn('Could not complete processing of contents',
1984 def testCbfsBadCompress(self):
1985 """Test handling of a bad architecture"""
1986 with self.assertRaises(ValueError) as e:
1987 self._DoReadFile('109_cbfs_bad_compress.dts')
1988 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1991 def testCbfsNamedEntries(self):
1992 """Test handling of named entries"""
1993 data = self._DoReadFile('110_cbfs_name.dts')
1995 cbfs = cbfs_util.CbfsReader(data)
1996 self.assertIn('FRED', cbfs.files)
1997 cfile1 = cbfs.files['FRED']
1998 self.assertEqual(U_BOOT_DATA, cfile1.data)
2000 self.assertIn('hello', cbfs.files)
2001 cfile2 = cbfs.files['hello']
2002 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2004 def _SetupIfwi(self, fname):
2005 """Set up to run an IFWI test
2008 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2012 # Intel Integrated Firmware Image (IFWI) file
2013 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2015 TestFunctional._MakeInputFile(fname,data)
2017 def _CheckIfwi(self, data):
2018 """Check that an image with an IFWI contains the correct output
2021 data: Conents of output file
2023 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2024 if data[:0x1000] != expected_desc:
2025 self.fail('Expected descriptor binary at start of image')
2027 # We expect to find the TPL wil in subpart IBBP entry IBBL
2028 image_fname = tools.GetOutputFilename('image.bin')
2029 tpl_fname = tools.GetOutputFilename('tpl.out')
2030 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2031 subpart='IBBP', entry_name='IBBL')
2033 tpl_data = tools.ReadFile(tpl_fname)
2034 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2036 def testPackX86RomIfwi(self):
2037 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2038 self._SetupIfwi('fitimage.bin')
2039 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2040 self._CheckIfwi(data)
2042 def testPackX86RomIfwiNoDesc(self):
2043 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2044 self._SetupIfwi('ifwi.bin')
2045 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2046 self._CheckIfwi(data)
2048 def testPackX86RomIfwiNoData(self):
2049 """Test that an x86 ROM with IFWI handles missing data"""
2050 self._SetupIfwi('ifwi.bin')
2051 with self.assertRaises(ValueError) as e:
2052 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2053 self.assertIn('Could not complete processing of contents',
2056 def testCbfsOffset(self):
2057 """Test a CBFS with files at particular offsets
2059 Like all CFBS tests, this is just checking the logic that calls
2060 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2062 data = self._DoReadFile('114_cbfs_offset.dts')
2065 cbfs = cbfs_util.CbfsReader(data)
2066 self.assertEqual(size, cbfs.rom_size)
2068 self.assertIn('u-boot', cbfs.files)
2069 cfile = cbfs.files['u-boot']
2070 self.assertEqual(U_BOOT_DATA, cfile.data)
2071 self.assertEqual(0x40, cfile.cbfs_offset)
2073 self.assertIn('u-boot-dtb', cbfs.files)
2074 cfile2 = cbfs.files['u-boot-dtb']
2075 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2076 self.assertEqual(0x140, cfile2.cbfs_offset)
2078 def testFdtmap(self):
2079 """Test an FDT map can be inserted in the image"""
2080 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2081 fdtmap_data = data[len(U_BOOT_DATA):]
2082 magic = fdtmap_data[:8]
2083 self.assertEqual('_FDTMAP_', magic)
2084 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2086 fdt_data = fdtmap_data[16:]
2087 dtb = fdt.Fdt.FromData(fdt_data)
2089 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2094 'u-boot:size': len(U_BOOT_DATA),
2095 'u-boot:image-pos': 0,
2096 'fdtmap:image-pos': 4,
2098 'fdtmap:size': len(fdtmap_data),
2102 def testFdtmapNoMatch(self):
2103 """Check handling of an FDT map when the section cannot be found"""
2104 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2106 # Mangle the section name, which should cause a mismatch between the
2107 # correct FDT path and the one expected by the section
2108 image = control.images['image']
2109 image._node.path += '-suffix'
2110 entries = image.GetEntries()
2111 fdtmap = entries['fdtmap']
2112 with self.assertRaises(ValueError) as e:
2114 self.assertIn("Cannot locate node for path '/binman-suffix'",
2117 def testFdtmapHeader(self):
2118 """Test an FDT map and image header can be inserted in the image"""
2119 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2120 fdtmap_pos = len(U_BOOT_DATA)
2121 fdtmap_data = data[fdtmap_pos:]
2122 fdt_data = fdtmap_data[16:]
2123 dtb = fdt.Fdt.FromData(fdt_data)
2124 fdt_size = dtb.GetFdtObj().totalsize()
2125 hdr_data = data[-8:]
2126 self.assertEqual('BinM', hdr_data[:4])
2127 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2128 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2130 def testFdtmapHeaderStart(self):
2131 """Test an image header can be inserted at the image start"""
2132 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2133 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2135 self.assertEqual('BinM', hdr_data[:4])
2136 offset = struct.unpack('<I', hdr_data[4:])[0]
2137 self.assertEqual(fdtmap_pos, offset)
2139 def testFdtmapHeaderPos(self):
2140 """Test an image header can be inserted at a chosen position"""
2141 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2142 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2143 hdr_data = data[0x80:0x88]
2144 self.assertEqual('BinM', hdr_data[:4])
2145 offset = struct.unpack('<I', hdr_data[4:])[0]
2146 self.assertEqual(fdtmap_pos, offset)
2148 def testHeaderMissingFdtmap(self):
2149 """Test an image header requires an fdtmap"""
2150 with self.assertRaises(ValueError) as e:
2151 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2152 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2155 def testHeaderNoLocation(self):
2156 """Test an image header with a no specified location is detected"""
2157 with self.assertRaises(ValueError) as e:
2158 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2159 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2162 def testEntryExpand(self):
2163 """Test expanding an entry after it is packed"""
2164 data = self._DoReadFile('121_entry_expand.dts')
2165 self.assertEqual(b'aaa', data[:3])
2166 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2167 self.assertEqual(b'aaa', data[-3:])
2169 def testEntryExpandBad(self):
2170 """Test expanding an entry after it is packed, twice"""
2171 with self.assertRaises(ValueError) as e:
2172 self._DoReadFile('122_entry_expand_twice.dts')
2173 self.assertIn("Image '/binman': Entries changed size after packing",
2176 def testEntryExpandSection(self):
2177 """Test expanding an entry within a section after it is packed"""
2178 data = self._DoReadFile('123_entry_expand_section.dts')
2179 self.assertEqual(b'aaa', data[:3])
2180 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2181 self.assertEqual(b'aaa', data[-3:])
2183 def testCompressDtb(self):
2184 """Test that compress of device-tree files is supported"""
2186 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2187 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2188 comp_data = data[len(U_BOOT_DATA):]
2189 orig = self._decompress(comp_data)
2190 dtb = fdt.Fdt.FromData(orig)
2192 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2194 'u-boot:size': len(U_BOOT_DATA),
2195 'u-boot-dtb:uncomp-size': len(orig),
2196 'u-boot-dtb:size': len(comp_data),
2199 self.assertEqual(expected, props)
2201 def testCbfsUpdateFdt(self):
2202 """Test that we can update the device tree with CBFS offset/size info"""
2204 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2206 dtb = fdt.Fdt(out_dtb_fname)
2208 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2209 del props['cbfs/u-boot:size']
2215 'cbfs:size': len(data),
2216 'cbfs:image-pos': 0,
2217 'cbfs/u-boot:offset': 0x38,
2218 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2219 'cbfs/u-boot:image-pos': 0x38,
2220 'cbfs/u-boot-dtb:offset': 0xb8,
2221 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2222 'cbfs/u-boot-dtb:image-pos': 0xb8,
2225 def testCbfsBadType(self):
2226 """Test an image header with a no specified location is detected"""
2227 with self.assertRaises(ValueError) as e:
2228 self._DoReadFile('126_cbfs_bad_type.dts')
2229 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2232 """Test listing the files in an image"""
2234 data = self._DoReadFile('127_list.dts')
2235 image = control.images['image']
2236 entries = image.BuildEntryList()
2237 self.assertEqual(7, len(entries))
2240 self.assertEqual(0, ent.indent)
2241 self.assertEqual('main-section', ent.name)
2242 self.assertEqual('section', ent.etype)
2243 self.assertEqual(len(data), ent.size)
2244 self.assertEqual(0, ent.image_pos)
2245 self.assertEqual(None, ent.uncomp_size)
2246 self.assertEqual(0, ent.offset)
2249 self.assertEqual(1, 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(0, ent.image_pos)
2254 self.assertEqual(None, ent.uncomp_size)
2255 self.assertEqual(0, ent.offset)
2258 self.assertEqual(1, ent.indent)
2259 self.assertEqual('section', ent.name)
2260 self.assertEqual('section', ent.etype)
2261 section_size = ent.size
2262 self.assertEqual(0x100, ent.image_pos)
2263 self.assertEqual(None, ent.uncomp_size)
2264 self.assertEqual(0x100, ent.offset)
2267 self.assertEqual(2, ent.indent)
2268 self.assertEqual('cbfs', ent.name)
2269 self.assertEqual('cbfs', ent.etype)
2270 self.assertEqual(0x400, ent.size)
2271 self.assertEqual(0x100, ent.image_pos)
2272 self.assertEqual(None, ent.uncomp_size)
2273 self.assertEqual(0, ent.offset)
2276 self.assertEqual(3, ent.indent)
2277 self.assertEqual('u-boot', ent.name)
2278 self.assertEqual('u-boot', ent.etype)
2279 self.assertEqual(len(U_BOOT_DATA), ent.size)
2280 self.assertEqual(0x138, ent.image_pos)
2281 self.assertEqual(None, ent.uncomp_size)
2282 self.assertEqual(0x38, ent.offset)
2285 self.assertEqual(3, ent.indent)
2286 self.assertEqual('u-boot-dtb', ent.name)
2287 self.assertEqual('text', ent.etype)
2288 self.assertGreater(len(COMPRESS_DATA), ent.size)
2289 self.assertEqual(0x178, ent.image_pos)
2290 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2291 self.assertEqual(0x78, ent.offset)
2294 self.assertEqual(2, ent.indent)
2295 self.assertEqual('u-boot-dtb', ent.name)
2296 self.assertEqual('u-boot-dtb', ent.etype)
2297 self.assertEqual(0x500, ent.image_pos)
2298 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2300 # Compressing this data expands it since headers are added
2301 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2302 self.assertEqual(0x400, ent.offset)
2304 self.assertEqual(len(data), 0x100 + section_size)
2305 self.assertEqual(section_size, 0x400 + dtb_size)
2307 def testFindFdtmap(self):
2308 """Test locating an FDT map in an image"""
2310 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2311 image = control.images['image']
2312 entries = image.GetEntries()
2313 entry = entries['fdtmap']
2314 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2316 def testFindFdtmapMissing(self):
2317 """Test failing to locate an FDP map"""
2318 data = self._DoReadFile('005_simple.dts')
2319 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2321 def testFindImageHeader(self):
2322 """Test locating a image header"""
2324 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2325 image = control.images['image']
2326 entries = image.GetEntries()
2327 entry = entries['fdtmap']
2328 # The header should point to the FDT map
2329 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2331 def testFindImageHeaderStart(self):
2332 """Test locating a image header located at the start of an image"""
2333 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2334 image = control.images['image']
2335 entries = image.GetEntries()
2336 entry = entries['fdtmap']
2337 # The header should point to the FDT map
2338 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2340 def testFindImageHeaderMissing(self):
2341 """Test failing to locate an image header"""
2342 data = self._DoReadFile('005_simple.dts')
2343 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2345 def testReadImage(self):
2346 """Test reading an image and accessing its FDT map"""
2348 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2349 image_fname = tools.GetOutputFilename('image.bin')
2350 orig_image = control.images['image']
2351 image = Image.FromFile(image_fname)
2352 self.assertEqual(orig_image.GetEntries().keys(),
2353 image.GetEntries().keys())
2355 orig_entry = orig_image.GetEntries()['fdtmap']
2356 entry = image.GetEntries()['fdtmap']
2357 self.assertEquals(orig_entry.offset, entry.offset)
2358 self.assertEquals(orig_entry.size, entry.size)
2359 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2361 def testReadImageNoHeader(self):
2362 """Test accessing an image's FDT map without an image header"""
2364 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2365 image_fname = tools.GetOutputFilename('image.bin')
2366 image = Image.FromFile(image_fname)
2367 self.assertTrue(isinstance(image, Image))
2368 self.assertEqual('image', image.image_name[-5:])
2370 def testReadImageFail(self):
2371 """Test failing to read an image image's FDT map"""
2372 self._DoReadFile('005_simple.dts')
2373 image_fname = tools.GetOutputFilename('image.bin')
2374 with self.assertRaises(ValueError) as e:
2375 image = Image.FromFile(image_fname)
2376 self.assertIn("Cannot find FDT map in image", str(e.exception))
2378 def testListCmd(self):
2379 """Test listing the files in an image using an Fdtmap"""
2381 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2383 # lz4 compression size differs depending on the version
2384 image = control.images['image']
2385 entries = image.GetEntries()
2386 section_size = entries['section'].size
2387 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2388 fdtmap_offset = entries['fdtmap'].offset
2391 tmpdir, updated_fname = self._SetupImageInTmpdir()
2392 with test_util.capture_sys_output() as (stdout, stderr):
2393 self._DoBinman('ls', '-i', updated_fname)
2395 shutil.rmtree(tmpdir)
2396 lines = stdout.getvalue().splitlines()
2398 'Name Image-pos Size Entry-type Offset Uncomp-size',
2399 '----------------------------------------------------------------------',
2400 'main-section 0 c00 section 0',
2401 ' u-boot 0 4 u-boot 0',
2402 ' section 100 %x section 100' % section_size,
2403 ' cbfs 100 400 cbfs 0',
2404 ' u-boot 138 4 u-boot 38',
2405 ' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2406 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2407 ' fdtmap %x 3b4 fdtmap %x' %
2408 (fdtmap_offset, fdtmap_offset),
2409 ' image-header bf8 8 image-header bf8',
2411 self.assertEqual(expected, lines)
2413 def testListCmdFail(self):
2414 """Test failing to list an image"""
2415 self._DoReadFile('005_simple.dts')
2417 tmpdir, updated_fname = self._SetupImageInTmpdir()
2418 with self.assertRaises(ValueError) as e:
2419 self._DoBinman('ls', '-i', updated_fname)
2421 shutil.rmtree(tmpdir)
2422 self.assertIn("Cannot find FDT map in image", str(e.exception))
2424 def _RunListCmd(self, paths, expected):
2425 """List out entries and check the result
2428 paths: List of paths to pass to the list command
2429 expected: Expected list of filenames to be returned, in order
2432 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2433 image_fname = tools.GetOutputFilename('image.bin')
2434 image = Image.FromFile(image_fname)
2435 lines = image.GetListEntries(paths)[1]
2436 files = [line[0].strip() for line in lines[1:]]
2437 self.assertEqual(expected, files)
2439 def testListCmdSection(self):
2440 """Test listing the files in a section"""
2441 self._RunListCmd(['section'],
2442 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2444 def testListCmdFile(self):
2445 """Test listing a particular file"""
2446 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2448 def testListCmdWildcard(self):
2449 """Test listing a wildcarded file"""
2450 self._RunListCmd(['*boot*'],
2451 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2453 def testListCmdWildcardMulti(self):
2454 """Test listing a wildcarded file"""
2455 self._RunListCmd(['*cb*', '*head*'],
2456 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2458 def testListCmdEmpty(self):
2459 """Test listing a wildcarded file"""
2460 self._RunListCmd(['nothing'], [])
2462 def testListCmdPath(self):
2463 """Test listing the files in a sub-entry of a section"""
2464 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2466 def _RunExtractCmd(self, entry_name, decomp=True):
2467 """Extract an entry from an image
2470 entry_name: Entry name to extract
2471 decomp: True to decompress the data if compressed, False to leave
2472 it in its raw uncompressed format
2478 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2479 image_fname = tools.GetOutputFilename('image.bin')
2480 return control.ReadEntry(image_fname, entry_name, decomp)
2482 def testExtractSimple(self):
2483 """Test extracting a single file"""
2484 data = self._RunExtractCmd('u-boot')
2485 self.assertEqual(U_BOOT_DATA, data)
2487 def testExtractSection(self):
2488 """Test extracting the files in a section"""
2489 data = self._RunExtractCmd('section')
2490 cbfs_data = data[:0x400]
2491 cbfs = cbfs_util.CbfsReader(cbfs_data)
2492 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2493 dtb_data = data[0x400:]
2494 dtb = self._decompress(dtb_data)
2495 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2497 def testExtractCompressed(self):
2498 """Test extracting compressed data"""
2499 data = self._RunExtractCmd('section/u-boot-dtb')
2500 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2502 def testExtractRaw(self):
2503 """Test extracting compressed data without decompressing it"""
2504 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2505 dtb = self._decompress(data)
2506 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2508 def testExtractCbfs(self):
2509 """Test extracting CBFS data"""
2510 data = self._RunExtractCmd('section/cbfs/u-boot')
2511 self.assertEqual(U_BOOT_DATA, data)
2513 def testExtractCbfsCompressed(self):
2514 """Test extracting CBFS compressed data"""
2515 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2516 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2518 def testExtractCbfsRaw(self):
2519 """Test extracting CBFS compressed data without decompressing it"""
2520 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2521 dtb = tools.Decompress(data, 'lzma', with_header=False)
2522 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2524 def testExtractBadEntry(self):
2525 """Test extracting a bad section path"""
2526 with self.assertRaises(ValueError) as e:
2527 self._RunExtractCmd('section/does-not-exist')
2528 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2531 def testExtractMissingFile(self):
2532 """Test extracting file that does not exist"""
2533 with self.assertRaises(IOError) as e:
2534 control.ReadEntry('missing-file', 'name')
2536 def testExtractBadFile(self):
2537 """Test extracting an invalid file"""
2538 fname = os.path.join(self._indir, 'badfile')
2539 tools.WriteFile(fname, b'')
2540 with self.assertRaises(ValueError) as e:
2541 control.ReadEntry(fname, 'name')
2543 def testExtractCmd(self):
2544 """Test extracting a file fron an image on the command line"""
2546 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2547 fname = os.path.join(self._indir, 'output.extact')
2549 tmpdir, updated_fname = self._SetupImageInTmpdir()
2550 with test_util.capture_sys_output() as (stdout, stderr):
2551 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2554 shutil.rmtree(tmpdir)
2555 data = tools.ReadFile(fname)
2556 self.assertEqual(U_BOOT_DATA, data)
2558 def testExtractOneEntry(self):
2559 """Test extracting a single entry fron an image """
2561 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2562 image_fname = tools.GetOutputFilename('image.bin')
2563 fname = os.path.join(self._indir, 'output.extact')
2564 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2565 data = tools.ReadFile(fname)
2566 self.assertEqual(U_BOOT_DATA, data)
2568 def _CheckExtractOutput(self, decomp):
2569 """Helper to test file output with and without decompression
2572 decomp: True to decompress entry data, False to output it raw
2574 def _CheckPresent(entry_path, expect_data, expect_size=None):
2575 """Check and remove expected file
2577 This checks the data/size of a file and removes the file both from
2578 the outfiles set and from the output directory. Once all files are
2579 processed, both the set and directory should be empty.
2582 entry_path: Entry path
2583 expect_data: Data to expect in file, or None to skip check
2584 expect_size: Size of data to expect in file, or None to skip
2586 path = os.path.join(outdir, entry_path)
2587 data = tools.ReadFile(path)
2590 self.assertEqual(expect_data, data)
2592 self.assertEqual(expect_size, len(data))
2593 outfiles.remove(path)
2595 def _CheckDirPresent(name):
2596 """Remove expected directory
2598 This gives an error if the directory does not exist as expected
2601 name: Name of directory to remove
2603 path = os.path.join(outdir, name)
2606 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2607 image_fname = tools.GetOutputFilename('image.bin')
2608 outdir = os.path.join(self._indir, 'extract')
2609 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2611 # Create a set of all file that were output (should be 9)
2613 for root, dirs, files in os.walk(outdir):
2614 outfiles |= set([os.path.join(root, fname) for fname in files])
2615 self.assertEqual(9, len(outfiles))
2616 self.assertEqual(9, len(einfos))
2618 image = control.images['image']
2619 entries = image.GetEntries()
2621 # Check the 9 files in various ways
2622 section = entries['section']
2623 section_entries = section.GetEntries()
2624 cbfs_entries = section_entries['cbfs'].GetEntries()
2625 _CheckPresent('u-boot', U_BOOT_DATA)
2626 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2627 dtb_len = EXTRACT_DTB_SIZE
2629 dtb_len = cbfs_entries['u-boot-dtb'].size
2630 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2632 dtb_len = section_entries['u-boot-dtb'].size
2633 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2635 fdtmap = entries['fdtmap']
2636 _CheckPresent('fdtmap', fdtmap.data)
2637 hdr = entries['image-header']
2638 _CheckPresent('image-header', hdr.data)
2640 _CheckPresent('section/root', section.data)
2641 cbfs = section_entries['cbfs']
2642 _CheckPresent('section/cbfs/root', cbfs.data)
2643 data = tools.ReadFile(image_fname)
2644 _CheckPresent('root', data)
2646 # There should be no files left. Remove all the directories to check.
2647 # If there are any files/dirs remaining, one of these checks will fail.
2648 self.assertEqual(0, len(outfiles))
2649 _CheckDirPresent('section/cbfs')
2650 _CheckDirPresent('section')
2651 _CheckDirPresent('')
2652 self.assertFalse(os.path.exists(outdir))
2654 def testExtractAllEntries(self):
2655 """Test extracting all entries"""
2657 self._CheckExtractOutput(decomp=True)
2659 def testExtractAllEntriesRaw(self):
2660 """Test extracting all entries without decompressing them"""
2662 self._CheckExtractOutput(decomp=False)
2664 def testExtractSelectedEntries(self):
2665 """Test extracting some entries"""
2667 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2668 image_fname = tools.GetOutputFilename('image.bin')
2669 outdir = os.path.join(self._indir, 'extract')
2670 einfos = control.ExtractEntries(image_fname, None, outdir,
2673 # File output is tested by testExtractAllEntries(), so just check that
2674 # the expected entries are selected
2675 names = [einfo.name for einfo in einfos]
2676 self.assertEqual(names,
2677 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2679 def testExtractNoEntryPaths(self):
2680 """Test extracting some entries"""
2682 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2683 image_fname = tools.GetOutputFilename('image.bin')
2684 with self.assertRaises(ValueError) as e:
2685 control.ExtractEntries(image_fname, 'fname', None, [])
2686 self.assertIn('Must specify an entry path to write with -o',
2689 def testExtractTooManyEntryPaths(self):
2690 """Test extracting some entries"""
2692 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2693 image_fname = tools.GetOutputFilename('image.bin')
2694 with self.assertRaises(ValueError) as e:
2695 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2696 self.assertIn('Must specify exactly one entry path to write with -o',
2699 def testPackAlignSection(self):
2700 """Test that sections can have alignment"""
2701 self._DoReadFile('131_pack_align_section.dts')
2703 self.assertIn('image', control.images)
2704 image = control.images['image']
2705 entries = image.GetEntries()
2706 self.assertEqual(3, len(entries))
2709 self.assertIn('u-boot', entries)
2710 entry = entries['u-boot']
2711 self.assertEqual(0, entry.offset)
2712 self.assertEqual(0, entry.image_pos)
2713 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2714 self.assertEqual(len(U_BOOT_DATA), entry.size)
2717 self.assertIn('section0', entries)
2718 section0 = entries['section0']
2719 self.assertEqual(0x10, section0.offset)
2720 self.assertEqual(0x10, section0.image_pos)
2721 self.assertEqual(len(U_BOOT_DATA), section0.size)
2724 section_entries = section0.GetEntries()
2725 self.assertIn('u-boot', section_entries)
2726 entry = section_entries['u-boot']
2727 self.assertEqual(0, entry.offset)
2728 self.assertEqual(0x10, entry.image_pos)
2729 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2730 self.assertEqual(len(U_BOOT_DATA), entry.size)
2733 self.assertIn('section1', entries)
2734 section1 = entries['section1']
2735 self.assertEqual(0x14, section1.offset)
2736 self.assertEqual(0x14, section1.image_pos)
2737 self.assertEqual(0x20, section1.size)
2740 section_entries = section1.GetEntries()
2741 self.assertIn('u-boot', section_entries)
2742 entry = section_entries['u-boot']
2743 self.assertEqual(0, entry.offset)
2744 self.assertEqual(0x14, entry.image_pos)
2745 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2746 self.assertEqual(len(U_BOOT_DATA), entry.size)
2749 self.assertIn('section2', section_entries)
2750 section2 = section_entries['section2']
2751 self.assertEqual(0x4, section2.offset)
2752 self.assertEqual(0x18, section2.image_pos)
2753 self.assertEqual(4, section2.size)
2756 section_entries = section2.GetEntries()
2757 self.assertIn('u-boot', section_entries)
2758 entry = section_entries['u-boot']
2759 self.assertEqual(0, entry.offset)
2760 self.assertEqual(0x18, entry.image_pos)
2761 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2762 self.assertEqual(len(U_BOOT_DATA), entry.size)
2764 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2765 dts='132_replace.dts'):
2766 """Replace an entry in an image
2768 This writes the entry data to update it, then opens the updated file and
2769 returns the value that it now finds there.
2772 entry_name: Entry name to replace
2773 data: Data to replace it with
2774 decomp: True to compress the data if needed, False if data is
2775 already compressed so should be used as is
2776 allow_resize: True to allow entries to change size, False to raise
2782 data from fdtmap (excluding header)
2783 Image object that was modified
2785 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2788 self.assertIn('image', control.images)
2789 image = control.images['image']
2790 entries = image.GetEntries()
2791 orig_dtb_data = entries['u-boot-dtb'].data
2792 orig_fdtmap_data = entries['fdtmap'].data
2794 image_fname = tools.GetOutputFilename('image.bin')
2795 updated_fname = tools.GetOutputFilename('image-updated.bin')
2796 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2797 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2799 data = control.ReadEntry(updated_fname, entry_name, decomp)
2801 # The DT data should not change unless resized:
2802 if not allow_resize:
2803 new_dtb_data = entries['u-boot-dtb'].data
2804 self.assertEqual(new_dtb_data, orig_dtb_data)
2805 new_fdtmap_data = entries['fdtmap'].data
2806 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2808 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2810 def testReplaceSimple(self):
2811 """Test replacing a single file"""
2812 expected = b'x' * len(U_BOOT_DATA)
2813 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2815 self.assertEqual(expected, data)
2817 # Test that the state looks right. There should be an FDT for the fdtmap
2818 # that we jsut read back in, and it should match what we find in the
2819 # 'control' tables. Checking for an FDT that does not exist should
2821 path, fdtmap = state.GetFdtContents('fdtmap')
2822 self.assertIsNotNone(path)
2823 self.assertEqual(expected_fdtmap, fdtmap)
2825 dtb = state.GetFdtForEtype('fdtmap')
2826 self.assertEqual(dtb.GetContents(), fdtmap)
2828 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2829 self.assertIsNone(missing_path)
2830 self.assertIsNone(missing_fdtmap)
2832 missing_dtb = state.GetFdtForEtype('missing')
2833 self.assertIsNone(missing_dtb)
2835 self.assertEqual('/binman', state.fdt_path_prefix)
2837 def testReplaceResizeFail(self):
2838 """Test replacing a file by something larger"""
2839 expected = U_BOOT_DATA + b'x'
2840 with self.assertRaises(ValueError) as e:
2841 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2842 dts='139_replace_repack.dts')
2843 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2846 def testReplaceMulti(self):
2847 """Test replacing entry data where multiple images are generated"""
2848 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2850 expected = b'x' * len(U_BOOT_DATA)
2851 updated_fname = tools.GetOutputFilename('image-updated.bin')
2852 tools.WriteFile(updated_fname, data)
2853 entry_name = 'u-boot'
2854 control.WriteEntry(updated_fname, entry_name, expected,
2856 data = control.ReadEntry(updated_fname, entry_name)
2857 self.assertEqual(expected, data)
2859 # Check the state looks right.
2860 self.assertEqual('/binman/image', state.fdt_path_prefix)
2862 # Now check we can write the first image
2863 image_fname = tools.GetOutputFilename('first-image.bin')
2864 updated_fname = tools.GetOutputFilename('first-updated.bin')
2865 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2866 entry_name = 'u-boot'
2867 control.WriteEntry(updated_fname, entry_name, expected,
2869 data = control.ReadEntry(updated_fname, entry_name)
2870 self.assertEqual(expected, data)
2872 # Check the state looks right.
2873 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2875 def testUpdateFdtAllRepack(self):
2876 """Test that all device trees are updated with offset/size info"""
2877 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2878 SECTION_SIZE = 0x300
2883 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2885 'section:offset': 0,
2886 'section:size': SECTION_SIZE,
2887 'section:image-pos': 0,
2888 'section/u-boot-dtb:offset': 4,
2889 'section/u-boot-dtb:size': 636,
2890 'section/u-boot-dtb:image-pos': 4,
2891 'u-boot-spl-dtb:offset': SECTION_SIZE,
2892 'u-boot-spl-dtb:size': DTB_SIZE,
2893 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2894 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2895 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2896 'u-boot-tpl-dtb:size': DTB_SIZE,
2897 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2898 'fdtmap:size': FDTMAP_SIZE,
2899 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2902 'section:orig-size': SECTION_SIZE,
2903 'section/u-boot-dtb:orig-offset': 4,
2906 # We expect three device-tree files in the output, with the first one
2907 # within a fixed-size section.
2908 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2909 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2910 # main U-Boot tree. All three should have the same positions and offset
2911 # except that the main tree should include the main_expected properties
2913 for item in ['', 'spl', 'tpl', None]:
2915 start += 16 # Move past fdtmap header
2916 dtb = fdt.Fdt.FromData(data[start:])
2918 props = self._GetPropTree(dtb,
2919 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2920 prefix='/' if item is None else '/binman/')
2921 expected = dict(base_expected)
2925 # Main DTB and fdtdec should include the 'orig-' properties
2926 expected.update(main_expected)
2927 # Helpful for debugging:
2928 #for prop in sorted(props):
2929 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2930 self.assertEqual(expected, props)
2932 start = SECTION_SIZE
2934 start += dtb._fdt_obj.totalsize()
2936 def testFdtmapHeaderMiddle(self):
2937 """Test an FDT map in the middle of an image when it should be at end"""
2938 with self.assertRaises(ValueError) as e:
2939 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2940 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2943 def testFdtmapHeaderStartBad(self):
2944 """Test an FDT map in middle of an image when it should be at start"""
2945 with self.assertRaises(ValueError) as e:
2946 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2947 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2950 def testFdtmapHeaderEndBad(self):
2951 """Test an FDT map at the start of an image when it should be at end"""
2952 with self.assertRaises(ValueError) as e:
2953 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2954 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2957 def testFdtmapHeaderNoSize(self):
2958 """Test an image header at the end of an image with undefined size"""
2959 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2961 def testReplaceResize(self):
2962 """Test replacing a single file in an entry with a larger file"""
2963 expected = U_BOOT_DATA + b'x'
2964 data, _, image = self._RunReplaceCmd('u-boot', expected,
2965 dts='139_replace_repack.dts')
2966 self.assertEqual(expected, data)
2968 entries = image.GetEntries()
2969 dtb_data = entries['u-boot-dtb'].data
2970 dtb = fdt.Fdt.FromData(dtb_data)
2973 # The u-boot section should now be larger in the dtb
2974 node = dtb.GetNode('/binman/u-boot')
2975 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
2977 # Same for the fdtmap
2978 fdata = entries['fdtmap'].data
2979 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
2981 fnode = fdtb.GetNode('/u-boot')
2982 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
2984 def testReplaceResizeNoRepack(self):
2985 """Test replacing an entry with a larger file when not allowed"""
2986 expected = U_BOOT_DATA + b'x'
2987 with self.assertRaises(ValueError) as e:
2988 self._RunReplaceCmd('u-boot', expected)
2989 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
2992 def testEntryShrink(self):
2993 """Test contracting an entry after it is packed"""
2995 state.SetAllowEntryContraction(True)
2996 data = self._DoReadFileDtb('140_entry_shrink.dts',
2999 state.SetAllowEntryContraction(False)
3000 self.assertEqual(b'a', data[:1])
3001 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3002 self.assertEqual(b'a', data[-1:])
3004 def testEntryShrinkFail(self):
3005 """Test not being allowed to contract an entry after it is packed"""
3006 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3008 # In this case there is a spare byte at the end of the data. The size of
3009 # the contents is only 1 byte but we still have the size before it
3011 self.assertEqual(b'a\0', data[:2])
3012 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3013 self.assertEqual(b'a\0', data[-2:])
3015 def testDescriptorOffset(self):
3016 """Test that the Intel descriptor is always placed at at the start"""
3017 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3018 image = control.images['image']
3019 entries = image.GetEntries()
3020 desc = entries['intel-descriptor']
3021 self.assertEqual(0xff800000, desc.offset);
3022 self.assertEqual(0xff800000, desc.image_pos);
3024 def testReplaceCbfs(self):
3025 """Test replacing a single file in CBFS without changing the size"""
3027 expected = b'x' * len(U_BOOT_DATA)
3028 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3029 updated_fname = tools.GetOutputFilename('image-updated.bin')
3030 tools.WriteFile(updated_fname, data)
3031 entry_name = 'section/cbfs/u-boot'
3032 control.WriteEntry(updated_fname, entry_name, expected,
3034 data = control.ReadEntry(updated_fname, entry_name)
3035 self.assertEqual(expected, data)
3037 def testReplaceResizeCbfs(self):
3038 """Test replacing a single file in CBFS with one of a different size"""
3040 expected = U_BOOT_DATA + b'x'
3041 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3042 updated_fname = tools.GetOutputFilename('image-updated.bin')
3043 tools.WriteFile(updated_fname, data)
3044 entry_name = 'section/cbfs/u-boot'
3045 control.WriteEntry(updated_fname, entry_name, expected,
3047 data = control.ReadEntry(updated_fname, entry_name)
3048 self.assertEqual(expected, data)
3051 if __name__ == "__main__":