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
12 from optparse import OptionParser
23 from binman import bintool
24 from binman import cbfs_util
25 from binman import cmdline
26 from binman import comp_util
27 from binman import control
28 from binman import elf
29 from binman import elf_test
30 from binman import fip_util
31 from binman import fmap_util
32 from binman import state
34 from dtoc import fdt_util
35 from binman.etype import fdtmap
36 from binman.etype import image_header
37 from binman.image import Image
38 from patman import command
39 from patman import test_util
40 from patman import tools
41 from patman import tout
43 # Contents of test files, corresponding to different entry types
45 U_BOOT_IMG_DATA = b'img'
46 U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
47 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
51 U_BOOT_DTB_DATA = b'udtb'
52 U_BOOT_SPL_DTB_DATA = b'spldtb'
53 U_BOOT_TPL_DTB_DATA = b'tpldtb'
54 X86_START16_DATA = b'start16'
55 X86_START16_SPL_DATA = b'start16spl'
56 X86_START16_TPL_DATA = b'start16tpl'
57 X86_RESET16_DATA = b'reset16'
58 X86_RESET16_SPL_DATA = b'reset16spl'
59 X86_RESET16_TPL_DATA = b'reset16tpl'
60 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
61 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
62 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
63 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
64 U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
65 U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
66 U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
74 CROS_EC_RW_DATA = b'ecrw'
78 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
79 b"sorry you're alive\n")
80 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
81 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
82 REFCODE_DATA = b'refcode'
86 ATF_BL31_DATA = b'bl31'
87 TEE_OS_DATA = b'this is some tee OS data'
88 ATF_BL2U_DATA = b'bl2u'
89 OPENSBI_DATA = b'opensbi'
91 TEST_FDT1_DATA = b'fdt1'
92 TEST_FDT2_DATA = b'test-fdt2'
93 ENV_DATA = b'var1=1\nvar2="2"'
95 # Subdirectory of the input dir to use to put test FDTs
96 TEST_FDT_SUBDIR = 'fdts'
98 # The expected size for the device tree in some tests
99 EXTRACT_DTB_SIZE = 0x3c9
101 # Properties expected to be in the device tree when update_dtb is used
102 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
104 # Extra properties expected to be in the device tree when allow-repack is used
105 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
108 class TestFunctional(unittest.TestCase):
109 """Functional tests for binman
111 Most of these use a sample .dts file to build an image and then check
112 that it looks correct. The sample files are in the test/ subdirectory
115 For each entry type a very small test file is created using fixed
116 string contents. This makes it easy to test that things look right, and
119 In some cases a 'real' file must be used - these are also supplied in
120 the test/ diurectory.
125 from binman import entry
127 # Handle the case where argv[0] is 'python'
128 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
129 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
131 # Create a temporary directory for input files
132 cls._indir = tempfile.mkdtemp(prefix='binmant.')
134 # Create some test files
135 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
136 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
138 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
139 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
140 TestFunctional._MakeInputFile('me.bin', ME_DATA)
141 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
144 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
146 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
147 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
148 X86_START16_SPL_DATA)
149 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
150 X86_START16_TPL_DATA)
152 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
154 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
155 X86_RESET16_SPL_DATA)
156 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
157 X86_RESET16_TPL_DATA)
159 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
160 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
161 U_BOOT_SPL_NODTB_DATA)
162 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
163 U_BOOT_TPL_NODTB_DATA)
164 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
165 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
166 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
167 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
168 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
169 TestFunctional._MakeInputDir('devkeys')
170 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
171 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
172 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
173 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
174 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
176 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
177 elf_test.BuildElfTestFiles(cls._elf_testdir)
179 # ELF file with a '_dt_ucode_base_size' symbol
180 TestFunctional._MakeInputFile('u-boot',
181 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
183 # Intel flash descriptor file
184 cls._SetupDescriptor()
186 shutil.copytree(cls.TestFile('files'),
187 os.path.join(cls._indir, 'files'))
189 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
190 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
191 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
192 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
193 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
194 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
195 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
197 # Add a few .dtb files for testing
198 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
200 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
203 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
205 cls.have_lz4 = comp_util.HAVE_LZ4
208 def tearDownClass(cls):
209 """Remove the temporary input directory and its contents"""
210 if cls.preserve_indir:
211 print('Preserving input dir: %s' % cls._indir)
214 shutil.rmtree(cls._indir)
218 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
219 toolpath=None, verbosity=None):
220 """Accept arguments controlling test execution
223 preserve_indir: Preserve the shared input directory used by all
225 preserve_outdir: Preserve the output directories used by tests. Each
226 test has its own, so this is normally only useful when running a
228 toolpath: ist of paths to use for tools
230 cls.preserve_indir = preserve_indir
231 cls.preserve_outdirs = preserve_outdirs
232 cls.toolpath = toolpath
233 cls.verbosity = verbosity
236 if not self.have_lz4:
237 self.skipTest('lz4 --no-frame-crc not available')
239 def _CleanupOutputDir(self):
240 """Remove the temporary output directory"""
241 if self.preserve_outdirs:
242 print('Preserving output dir: %s' % tools.outdir)
244 tools._finalise_for_test()
247 # Enable this to turn on debugging output
248 # tout.init(tout.DEBUG)
249 command.test_result = None
252 """Remove the temporary output directory"""
253 self._CleanupOutputDir()
255 def _SetupImageInTmpdir(self):
256 """Set up the output image in a new temporary directory
258 This is used when an image has been generated in the output directory,
259 but we want to run binman again. This will create a new output
260 directory and fail to delete the original one.
262 This creates a new temporary directory, copies the image to it (with a
263 new name) and removes the old output directory.
267 Temporary directory to use
270 image_fname = tools.get_output_filename('image.bin')
271 tmpdir = tempfile.mkdtemp(prefix='binman.')
272 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
273 tools.write_file(updated_fname, tools.read_file(image_fname))
274 self._CleanupOutputDir()
275 return tmpdir, updated_fname
279 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
280 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
281 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
283 def _RunBinman(self, *args, **kwargs):
284 """Run binman using the command line
287 Arguments to pass, as a list of strings
288 kwargs: Arguments to pass to Command.RunPipe()
290 result = command.run_pipe([[self._binman_pathname] + list(args)],
291 capture=True, capture_stderr=True, raise_on_error=False)
292 if result.return_code and kwargs.get('raise_on_error', True):
293 raise Exception("Error running '%s': %s" % (' '.join(args),
294 result.stdout + result.stderr))
297 def _DoBinman(self, *argv):
298 """Run binman using directly (in the same process)
301 Arguments to pass, as a list of strings
303 Return value (0 for success)
306 args = cmdline.ParseArgs(argv)
307 args.pager = 'binman-invalid-pager'
308 args.build_dir = self._indir
310 # For testing, you can force an increase in verbosity here
311 # args.verbosity = tout.DEBUG
312 return control.Binman(args)
314 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
315 entry_args=None, images=None, use_real_dtb=False,
316 use_expanded=False, verbosity=None, allow_missing=False,
317 allow_fake_blobs=False, extra_indirs=None, threads=None,
318 test_section_timeout=False, update_fdt_in_elf=None,
319 force_missing_bintools=''):
320 """Run binman with a given test file
323 fname: Device-tree source filename to use (e.g. 005_simple.dts)
324 debug: True to enable debugging output
325 map: True to output map files for the images
326 update_dtb: Update the offset and size of each entry in the device
327 tree before packing it into the image
328 entry_args: Dict of entry args to supply to binman
330 value: value of that arg
331 images: List of image names to build
332 use_real_dtb: True to use the test file as the contents of
333 the u-boot-dtb entry. Normally this is not needed and the
334 test contents (the U_BOOT_DTB_DATA string) can be used.
335 But in some test we need the real contents.
336 use_expanded: True to use expanded entries where available, e.g.
337 'u-boot-expanded' instead of 'u-boot'
338 verbosity: Verbosity level to use (0-3, None=don't set it)
339 allow_missing: Set the '--allow-missing' flag so that missing
340 external binaries just produce a warning instead of an error
341 allow_fake_blobs: Set the '--fake-ext-blobs' flag
342 extra_indirs: Extra input directories to add using -I
343 threads: Number of threads to use (None for default, 0 for
345 test_section_timeout: True to force the first time to timeout, as
346 used in testThreadTimeout()
347 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
348 force_missing_tools (str): comma-separated list of bintools to
352 int return code, 0 on success
357 if verbosity is not None:
358 args.append('-v%d' % verbosity)
360 args.append('-v%d' % self.verbosity)
362 for path in self.toolpath:
363 args += ['--toolpath', path]
364 if threads is not None:
365 args.append('-T%d' % threads)
366 if test_section_timeout:
367 args.append('--test-section-timeout')
368 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
374 args.append('--fake-dtb')
376 args.append('--no-expanded')
378 for arg, value in entry_args.items():
379 args.append('-a%s=%s' % (arg, value))
383 args.append('--fake-ext-blobs')
384 if force_missing_bintools:
385 args += ['--force-missing-bintools', force_missing_bintools]
386 if update_fdt_in_elf:
387 args += ['--update-fdt-in-elf', update_fdt_in_elf]
390 args += ['-i', image]
392 for indir in extra_indirs:
393 args += ['-I', indir]
394 return self._DoBinman(*args)
396 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
397 """Set up a new test device-tree file
399 The given file is compiled and set up as the device tree to be used
403 fname: Filename of .dts file to read
404 outfile: Output filename for compiled device-tree binary
407 Contents of device-tree binary
409 tmpdir = tempfile.mkdtemp(prefix='binmant.')
410 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
411 with open(dtb, 'rb') as fd:
413 TestFunctional._MakeInputFile(outfile, data)
414 shutil.rmtree(tmpdir)
417 def _GetDtbContentsForSplTpl(self, dtb_data, name):
418 """Create a version of the main DTB for SPL or SPL
420 For testing we don't actually have different versions of the DTB. With
421 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
422 we don't normally have any unwanted nodes.
424 We still want the DTBs for SPL and TPL to be different though, since
425 otherwise it is confusing to know which one we are looking at. So add
426 an 'spl' or 'tpl' property to the top-level node.
429 dtb_data: dtb data to modify (this should be a value devicetree)
430 name: Name of a new property to add
433 New dtb data with the property added
435 dtb = fdt.Fdt.FromData(dtb_data)
437 dtb.GetNode('/binman').AddZeroProp(name)
438 dtb.Sync(auto_resize=True)
440 return dtb.GetContents()
442 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
443 map=False, update_dtb=False, entry_args=None,
444 reset_dtbs=True, extra_indirs=None, threads=None):
445 """Run binman and return the resulting image
447 This runs binman with a given test file and then reads the resulting
448 output file. It is a shortcut function since most tests need to do
451 Raises an assertion failure if binman returns a non-zero exit code.
454 fname: Device-tree source filename to use (e.g. 005_simple.dts)
455 use_real_dtb: True to use the test file as the contents of
456 the u-boot-dtb entry. Normally this is not needed and the
457 test contents (the U_BOOT_DTB_DATA string) can be used.
458 But in some test we need the real contents.
459 use_expanded: True to use expanded entries where available, e.g.
460 'u-boot-expanded' instead of 'u-boot'
461 map: True to output map files for the images
462 update_dtb: Update the offset and size of each entry in the device
463 tree before packing it into the image
464 entry_args: Dict of entry args to supply to binman
466 value: value of that arg
467 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
468 function. If reset_dtbs is True, then the original test dtb
469 is written back before this function finishes
470 extra_indirs: Extra input directories to add using -I
471 threads: Number of threads to use (None for default, 0 for
476 Resulting image contents
478 Map data showing contents of image (or None if none)
479 Output device tree binary filename ('u-boot.dtb' path)
482 # Use the compiled test file as the u-boot-dtb input
484 dtb_data = self._SetupDtb(fname)
486 # For testing purposes, make a copy of the DT for SPL and TPL. Add
487 # a node indicating which it is, so aid verification.
488 for name in ['spl', 'tpl']:
489 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
490 outfile = os.path.join(self._indir, dtb_fname)
491 TestFunctional._MakeInputFile(dtb_fname,
492 self._GetDtbContentsForSplTpl(dtb_data, name))
495 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
496 entry_args=entry_args, use_real_dtb=use_real_dtb,
497 use_expanded=use_expanded, extra_indirs=extra_indirs,
499 self.assertEqual(0, retcode)
500 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
502 # Find the (only) image, read it and return its contents
503 image = control.images['image']
504 image_fname = tools.get_output_filename('image.bin')
505 self.assertTrue(os.path.exists(image_fname))
507 map_fname = tools.get_output_filename('image.map')
508 with open(map_fname) as fd:
512 with open(image_fname, 'rb') as fd:
513 return fd.read(), dtb_data, map_data, out_dtb_fname
515 # Put the test file back
516 if reset_dtbs and use_real_dtb:
519 def _DoReadFileRealDtb(self, fname):
520 """Run binman with a real .dtb file and return the resulting data
523 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
526 Resulting image contents
528 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
530 def _DoReadFile(self, fname, use_real_dtb=False):
531 """Helper function which discards the device-tree binary
534 fname: Device-tree source filename to use (e.g. 005_simple.dts)
535 use_real_dtb: True to use the test file as the contents of
536 the u-boot-dtb entry. Normally this is not needed and the
537 test contents (the U_BOOT_DTB_DATA string) can be used.
538 But in some test we need the real contents.
541 Resulting image contents
543 return self._DoReadFileDtb(fname, use_real_dtb)[0]
546 def _MakeInputFile(cls, fname, contents):
547 """Create a new test input file, creating directories as needed
550 fname: Filename to create
551 contents: File contents to write in to the file
553 Full pathname of file created
555 pathname = os.path.join(cls._indir, fname)
556 dirname = os.path.dirname(pathname)
557 if dirname and not os.path.exists(dirname):
559 with open(pathname, 'wb') as fd:
564 def _MakeInputDir(cls, dirname):
565 """Create a new test input directory, creating directories as needed
568 dirname: Directory name to create
571 Full pathname of directory created
573 pathname = os.path.join(cls._indir, dirname)
574 if not os.path.exists(pathname):
575 os.makedirs(pathname)
579 def _SetupSplElf(cls, src_fname='bss_data'):
580 """Set up an ELF file with a '_dt_ucode_base_size' symbol
583 Filename of ELF file to use as SPL
585 TestFunctional._MakeInputFile('spl/u-boot-spl',
586 tools.read_file(cls.ElfTestFile(src_fname)))
589 def _SetupTplElf(cls, src_fname='bss_data'):
590 """Set up an ELF file with a '_dt_ucode_base_size' symbol
593 Filename of ELF file to use as TPL
595 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
596 tools.read_file(cls.ElfTestFile(src_fname)))
599 def _SetupDescriptor(cls):
600 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
601 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
604 def TestFile(cls, fname):
605 return os.path.join(cls._binman_dir, 'test', fname)
608 def ElfTestFile(cls, fname):
609 return os.path.join(cls._elf_testdir, fname)
611 def AssertInList(self, grep_list, target):
612 """Assert that at least one of a list of things is in a target
615 grep_list: List of strings to check
616 target: Target string
618 for grep in grep_list:
621 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
623 def CheckNoGaps(self, entries):
624 """Check that all entries fit together without gaps
627 entries: List of entries to check
630 for entry in entries.values():
631 self.assertEqual(offset, entry.offset)
634 def GetFdtLen(self, dtb):
635 """Get the totalsize field from a device-tree binary
638 dtb: Device-tree binary contents
641 Total size of device-tree binary, from the header
643 return struct.unpack('>L', dtb[4:8])[0]
645 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
646 def AddNode(node, path):
648 path += '/' + node.name
649 for prop in node.props.values():
650 if prop.name in prop_names:
651 prop_path = path + ':' + prop.name
652 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
654 for subnode in node.subnodes:
655 AddNode(subnode, path)
658 AddNode(dtb.GetRoot(), '')
662 """Test a basic run with valid args"""
663 result = self._RunBinman('-h')
665 def testFullHelp(self):
666 """Test that the full help is displayed with -H"""
667 result = self._RunBinman('-H')
668 help_file = os.path.join(self._binman_dir, 'README.rst')
669 # Remove possible extraneous strings
670 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
671 gothelp = result.stdout.replace(extra, '')
672 self.assertEqual(len(gothelp), os.path.getsize(help_file))
673 self.assertEqual(0, len(result.stderr))
674 self.assertEqual(0, result.return_code)
676 def testFullHelpInternal(self):
677 """Test that the full help is displayed with -H"""
679 command.test_result = command.CommandResult()
680 result = self._DoBinman('-H')
681 help_file = os.path.join(self._binman_dir, 'README.rst')
683 command.test_result = None
686 """Test that the basic help is displayed with -h"""
687 result = self._RunBinman('-h')
688 self.assertTrue(len(result.stdout) > 200)
689 self.assertEqual(0, len(result.stderr))
690 self.assertEqual(0, result.return_code)
693 """Test that we can run it with a specific board"""
694 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
695 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
696 result = self._DoBinman('build', '-n', '-b', 'sandbox')
697 self.assertEqual(0, result)
699 def testNeedBoard(self):
700 """Test that we get an error when no board ius supplied"""
701 with self.assertRaises(ValueError) as e:
702 result = self._DoBinman('build')
703 self.assertIn("Must provide a board to process (use -b <board>)",
706 def testMissingDt(self):
707 """Test that an invalid device-tree file generates an error"""
708 with self.assertRaises(Exception) as e:
709 self._RunBinman('build', '-d', 'missing_file')
710 # We get one error from libfdt, and a different one from fdtget.
711 self.AssertInList(["Couldn't open blob from 'missing_file'",
712 'No such file or directory'], str(e.exception))
714 def testBrokenDt(self):
715 """Test that an invalid device-tree source file generates an error
717 Since this is a source file it should be compiled and the error
718 will come from the device-tree compiler (dtc).
720 with self.assertRaises(Exception) as e:
721 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
722 self.assertIn("FATAL ERROR: Unable to parse input tree",
725 def testMissingNode(self):
726 """Test that a device tree without a 'binman' node generates an error"""
727 with self.assertRaises(Exception) as e:
728 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
729 self.assertIn("does not have a 'binman' node", str(e.exception))
732 """Test that an empty binman node works OK (i.e. does nothing)"""
733 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
734 self.assertEqual(0, len(result.stderr))
735 self.assertEqual(0, result.return_code)
737 def testInvalidEntry(self):
738 """Test that an invalid entry is flagged"""
739 with self.assertRaises(Exception) as e:
740 result = self._RunBinman('build', '-d',
741 self.TestFile('004_invalid_entry.dts'))
742 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
743 "'/binman/not-a-valid-type'", str(e.exception))
745 def testSimple(self):
746 """Test a simple binman with a single file"""
747 data = self._DoReadFile('005_simple.dts')
748 self.assertEqual(U_BOOT_DATA, data)
750 def testSimpleDebug(self):
751 """Test a simple binman run with debugging enabled"""
752 self._DoTestFile('005_simple.dts', debug=True)
755 """Test that we can handle creating two images
757 This also tests image padding.
759 retcode = self._DoTestFile('006_dual_image.dts')
760 self.assertEqual(0, retcode)
762 image = control.images['image1']
763 self.assertEqual(len(U_BOOT_DATA), image.size)
764 fname = tools.get_output_filename('image1.bin')
765 self.assertTrue(os.path.exists(fname))
766 with open(fname, 'rb') as fd:
768 self.assertEqual(U_BOOT_DATA, data)
770 image = control.images['image2']
771 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
772 fname = tools.get_output_filename('image2.bin')
773 self.assertTrue(os.path.exists(fname))
774 with open(fname, 'rb') as fd:
776 self.assertEqual(U_BOOT_DATA, data[3:7])
777 self.assertEqual(tools.get_bytes(0, 3), data[:3])
778 self.assertEqual(tools.get_bytes(0, 5), data[7:])
780 def testBadAlign(self):
781 """Test that an invalid alignment value is detected"""
782 with self.assertRaises(ValueError) as e:
783 self._DoTestFile('007_bad_align.dts')
784 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
785 "of two", str(e.exception))
787 def testPackSimple(self):
788 """Test that packing works as expected"""
789 retcode = self._DoTestFile('008_pack.dts')
790 self.assertEqual(0, retcode)
791 self.assertIn('image', control.images)
792 image = control.images['image']
793 entries = image.GetEntries()
794 self.assertEqual(5, len(entries))
797 self.assertIn('u-boot', entries)
798 entry = entries['u-boot']
799 self.assertEqual(0, entry.offset)
800 self.assertEqual(len(U_BOOT_DATA), entry.size)
802 # Second u-boot, aligned to 16-byte boundary
803 self.assertIn('u-boot-align', entries)
804 entry = entries['u-boot-align']
805 self.assertEqual(16, entry.offset)
806 self.assertEqual(len(U_BOOT_DATA), entry.size)
808 # Third u-boot, size 23 bytes
809 self.assertIn('u-boot-size', entries)
810 entry = entries['u-boot-size']
811 self.assertEqual(20, entry.offset)
812 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
813 self.assertEqual(23, entry.size)
815 # Fourth u-boot, placed immediate after the above
816 self.assertIn('u-boot-next', entries)
817 entry = entries['u-boot-next']
818 self.assertEqual(43, entry.offset)
819 self.assertEqual(len(U_BOOT_DATA), entry.size)
821 # Fifth u-boot, placed at a fixed offset
822 self.assertIn('u-boot-fixed', entries)
823 entry = entries['u-boot-fixed']
824 self.assertEqual(61, entry.offset)
825 self.assertEqual(len(U_BOOT_DATA), entry.size)
827 self.assertEqual(65, image.size)
829 def testPackExtra(self):
830 """Test that extra packing feature works as expected"""
831 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
834 self.assertIn('image', control.images)
835 image = control.images['image']
836 entries = image.GetEntries()
837 self.assertEqual(5, len(entries))
839 # First u-boot with padding before and after
840 self.assertIn('u-boot', entries)
841 entry = entries['u-boot']
842 self.assertEqual(0, entry.offset)
843 self.assertEqual(3, entry.pad_before)
844 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
845 self.assertEqual(U_BOOT_DATA, entry.data)
846 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
847 tools.get_bytes(0, 5), data[:entry.size])
850 # Second u-boot has an aligned size, but it has no effect
851 self.assertIn('u-boot-align-size-nop', entries)
852 entry = entries['u-boot-align-size-nop']
853 self.assertEqual(pos, entry.offset)
854 self.assertEqual(len(U_BOOT_DATA), entry.size)
855 self.assertEqual(U_BOOT_DATA, entry.data)
856 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
859 # Third u-boot has an aligned size too
860 self.assertIn('u-boot-align-size', entries)
861 entry = entries['u-boot-align-size']
862 self.assertEqual(pos, entry.offset)
863 self.assertEqual(32, entry.size)
864 self.assertEqual(U_BOOT_DATA, entry.data)
865 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
866 data[pos:pos + entry.size])
869 # Fourth u-boot has an aligned end
870 self.assertIn('u-boot-align-end', entries)
871 entry = entries['u-boot-align-end']
872 self.assertEqual(48, entry.offset)
873 self.assertEqual(16, entry.size)
874 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
875 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
876 data[pos:pos + entry.size])
879 # Fifth u-boot immediately afterwards
880 self.assertIn('u-boot-align-both', entries)
881 entry = entries['u-boot-align-both']
882 self.assertEqual(64, entry.offset)
883 self.assertEqual(64, entry.size)
884 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
885 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
886 data[pos:pos + entry.size])
888 self.CheckNoGaps(entries)
889 self.assertEqual(128, image.size)
891 dtb = fdt.Fdt(out_dtb_fname)
893 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
899 'u-boot:image-pos': 0,
901 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
903 'u-boot-align-size-nop:image-pos': 12,
904 'u-boot-align-size-nop:offset': 12,
905 'u-boot-align-size-nop:size': 4,
907 'u-boot-align-size:image-pos': 16,
908 'u-boot-align-size:offset': 16,
909 'u-boot-align-size:size': 32,
911 'u-boot-align-end:image-pos': 48,
912 'u-boot-align-end:offset': 48,
913 'u-boot-align-end:size': 16,
915 'u-boot-align-both:image-pos': 64,
916 'u-boot-align-both:offset': 64,
917 'u-boot-align-both:size': 64,
919 self.assertEqual(expected, props)
921 def testPackAlignPowerOf2(self):
922 """Test that invalid entry alignment is detected"""
923 with self.assertRaises(ValueError) as e:
924 self._DoTestFile('010_pack_align_power2.dts')
925 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
926 "of two", str(e.exception))
928 def testPackAlignSizePowerOf2(self):
929 """Test that invalid entry size alignment is detected"""
930 with self.assertRaises(ValueError) as e:
931 self._DoTestFile('011_pack_align_size_power2.dts')
932 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
933 "power of two", str(e.exception))
935 def testPackInvalidAlign(self):
936 """Test detection of an offset that does not match its alignment"""
937 with self.assertRaises(ValueError) as e:
938 self._DoTestFile('012_pack_inv_align.dts')
939 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
940 "align 0x4 (4)", str(e.exception))
942 def testPackInvalidSizeAlign(self):
943 """Test that invalid entry size alignment is detected"""
944 with self.assertRaises(ValueError) as e:
945 self._DoTestFile('013_pack_inv_size_align.dts')
946 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
947 "align-size 0x4 (4)", str(e.exception))
949 def testPackOverlap(self):
950 """Test that overlapping regions are detected"""
951 with self.assertRaises(ValueError) as e:
952 self._DoTestFile('014_pack_overlap.dts')
953 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
954 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
957 def testPackEntryOverflow(self):
958 """Test that entries that overflow their size are detected"""
959 with self.assertRaises(ValueError) as e:
960 self._DoTestFile('015_pack_overflow.dts')
961 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
962 "but entry size is 0x3 (3)", str(e.exception))
964 def testPackImageOverflow(self):
965 """Test that entries which overflow the image size are detected"""
966 with self.assertRaises(ValueError) as e:
967 self._DoTestFile('016_pack_image_overflow.dts')
968 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
969 "size 0x3 (3)", str(e.exception))
971 def testPackImageSize(self):
972 """Test that the image size can be set"""
973 retcode = self._DoTestFile('017_pack_image_size.dts')
974 self.assertEqual(0, retcode)
975 self.assertIn('image', control.images)
976 image = control.images['image']
977 self.assertEqual(7, image.size)
979 def testPackImageSizeAlign(self):
980 """Test that image size alignemnt works as expected"""
981 retcode = self._DoTestFile('018_pack_image_align.dts')
982 self.assertEqual(0, retcode)
983 self.assertIn('image', control.images)
984 image = control.images['image']
985 self.assertEqual(16, image.size)
987 def testPackInvalidImageAlign(self):
988 """Test that invalid image alignment is detected"""
989 with self.assertRaises(ValueError) as e:
990 self._DoTestFile('019_pack_inv_image_align.dts')
991 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
992 "align-size 0x8 (8)", str(e.exception))
994 def testPackAlignPowerOf2Inv(self):
995 """Test that invalid image alignment is detected"""
996 with self.assertRaises(ValueError) as e:
997 self._DoTestFile('020_pack_inv_image_align_power2.dts')
998 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
999 "two", str(e.exception))
1001 def testImagePadByte(self):
1002 """Test that the image pad byte can be specified"""
1004 data = self._DoReadFile('021_image_pad.dts')
1005 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
1008 def testImageName(self):
1009 """Test that image files can be named"""
1010 retcode = self._DoTestFile('022_image_name.dts')
1011 self.assertEqual(0, retcode)
1012 image = control.images['image1']
1013 fname = tools.get_output_filename('test-name')
1014 self.assertTrue(os.path.exists(fname))
1016 image = control.images['image2']
1017 fname = tools.get_output_filename('test-name.xx')
1018 self.assertTrue(os.path.exists(fname))
1020 def testBlobFilename(self):
1021 """Test that generic blobs can be provided by filename"""
1022 data = self._DoReadFile('023_blob.dts')
1023 self.assertEqual(BLOB_DATA, data)
1025 def testPackSorted(self):
1026 """Test that entries can be sorted"""
1028 data = self._DoReadFile('024_sorted.dts')
1029 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1030 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
1032 def testPackZeroOffset(self):
1033 """Test that an entry at offset 0 is not given a new offset"""
1034 with self.assertRaises(ValueError) as e:
1035 self._DoTestFile('025_pack_zero_size.dts')
1036 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1037 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1040 def testPackUbootDtb(self):
1041 """Test that a device tree can be added to U-Boot"""
1042 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1043 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1045 def testPackX86RomNoSize(self):
1046 """Test that the end-at-4gb property requires a size property"""
1047 with self.assertRaises(ValueError) as e:
1048 self._DoTestFile('027_pack_4gb_no_size.dts')
1049 self.assertIn("Image '/binman': Section size must be provided when "
1050 "using end-at-4gb", str(e.exception))
1052 def test4gbAndSkipAtStartTogether(self):
1053 """Test that the end-at-4gb and skip-at-size property can't be used
1055 with self.assertRaises(ValueError) as e:
1056 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1057 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1058 "'skip-at-start'", str(e.exception))
1060 def testPackX86RomOutside(self):
1061 """Test that the end-at-4gb property checks for offset boundaries"""
1062 with self.assertRaises(ValueError) as e:
1063 self._DoTestFile('028_pack_4gb_outside.dts')
1064 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1065 "is outside the section '/binman' starting at "
1066 '0xffffffe0 (4294967264) of size 0x20 (32)',
1069 def testPackX86Rom(self):
1070 """Test that a basic x86 ROM can be created"""
1072 data = self._DoReadFile('029_x86_rom.dts')
1073 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1074 tools.get_bytes(0, 2), data)
1076 def testPackX86RomMeNoDesc(self):
1077 """Test that an invalid Intel descriptor entry is detected"""
1079 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1080 with self.assertRaises(ValueError) as e:
1081 self._DoTestFile('163_x86_rom_me_empty.dts')
1082 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1085 self._SetupDescriptor()
1087 def testPackX86RomBadDesc(self):
1088 """Test that the Intel requires a descriptor entry"""
1089 with self.assertRaises(ValueError) as e:
1090 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1091 self.assertIn("Node '/binman/intel-me': No offset set with "
1092 "offset-unset: should another entry provide this correct "
1093 "offset?", str(e.exception))
1095 def testPackX86RomMe(self):
1096 """Test that an x86 ROM with an ME region can be created"""
1097 data = self._DoReadFile('031_x86_rom_me.dts')
1098 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
1099 if data[:0x1000] != expected_desc:
1100 self.fail('Expected descriptor binary at start of image')
1101 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1103 def testPackVga(self):
1104 """Test that an image with a VGA binary can be created"""
1105 data = self._DoReadFile('032_intel_vga.dts')
1106 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1108 def testPackStart16(self):
1109 """Test that an image with an x86 start16 region can be created"""
1110 data = self._DoReadFile('033_x86_start16.dts')
1111 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1113 def testPackPowerpcMpc85xxBootpgResetvec(self):
1114 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1116 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1117 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1119 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1120 """Handle running a test for insertion of microcode
1123 dts_fname: Name of test .dts file
1124 nodtb_data: Data that we expect in the first section
1125 ucode_second: True if the microsecond entry is second instead of
1130 Contents of first region (U-Boot or SPL)
1131 Offset and size components of microcode pointer, as inserted
1132 in the above (two 4-byte words)
1134 data = self._DoReadFile(dts_fname, True)
1136 # Now check the device tree has no microcode
1138 ucode_content = data[len(nodtb_data):]
1139 ucode_pos = len(nodtb_data)
1140 dtb_with_ucode = ucode_content[16:]
1141 fdt_len = self.GetFdtLen(dtb_with_ucode)
1143 dtb_with_ucode = data[len(nodtb_data):]
1144 fdt_len = self.GetFdtLen(dtb_with_ucode)
1145 ucode_content = dtb_with_ucode[fdt_len:]
1146 ucode_pos = len(nodtb_data) + fdt_len
1147 fname = tools.get_output_filename('test.dtb')
1148 with open(fname, 'wb') as fd:
1149 fd.write(dtb_with_ucode)
1150 dtb = fdt.FdtScan(fname)
1151 ucode = dtb.GetNode('/microcode')
1152 self.assertTrue(ucode)
1153 for node in ucode.subnodes:
1154 self.assertFalse(node.props.get('data'))
1156 # Check that the microcode appears immediately after the Fdt
1157 # This matches the concatenation of the data properties in
1158 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1159 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1161 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1163 # Check that the microcode pointer was inserted. It should match the
1164 # expected offset and size
1165 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1167 u_boot = data[:len(nodtb_data)]
1168 return u_boot, pos_and_size
1170 def testPackUbootMicrocode(self):
1171 """Test that x86 microcode can be handled correctly
1173 We expect to see the following in the image, in order:
1174 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1176 u-boot.dtb with the microcode removed
1179 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1181 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1182 b' somewhere in here', first)
1184 def _RunPackUbootSingleMicrocode(self):
1185 """Test that x86 microcode can be handled correctly
1187 We expect to see the following in the image, in order:
1188 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1190 u-boot.dtb with the microcode
1191 an empty microcode region
1193 # We need the libfdt library to run this test since only that allows
1194 # finding the offset of a property. This is required by
1195 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1196 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1198 second = data[len(U_BOOT_NODTB_DATA):]
1200 fdt_len = self.GetFdtLen(second)
1201 third = second[fdt_len:]
1202 second = second[:fdt_len]
1204 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1205 self.assertIn(ucode_data, second)
1206 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1208 # Check that the microcode pointer was inserted. It should match the
1209 # expected offset and size
1210 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1212 first = data[:len(U_BOOT_NODTB_DATA)]
1213 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1214 b' somewhere in here', first)
1216 def testPackUbootSingleMicrocode(self):
1217 """Test that x86 microcode can be handled correctly with fdt_normal.
1219 self._RunPackUbootSingleMicrocode()
1221 def testUBootImg(self):
1222 """Test that u-boot.img can be put in a file"""
1223 data = self._DoReadFile('036_u_boot_img.dts')
1224 self.assertEqual(U_BOOT_IMG_DATA, data)
1226 def testNoMicrocode(self):
1227 """Test that a missing microcode region is detected"""
1228 with self.assertRaises(ValueError) as e:
1229 self._DoReadFile('037_x86_no_ucode.dts', True)
1230 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1231 "node found in ", str(e.exception))
1233 def testMicrocodeWithoutNode(self):
1234 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1235 with self.assertRaises(ValueError) as e:
1236 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1237 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1238 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1240 def testMicrocodeWithoutNode2(self):
1241 """Test that a missing u-boot-ucode node is detected"""
1242 with self.assertRaises(ValueError) as e:
1243 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1244 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1245 "microcode region u-boot-ucode", str(e.exception))
1247 def testMicrocodeWithoutPtrInElf(self):
1248 """Test that a U-Boot binary without the microcode symbol is detected"""
1249 # ELF file without a '_dt_ucode_base_size' symbol
1251 TestFunctional._MakeInputFile('u-boot',
1252 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1254 with self.assertRaises(ValueError) as e:
1255 self._RunPackUbootSingleMicrocode()
1256 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1257 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1260 # Put the original file back
1261 TestFunctional._MakeInputFile('u-boot',
1262 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
1264 def testMicrocodeNotInImage(self):
1265 """Test that microcode must be placed within the image"""
1266 with self.assertRaises(ValueError) as e:
1267 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1268 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1269 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1270 "section ranging from 00000000 to 0000002e", str(e.exception))
1272 def testWithoutMicrocode(self):
1273 """Test that we can cope with an image without microcode (e.g. qemu)"""
1274 TestFunctional._MakeInputFile('u-boot',
1275 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1276 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1278 # Now check the device tree has no microcode
1279 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1280 second = data[len(U_BOOT_NODTB_DATA):]
1282 fdt_len = self.GetFdtLen(second)
1283 self.assertEqual(dtb, second[:fdt_len])
1285 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1286 third = data[used_len:]
1287 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
1289 def testUnknownPosSize(self):
1290 """Test that microcode must be placed within the image"""
1291 with self.assertRaises(ValueError) as e:
1292 self._DoReadFile('041_unknown_pos_size.dts', True)
1293 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1294 "entry 'invalid-entry'", str(e.exception))
1296 def testPackFsp(self):
1297 """Test that an image with a FSP binary can be created"""
1298 data = self._DoReadFile('042_intel_fsp.dts')
1299 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1301 def testPackCmc(self):
1302 """Test that an image with a CMC binary can be created"""
1303 data = self._DoReadFile('043_intel_cmc.dts')
1304 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1306 def testPackVbt(self):
1307 """Test that an image with a VBT binary can be created"""
1308 data = self._DoReadFile('046_intel_vbt.dts')
1309 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1311 def testSplBssPad(self):
1312 """Test that we can pad SPL's BSS with zeros"""
1313 # ELF file with a '__bss_size' symbol
1315 data = self._DoReadFile('047_spl_bss_pad.dts')
1316 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
1319 def testSplBssPadMissing(self):
1320 """Test that a missing symbol is detected"""
1321 self._SetupSplElf('u_boot_ucode_ptr')
1322 with self.assertRaises(ValueError) as e:
1323 self._DoReadFile('047_spl_bss_pad.dts')
1324 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1327 def testPackStart16Spl(self):
1328 """Test that an image with an x86 start16 SPL region can be created"""
1329 data = self._DoReadFile('048_x86_start16_spl.dts')
1330 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1332 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1333 """Helper function for microcode tests
1335 We expect to see the following in the image, in order:
1336 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1338 u-boot.dtb with the microcode removed
1342 dts: Device tree file to use for test
1343 ucode_second: True if the microsecond entry is second instead of
1346 self._SetupSplElf('u_boot_ucode_ptr')
1347 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1348 ucode_second=ucode_second)
1349 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1350 b'ter somewhere in here', first)
1352 def testPackUbootSplMicrocode(self):
1353 """Test that x86 microcode can be handled correctly in SPL"""
1354 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1356 def testPackUbootSplMicrocodeReorder(self):
1357 """Test that order doesn't matter for microcode entries
1359 This is the same as testPackUbootSplMicrocode but when we process the
1360 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1361 entry, so we reply on binman to try later.
1363 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1366 def testPackMrc(self):
1367 """Test that an image with an MRC binary can be created"""
1368 data = self._DoReadFile('050_intel_mrc.dts')
1369 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1371 def testSplDtb(self):
1372 """Test that an image with spl/u-boot-spl.dtb can be created"""
1373 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1374 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1376 def testSplNoDtb(self):
1377 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1379 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1380 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1382 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1383 use_expanded=False):
1384 """Check the image contains the expected symbol values
1387 dts: Device tree file to use for test
1388 base_data: Data before and after 'u-boot' section
1389 u_boot_offset: Offset of 'u-boot' section in image
1390 entry_args: Dict of entry args to supply to binman
1392 value: value of that arg
1393 use_expanded: True to use expanded entries where available, e.g.
1394 'u-boot-expanded' instead of 'u-boot'
1396 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1397 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1398 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1399 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1402 self._SetupSplElf('u_boot_binman_syms')
1403 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1404 use_expanded=use_expanded)[0]
1405 # The image should contain the symbols from u_boot_binman_syms.c
1406 # Note that image_pos is adjusted by the base address of the image,
1407 # which is 0x10 in our test image
1408 sym_values = struct.pack('<LQLL', 0x00,
1409 u_boot_offset + len(U_BOOT_DATA),
1410 0x10 + u_boot_offset, 0x04)
1411 expected = (sym_values + base_data[20:] +
1412 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1414 self.assertEqual(expected, data)
1416 def testSymbols(self):
1417 """Test binman can assign symbols embedded in U-Boot"""
1418 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1420 def testSymbolsNoDtb(self):
1421 """Test binman can assign symbols embedded in U-Boot SPL"""
1422 self.checkSymbols('196_symbols_nodtb.dts',
1423 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1426 def testPackUnitAddress(self):
1427 """Test that we support multiple binaries with the same name"""
1428 data = self._DoReadFile('054_unit_address.dts')
1429 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1431 def testSections(self):
1432 """Basic test of sections"""
1433 data = self._DoReadFile('055_sections.dts')
1434 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1435 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1436 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
1437 self.assertEqual(expected, data)
1440 """Tests outputting a map of the images"""
1441 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1442 self.assertEqual('''ImagePos Offset Size Name
1443 00000000 00000000 00000028 main-section
1444 00000000 00000000 00000010 section@0
1445 00000000 00000000 00000004 u-boot
1446 00000010 00000010 00000010 section@1
1447 00000010 00000000 00000004 u-boot
1448 00000020 00000020 00000004 section@2
1449 00000020 00000000 00000004 u-boot
1452 def testNamePrefix(self):
1453 """Tests that name prefixes are used"""
1454 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1455 self.assertEqual('''ImagePos Offset Size Name
1456 00000000 00000000 00000028 main-section
1457 00000000 00000000 00000010 section@0
1458 00000000 00000000 00000004 ro-u-boot
1459 00000010 00000010 00000010 section@1
1460 00000010 00000000 00000004 rw-u-boot
1463 def testUnknownContents(self):
1464 """Test that obtaining the contents works as expected"""
1465 with self.assertRaises(ValueError) as e:
1466 self._DoReadFile('057_unknown_contents.dts', True)
1467 self.assertIn("Image '/binman': Internal error: Could not complete "
1468 "processing of contents: remaining ["
1469 "<binman.etype._testing.Entry__testing ", str(e.exception))
1471 def testBadChangeSize(self):
1472 """Test that trying to change the size of an entry fails"""
1474 state.SetAllowEntryExpansion(False)
1475 with self.assertRaises(ValueError) as e:
1476 self._DoReadFile('059_change_size.dts', True)
1477 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1480 state.SetAllowEntryExpansion(True)
1482 def testUpdateFdt(self):
1483 """Test that we can update the device tree with offset/size info"""
1484 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1486 dtb = fdt.Fdt(out_dtb_fname)
1488 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1492 '_testing:offset': 32,
1494 '_testing:image-pos': 32,
1495 'section@0/u-boot:offset': 0,
1496 'section@0/u-boot:size': len(U_BOOT_DATA),
1497 'section@0/u-boot:image-pos': 0,
1498 'section@0:offset': 0,
1499 'section@0:size': 16,
1500 'section@0:image-pos': 0,
1502 'section@1/u-boot:offset': 0,
1503 'section@1/u-boot:size': len(U_BOOT_DATA),
1504 'section@1/u-boot:image-pos': 16,
1505 'section@1:offset': 16,
1506 'section@1:size': 16,
1507 'section@1:image-pos': 16,
1511 def testUpdateFdtBad(self):
1512 """Test that we detect when ProcessFdt never completes"""
1513 with self.assertRaises(ValueError) as e:
1514 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1515 self.assertIn('Could not complete processing of Fdt: remaining '
1516 '[<binman.etype._testing.Entry__testing',
1519 def testEntryArgs(self):
1520 """Test passing arguments to entries from the command line"""
1522 'test-str-arg': 'test1',
1523 'test-int-arg': '456',
1525 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1526 self.assertIn('image', control.images)
1527 entry = control.images['image'].GetEntries()['_testing']
1528 self.assertEqual('test0', entry.test_str_fdt)
1529 self.assertEqual('test1', entry.test_str_arg)
1530 self.assertEqual(123, entry.test_int_fdt)
1531 self.assertEqual(456, entry.test_int_arg)
1533 def testEntryArgsMissing(self):
1534 """Test missing arguments and properties"""
1536 'test-int-arg': '456',
1538 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1539 entry = control.images['image'].GetEntries()['_testing']
1540 self.assertEqual('test0', entry.test_str_fdt)
1541 self.assertEqual(None, entry.test_str_arg)
1542 self.assertEqual(None, entry.test_int_fdt)
1543 self.assertEqual(456, entry.test_int_arg)
1545 def testEntryArgsRequired(self):
1546 """Test missing arguments and properties"""
1548 'test-int-arg': '456',
1550 with self.assertRaises(ValueError) as e:
1551 self._DoReadFileDtb('064_entry_args_required.dts')
1552 self.assertIn("Node '/binman/_testing': "
1553 'Missing required properties/entry args: test-str-arg, '
1554 'test-int-fdt, test-int-arg',
1557 def testEntryArgsInvalidFormat(self):
1558 """Test that an invalid entry-argument format is detected"""
1559 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1561 with self.assertRaises(ValueError) as e:
1562 self._DoBinman(*args)
1563 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1565 def testEntryArgsInvalidInteger(self):
1566 """Test that an invalid entry-argument integer is detected"""
1568 'test-int-arg': 'abc',
1570 with self.assertRaises(ValueError) as e:
1571 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1572 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1573 "'test-int-arg' (value 'abc') to integer",
1576 def testEntryArgsInvalidDatatype(self):
1577 """Test that an invalid entry-argument datatype is detected
1579 This test could be written in entry_test.py except that it needs
1580 access to control.entry_args, which seems more than that module should
1584 'test-bad-datatype-arg': '12',
1586 with self.assertRaises(ValueError) as e:
1587 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1588 entry_args=entry_args)
1589 self.assertIn('GetArg() internal error: Unknown data type ',
1593 """Test for a text entry type"""
1595 'test-id': TEXT_DATA,
1596 'test-id2': TEXT_DATA2,
1597 'test-id3': TEXT_DATA3,
1599 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1600 entry_args=entry_args)
1601 expected = (tools.to_bytes(TEXT_DATA) +
1602 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1603 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
1604 b'some text' + b'more text')
1605 self.assertEqual(expected, data)
1607 def testEntryDocs(self):
1608 """Test for creation of entry documentation"""
1609 with test_util.capture_sys_output() as (stdout, stderr):
1610 control.WriteEntryDocs(control.GetEntryModules())
1611 self.assertTrue(len(stdout.getvalue()) > 0)
1613 def testEntryDocsMissing(self):
1614 """Test handling of missing entry documentation"""
1615 with self.assertRaises(ValueError) as e:
1616 with test_util.capture_sys_output() as (stdout, stderr):
1617 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1618 self.assertIn('Documentation is missing for modules: u_boot',
1622 """Basic test of generation of a flashrom fmap"""
1623 data = self._DoReadFile('067_fmap.dts')
1624 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1625 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1626 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
1627 self.assertEqual(expected, data[:32])
1628 self.assertEqual(b'__FMAP__', fhdr.signature)
1629 self.assertEqual(1, fhdr.ver_major)
1630 self.assertEqual(0, fhdr.ver_minor)
1631 self.assertEqual(0, fhdr.base)
1632 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1633 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1634 self.assertEqual(b'FMAP', fhdr.name)
1635 self.assertEqual(5, fhdr.nareas)
1636 fiter = iter(fentries)
1638 fentry = next(fiter)
1639 self.assertEqual(b'SECTION0', fentry.name)
1640 self.assertEqual(0, fentry.offset)
1641 self.assertEqual(16, fentry.size)
1642 self.assertEqual(0, fentry.flags)
1644 fentry = next(fiter)
1645 self.assertEqual(b'RO_U_BOOT', fentry.name)
1646 self.assertEqual(0, fentry.offset)
1647 self.assertEqual(4, fentry.size)
1648 self.assertEqual(0, fentry.flags)
1650 fentry = next(fiter)
1651 self.assertEqual(b'SECTION1', fentry.name)
1652 self.assertEqual(16, fentry.offset)
1653 self.assertEqual(16, fentry.size)
1654 self.assertEqual(0, fentry.flags)
1656 fentry = next(fiter)
1657 self.assertEqual(b'RW_U_BOOT', fentry.name)
1658 self.assertEqual(16, fentry.offset)
1659 self.assertEqual(4, fentry.size)
1660 self.assertEqual(0, fentry.flags)
1662 fentry = next(fiter)
1663 self.assertEqual(b'FMAP', fentry.name)
1664 self.assertEqual(32, fentry.offset)
1665 self.assertEqual(expect_size, fentry.size)
1666 self.assertEqual(0, fentry.flags)
1668 def testBlobNamedByArg(self):
1669 """Test we can add a blob with the filename coming from an entry arg"""
1671 'cros-ec-rw-path': 'ecrw.bin',
1673 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1676 """Test for an fill entry type"""
1677 data = self._DoReadFile('069_fill.dts')
1678 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
1679 self.assertEqual(expected, data)
1681 def testFillNoSize(self):
1682 """Test for an fill entry type with no size"""
1683 with self.assertRaises(ValueError) as e:
1684 self._DoReadFile('070_fill_no_size.dts')
1685 self.assertIn("'fill' entry must have a size property",
1688 def _HandleGbbCommand(self, pipe_list):
1689 """Fake calls to the futility utility"""
1690 if pipe_list[0][0] == 'futility':
1691 fname = pipe_list[0][-1]
1692 # Append our GBB data to the file, which will happen every time the
1693 # futility command is called.
1694 with open(fname, 'ab') as fd:
1696 return command.CommandResult()
1699 """Test for the Chromium OS Google Binary Block"""
1700 command.test_result = self._HandleGbbCommand
1702 'keydir': 'devkeys',
1703 'bmpblk': 'bmpblk.bin',
1705 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1708 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1709 tools.get_bytes(0, 0x2180 - 16))
1710 self.assertEqual(expected, data)
1712 def testGbbTooSmall(self):
1713 """Test for the Chromium OS Google Binary Block being large enough"""
1714 with self.assertRaises(ValueError) as e:
1715 self._DoReadFileDtb('072_gbb_too_small.dts')
1716 self.assertIn("Node '/binman/gbb': GBB is too small",
1719 def testGbbNoSize(self):
1720 """Test for the Chromium OS Google Binary Block having a size"""
1721 with self.assertRaises(ValueError) as e:
1722 self._DoReadFileDtb('073_gbb_no_size.dts')
1723 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1726 def testGbbMissing(self):
1727 """Test that binman still produces an image if futility is missing"""
1729 'keydir': 'devkeys',
1731 with test_util.capture_sys_output() as (_, stderr):
1732 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1733 entry_args=entry_args)
1734 err = stderr.getvalue()
1735 self.assertRegex(err,
1736 "Image 'main-section'.*missing bintools.*: futility")
1738 def _HandleVblockCommand(self, pipe_list):
1739 """Fake calls to the futility utility
1741 The expected pipe is:
1743 [('futility', 'vbutil_firmware', '--vblock',
1744 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1745 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1746 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1747 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1749 This writes to the output file (here, 'vblock.vblock'). If
1750 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1751 of the input data (here, 'input.vblock').
1753 if pipe_list[0][0] == 'futility':
1754 fname = pipe_list[0][3]
1755 with open(fname, 'wb') as fd:
1757 infile = pipe_list[0][11]
1758 m = hashlib.sha256()
1759 data = tools.read_file(infile)
1761 fd.write(m.digest())
1763 fd.write(VBLOCK_DATA)
1765 return command.CommandResult()
1767 def testVblock(self):
1768 """Test for the Chromium OS Verified Boot Block"""
1769 self._hash_data = False
1770 command.test_result = self._HandleVblockCommand
1772 'keydir': 'devkeys',
1774 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1775 entry_args=entry_args)
1776 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1777 self.assertEqual(expected, data)
1779 def testVblockNoContent(self):
1780 """Test we detect a vblock which has no content to sign"""
1781 with self.assertRaises(ValueError) as e:
1782 self._DoReadFile('075_vblock_no_content.dts')
1783 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1784 'property', str(e.exception))
1786 def testVblockBadPhandle(self):
1787 """Test that we detect a vblock with an invalid phandle in contents"""
1788 with self.assertRaises(ValueError) as e:
1789 self._DoReadFile('076_vblock_bad_phandle.dts')
1790 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1791 '1000', str(e.exception))
1793 def testVblockBadEntry(self):
1794 """Test that we detect an entry that points to a non-entry"""
1795 with self.assertRaises(ValueError) as e:
1796 self._DoReadFile('077_vblock_bad_entry.dts')
1797 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1798 "'other'", str(e.exception))
1800 def testVblockContent(self):
1801 """Test that the vblock signs the right data"""
1802 self._hash_data = True
1803 command.test_result = self._HandleVblockCommand
1805 'keydir': 'devkeys',
1807 data = self._DoReadFileDtb(
1808 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1809 entry_args=entry_args)[0]
1810 hashlen = 32 # SHA256 hash is 32 bytes
1811 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1812 hashval = data[-hashlen:]
1813 dtb = data[len(U_BOOT_DATA):-hashlen]
1815 expected_data = U_BOOT_DATA + dtb
1817 # The hashval should be a hash of the dtb
1818 m = hashlib.sha256()
1819 m.update(expected_data)
1820 expected_hashval = m.digest()
1821 self.assertEqual(expected_hashval, hashval)
1823 def testVblockMissing(self):
1824 """Test that binman still produces an image if futility is missing"""
1826 'keydir': 'devkeys',
1828 with test_util.capture_sys_output() as (_, stderr):
1829 self._DoTestFile('074_vblock.dts',
1830 force_missing_bintools='futility',
1831 entry_args=entry_args)
1832 err = stderr.getvalue()
1833 self.assertRegex(err,
1834 "Image 'main-section'.*missing bintools.*: futility")
1837 """Test that an image with TPL and its device tree can be created"""
1838 # ELF file with a '__bss_size' symbol
1840 data = self._DoReadFile('078_u_boot_tpl.dts')
1841 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1843 def testUsesPos(self):
1844 """Test that the 'pos' property cannot be used anymore"""
1845 with self.assertRaises(ValueError) as e:
1846 data = self._DoReadFile('079_uses_pos.dts')
1847 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1848 "'pos'", str(e.exception))
1850 def testFillZero(self):
1851 """Test for an fill entry type with a size of 0"""
1852 data = self._DoReadFile('080_fill_empty.dts')
1853 self.assertEqual(tools.get_bytes(0, 16), data)
1855 def testTextMissing(self):
1856 """Test for a text entry type where there is no text"""
1857 with self.assertRaises(ValueError) as e:
1858 self._DoReadFileDtb('066_text.dts',)
1859 self.assertIn("Node '/binman/text': No value provided for text label "
1860 "'test-id'", str(e.exception))
1862 def testPackStart16Tpl(self):
1863 """Test that an image with an x86 start16 TPL region can be created"""
1864 data = self._DoReadFile('081_x86_start16_tpl.dts')
1865 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1867 def testSelectImage(self):
1868 """Test that we can select which images to build"""
1869 expected = 'Skipping images: image1'
1871 # We should only get the expected message in verbose mode
1872 for verbosity in (0, 2):
1873 with test_util.capture_sys_output() as (stdout, stderr):
1874 retcode = self._DoTestFile('006_dual_image.dts',
1875 verbosity=verbosity,
1877 self.assertEqual(0, retcode)
1879 self.assertIn(expected, stdout.getvalue())
1881 self.assertNotIn(expected, stdout.getvalue())
1883 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1884 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
1885 self._CleanupOutputDir()
1887 def testUpdateFdtAll(self):
1888 """Test that all device trees are updated with offset/size info"""
1889 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1892 'section:image-pos': 0,
1893 'u-boot-tpl-dtb:size': 513,
1894 'u-boot-spl-dtb:size': 513,
1895 'u-boot-spl-dtb:offset': 493,
1897 'section/u-boot-dtb:image-pos': 0,
1898 'u-boot-spl-dtb:image-pos': 493,
1899 'section/u-boot-dtb:size': 493,
1900 'u-boot-tpl-dtb:image-pos': 1006,
1901 'section/u-boot-dtb:offset': 0,
1902 'section:size': 493,
1904 'section:offset': 0,
1905 'u-boot-tpl-dtb:offset': 1006,
1909 # We expect three device-tree files in the output, one after the other.
1910 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1911 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1912 # main U-Boot tree. All three should have the same postions and offset.
1914 for item in ['', 'spl', 'tpl']:
1915 dtb = fdt.Fdt.FromData(data[start:])
1917 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1919 expected = dict(base_expected)
1922 self.assertEqual(expected, props)
1923 start += dtb._fdt_obj.totalsize()
1925 def testUpdateFdtOutput(self):
1926 """Test that output DTB files are updated"""
1928 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1929 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1931 # Unfortunately, compiling a source file always results in a file
1932 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1933 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1934 # binman as a file called u-boot.dtb. To fix this, copy the file
1935 # over to the expected place.
1937 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1938 'tpl/u-boot-tpl.dtb.out']:
1939 dtb = fdt.Fdt.FromData(data[start:])
1940 size = dtb._fdt_obj.totalsize()
1941 pathname = tools.get_output_filename(os.path.split(fname)[1])
1942 outdata = tools.read_file(pathname)
1943 name = os.path.split(fname)[0]
1946 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1948 orig_indata = dtb_data
1949 self.assertNotEqual(outdata, orig_indata,
1950 "Expected output file '%s' be updated" % pathname)
1951 self.assertEqual(outdata, data[start:start + size],
1952 "Expected output file '%s' to match output image" %
1958 def _decompress(self, data):
1959 return comp_util.decompress(data, 'lz4')
1961 def testCompress(self):
1962 """Test compression of blobs"""
1964 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1965 use_real_dtb=True, update_dtb=True)
1966 dtb = fdt.Fdt(out_dtb_fname)
1968 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1969 orig = self._decompress(data)
1970 self.assertEquals(COMPRESS_DATA, orig)
1972 # Do a sanity check on various fields
1973 image = control.images['image']
1974 entries = image.GetEntries()
1975 self.assertEqual(1, len(entries))
1977 entry = entries['blob']
1978 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1979 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1980 orig = self._decompress(entry.data)
1981 self.assertEqual(orig, entry.uncomp_data)
1983 self.assertEqual(image.data, entry.data)
1986 'blob:uncomp-size': len(COMPRESS_DATA),
1987 'blob:size': len(data),
1990 self.assertEqual(expected, props)
1992 def testFiles(self):
1993 """Test bringing in multiple files"""
1994 data = self._DoReadFile('084_files.dts')
1995 self.assertEqual(FILES_DATA, data)
1997 def testFilesCompress(self):
1998 """Test bringing in multiple files and compressing them"""
2000 data = self._DoReadFile('085_files_compress.dts')
2002 image = control.images['image']
2003 entries = image.GetEntries()
2004 files = entries['files']
2005 entries = files._entries
2008 for i in range(1, 3):
2010 start = entries[key].image_pos
2011 len = entries[key].size
2012 chunk = data[start:start + len]
2013 orig += self._decompress(chunk)
2015 self.assertEqual(FILES_DATA, orig)
2017 def testFilesMissing(self):
2018 """Test missing files"""
2019 with self.assertRaises(ValueError) as e:
2020 data = self._DoReadFile('086_files_none.dts')
2021 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2022 'no files', str(e.exception))
2024 def testFilesNoPattern(self):
2025 """Test missing files"""
2026 with self.assertRaises(ValueError) as e:
2027 data = self._DoReadFile('087_files_no_pattern.dts')
2028 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2031 def testExtendSize(self):
2032 """Test an extending entry"""
2033 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
2035 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2036 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2037 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2038 tools.get_bytes(ord('d'), 8))
2039 self.assertEqual(expect, data)
2040 self.assertEqual('''ImagePos Offset Size Name
2041 00000000 00000000 00000028 main-section
2042 00000000 00000000 00000008 fill
2043 00000008 00000008 00000004 u-boot
2044 0000000c 0000000c 00000004 section
2045 0000000c 00000000 00000003 intel-mrc
2046 00000010 00000010 00000004 u-boot2
2047 00000014 00000014 0000000c section2
2048 00000014 00000000 00000008 fill
2049 0000001c 00000008 00000004 u-boot
2050 00000020 00000020 00000008 fill2
2053 def testExtendSizeBad(self):
2054 """Test an extending entry which fails to provide contents"""
2055 with test_util.capture_sys_output() as (stdout, stderr):
2056 with self.assertRaises(ValueError) as e:
2057 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
2058 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2059 'expanding entry', str(e.exception))
2062 """Test hashing of the contents of an entry"""
2063 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2064 use_real_dtb=True, update_dtb=True)
2065 dtb = fdt.Fdt(out_dtb_fname)
2067 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2068 m = hashlib.sha256()
2069 m.update(U_BOOT_DATA)
2070 self.assertEqual(m.digest(), b''.join(hash_node.value))
2072 def testHashNoAlgo(self):
2073 with self.assertRaises(ValueError) as e:
2074 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2075 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2076 'hash node', str(e.exception))
2078 def testHashBadAlgo(self):
2079 with self.assertRaises(ValueError) as e:
2080 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2081 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
2084 def testHashSection(self):
2085 """Test hashing of the contents of an entry"""
2086 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2087 use_real_dtb=True, update_dtb=True)
2088 dtb = fdt.Fdt(out_dtb_fname)
2090 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2091 m = hashlib.sha256()
2092 m.update(U_BOOT_DATA)
2093 m.update(tools.get_bytes(ord('a'), 16))
2094 self.assertEqual(m.digest(), b''.join(hash_node.value))
2096 def testPackUBootTplMicrocode(self):
2097 """Test that x86 microcode can be handled correctly in TPL
2099 We expect to see the following in the image, in order:
2100 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2102 u-boot-tpl.dtb with the microcode removed
2105 self._SetupTplElf('u_boot_ucode_ptr')
2106 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2107 U_BOOT_TPL_NODTB_DATA)
2108 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2109 b'ter somewhere in here', first)
2111 def testFmapX86(self):
2112 """Basic test of generation of a flashrom fmap"""
2113 data = self._DoReadFile('094_fmap_x86.dts')
2114 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2115 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
2116 self.assertEqual(expected, data[:32])
2117 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2119 self.assertEqual(0x100, fhdr.image_size)
2121 self.assertEqual(0, fentries[0].offset)
2122 self.assertEqual(4, fentries[0].size)
2123 self.assertEqual(b'U_BOOT', fentries[0].name)
2125 self.assertEqual(4, fentries[1].offset)
2126 self.assertEqual(3, fentries[1].size)
2127 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2129 self.assertEqual(32, fentries[2].offset)
2130 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2131 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2132 self.assertEqual(b'FMAP', fentries[2].name)
2134 def testFmapX86Section(self):
2135 """Basic test of generation of a flashrom fmap"""
2136 data = self._DoReadFile('095_fmap_x86_section.dts')
2137 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
2138 self.assertEqual(expected, data[:32])
2139 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2141 self.assertEqual(0x180, fhdr.image_size)
2142 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2143 fiter = iter(fentries)
2145 fentry = next(fiter)
2146 self.assertEqual(b'U_BOOT', fentry.name)
2147 self.assertEqual(0, fentry.offset)
2148 self.assertEqual(4, fentry.size)
2150 fentry = next(fiter)
2151 self.assertEqual(b'SECTION', fentry.name)
2152 self.assertEqual(4, fentry.offset)
2153 self.assertEqual(0x20 + expect_size, fentry.size)
2155 fentry = next(fiter)
2156 self.assertEqual(b'INTEL_MRC', fentry.name)
2157 self.assertEqual(4, fentry.offset)
2158 self.assertEqual(3, fentry.size)
2160 fentry = next(fiter)
2161 self.assertEqual(b'FMAP', fentry.name)
2162 self.assertEqual(36, fentry.offset)
2163 self.assertEqual(expect_size, fentry.size)
2166 """Basic test of ELF entries"""
2169 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2170 TestFunctional._MakeInputFile('-boot', fd.read())
2171 data = self._DoReadFile('096_elf.dts')
2173 def testElfStrip(self):
2174 """Basic test of ELF entries"""
2176 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2177 TestFunctional._MakeInputFile('-boot', fd.read())
2178 data = self._DoReadFile('097_elf_strip.dts')
2180 def testPackOverlapMap(self):
2181 """Test that overlapping regions are detected"""
2182 with test_util.capture_sys_output() as (stdout, stderr):
2183 with self.assertRaises(ValueError) as e:
2184 self._DoTestFile('014_pack_overlap.dts', map=True)
2185 map_fname = tools.get_output_filename('image.map')
2186 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2189 # We should not get an inmage, but there should be a map file
2190 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
2191 self.assertTrue(os.path.exists(map_fname))
2192 map_data = tools.read_file(map_fname, binary=False)
2193 self.assertEqual('''ImagePos Offset Size Name
2194 <none> 00000000 00000008 main-section
2195 <none> 00000000 00000004 u-boot
2196 <none> 00000003 00000004 u-boot-align
2199 def testPackRefCode(self):
2200 """Test that an image with an Intel Reference code binary works"""
2201 data = self._DoReadFile('100_intel_refcode.dts')
2202 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2204 def testSectionOffset(self):
2205 """Tests use of a section with an offset"""
2206 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2208 self.assertEqual('''ImagePos Offset Size Name
2209 00000000 00000000 00000038 main-section
2210 00000004 00000004 00000010 section@0
2211 00000004 00000000 00000004 u-boot
2212 00000018 00000018 00000010 section@1
2213 00000018 00000000 00000004 u-boot
2214 0000002c 0000002c 00000004 section@2
2215 0000002c 00000000 00000004 u-boot
2217 self.assertEqual(data,
2218 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2219 tools.get_bytes(0x21, 12) +
2220 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2221 tools.get_bytes(0x61, 12) +
2222 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2223 tools.get_bytes(0x26, 8))
2225 def testCbfsRaw(self):
2226 """Test base handling of a Coreboot Filesystem (CBFS)
2228 The exact contents of the CBFS is verified by similar tests in
2229 cbfs_util_test.py. The tests here merely check that the files added to
2230 the CBFS can be found in the final image.
2232 data = self._DoReadFile('102_cbfs_raw.dts')
2235 cbfs = cbfs_util.CbfsReader(data)
2236 self.assertEqual(size, cbfs.rom_size)
2238 self.assertIn('u-boot-dtb', cbfs.files)
2239 cfile = cbfs.files['u-boot-dtb']
2240 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2242 def testCbfsArch(self):
2243 """Test on non-x86 architecture"""
2244 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2247 cbfs = cbfs_util.CbfsReader(data)
2248 self.assertEqual(size, cbfs.rom_size)
2250 self.assertIn('u-boot-dtb', cbfs.files)
2251 cfile = cbfs.files['u-boot-dtb']
2252 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2254 def testCbfsStage(self):
2255 """Tests handling of a Coreboot Filesystem (CBFS)"""
2256 if not elf.ELF_TOOLS:
2257 self.skipTest('Python elftools not available')
2258 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2259 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2262 data = self._DoReadFile('104_cbfs_stage.dts')
2263 cbfs = cbfs_util.CbfsReader(data)
2264 self.assertEqual(size, cbfs.rom_size)
2266 self.assertIn('u-boot', cbfs.files)
2267 cfile = cbfs.files['u-boot']
2268 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2270 def testCbfsRawCompress(self):
2271 """Test handling of compressing raw files"""
2273 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2276 cbfs = cbfs_util.CbfsReader(data)
2277 self.assertIn('u-boot', cbfs.files)
2278 cfile = cbfs.files['u-boot']
2279 self.assertEqual(COMPRESS_DATA, cfile.data)
2281 def testCbfsBadArch(self):
2282 """Test handling of a bad architecture"""
2283 with self.assertRaises(ValueError) as e:
2284 self._DoReadFile('106_cbfs_bad_arch.dts')
2285 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2287 def testCbfsNoSize(self):
2288 """Test handling of a missing size property"""
2289 with self.assertRaises(ValueError) as e:
2290 self._DoReadFile('107_cbfs_no_size.dts')
2291 self.assertIn('entry must have a size property', str(e.exception))
2293 def testCbfsNoContents(self):
2294 """Test handling of a CBFS entry which does not provide contentsy"""
2295 with self.assertRaises(ValueError) as e:
2296 self._DoReadFile('108_cbfs_no_contents.dts')
2297 self.assertIn('Could not complete processing of contents',
2300 def testCbfsBadCompress(self):
2301 """Test handling of a bad architecture"""
2302 with self.assertRaises(ValueError) as e:
2303 self._DoReadFile('109_cbfs_bad_compress.dts')
2304 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2307 def testCbfsNamedEntries(self):
2308 """Test handling of named entries"""
2309 data = self._DoReadFile('110_cbfs_name.dts')
2311 cbfs = cbfs_util.CbfsReader(data)
2312 self.assertIn('FRED', cbfs.files)
2313 cfile1 = cbfs.files['FRED']
2314 self.assertEqual(U_BOOT_DATA, cfile1.data)
2316 self.assertIn('hello', cbfs.files)
2317 cfile2 = cbfs.files['hello']
2318 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2320 def _SetupIfwi(self, fname):
2321 """Set up to run an IFWI test
2324 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2329 # Intel Integrated Firmware Image (IFWI) file
2330 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2332 TestFunctional._MakeInputFile(fname,data)
2334 def _CheckIfwi(self, data):
2335 """Check that an image with an IFWI contains the correct output
2338 data: Conents of output file
2340 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
2341 if data[:0x1000] != expected_desc:
2342 self.fail('Expected descriptor binary at start of image')
2344 # We expect to find the TPL wil in subpart IBBP entry IBBL
2345 image_fname = tools.get_output_filename('image.bin')
2346 tpl_fname = tools.get_output_filename('tpl.out')
2347 ifwitool = bintool.Bintool.create('ifwitool')
2348 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
2350 tpl_data = tools.read_file(tpl_fname)
2351 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2353 def testPackX86RomIfwi(self):
2354 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2355 self._SetupIfwi('fitimage.bin')
2356 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2357 self._CheckIfwi(data)
2359 def testPackX86RomIfwiNoDesc(self):
2360 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2361 self._SetupIfwi('ifwi.bin')
2362 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2363 self._CheckIfwi(data)
2365 def testPackX86RomIfwiNoData(self):
2366 """Test that an x86 ROM with IFWI handles missing data"""
2367 self._SetupIfwi('ifwi.bin')
2368 with self.assertRaises(ValueError) as e:
2369 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2370 self.assertIn('Could not complete processing of contents',
2373 def testIfwiMissing(self):
2374 """Test that binman still produces an image if ifwitool is missing"""
2375 self._SetupIfwi('fitimage.bin')
2376 with test_util.capture_sys_output() as (_, stderr):
2377 self._DoTestFile('111_x86_rom_ifwi.dts',
2378 force_missing_bintools='ifwitool')
2379 err = stderr.getvalue()
2380 self.assertRegex(err,
2381 "Image 'main-section'.*missing bintools.*: ifwitool")
2383 def testCbfsOffset(self):
2384 """Test a CBFS with files at particular offsets
2386 Like all CFBS tests, this is just checking the logic that calls
2387 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2389 data = self._DoReadFile('114_cbfs_offset.dts')
2392 cbfs = cbfs_util.CbfsReader(data)
2393 self.assertEqual(size, cbfs.rom_size)
2395 self.assertIn('u-boot', cbfs.files)
2396 cfile = cbfs.files['u-boot']
2397 self.assertEqual(U_BOOT_DATA, cfile.data)
2398 self.assertEqual(0x40, cfile.cbfs_offset)
2400 self.assertIn('u-boot-dtb', cbfs.files)
2401 cfile2 = cbfs.files['u-boot-dtb']
2402 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2403 self.assertEqual(0x140, cfile2.cbfs_offset)
2405 def testFdtmap(self):
2406 """Test an FDT map can be inserted in the image"""
2407 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2408 fdtmap_data = data[len(U_BOOT_DATA):]
2409 magic = fdtmap_data[:8]
2410 self.assertEqual(b'_FDTMAP_', magic)
2411 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
2413 fdt_data = fdtmap_data[16:]
2414 dtb = fdt.Fdt.FromData(fdt_data)
2416 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2421 'u-boot:size': len(U_BOOT_DATA),
2422 'u-boot:image-pos': 0,
2423 'fdtmap:image-pos': 4,
2425 'fdtmap:size': len(fdtmap_data),
2429 def testFdtmapNoMatch(self):
2430 """Check handling of an FDT map when the section cannot be found"""
2431 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2433 # Mangle the section name, which should cause a mismatch between the
2434 # correct FDT path and the one expected by the section
2435 image = control.images['image']
2436 image._node.path += '-suffix'
2437 entries = image.GetEntries()
2438 fdtmap = entries['fdtmap']
2439 with self.assertRaises(ValueError) as e:
2441 self.assertIn("Cannot locate node for path '/binman-suffix'",
2444 def testFdtmapHeader(self):
2445 """Test an FDT map and image header can be inserted in the image"""
2446 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2447 fdtmap_pos = len(U_BOOT_DATA)
2448 fdtmap_data = data[fdtmap_pos:]
2449 fdt_data = fdtmap_data[16:]
2450 dtb = fdt.Fdt.FromData(fdt_data)
2451 fdt_size = dtb.GetFdtObj().totalsize()
2452 hdr_data = data[-8:]
2453 self.assertEqual(b'BinM', hdr_data[:4])
2454 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2455 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2457 def testFdtmapHeaderStart(self):
2458 """Test an image header can be inserted at the image start"""
2459 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2460 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2462 self.assertEqual(b'BinM', hdr_data[:4])
2463 offset = struct.unpack('<I', hdr_data[4:])[0]
2464 self.assertEqual(fdtmap_pos, offset)
2466 def testFdtmapHeaderPos(self):
2467 """Test an image header can be inserted at a chosen position"""
2468 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2469 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2470 hdr_data = data[0x80:0x88]
2471 self.assertEqual(b'BinM', hdr_data[:4])
2472 offset = struct.unpack('<I', hdr_data[4:])[0]
2473 self.assertEqual(fdtmap_pos, offset)
2475 def testHeaderMissingFdtmap(self):
2476 """Test an image header requires an fdtmap"""
2477 with self.assertRaises(ValueError) as e:
2478 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2479 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2482 def testHeaderNoLocation(self):
2483 """Test an image header with a no specified location is detected"""
2484 with self.assertRaises(ValueError) as e:
2485 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2486 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2489 def testEntryExpand(self):
2490 """Test extending an entry after it is packed"""
2491 data = self._DoReadFile('121_entry_extend.dts')
2492 self.assertEqual(b'aaa', data[:3])
2493 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2494 self.assertEqual(b'aaa', data[-3:])
2496 def testEntryExtendBad(self):
2497 """Test extending an entry after it is packed, twice"""
2498 with self.assertRaises(ValueError) as e:
2499 self._DoReadFile('122_entry_extend_twice.dts')
2500 self.assertIn("Image '/binman': Entries changed size after packing",
2503 def testEntryExtendSection(self):
2504 """Test extending an entry within a section after it is packed"""
2505 data = self._DoReadFile('123_entry_extend_section.dts')
2506 self.assertEqual(b'aaa', data[:3])
2507 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2508 self.assertEqual(b'aaa', data[-3:])
2510 def testCompressDtb(self):
2511 """Test that compress of device-tree files is supported"""
2513 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2514 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2515 comp_data = data[len(U_BOOT_DATA):]
2516 orig = self._decompress(comp_data)
2517 dtb = fdt.Fdt.FromData(orig)
2519 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2521 'u-boot:size': len(U_BOOT_DATA),
2522 'u-boot-dtb:uncomp-size': len(orig),
2523 'u-boot-dtb:size': len(comp_data),
2526 self.assertEqual(expected, props)
2528 def testCbfsUpdateFdt(self):
2529 """Test that we can update the device tree with CBFS offset/size info"""
2531 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2533 dtb = fdt.Fdt(out_dtb_fname)
2535 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2536 del props['cbfs/u-boot:size']
2542 'cbfs:size': len(data),
2543 'cbfs:image-pos': 0,
2544 'cbfs/u-boot:offset': 0x38,
2545 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2546 'cbfs/u-boot:image-pos': 0x38,
2547 'cbfs/u-boot-dtb:offset': 0xb8,
2548 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2549 'cbfs/u-boot-dtb:image-pos': 0xb8,
2552 def testCbfsBadType(self):
2553 """Test an image header with a no specified location is detected"""
2554 with self.assertRaises(ValueError) as e:
2555 self._DoReadFile('126_cbfs_bad_type.dts')
2556 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2559 """Test listing the files in an image"""
2561 data = self._DoReadFile('127_list.dts')
2562 image = control.images['image']
2563 entries = image.BuildEntryList()
2564 self.assertEqual(7, len(entries))
2567 self.assertEqual(0, ent.indent)
2568 self.assertEqual('main-section', ent.name)
2569 self.assertEqual('section', ent.etype)
2570 self.assertEqual(len(data), ent.size)
2571 self.assertEqual(0, ent.image_pos)
2572 self.assertEqual(None, ent.uncomp_size)
2573 self.assertEqual(0, ent.offset)
2576 self.assertEqual(1, ent.indent)
2577 self.assertEqual('u-boot', ent.name)
2578 self.assertEqual('u-boot', ent.etype)
2579 self.assertEqual(len(U_BOOT_DATA), ent.size)
2580 self.assertEqual(0, ent.image_pos)
2581 self.assertEqual(None, ent.uncomp_size)
2582 self.assertEqual(0, ent.offset)
2585 self.assertEqual(1, ent.indent)
2586 self.assertEqual('section', ent.name)
2587 self.assertEqual('section', ent.etype)
2588 section_size = ent.size
2589 self.assertEqual(0x100, ent.image_pos)
2590 self.assertEqual(None, ent.uncomp_size)
2591 self.assertEqual(0x100, ent.offset)
2594 self.assertEqual(2, ent.indent)
2595 self.assertEqual('cbfs', ent.name)
2596 self.assertEqual('cbfs', ent.etype)
2597 self.assertEqual(0x400, ent.size)
2598 self.assertEqual(0x100, ent.image_pos)
2599 self.assertEqual(None, ent.uncomp_size)
2600 self.assertEqual(0, ent.offset)
2603 self.assertEqual(3, ent.indent)
2604 self.assertEqual('u-boot', ent.name)
2605 self.assertEqual('u-boot', ent.etype)
2606 self.assertEqual(len(U_BOOT_DATA), ent.size)
2607 self.assertEqual(0x138, ent.image_pos)
2608 self.assertEqual(None, ent.uncomp_size)
2609 self.assertEqual(0x38, ent.offset)
2612 self.assertEqual(3, ent.indent)
2613 self.assertEqual('u-boot-dtb', ent.name)
2614 self.assertEqual('text', ent.etype)
2615 self.assertGreater(len(COMPRESS_DATA), ent.size)
2616 self.assertEqual(0x178, ent.image_pos)
2617 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2618 self.assertEqual(0x78, ent.offset)
2621 self.assertEqual(2, ent.indent)
2622 self.assertEqual('u-boot-dtb', ent.name)
2623 self.assertEqual('u-boot-dtb', ent.etype)
2624 self.assertEqual(0x500, ent.image_pos)
2625 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2627 # Compressing this data expands it since headers are added
2628 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2629 self.assertEqual(0x400, ent.offset)
2631 self.assertEqual(len(data), 0x100 + section_size)
2632 self.assertEqual(section_size, 0x400 + dtb_size)
2634 def testFindFdtmap(self):
2635 """Test locating an FDT map in an image"""
2637 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2638 image = control.images['image']
2639 entries = image.GetEntries()
2640 entry = entries['fdtmap']
2641 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2643 def testFindFdtmapMissing(self):
2644 """Test failing to locate an FDP map"""
2645 data = self._DoReadFile('005_simple.dts')
2646 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2648 def testFindImageHeader(self):
2649 """Test locating a image header"""
2651 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2652 image = control.images['image']
2653 entries = image.GetEntries()
2654 entry = entries['fdtmap']
2655 # The header should point to the FDT map
2656 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2658 def testFindImageHeaderStart(self):
2659 """Test locating a image header located at the start of an image"""
2660 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2661 image = control.images['image']
2662 entries = image.GetEntries()
2663 entry = entries['fdtmap']
2664 # The header should point to the FDT map
2665 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2667 def testFindImageHeaderMissing(self):
2668 """Test failing to locate an image header"""
2669 data = self._DoReadFile('005_simple.dts')
2670 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2672 def testReadImage(self):
2673 """Test reading an image and accessing its FDT map"""
2675 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2676 image_fname = tools.get_output_filename('image.bin')
2677 orig_image = control.images['image']
2678 image = Image.FromFile(image_fname)
2679 self.assertEqual(orig_image.GetEntries().keys(),
2680 image.GetEntries().keys())
2682 orig_entry = orig_image.GetEntries()['fdtmap']
2683 entry = image.GetEntries()['fdtmap']
2684 self.assertEquals(orig_entry.offset, entry.offset)
2685 self.assertEquals(orig_entry.size, entry.size)
2686 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2688 def testReadImageNoHeader(self):
2689 """Test accessing an image's FDT map without an image header"""
2691 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2692 image_fname = tools.get_output_filename('image.bin')
2693 image = Image.FromFile(image_fname)
2694 self.assertTrue(isinstance(image, Image))
2695 self.assertEqual('image', image.image_name[-5:])
2697 def testReadImageFail(self):
2698 """Test failing to read an image image's FDT map"""
2699 self._DoReadFile('005_simple.dts')
2700 image_fname = tools.get_output_filename('image.bin')
2701 with self.assertRaises(ValueError) as e:
2702 image = Image.FromFile(image_fname)
2703 self.assertIn("Cannot find FDT map in image", str(e.exception))
2705 def testListCmd(self):
2706 """Test listing the files in an image using an Fdtmap"""
2708 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2710 # lz4 compression size differs depending on the version
2711 image = control.images['image']
2712 entries = image.GetEntries()
2713 section_size = entries['section'].size
2714 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2715 fdtmap_offset = entries['fdtmap'].offset
2718 tmpdir, updated_fname = self._SetupImageInTmpdir()
2719 with test_util.capture_sys_output() as (stdout, stderr):
2720 self._DoBinman('ls', '-i', updated_fname)
2722 shutil.rmtree(tmpdir)
2723 lines = stdout.getvalue().splitlines()
2725 'Name Image-pos Size Entry-type Offset Uncomp-size',
2726 '----------------------------------------------------------------------',
2727 'main-section 0 c00 section 0',
2728 ' u-boot 0 4 u-boot 0',
2729 ' section 100 %x section 100' % section_size,
2730 ' cbfs 100 400 cbfs 0',
2731 ' u-boot 138 4 u-boot 38',
2732 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2733 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2734 ' fdtmap %x 3bd fdtmap %x' %
2735 (fdtmap_offset, fdtmap_offset),
2736 ' image-header bf8 8 image-header bf8',
2738 self.assertEqual(expected, lines)
2740 def testListCmdFail(self):
2741 """Test failing to list an image"""
2742 self._DoReadFile('005_simple.dts')
2744 tmpdir, updated_fname = self._SetupImageInTmpdir()
2745 with self.assertRaises(ValueError) as e:
2746 self._DoBinman('ls', '-i', updated_fname)
2748 shutil.rmtree(tmpdir)
2749 self.assertIn("Cannot find FDT map in image", str(e.exception))
2751 def _RunListCmd(self, paths, expected):
2752 """List out entries and check the result
2755 paths: List of paths to pass to the list command
2756 expected: Expected list of filenames to be returned, in order
2759 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2760 image_fname = tools.get_output_filename('image.bin')
2761 image = Image.FromFile(image_fname)
2762 lines = image.GetListEntries(paths)[1]
2763 files = [line[0].strip() for line in lines[1:]]
2764 self.assertEqual(expected, files)
2766 def testListCmdSection(self):
2767 """Test listing the files in a section"""
2768 self._RunListCmd(['section'],
2769 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2771 def testListCmdFile(self):
2772 """Test listing a particular file"""
2773 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2775 def testListCmdWildcard(self):
2776 """Test listing a wildcarded file"""
2777 self._RunListCmd(['*boot*'],
2778 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2780 def testListCmdWildcardMulti(self):
2781 """Test listing a wildcarded file"""
2782 self._RunListCmd(['*cb*', '*head*'],
2783 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2785 def testListCmdEmpty(self):
2786 """Test listing a wildcarded file"""
2787 self._RunListCmd(['nothing'], [])
2789 def testListCmdPath(self):
2790 """Test listing the files in a sub-entry of a section"""
2791 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2793 def _RunExtractCmd(self, entry_name, decomp=True):
2794 """Extract an entry from an image
2797 entry_name: Entry name to extract
2798 decomp: True to decompress the data if compressed, False to leave
2799 it in its raw uncompressed format
2805 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2806 image_fname = tools.get_output_filename('image.bin')
2807 return control.ReadEntry(image_fname, entry_name, decomp)
2809 def testExtractSimple(self):
2810 """Test extracting a single file"""
2811 data = self._RunExtractCmd('u-boot')
2812 self.assertEqual(U_BOOT_DATA, data)
2814 def testExtractSection(self):
2815 """Test extracting the files in a section"""
2816 data = self._RunExtractCmd('section')
2817 cbfs_data = data[:0x400]
2818 cbfs = cbfs_util.CbfsReader(cbfs_data)
2819 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2820 dtb_data = data[0x400:]
2821 dtb = self._decompress(dtb_data)
2822 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2824 def testExtractCompressed(self):
2825 """Test extracting compressed data"""
2826 data = self._RunExtractCmd('section/u-boot-dtb')
2827 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2829 def testExtractRaw(self):
2830 """Test extracting compressed data without decompressing it"""
2831 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2832 dtb = self._decompress(data)
2833 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2835 def testExtractCbfs(self):
2836 """Test extracting CBFS data"""
2837 data = self._RunExtractCmd('section/cbfs/u-boot')
2838 self.assertEqual(U_BOOT_DATA, data)
2840 def testExtractCbfsCompressed(self):
2841 """Test extracting CBFS compressed data"""
2842 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2843 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2845 def testExtractCbfsRaw(self):
2846 """Test extracting CBFS compressed data without decompressing it"""
2847 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2848 dtb = comp_util.decompress(data, 'lzma', with_header=False)
2849 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2851 def testExtractBadEntry(self):
2852 """Test extracting a bad section path"""
2853 with self.assertRaises(ValueError) as e:
2854 self._RunExtractCmd('section/does-not-exist')
2855 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2858 def testExtractMissingFile(self):
2859 """Test extracting file that does not exist"""
2860 with self.assertRaises(IOError) as e:
2861 control.ReadEntry('missing-file', 'name')
2863 def testExtractBadFile(self):
2864 """Test extracting an invalid file"""
2865 fname = os.path.join(self._indir, 'badfile')
2866 tools.write_file(fname, b'')
2867 with self.assertRaises(ValueError) as e:
2868 control.ReadEntry(fname, 'name')
2870 def testExtractCmd(self):
2871 """Test extracting a file fron an image on the command line"""
2873 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2874 fname = os.path.join(self._indir, 'output.extact')
2876 tmpdir, updated_fname = self._SetupImageInTmpdir()
2877 with test_util.capture_sys_output() as (stdout, stderr):
2878 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2881 shutil.rmtree(tmpdir)
2882 data = tools.read_file(fname)
2883 self.assertEqual(U_BOOT_DATA, data)
2885 def testExtractOneEntry(self):
2886 """Test extracting a single entry fron an image """
2888 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2889 image_fname = tools.get_output_filename('image.bin')
2890 fname = os.path.join(self._indir, 'output.extact')
2891 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2892 data = tools.read_file(fname)
2893 self.assertEqual(U_BOOT_DATA, data)
2895 def _CheckExtractOutput(self, decomp):
2896 """Helper to test file output with and without decompression
2899 decomp: True to decompress entry data, False to output it raw
2901 def _CheckPresent(entry_path, expect_data, expect_size=None):
2902 """Check and remove expected file
2904 This checks the data/size of a file and removes the file both from
2905 the outfiles set and from the output directory. Once all files are
2906 processed, both the set and directory should be empty.
2909 entry_path: Entry path
2910 expect_data: Data to expect in file, or None to skip check
2911 expect_size: Size of data to expect in file, or None to skip
2913 path = os.path.join(outdir, entry_path)
2914 data = tools.read_file(path)
2917 self.assertEqual(expect_data, data)
2919 self.assertEqual(expect_size, len(data))
2920 outfiles.remove(path)
2922 def _CheckDirPresent(name):
2923 """Remove expected directory
2925 This gives an error if the directory does not exist as expected
2928 name: Name of directory to remove
2930 path = os.path.join(outdir, name)
2933 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2934 image_fname = tools.get_output_filename('image.bin')
2935 outdir = os.path.join(self._indir, 'extract')
2936 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2938 # Create a set of all file that were output (should be 9)
2940 for root, dirs, files in os.walk(outdir):
2941 outfiles |= set([os.path.join(root, fname) for fname in files])
2942 self.assertEqual(9, len(outfiles))
2943 self.assertEqual(9, len(einfos))
2945 image = control.images['image']
2946 entries = image.GetEntries()
2948 # Check the 9 files in various ways
2949 section = entries['section']
2950 section_entries = section.GetEntries()
2951 cbfs_entries = section_entries['cbfs'].GetEntries()
2952 _CheckPresent('u-boot', U_BOOT_DATA)
2953 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2954 dtb_len = EXTRACT_DTB_SIZE
2956 dtb_len = cbfs_entries['u-boot-dtb'].size
2957 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2959 dtb_len = section_entries['u-boot-dtb'].size
2960 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2962 fdtmap = entries['fdtmap']
2963 _CheckPresent('fdtmap', fdtmap.data)
2964 hdr = entries['image-header']
2965 _CheckPresent('image-header', hdr.data)
2967 _CheckPresent('section/root', section.data)
2968 cbfs = section_entries['cbfs']
2969 _CheckPresent('section/cbfs/root', cbfs.data)
2970 data = tools.read_file(image_fname)
2971 _CheckPresent('root', data)
2973 # There should be no files left. Remove all the directories to check.
2974 # If there are any files/dirs remaining, one of these checks will fail.
2975 self.assertEqual(0, len(outfiles))
2976 _CheckDirPresent('section/cbfs')
2977 _CheckDirPresent('section')
2978 _CheckDirPresent('')
2979 self.assertFalse(os.path.exists(outdir))
2981 def testExtractAllEntries(self):
2982 """Test extracting all entries"""
2984 self._CheckExtractOutput(decomp=True)
2986 def testExtractAllEntriesRaw(self):
2987 """Test extracting all entries without decompressing them"""
2989 self._CheckExtractOutput(decomp=False)
2991 def testExtractSelectedEntries(self):
2992 """Test extracting some entries"""
2994 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2995 image_fname = tools.get_output_filename('image.bin')
2996 outdir = os.path.join(self._indir, 'extract')
2997 einfos = control.ExtractEntries(image_fname, None, outdir,
3000 # File output is tested by testExtractAllEntries(), so just check that
3001 # the expected entries are selected
3002 names = [einfo.name for einfo in einfos]
3003 self.assertEqual(names,
3004 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3006 def testExtractNoEntryPaths(self):
3007 """Test extracting some entries"""
3009 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3010 image_fname = tools.get_output_filename('image.bin')
3011 with self.assertRaises(ValueError) as e:
3012 control.ExtractEntries(image_fname, 'fname', None, [])
3013 self.assertIn('Must specify an entry path to write with -f',
3016 def testExtractTooManyEntryPaths(self):
3017 """Test extracting some entries"""
3019 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3020 image_fname = tools.get_output_filename('image.bin')
3021 with self.assertRaises(ValueError) as e:
3022 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
3023 self.assertIn('Must specify exactly one entry path to write with -f',
3026 def testPackAlignSection(self):
3027 """Test that sections can have alignment"""
3028 self._DoReadFile('131_pack_align_section.dts')
3030 self.assertIn('image', control.images)
3031 image = control.images['image']
3032 entries = image.GetEntries()
3033 self.assertEqual(3, len(entries))
3036 self.assertIn('u-boot', entries)
3037 entry = entries['u-boot']
3038 self.assertEqual(0, entry.offset)
3039 self.assertEqual(0, entry.image_pos)
3040 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3041 self.assertEqual(len(U_BOOT_DATA), entry.size)
3044 self.assertIn('section0', entries)
3045 section0 = entries['section0']
3046 self.assertEqual(0x10, section0.offset)
3047 self.assertEqual(0x10, section0.image_pos)
3048 self.assertEqual(len(U_BOOT_DATA), section0.size)
3051 section_entries = section0.GetEntries()
3052 self.assertIn('u-boot', section_entries)
3053 entry = section_entries['u-boot']
3054 self.assertEqual(0, entry.offset)
3055 self.assertEqual(0x10, entry.image_pos)
3056 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3057 self.assertEqual(len(U_BOOT_DATA), entry.size)
3060 self.assertIn('section1', entries)
3061 section1 = entries['section1']
3062 self.assertEqual(0x14, section1.offset)
3063 self.assertEqual(0x14, section1.image_pos)
3064 self.assertEqual(0x20, section1.size)
3067 section_entries = section1.GetEntries()
3068 self.assertIn('u-boot', section_entries)
3069 entry = section_entries['u-boot']
3070 self.assertEqual(0, entry.offset)
3071 self.assertEqual(0x14, entry.image_pos)
3072 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3073 self.assertEqual(len(U_BOOT_DATA), entry.size)
3076 self.assertIn('section2', section_entries)
3077 section2 = section_entries['section2']
3078 self.assertEqual(0x4, section2.offset)
3079 self.assertEqual(0x18, section2.image_pos)
3080 self.assertEqual(4, section2.size)
3083 section_entries = section2.GetEntries()
3084 self.assertIn('u-boot', section_entries)
3085 entry = section_entries['u-boot']
3086 self.assertEqual(0, entry.offset)
3087 self.assertEqual(0x18, entry.image_pos)
3088 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3089 self.assertEqual(len(U_BOOT_DATA), entry.size)
3091 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3092 dts='132_replace.dts'):
3093 """Replace an entry in an image
3095 This writes the entry data to update it, then opens the updated file and
3096 returns the value that it now finds there.
3099 entry_name: Entry name to replace
3100 data: Data to replace it with
3101 decomp: True to compress the data if needed, False if data is
3102 already compressed so should be used as is
3103 allow_resize: True to allow entries to change size, False to raise
3109 data from fdtmap (excluding header)
3110 Image object that was modified
3112 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3115 self.assertIn('image', control.images)
3116 image = control.images['image']
3117 entries = image.GetEntries()
3118 orig_dtb_data = entries['u-boot-dtb'].data
3119 orig_fdtmap_data = entries['fdtmap'].data
3121 image_fname = tools.get_output_filename('image.bin')
3122 updated_fname = tools.get_output_filename('image-updated.bin')
3123 tools.write_file(updated_fname, tools.read_file(image_fname))
3124 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3126 data = control.ReadEntry(updated_fname, entry_name, decomp)
3128 # The DT data should not change unless resized:
3129 if not allow_resize:
3130 new_dtb_data = entries['u-boot-dtb'].data
3131 self.assertEqual(new_dtb_data, orig_dtb_data)
3132 new_fdtmap_data = entries['fdtmap'].data
3133 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3135 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3137 def testReplaceSimple(self):
3138 """Test replacing a single file"""
3139 expected = b'x' * len(U_BOOT_DATA)
3140 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3142 self.assertEqual(expected, data)
3144 # Test that the state looks right. There should be an FDT for the fdtmap
3145 # that we jsut read back in, and it should match what we find in the
3146 # 'control' tables. Checking for an FDT that does not exist should
3148 path, fdtmap = state.GetFdtContents('fdtmap')
3149 self.assertIsNotNone(path)
3150 self.assertEqual(expected_fdtmap, fdtmap)
3152 dtb = state.GetFdtForEtype('fdtmap')
3153 self.assertEqual(dtb.GetContents(), fdtmap)
3155 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3156 self.assertIsNone(missing_path)
3157 self.assertIsNone(missing_fdtmap)
3159 missing_dtb = state.GetFdtForEtype('missing')
3160 self.assertIsNone(missing_dtb)
3162 self.assertEqual('/binman', state.fdt_path_prefix)
3164 def testReplaceResizeFail(self):
3165 """Test replacing a file by something larger"""
3166 expected = U_BOOT_DATA + b'x'
3167 with self.assertRaises(ValueError) as e:
3168 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3169 dts='139_replace_repack.dts')
3170 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3173 def testReplaceMulti(self):
3174 """Test replacing entry data where multiple images are generated"""
3175 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3177 expected = b'x' * len(U_BOOT_DATA)
3178 updated_fname = tools.get_output_filename('image-updated.bin')
3179 tools.write_file(updated_fname, data)
3180 entry_name = 'u-boot'
3181 control.WriteEntry(updated_fname, entry_name, expected,
3183 data = control.ReadEntry(updated_fname, entry_name)
3184 self.assertEqual(expected, data)
3186 # Check the state looks right.
3187 self.assertEqual('/binman/image', state.fdt_path_prefix)
3189 # Now check we can write the first image
3190 image_fname = tools.get_output_filename('first-image.bin')
3191 updated_fname = tools.get_output_filename('first-updated.bin')
3192 tools.write_file(updated_fname, tools.read_file(image_fname))
3193 entry_name = 'u-boot'
3194 control.WriteEntry(updated_fname, entry_name, expected,
3196 data = control.ReadEntry(updated_fname, entry_name)
3197 self.assertEqual(expected, data)
3199 # Check the state looks right.
3200 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3202 def testUpdateFdtAllRepack(self):
3203 """Test that all device trees are updated with offset/size info"""
3204 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3205 SECTION_SIZE = 0x300
3210 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3212 'section:offset': 0,
3213 'section:size': SECTION_SIZE,
3214 'section:image-pos': 0,
3215 'section/u-boot-dtb:offset': 4,
3216 'section/u-boot-dtb:size': 636,
3217 'section/u-boot-dtb:image-pos': 4,
3218 'u-boot-spl-dtb:offset': SECTION_SIZE,
3219 'u-boot-spl-dtb:size': DTB_SIZE,
3220 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3221 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3222 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3223 'u-boot-tpl-dtb:size': DTB_SIZE,
3224 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3225 'fdtmap:size': FDTMAP_SIZE,
3226 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3229 'section:orig-size': SECTION_SIZE,
3230 'section/u-boot-dtb:orig-offset': 4,
3233 # We expect three device-tree files in the output, with the first one
3234 # within a fixed-size section.
3235 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3236 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3237 # main U-Boot tree. All three should have the same positions and offset
3238 # except that the main tree should include the main_expected properties
3240 for item in ['', 'spl', 'tpl', None]:
3242 start += 16 # Move past fdtmap header
3243 dtb = fdt.Fdt.FromData(data[start:])
3245 props = self._GetPropTree(dtb,
3246 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3247 prefix='/' if item is None else '/binman/')
3248 expected = dict(base_expected)
3252 # Main DTB and fdtdec should include the 'orig-' properties
3253 expected.update(main_expected)
3254 # Helpful for debugging:
3255 #for prop in sorted(props):
3256 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3257 self.assertEqual(expected, props)
3259 start = SECTION_SIZE
3261 start += dtb._fdt_obj.totalsize()
3263 def testFdtmapHeaderMiddle(self):
3264 """Test an FDT map in the middle of an image when it should be at end"""
3265 with self.assertRaises(ValueError) as e:
3266 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3267 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3270 def testFdtmapHeaderStartBad(self):
3271 """Test an FDT map in middle of an image when it should be at start"""
3272 with self.assertRaises(ValueError) as e:
3273 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3274 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3277 def testFdtmapHeaderEndBad(self):
3278 """Test an FDT map at the start of an image when it should be at end"""
3279 with self.assertRaises(ValueError) as e:
3280 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3281 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3284 def testFdtmapHeaderNoSize(self):
3285 """Test an image header at the end of an image with undefined size"""
3286 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3288 def testReplaceResize(self):
3289 """Test replacing a single file in an entry with a larger file"""
3290 expected = U_BOOT_DATA + b'x'
3291 data, _, image = self._RunReplaceCmd('u-boot', expected,
3292 dts='139_replace_repack.dts')
3293 self.assertEqual(expected, data)
3295 entries = image.GetEntries()
3296 dtb_data = entries['u-boot-dtb'].data
3297 dtb = fdt.Fdt.FromData(dtb_data)
3300 # The u-boot section should now be larger in the dtb
3301 node = dtb.GetNode('/binman/u-boot')
3302 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3304 # Same for the fdtmap
3305 fdata = entries['fdtmap'].data
3306 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3308 fnode = fdtb.GetNode('/u-boot')
3309 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3311 def testReplaceResizeNoRepack(self):
3312 """Test replacing an entry with a larger file when not allowed"""
3313 expected = U_BOOT_DATA + b'x'
3314 with self.assertRaises(ValueError) as e:
3315 self._RunReplaceCmd('u-boot', expected)
3316 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3319 def testEntryShrink(self):
3320 """Test contracting an entry after it is packed"""
3322 state.SetAllowEntryContraction(True)
3323 data = self._DoReadFileDtb('140_entry_shrink.dts',
3326 state.SetAllowEntryContraction(False)
3327 self.assertEqual(b'a', data[:1])
3328 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3329 self.assertEqual(b'a', data[-1:])
3331 def testEntryShrinkFail(self):
3332 """Test not being allowed to contract an entry after it is packed"""
3333 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3335 # In this case there is a spare byte at the end of the data. The size of
3336 # the contents is only 1 byte but we still have the size before it
3338 self.assertEqual(b'a\0', data[:2])
3339 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3340 self.assertEqual(b'a\0', data[-2:])
3342 def testDescriptorOffset(self):
3343 """Test that the Intel descriptor is always placed at at the start"""
3344 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3345 image = control.images['image']
3346 entries = image.GetEntries()
3347 desc = entries['intel-descriptor']
3348 self.assertEqual(0xff800000, desc.offset);
3349 self.assertEqual(0xff800000, desc.image_pos);
3351 def testReplaceCbfs(self):
3352 """Test replacing a single file in CBFS without changing the size"""
3354 expected = b'x' * len(U_BOOT_DATA)
3355 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3356 updated_fname = tools.get_output_filename('image-updated.bin')
3357 tools.write_file(updated_fname, data)
3358 entry_name = 'section/cbfs/u-boot'
3359 control.WriteEntry(updated_fname, entry_name, expected,
3361 data = control.ReadEntry(updated_fname, entry_name)
3362 self.assertEqual(expected, data)
3364 def testReplaceResizeCbfs(self):
3365 """Test replacing a single file in CBFS with one of a different size"""
3367 expected = U_BOOT_DATA + b'x'
3368 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3369 updated_fname = tools.get_output_filename('image-updated.bin')
3370 tools.write_file(updated_fname, data)
3371 entry_name = 'section/cbfs/u-boot'
3372 control.WriteEntry(updated_fname, entry_name, expected,
3374 data = control.ReadEntry(updated_fname, entry_name)
3375 self.assertEqual(expected, data)
3377 def _SetupForReplace(self):
3378 """Set up some files to use to replace entries
3380 This generates an image, copies it to a new file, extracts all the files
3381 in it and updates some of them
3387 Expected values for updated entries, each a string
3389 data = self._DoReadFileRealDtb('143_replace_all.dts')
3391 updated_fname = tools.get_output_filename('image-updated.bin')
3392 tools.write_file(updated_fname, data)
3394 outdir = os.path.join(self._indir, 'extract')
3395 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3397 expected1 = b'x' + U_BOOT_DATA + b'y'
3398 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3399 tools.write_file(u_boot_fname1, expected1)
3401 expected2 = b'a' + U_BOOT_DATA + b'b'
3402 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3403 tools.write_file(u_boot_fname2, expected2)
3405 expected_text = b'not the same text'
3406 text_fname = os.path.join(outdir, 'text')
3407 tools.write_file(text_fname, expected_text)
3409 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3410 dtb = fdt.FdtScan(dtb_fname)
3411 node = dtb.GetNode('/binman/text')
3412 node.AddString('my-property', 'the value')
3413 dtb.Sync(auto_resize=True)
3416 return updated_fname, outdir, expected1, expected2, expected_text
3418 def _CheckReplaceMultiple(self, entry_paths):
3419 """Handle replacing the contents of multiple entries
3422 entry_paths: List of entry paths to replace
3426 Dict of entries in the image:
3429 Expected values for updated entries, each a string
3431 updated_fname, outdir, expected1, expected2, expected_text = (
3432 self._SetupForReplace())
3433 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3435 image = Image.FromFile(updated_fname)
3437 return image.GetEntries(), expected1, expected2, expected_text
3439 def testReplaceAll(self):
3440 """Test replacing the contents of all entries"""
3441 entries, expected1, expected2, expected_text = (
3442 self._CheckReplaceMultiple([]))
3443 data = entries['u-boot'].data
3444 self.assertEqual(expected1, data)
3446 data = entries['u-boot2'].data
3447 self.assertEqual(expected2, data)
3449 data = entries['text'].data
3450 self.assertEqual(expected_text, data)
3452 # Check that the device tree is updated
3453 data = entries['u-boot-dtb'].data
3454 dtb = fdt.Fdt.FromData(data)
3456 node = dtb.GetNode('/binman/text')
3457 self.assertEqual('the value', node.props['my-property'].value)
3459 def testReplaceSome(self):
3460 """Test replacing the contents of a few entries"""
3461 entries, expected1, expected2, expected_text = (
3462 self._CheckReplaceMultiple(['u-boot2', 'text']))
3464 # This one should not change
3465 data = entries['u-boot'].data
3466 self.assertEqual(U_BOOT_DATA, data)
3468 data = entries['u-boot2'].data
3469 self.assertEqual(expected2, data)
3471 data = entries['text'].data
3472 self.assertEqual(expected_text, data)
3474 def testReplaceCmd(self):
3475 """Test replacing a file fron an image on the command line"""
3476 self._DoReadFileRealDtb('143_replace_all.dts')
3479 tmpdir, updated_fname = self._SetupImageInTmpdir()
3481 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3482 expected = b'x' * len(U_BOOT_DATA)
3483 tools.write_file(fname, expected)
3485 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3486 data = tools.read_file(updated_fname)
3487 self.assertEqual(expected, data[:len(expected)])
3488 map_fname = os.path.join(tmpdir, 'image-updated.map')
3489 self.assertFalse(os.path.exists(map_fname))
3491 shutil.rmtree(tmpdir)
3493 def testReplaceCmdSome(self):
3494 """Test replacing some files fron an image on the command line"""
3495 updated_fname, outdir, expected1, expected2, expected_text = (
3496 self._SetupForReplace())
3498 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3501 tools.prepare_output_dir(None)
3502 image = Image.FromFile(updated_fname)
3504 entries = image.GetEntries()
3506 # This one should not change
3507 data = entries['u-boot'].data
3508 self.assertEqual(U_BOOT_DATA, data)
3510 data = entries['u-boot2'].data
3511 self.assertEqual(expected2, data)
3513 data = entries['text'].data
3514 self.assertEqual(expected_text, data)
3516 def testReplaceMissing(self):
3517 """Test replacing entries where the file is missing"""
3518 updated_fname, outdir, expected1, expected2, expected_text = (
3519 self._SetupForReplace())
3521 # Remove one of the files, to generate a warning
3522 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3523 os.remove(u_boot_fname1)
3525 with test_util.capture_sys_output() as (stdout, stderr):
3526 control.ReplaceEntries(updated_fname, None, outdir, [])
3527 self.assertIn("Skipping entry '/u-boot' from missing file",
3530 def testReplaceCmdMap(self):
3531 """Test replacing a file fron an image on the command line"""
3532 self._DoReadFileRealDtb('143_replace_all.dts')
3535 tmpdir, updated_fname = self._SetupImageInTmpdir()
3537 fname = os.path.join(self._indir, 'update-u-boot.bin')
3538 expected = b'x' * len(U_BOOT_DATA)
3539 tools.write_file(fname, expected)
3541 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3543 map_fname = os.path.join(tmpdir, 'image-updated.map')
3544 self.assertTrue(os.path.exists(map_fname))
3546 shutil.rmtree(tmpdir)
3548 def testReplaceNoEntryPaths(self):
3549 """Test replacing an entry without an entry path"""
3550 self._DoReadFileRealDtb('143_replace_all.dts')
3551 image_fname = tools.get_output_filename('image.bin')
3552 with self.assertRaises(ValueError) as e:
3553 control.ReplaceEntries(image_fname, 'fname', None, [])
3554 self.assertIn('Must specify an entry path to read with -f',
3557 def testReplaceTooManyEntryPaths(self):
3558 """Test extracting some entries"""
3559 self._DoReadFileRealDtb('143_replace_all.dts')
3560 image_fname = tools.get_output_filename('image.bin')
3561 with self.assertRaises(ValueError) as e:
3562 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3563 self.assertIn('Must specify exactly one entry path to write with -f',
3566 def testPackReset16(self):
3567 """Test that an image with an x86 reset16 region can be created"""
3568 data = self._DoReadFile('144_x86_reset16.dts')
3569 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3571 def testPackReset16Spl(self):
3572 """Test that an image with an x86 reset16-spl region can be created"""
3573 data = self._DoReadFile('145_x86_reset16_spl.dts')
3574 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3576 def testPackReset16Tpl(self):
3577 """Test that an image with an x86 reset16-tpl region can be created"""
3578 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3579 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3581 def testPackIntelFit(self):
3582 """Test that an image with an Intel FIT and pointer can be created"""
3583 data = self._DoReadFile('147_intel_fit.dts')
3584 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3586 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3587 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3589 image = control.images['image']
3590 entries = image.GetEntries()
3591 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3592 self.assertEqual(expected_ptr, ptr)
3594 def testPackIntelFitMissing(self):
3595 """Test detection of a FIT pointer with not FIT region"""
3596 with self.assertRaises(ValueError) as e:
3597 self._DoReadFile('148_intel_fit_missing.dts')
3598 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3601 def _CheckSymbolsTplSection(self, dts, expected_vals):
3602 data = self._DoReadFile(dts)
3603 sym_values = struct.pack('<LQLL', *expected_vals)
3604 upto1 = 4 + len(U_BOOT_SPL_DATA)
3605 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3606 self.assertEqual(expected1, data[:upto1])
3608 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3609 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3610 self.assertEqual(expected2, data[upto1:upto2])
3612 upto3 = 0x34 + len(U_BOOT_DATA)
3613 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
3614 self.assertEqual(expected3, data[upto2:upto3])
3616 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3617 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3619 def testSymbolsTplSection(self):
3620 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3621 self._SetupSplElf('u_boot_binman_syms')
3622 self._SetupTplElf('u_boot_binman_syms')
3623 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3624 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3626 def testSymbolsTplSectionX86(self):
3627 """Test binman can assign symbols in a section with end-at-4gb"""
3628 self._SetupSplElf('u_boot_binman_syms_x86')
3629 self._SetupTplElf('u_boot_binman_syms_x86')
3630 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3631 [0xffffff04, 0xffffff1c, 0xffffff34,
3634 def testPackX86RomIfwiSectiom(self):
3635 """Test that a section can be placed in an IFWI region"""
3636 self._SetupIfwi('fitimage.bin')
3637 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3638 self._CheckIfwi(data)
3640 def testPackFspM(self):
3641 """Test that an image with a FSP memory-init binary can be created"""
3642 data = self._DoReadFile('152_intel_fsp_m.dts')
3643 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3645 def testPackFspS(self):
3646 """Test that an image with a FSP silicon-init binary can be created"""
3647 data = self._DoReadFile('153_intel_fsp_s.dts')
3648 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3650 def testPackFspT(self):
3651 """Test that an image with a FSP temp-ram-init binary can be created"""
3652 data = self._DoReadFile('154_intel_fsp_t.dts')
3653 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3655 def testMkimage(self):
3656 """Test using mkimage to build an image"""
3657 data = self._DoReadFile('156_mkimage.dts')
3659 # Just check that the data appears in the file somewhere
3660 self.assertIn(U_BOOT_SPL_DATA, data)
3662 def testMkimageMissing(self):
3663 """Test that binman still produces an image if mkimage is missing"""
3664 with test_util.capture_sys_output() as (_, stderr):
3665 self._DoTestFile('156_mkimage.dts',
3666 force_missing_bintools='mkimage')
3667 err = stderr.getvalue()
3668 self.assertRegex(err,
3669 "Image 'main-section'.*missing bintools.*: mkimage")
3671 def testExtblob(self):
3672 """Test an image with an external blob"""
3673 data = self._DoReadFile('157_blob_ext.dts')
3674 self.assertEqual(REFCODE_DATA, data)
3676 def testExtblobMissing(self):
3677 """Test an image with a missing external blob"""
3678 with self.assertRaises(ValueError) as e:
3679 self._DoReadFile('158_blob_ext_missing.dts')
3680 self.assertIn("Filename 'missing-file' not found in input path",
3683 def testExtblobMissingOk(self):
3684 """Test an image with an missing external blob that is allowed"""
3685 with test_util.capture_sys_output() as (stdout, stderr):
3686 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3687 err = stderr.getvalue()
3688 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3690 def testExtblobMissingOkSect(self):
3691 """Test an image with an missing external blob that is allowed"""
3692 with test_util.capture_sys_output() as (stdout, stderr):
3693 self._DoTestFile('159_blob_ext_missing_sect.dts',
3695 err = stderr.getvalue()
3696 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3697 "blob-ext blob-ext2")
3699 def testPackX86RomMeMissingDesc(self):
3700 """Test that an missing Intel descriptor entry is allowed"""
3701 with test_util.capture_sys_output() as (stdout, stderr):
3702 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3703 err = stderr.getvalue()
3704 self.assertRegex(err,
3705 "Image 'main-section'.*missing.*: intel-descriptor")
3707 def testPackX86RomMissingIfwi(self):
3708 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3709 self._SetupIfwi('fitimage.bin')
3710 pathname = os.path.join(self._indir, 'fitimage.bin')
3712 with test_util.capture_sys_output() as (stdout, stderr):
3713 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3714 err = stderr.getvalue()
3715 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3717 def testPackOverlapZero(self):
3718 """Test that zero-size overlapping regions are ignored"""
3719 self._DoTestFile('160_pack_overlap_zero.dts')
3721 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
3722 # The data should be inside the FIT
3723 dtb = fdt.Fdt.FromData(fit_data)
3725 fnode = dtb.GetNode('/images/kernel')
3726 self.assertIn('data', fnode.props)
3728 fname = os.path.join(self._indir, 'fit_data.fit')
3729 tools.write_file(fname, fit_data)
3730 out = tools.run('dumpimage', '-l', fname)
3732 # Check a few features to make sure the plumbing works. We don't need
3733 # to test the operation of mkimage or dumpimage here. First convert the
3734 # output into a dict where the keys are the fields printed by dumpimage
3735 # and the values are a list of values for each field
3736 lines = out.splitlines()
3738 # Converts "Compression: gzip compressed" into two groups:
3739 # 'Compression' and 'gzip compressed'
3740 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3741 vals = collections.defaultdict(list)
3743 mat = re_line.match(line)
3744 vals[mat.group(1)].append(mat.group(2))
3746 self.assertEquals('FIT description: test-desc', lines[0])
3747 self.assertIn('Created:', lines[1])
3748 self.assertIn('Image 0 (kernel)', vals)
3749 self.assertIn('Hash value', vals)
3750 data_sizes = vals.get('Data Size')
3751 self.assertIsNotNone(data_sizes)
3752 self.assertEqual(2, len(data_sizes))
3753 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3754 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3755 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3757 def testSimpleFit(self):
3758 """Test an image with a FIT inside"""
3759 data = self._DoReadFile('161_fit.dts')
3760 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3761 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3762 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3764 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3766 def testSimpleFitExpandsSubentries(self):
3767 """Test that FIT images expand their subentries"""
3768 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3769 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3770 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3771 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3773 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
3775 def testSimpleFitImagePos(self):
3776 """Test that we have correct image-pos for FIT subentries"""
3777 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3779 dtb = fdt.Fdt(out_dtb_fname)
3781 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3789 'u-boot:image-pos': 0,
3797 'fit/images/kernel:image-pos': 304,
3798 'fit/images/kernel:offset': 300,
3799 'fit/images/kernel:size': 4,
3801 'fit/images/kernel/u-boot:image-pos': 304,
3802 'fit/images/kernel/u-boot:offset': 0,
3803 'fit/images/kernel/u-boot:size': 4,
3805 'fit/images/fdt-1:image-pos': 552,
3806 'fit/images/fdt-1:offset': 548,
3807 'fit/images/fdt-1:size': 6,
3809 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
3810 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3811 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3813 'u-boot-nodtb:image-pos': 1844,
3814 'u-boot-nodtb:offset': 1844,
3815 'u-boot-nodtb:size': 46,
3818 # Actually check the data is where we think it is
3819 for node, expected in [
3820 ("u-boot", U_BOOT_DATA),
3821 ("fit/images/kernel", U_BOOT_DATA),
3822 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3823 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3824 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3825 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3827 image_pos = props[f"{node}:image-pos"]
3828 size = props[f"{node}:size"]
3829 self.assertEqual(len(expected), size)
3830 self.assertEqual(expected, data[image_pos:image_pos+size])
3832 def testFitExternal(self):
3833 """Test an image with an FIT with external images"""
3834 data = self._DoReadFile('162_fit_external.dts')
3835 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3837 # Size of the external-data region as set up by mkimage
3838 external_data_size = len(U_BOOT_DATA) + 2
3839 expected_size = (len(U_BOOT_DATA) + 0x400 +
3840 tools.align(external_data_size, 4) +
3841 len(U_BOOT_NODTB_DATA))
3843 # The data should be outside the FIT
3844 dtb = fdt.Fdt.FromData(fit_data)
3846 fnode = dtb.GetNode('/images/kernel')
3847 self.assertNotIn('data', fnode.props)
3848 self.assertEqual(len(U_BOOT_DATA),
3849 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3853 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3855 self.assertEquals(expected_size, len(data))
3856 actual_pos = len(U_BOOT_DATA) + fit_pos
3857 self.assertEqual(U_BOOT_DATA + b'aa',
3858 data[actual_pos:actual_pos + external_data_size])
3860 def testFitExternalImagePos(self):
3861 """Test that we have correct image-pos for external FIT subentries"""
3862 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3864 dtb = fdt.Fdt(out_dtb_fname)
3866 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3873 'u-boot:image-pos': 0,
3881 'fit/images/kernel:size': 4,
3882 'fit/images/kernel:offset': 1024,
3883 'fit/images/kernel:image-pos': 1028,
3885 'fit/images/kernel/u-boot:size': 4,
3886 'fit/images/kernel/u-boot:offset': 0,
3887 'fit/images/kernel/u-boot:image-pos': 1028,
3889 'fit/images/fdt-1:size': 2,
3890 'fit/images/fdt-1:offset': 1028,
3891 'fit/images/fdt-1:image-pos': 1032,
3893 'fit/images/fdt-1/_testing:size': 2,
3894 'fit/images/fdt-1/_testing:offset': 0,
3895 'fit/images/fdt-1/_testing:image-pos': 1032,
3897 'u-boot-nodtb:image-pos': 1036,
3898 'u-boot-nodtb:offset': 1036,
3899 'u-boot-nodtb:size': 46,
3902 # Actually check the data is where we think it is
3903 for node, expected in [
3904 ("u-boot", U_BOOT_DATA),
3905 ("fit/images/kernel", U_BOOT_DATA),
3906 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3907 ("fit/images/fdt-1", b'aa'),
3908 ("fit/images/fdt-1/_testing", b'aa'),
3909 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3911 image_pos = props[f"{node}:image-pos"]
3912 size = props[f"{node}:size"]
3913 self.assertEqual(len(expected), size)
3914 self.assertEqual(expected, data[image_pos:image_pos+size])
3916 def testFitMissing(self):
3917 """Test that binman still produces a FIT image if mkimage is missing"""
3918 with test_util.capture_sys_output() as (_, stderr):
3919 self._DoTestFile('162_fit_external.dts',
3920 force_missing_bintools='mkimage')
3921 err = stderr.getvalue()
3922 self.assertRegex(err,
3923 "Image 'main-section'.*missing bintools.*: mkimage")
3925 def testSectionIgnoreHashSignature(self):
3926 """Test that sections ignore hash, signature nodes for its data"""
3927 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3928 expected = (U_BOOT_DATA + U_BOOT_DATA)
3929 self.assertEqual(expected, data)
3931 def testPadInSections(self):
3932 """Test pad-before, pad-after for entries in sections"""
3933 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3934 '166_pad_in_sections.dts', update_dtb=True)
3935 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3936 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
3938 self.assertEqual(expected, data)
3940 dtb = fdt.Fdt(out_dtb_fname)
3942 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3946 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3948 'section:image-pos': 0,
3949 'section:offset': 0,
3950 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3952 'section/before:image-pos': 0,
3953 'section/before:offset': 0,
3954 'section/before:size': len(U_BOOT_DATA),
3956 'section/u-boot:image-pos': 4,
3957 'section/u-boot:offset': 4,
3958 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3960 'section/after:image-pos': 26,
3961 'section/after:offset': 26,
3962 'section/after:size': len(U_BOOT_DATA),
3964 self.assertEqual(expected, props)
3966 def testFitImageSubentryAlignment(self):
3967 """Test relative alignability of FIT image subentries"""
3970 'test-id': TEXT_DATA,
3972 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3973 entry_args=entry_args)
3974 dtb = fdt.Fdt.FromData(data)
3977 node = dtb.GetNode('/images/kernel')
3978 data = dtb.GetProps(node)["data"].bytes
3979 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3980 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3981 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
3982 self.assertEqual(expected, data)
3984 node = dtb.GetNode('/images/fdt-1')
3985 data = dtb.GetProps(node)["data"].bytes
3986 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
3987 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
3989 self.assertEqual(expected, data)
3991 def testFitExtblobMissingOk(self):
3992 """Test a FIT with a missing external blob that is allowed"""
3993 with test_util.capture_sys_output() as (stdout, stderr):
3994 self._DoTestFile('168_fit_missing_blob.dts',
3996 err = stderr.getvalue()
3997 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3999 def testBlobNamedByArgMissing(self):
4000 """Test handling of a missing entry arg"""
4001 with self.assertRaises(ValueError) as e:
4002 self._DoReadFile('068_blob_named_by_arg.dts')
4003 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4006 def testPackBl31(self):
4007 """Test that an image with an ATF BL31 binary can be created"""
4008 data = self._DoReadFile('169_atf_bl31.dts')
4009 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4011 def testPackScp(self):
4012 """Test that an image with an SCP binary can be created"""
4013 data = self._DoReadFile('172_scp.dts')
4014 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4016 def testFitFdt(self):
4017 """Test an image with an FIT with multiple FDT images"""
4018 def _CheckFdt(seq, expected_data):
4019 """Check the FDT nodes
4022 seq: Sequence number to check (0 or 1)
4023 expected_data: Expected contents of 'data' property
4025 name = 'fdt-%d' % seq
4026 fnode = dtb.GetNode('/images/%s' % name)
4027 self.assertIsNotNone(fnode)
4028 self.assertEqual({'description','type', 'compression', 'data'},
4029 set(fnode.props.keys()))
4030 self.assertEqual(expected_data, fnode.props['data'].bytes)
4031 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4032 fnode.props['description'].value)
4033 self.assertEqual(fnode.subnodes[0].name, 'hash')
4035 def _CheckConfig(seq, expected_data):
4036 """Check the configuration nodes
4039 seq: Sequence number to check (0 or 1)
4040 expected_data: Expected contents of 'data' property
4042 cnode = dtb.GetNode('/configurations')
4043 self.assertIn('default', cnode.props)
4044 self.assertEqual('config-2', cnode.props['default'].value)
4046 name = 'config-%d' % seq
4047 fnode = dtb.GetNode('/configurations/%s' % name)
4048 self.assertIsNotNone(fnode)
4049 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4050 set(fnode.props.keys()))
4051 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4052 fnode.props['description'].value)
4053 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4056 'of-list': 'test-fdt1 test-fdt2',
4057 'default-dt': 'test-fdt2',
4059 data = self._DoReadFileDtb(
4061 entry_args=entry_args,
4062 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4063 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4064 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4066 dtb = fdt.Fdt.FromData(fit_data)
4068 fnode = dtb.GetNode('/images/kernel')
4069 self.assertIn('data', fnode.props)
4071 # Check all the properties in fdt-1 and fdt-2
4072 _CheckFdt(1, TEST_FDT1_DATA)
4073 _CheckFdt(2, TEST_FDT2_DATA)
4075 # Check configurations
4076 _CheckConfig(1, TEST_FDT1_DATA)
4077 _CheckConfig(2, TEST_FDT2_DATA)
4079 def testFitFdtMissingList(self):
4080 """Test handling of a missing 'of-list' entry arg"""
4081 with self.assertRaises(ValueError) as e:
4082 self._DoReadFile('170_fit_fdt.dts')
4083 self.assertIn("Generator node requires 'of-list' entry argument",
4086 def testFitFdtEmptyList(self):
4087 """Test handling of an empty 'of-list' entry arg"""
4091 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4093 def testFitFdtMissingProp(self):
4094 """Test handling of a missing 'fit,fdt-list' property"""
4095 with self.assertRaises(ValueError) as e:
4096 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4097 self.assertIn("Generator node requires 'fit,fdt-list' property",
4100 def testFitFdtMissing(self):
4101 """Test handling of a missing 'default-dt' entry arg"""
4103 'of-list': 'test-fdt1 test-fdt2',
4105 with self.assertRaises(ValueError) as e:
4106 self._DoReadFileDtb(
4108 entry_args=entry_args,
4109 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4110 self.assertIn("Generated 'default' node requires default-dt entry argument",
4113 def testFitFdtNotInList(self):
4114 """Test handling of a default-dt that is not in the of-list"""
4116 'of-list': 'test-fdt1 test-fdt2',
4117 'default-dt': 'test-fdt3',
4119 with self.assertRaises(ValueError) as e:
4120 self._DoReadFileDtb(
4122 entry_args=entry_args,
4123 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4124 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4127 def testFitExtblobMissingHelp(self):
4128 """Test display of help messages when an external blob is missing"""
4129 control.missing_blob_help = control._ReadMissingBlobHelp()
4130 control.missing_blob_help['wibble'] = 'Wibble test'
4131 control.missing_blob_help['another'] = 'Another test'
4132 with test_util.capture_sys_output() as (stdout, stderr):
4133 self._DoTestFile('168_fit_missing_blob.dts',
4135 err = stderr.getvalue()
4137 # We can get the tag from the name, the type or the missing-msg
4138 # property. Check all three.
4139 self.assertIn('You may need to build ARM Trusted', err)
4140 self.assertIn('Wibble test', err)
4141 self.assertIn('Another test', err)
4143 def testMissingBlob(self):
4144 """Test handling of a blob containing a missing file"""
4145 with self.assertRaises(ValueError) as e:
4146 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4147 self.assertIn("Filename 'missing' not found in input path",
4150 def testEnvironment(self):
4151 """Test adding a U-Boot environment"""
4152 data = self._DoReadFile('174_env.dts')
4153 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4154 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4155 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4156 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4159 def testEnvironmentNoSize(self):
4160 """Test that a missing 'size' property is detected"""
4161 with self.assertRaises(ValueError) as e:
4162 self._DoTestFile('175_env_no_size.dts')
4163 self.assertIn("'u-boot-env' entry must have a size property",
4166 def testEnvironmentTooSmall(self):
4167 """Test handling of an environment that does not fit"""
4168 with self.assertRaises(ValueError) as e:
4169 self._DoTestFile('176_env_too_small.dts')
4171 # checksum, start byte, environment with \0 terminator, final \0
4172 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4174 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4177 def testSkipAtStart(self):
4178 """Test handling of skip-at-start section"""
4179 data = self._DoReadFile('177_skip_at_start.dts')
4180 self.assertEqual(U_BOOT_DATA, data)
4182 image = control.images['image']
4183 entries = image.GetEntries()
4184 section = entries['section']
4185 self.assertEqual(0, section.offset)
4186 self.assertEqual(len(U_BOOT_DATA), section.size)
4187 self.assertEqual(U_BOOT_DATA, section.GetData())
4189 entry = section.GetEntries()['u-boot']
4190 self.assertEqual(16, entry.offset)
4191 self.assertEqual(len(U_BOOT_DATA), entry.size)
4192 self.assertEqual(U_BOOT_DATA, entry.data)
4194 def testSkipAtStartPad(self):
4195 """Test handling of skip-at-start section with padded entry"""
4196 data = self._DoReadFile('178_skip_at_start_pad.dts')
4197 before = tools.get_bytes(0, 8)
4198 after = tools.get_bytes(0, 4)
4199 all = before + U_BOOT_DATA + after
4200 self.assertEqual(all, data)
4202 image = control.images['image']
4203 entries = image.GetEntries()
4204 section = entries['section']
4205 self.assertEqual(0, section.offset)
4206 self.assertEqual(len(all), section.size)
4207 self.assertEqual(all, section.GetData())
4209 entry = section.GetEntries()['u-boot']
4210 self.assertEqual(16, entry.offset)
4211 self.assertEqual(len(all), entry.size)
4212 self.assertEqual(U_BOOT_DATA, entry.data)
4214 def testSkipAtStartSectionPad(self):
4215 """Test handling of skip-at-start section with padding"""
4216 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4217 before = tools.get_bytes(0, 8)
4218 after = tools.get_bytes(0, 4)
4219 all = before + U_BOOT_DATA + after
4220 self.assertEqual(all, data)
4222 image = control.images['image']
4223 entries = image.GetEntries()
4224 section = entries['section']
4225 self.assertEqual(0, section.offset)
4226 self.assertEqual(len(all), section.size)
4227 self.assertEqual(U_BOOT_DATA, section.data)
4228 self.assertEqual(all, section.GetPaddedData())
4230 entry = section.GetEntries()['u-boot']
4231 self.assertEqual(16, entry.offset)
4232 self.assertEqual(len(U_BOOT_DATA), entry.size)
4233 self.assertEqual(U_BOOT_DATA, entry.data)
4235 def testSectionPad(self):
4236 """Testing padding with sections"""
4237 data = self._DoReadFile('180_section_pad.dts')
4238 expected = (tools.get_bytes(ord('&'), 3) +
4239 tools.get_bytes(ord('!'), 5) +
4241 tools.get_bytes(ord('!'), 1) +
4242 tools.get_bytes(ord('&'), 2))
4243 self.assertEqual(expected, data)
4245 def testSectionAlign(self):
4246 """Testing alignment with sections"""
4247 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4248 expected = (b'\0' + # fill section
4249 tools.get_bytes(ord('&'), 1) + # padding to section align
4250 b'\0' + # fill section
4251 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
4253 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4254 tools.get_bytes(ord('!'), 4)) # padding to section size
4255 self.assertEqual(expected, data)
4257 def testCompressImage(self):
4258 """Test compression of the entire image"""
4260 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4261 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4262 dtb = fdt.Fdt(out_dtb_fname)
4264 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4266 orig = self._decompress(data)
4267 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4269 # Do a sanity check on various fields
4270 image = control.images['image']
4271 entries = image.GetEntries()
4272 self.assertEqual(2, len(entries))
4274 entry = entries['blob']
4275 self.assertEqual(COMPRESS_DATA, entry.data)
4276 self.assertEqual(len(COMPRESS_DATA), entry.size)
4278 entry = entries['u-boot']
4279 self.assertEqual(U_BOOT_DATA, entry.data)
4280 self.assertEqual(len(U_BOOT_DATA), entry.size)
4282 self.assertEqual(len(data), image.size)
4283 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4284 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4285 orig = self._decompress(image.data)
4286 self.assertEqual(orig, image.uncomp_data)
4290 'blob:size': len(COMPRESS_DATA),
4291 'u-boot:offset': len(COMPRESS_DATA),
4292 'u-boot:size': len(U_BOOT_DATA),
4293 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4298 self.assertEqual(expected, props)
4300 def testCompressImageLess(self):
4301 """Test compression where compression reduces the image size"""
4303 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4304 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4305 dtb = fdt.Fdt(out_dtb_fname)
4307 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4309 orig = self._decompress(data)
4311 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4313 # Do a sanity check on various fields
4314 image = control.images['image']
4315 entries = image.GetEntries()
4316 self.assertEqual(2, len(entries))
4318 entry = entries['blob']
4319 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4320 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4322 entry = entries['u-boot']
4323 self.assertEqual(U_BOOT_DATA, entry.data)
4324 self.assertEqual(len(U_BOOT_DATA), entry.size)
4326 self.assertEqual(len(data), image.size)
4327 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4328 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4330 orig = self._decompress(image.data)
4331 self.assertEqual(orig, image.uncomp_data)
4335 'blob:size': len(COMPRESS_DATA_BIG),
4336 'u-boot:offset': len(COMPRESS_DATA_BIG),
4337 'u-boot:size': len(U_BOOT_DATA),
4338 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4343 self.assertEqual(expected, props)
4345 def testCompressSectionSize(self):
4346 """Test compression of a section with a fixed size"""
4348 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4349 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4350 dtb = fdt.Fdt(out_dtb_fname)
4352 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4354 orig = self._decompress(data)
4355 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4357 'section/blob:offset': 0,
4358 'section/blob:size': len(COMPRESS_DATA),
4359 'section/u-boot:offset': len(COMPRESS_DATA),
4360 'section/u-boot:size': len(U_BOOT_DATA),
4361 'section:offset': 0,
4362 'section:image-pos': 0,
4363 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4364 'section:size': 0x30,
4369 self.assertEqual(expected, props)
4371 def testCompressSection(self):
4372 """Test compression of a section with no fixed size"""
4374 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4375 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4376 dtb = fdt.Fdt(out_dtb_fname)
4378 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4380 orig = self._decompress(data)
4381 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4383 'section/blob:offset': 0,
4384 'section/blob:size': len(COMPRESS_DATA),
4385 'section/u-boot:offset': len(COMPRESS_DATA),
4386 'section/u-boot:size': len(U_BOOT_DATA),
4387 'section:offset': 0,
4388 'section:image-pos': 0,
4389 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4390 'section:size': len(data),
4395 self.assertEqual(expected, props)
4397 def testCompressExtra(self):
4398 """Test compression of a section with no fixed size"""
4400 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4401 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4402 dtb = fdt.Fdt(out_dtb_fname)
4404 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4407 base = data[len(U_BOOT_DATA):]
4408 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4409 rest = base[len(U_BOOT_DATA):]
4411 # Check compressed data
4412 section1 = self._decompress(rest)
4413 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4414 self.assertEquals(expect1, rest[:len(expect1)])
4415 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4416 rest1 = rest[len(expect1):]
4418 section2 = self._decompress(rest1)
4419 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4420 self.assertEquals(expect2, rest1[:len(expect2)])
4421 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4422 rest2 = rest1[len(expect2):]
4424 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4425 len(expect2) + len(U_BOOT_DATA))
4426 #self.assertEquals(expect_size, len(data))
4428 #self.assertEquals(U_BOOT_DATA, rest2)
4433 'u-boot:image-pos': 0,
4434 'u-boot:size': len(U_BOOT_DATA),
4436 'base:offset': len(U_BOOT_DATA),
4437 'base:image-pos': len(U_BOOT_DATA),
4438 'base:size': len(data) - len(U_BOOT_DATA),
4439 'base/u-boot:offset': 0,
4440 'base/u-boot:image-pos': len(U_BOOT_DATA),
4441 'base/u-boot:size': len(U_BOOT_DATA),
4442 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4444 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4446 'base/u-boot2:size': len(U_BOOT_DATA),
4448 'base/section:offset': len(U_BOOT_DATA),
4449 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4450 'base/section:size': len(expect1),
4451 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4452 'base/section/blob:offset': 0,
4453 'base/section/blob:size': len(COMPRESS_DATA),
4454 'base/section/u-boot:offset': len(COMPRESS_DATA),
4455 'base/section/u-boot:size': len(U_BOOT_DATA),
4457 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4458 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4459 'base/section2:size': len(expect2),
4460 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4461 'base/section2/blob:offset': 0,
4462 'base/section2/blob:size': len(COMPRESS_DATA),
4463 'base/section2/blob2:offset': len(COMPRESS_DATA),
4464 'base/section2/blob2:size': len(COMPRESS_DATA),
4470 self.assertEqual(expected, props)
4472 def testSymbolsSubsection(self):
4473 """Test binman can assign symbols from a subsection"""
4474 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4476 def testReadImageEntryArg(self):
4477 """Test reading an image that would need an entry arg to generate"""
4479 'cros-ec-rw-path': 'ecrw.bin',
4481 data = self.data = self._DoReadFileDtb(
4482 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4483 entry_args=entry_args)
4485 image_fname = tools.get_output_filename('image.bin')
4486 orig_image = control.images['image']
4488 # This should not generate an error about the missing 'cros-ec-rw-path'
4489 # since we are reading the image from a file. Compare with
4490 # testEntryArgsRequired()
4491 image = Image.FromFile(image_fname)
4492 self.assertEqual(orig_image.GetEntries().keys(),
4493 image.GetEntries().keys())
4495 def testFilesAlign(self):
4496 """Test alignment with files"""
4497 data = self._DoReadFile('190_files_align.dts')
4499 # The first string is 15 bytes so will align to 16
4500 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4501 self.assertEqual(expect, data)
4503 def testReadImageSkip(self):
4504 """Test reading an image and accessing its FDT map"""
4505 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4506 image_fname = tools.get_output_filename('image.bin')
4507 orig_image = control.images['image']
4508 image = Image.FromFile(image_fname)
4509 self.assertEqual(orig_image.GetEntries().keys(),
4510 image.GetEntries().keys())
4512 orig_entry = orig_image.GetEntries()['fdtmap']
4513 entry = image.GetEntries()['fdtmap']
4514 self.assertEqual(orig_entry.offset, entry.offset)
4515 self.assertEqual(orig_entry.size, entry.size)
4516 self.assertEqual(16, entry.image_pos)
4518 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4520 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4522 def testTplNoDtb(self):
4523 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4525 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4526 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4527 data[:len(U_BOOT_TPL_NODTB_DATA)])
4529 def testTplBssPad(self):
4530 """Test that we can pad TPL's BSS with zeros"""
4531 # ELF file with a '__bss_size' symbol
4533 data = self._DoReadFile('193_tpl_bss_pad.dts')
4534 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
4537 def testTplBssPadMissing(self):
4538 """Test that a missing symbol is detected"""
4539 self._SetupTplElf('u_boot_ucode_ptr')
4540 with self.assertRaises(ValueError) as e:
4541 self._DoReadFile('193_tpl_bss_pad.dts')
4542 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4545 def checkDtbSizes(self, data, pad_len, start):
4546 """Check the size arguments in a dtb embedded in an image
4549 data: The image data
4550 pad_len: Length of the pad section in the image, in bytes
4551 start: Start offset of the devicetree to examine, within the image
4554 Size of the devicetree in bytes
4556 dtb_data = data[start:]
4557 dtb = fdt.Fdt.FromData(dtb_data)
4558 fdt_size = dtb.GetFdtObj().totalsize()
4560 props = self._GetPropTree(dtb, 'size')
4563 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4564 'u-boot-spl/u-boot-spl-dtb:size': 801,
4565 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4566 'u-boot-spl:size': 860,
4567 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4568 'u-boot/u-boot-dtb:size': 781,
4569 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4574 def testExpanded(self):
4575 """Test that an expanded entry type is selected when needed"""
4579 # SPL has a devicetree, TPL does not
4585 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4586 entry_args=entry_args)
4587 image = control.images['image']
4588 entries = image.GetEntries()
4589 self.assertEqual(3, len(entries))
4591 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4592 self.assertIn('u-boot', entries)
4593 entry = entries['u-boot']
4594 self.assertEqual('u-boot-expanded', entry.etype)
4595 subent = entry.GetEntries()
4596 self.assertEqual(2, len(subent))
4597 self.assertIn('u-boot-nodtb', subent)
4598 self.assertIn('u-boot-dtb', subent)
4600 # Second, u-boot-spl, which should be expanded into three parts
4601 self.assertIn('u-boot-spl', entries)
4602 entry = entries['u-boot-spl']
4603 self.assertEqual('u-boot-spl-expanded', entry.etype)
4604 subent = entry.GetEntries()
4605 self.assertEqual(3, len(subent))
4606 self.assertIn('u-boot-spl-nodtb', subent)
4607 self.assertIn('u-boot-spl-bss-pad', subent)
4608 self.assertIn('u-boot-spl-dtb', subent)
4610 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4612 self.assertIn('u-boot-tpl', entries)
4613 entry = entries['u-boot-tpl']
4614 self.assertEqual('u-boot-tpl', entry.etype)
4615 self.assertEqual(None, entry.GetEntries())
4617 def testExpandedTpl(self):
4618 """Test that an expanded entry type is selected for TPL when needed"""
4625 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4626 entry_args=entry_args)
4627 image = control.images['image']
4628 entries = image.GetEntries()
4629 self.assertEqual(1, len(entries))
4631 # We only have u-boot-tpl, which be expanded
4632 self.assertIn('u-boot-tpl', entries)
4633 entry = entries['u-boot-tpl']
4634 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4635 subent = entry.GetEntries()
4636 self.assertEqual(3, len(subent))
4637 self.assertIn('u-boot-tpl-nodtb', subent)
4638 self.assertIn('u-boot-tpl-bss-pad', subent)
4639 self.assertIn('u-boot-tpl-dtb', subent)
4641 def testExpandedNoPad(self):
4642 """Test an expanded entry without BSS pad enabled"""
4646 # SPL has a devicetree, TPL does not
4648 'spl-dtb': 'something',
4652 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4653 entry_args=entry_args)
4654 image = control.images['image']
4655 entries = image.GetEntries()
4657 # Just check u-boot-spl, which should be expanded into two parts
4658 self.assertIn('u-boot-spl', entries)
4659 entry = entries['u-boot-spl']
4660 self.assertEqual('u-boot-spl-expanded', entry.etype)
4661 subent = entry.GetEntries()
4662 self.assertEqual(2, len(subent))
4663 self.assertIn('u-boot-spl-nodtb', subent)
4664 self.assertIn('u-boot-spl-dtb', subent)
4666 def testExpandedTplNoPad(self):
4667 """Test that an expanded entry type with padding disabled in TPL"""
4674 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4675 entry_args=entry_args)
4676 image = control.images['image']
4677 entries = image.GetEntries()
4678 self.assertEqual(1, len(entries))
4680 # We only have u-boot-tpl, which be expanded
4681 self.assertIn('u-boot-tpl', entries)
4682 entry = entries['u-boot-tpl']
4683 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4684 subent = entry.GetEntries()
4685 self.assertEqual(2, len(subent))
4686 self.assertIn('u-boot-tpl-nodtb', subent)
4687 self.assertIn('u-boot-tpl-dtb', subent)
4689 def testFdtInclude(self):
4690 """Test that an Fdt is update within all binaries"""
4694 # SPL has a devicetree, TPL does not
4701 # Build the image. It includes two separate devicetree binaries, each
4702 # with their own contents, but all contain the binman definition.
4703 data = self._DoReadFileDtb(
4704 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4705 update_dtb=True, entry_args=entry_args)[0]
4708 # Check the U-Boot dtb
4709 start = len(U_BOOT_NODTB_DATA)
4710 fdt_size = self.checkDtbSizes(data, pad_len, start)
4713 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4714 fdt_size = self.checkDtbSizes(data, pad_len, start)
4716 # TPL has no devicetree
4717 start += fdt_size + len(U_BOOT_TPL_DATA)
4718 self.assertEqual(len(data), start)
4720 def testSymbolsExpanded(self):
4721 """Test binman can assign symbols in expanded entries"""
4725 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4726 U_BOOT_SPL_DTB_DATA, 0x38,
4727 entry_args=entry_args, use_expanded=True)
4729 def testCollection(self):
4730 """Test a collection"""
4731 data = self._DoReadFile('198_collection.dts')
4732 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4733 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4734 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
4737 def testCollectionSection(self):
4738 """Test a collection where a section must be built first"""
4739 # Sections never have their contents when GetData() is called, but when
4740 # BuildSectionData() is called with required=True, a section will force
4741 # building the contents, producing an error is anything is still
4743 data = self._DoReadFile('199_collection_section.dts')
4744 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4745 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4746 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
4749 def testAlignDefault(self):
4750 """Test that default alignment works on sections"""
4751 data = self._DoReadFile('200_align_default.dts')
4752 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
4754 # Special alignment for section
4755 expected += tools.get_bytes(0, 32 - len(expected))
4756 # No alignment within the nested section
4757 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4758 # Now the final piece, which should be default-aligned
4759 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4760 self.assertEqual(expected, data)
4762 def testPackOpenSBI(self):
4763 """Test that an image with an OpenSBI binary can be created"""
4764 data = self._DoReadFile('201_opensbi.dts')
4765 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4767 def testSectionsSingleThread(self):
4768 """Test sections without multithreading"""
4769 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4770 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4771 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4772 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
4773 self.assertEqual(expected, data)
4775 def testThreadTimeout(self):
4776 """Test handling a thread that takes too long"""
4777 with self.assertRaises(ValueError) as e:
4778 self._DoTestFile('202_section_timeout.dts',
4779 test_section_timeout=True)
4780 self.assertIn("Timed out obtaining contents", str(e.exception))
4782 def testTiming(self):
4783 """Test output of timing information"""
4784 data = self._DoReadFile('055_sections.dts')
4785 with test_util.capture_sys_output() as (stdout, stderr):
4787 self.assertIn('read:', stdout.getvalue())
4788 self.assertIn('compress:', stdout.getvalue())
4790 def testUpdateFdtInElf(self):
4791 """Test that we can update the devicetree in an ELF file"""
4792 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4793 outfile = os.path.join(self._indir, 'u-boot.out')
4794 begin_sym = 'dtb_embed_begin'
4795 end_sym = 'dtb_embed_end'
4796 retcode = self._DoTestFile(
4797 '060_fdt_update.dts', update_dtb=True,
4798 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4799 self.assertEqual(0, retcode)
4801 # Check that the output file does in fact contact a dtb with the binman
4802 # definition in the correct place
4803 syms = elf.GetSymbolFileOffset(infile,
4804 ['dtb_embed_begin', 'dtb_embed_end'])
4805 data = tools.read_file(outfile)
4806 dtb_data = data[syms['dtb_embed_begin'].offset:
4807 syms['dtb_embed_end'].offset]
4809 dtb = fdt.Fdt.FromData(dtb_data)
4811 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4815 '_testing:offset': 32,
4817 '_testing:image-pos': 32,
4818 'section@0/u-boot:offset': 0,
4819 'section@0/u-boot:size': len(U_BOOT_DATA),
4820 'section@0/u-boot:image-pos': 0,
4821 'section@0:offset': 0,
4822 'section@0:size': 16,
4823 'section@0:image-pos': 0,
4825 'section@1/u-boot:offset': 0,
4826 'section@1/u-boot:size': len(U_BOOT_DATA),
4827 'section@1/u-boot:image-pos': 16,
4828 'section@1:offset': 16,
4829 'section@1:size': 16,
4830 'section@1:image-pos': 16,
4834 def testUpdateFdtInElfInvalid(self):
4835 """Test that invalid args are detected with --update-fdt-in-elf"""
4836 with self.assertRaises(ValueError) as e:
4837 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4838 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4841 def testUpdateFdtInElfNoSyms(self):
4842 """Test that missing symbols are detected with --update-fdt-in-elf"""
4843 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4845 begin_sym = 'wrong_begin'
4846 end_sym = 'wrong_end'
4847 with self.assertRaises(ValueError) as e:
4849 '060_fdt_update.dts',
4850 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4851 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4854 def testUpdateFdtInElfTooSmall(self):
4855 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4856 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4857 outfile = os.path.join(self._indir, 'u-boot.out')
4858 begin_sym = 'dtb_embed_begin'
4859 end_sym = 'dtb_embed_end'
4860 with self.assertRaises(ValueError) as e:
4862 '060_fdt_update.dts', update_dtb=True,
4863 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4866 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4868 def testVersion(self):
4869 """Test we can get the binman version"""
4870 version = '(unreleased)'
4871 self.assertEqual(version, state.GetVersion(self._indir))
4873 with self.assertRaises(SystemExit):
4874 with test_util.capture_sys_output() as (_, stderr):
4875 self._DoBinman('-V')
4876 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4878 # Try running the tool too, just to be safe
4879 result = self._RunBinman('-V')
4880 self.assertEqual('Binman %s\n' % version, result.stderr)
4882 # Set up a version file to make sure that works
4883 version = 'v2025.01-rc2'
4884 tools.write_file(os.path.join(self._indir, 'version'), version,
4886 self.assertEqual(version, state.GetVersion(self._indir))
4888 def testAltFormat(self):
4889 """Test that alternative formats can be used to extract"""
4890 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4893 tmpdir, updated_fname = self._SetupImageInTmpdir()
4894 with test_util.capture_sys_output() as (stdout, _):
4895 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4897 '''Flag (-F) Entry type Description
4898 fdt fdtmap Extract the devicetree blob from the fdtmap
4902 dtb = os.path.join(tmpdir, 'fdt.dtb')
4903 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4906 # Check that we can read it and it can be scanning, meaning it does
4907 # not have a 16-byte fdtmap header
4908 data = tools.read_file(dtb)
4909 dtb = fdt.Fdt.FromData(data)
4912 # Now check u-boot which has no alt_format
4913 fname = os.path.join(tmpdir, 'fdt.dtb')
4914 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4915 '-f', fname, 'u-boot')
4916 data = tools.read_file(fname)
4917 self.assertEqual(U_BOOT_DATA, data)
4920 shutil.rmtree(tmpdir)
4922 def testExtblobList(self):
4923 """Test an image with an external blob list"""
4924 data = self._DoReadFile('215_blob_ext_list.dts')
4925 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4927 def testExtblobListMissing(self):
4928 """Test an image with a missing external blob"""
4929 with self.assertRaises(ValueError) as e:
4930 self._DoReadFile('216_blob_ext_list_missing.dts')
4931 self.assertIn("Filename 'missing-file' not found in input path",
4934 def testExtblobListMissingOk(self):
4935 """Test an image with an missing external blob that is allowed"""
4936 with test_util.capture_sys_output() as (stdout, stderr):
4937 self._DoTestFile('216_blob_ext_list_missing.dts',
4939 err = stderr.getvalue()
4940 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4943 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4944 data = self._DoReadFile('203_fip.dts')
4945 hdr, fents = fip_util.decode_fip(data)
4946 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4947 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4948 self.assertEqual(0x123, hdr.flags)
4950 self.assertEqual(2, len(fents))
4954 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4955 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4956 self.assertEqual('soc-fw', fent.fip_type)
4957 self.assertEqual(0x88, fent.offset)
4958 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4959 self.assertEqual(0x123456789abcdef, fent.flags)
4960 self.assertEqual(ATF_BL31_DATA, fent.data)
4961 self.assertEqual(True, fent.valid)
4965 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4966 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4967 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4968 self.assertEqual(0x8c, fent.offset)
4969 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4970 self.assertEqual(0, fent.flags)
4971 self.assertEqual(ATF_BL2U_DATA, fent.data)
4972 self.assertEqual(True, fent.valid)
4974 def testFipOther(self):
4975 """Basic FIP with something that isn't a external blob"""
4976 data = self._DoReadFile('204_fip_other.dts')
4977 hdr, fents = fip_util.decode_fip(data)
4979 self.assertEqual(2, len(fents))
4981 self.assertEqual('rot-cert', fent.fip_type)
4982 self.assertEqual(b'aa', fent.data)
4984 def testFipNoType(self):
4985 """FIP with an entry of an unknown type"""
4986 with self.assertRaises(ValueError) as e:
4987 self._DoReadFile('205_fip_no_type.dts')
4988 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4991 def testFipUuid(self):
4992 """Basic FIP with a manual uuid"""
4993 data = self._DoReadFile('206_fip_uuid.dts')
4994 hdr, fents = fip_util.decode_fip(data)
4996 self.assertEqual(2, len(fents))
4998 self.assertEqual(None, fent.fip_type)
5000 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5001 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5003 self.assertEqual(U_BOOT_DATA, fent.data)
5005 def testFipLs(self):
5006 """Test listing a FIP"""
5007 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5008 hdr, fents = fip_util.decode_fip(data)
5011 tmpdir, updated_fname = self._SetupImageInTmpdir()
5012 with test_util.capture_sys_output() as (stdout, stderr):
5013 self._DoBinman('ls', '-i', updated_fname)
5015 shutil.rmtree(tmpdir)
5016 lines = stdout.getvalue().splitlines()
5018 'Name Image-pos Size Entry-type Offset Uncomp-size',
5019 '----------------------------------------------------------------',
5020 'main-section 0 2d3 section 0',
5021 ' atf-fip 0 90 atf-fip 0',
5022 ' soc-fw 88 4 blob-ext 88',
5023 ' u-boot 8c 4 u-boot 8c',
5024 ' fdtmap 90 243 fdtmap 90',
5026 self.assertEqual(expected, lines)
5028 image = control.images['image']
5029 entries = image.GetEntries()
5030 fdtmap = entries['fdtmap']
5032 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5033 magic = fdtmap_data[:8]
5034 self.assertEqual(b'_FDTMAP_', magic)
5035 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
5037 fdt_data = fdtmap_data[16:]
5038 dtb = fdt.Fdt.FromData(fdt_data)
5040 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5042 'atf-fip/soc-fw:image-pos': 136,
5043 'atf-fip/soc-fw:offset': 136,
5044 'atf-fip/soc-fw:size': 4,
5045 'atf-fip/u-boot:image-pos': 140,
5046 'atf-fip/u-boot:offset': 140,
5047 'atf-fip/u-boot:size': 4,
5048 'atf-fip:image-pos': 0,
5049 'atf-fip:offset': 0,
5050 'atf-fip:size': 144,
5053 'fdtmap:image-pos': fdtmap.image_pos,
5054 'fdtmap:offset': fdtmap.offset,
5055 'fdtmap:size': len(fdtmap_data),
5059 def testFipExtractOneEntry(self):
5060 """Test extracting a single entry fron an FIP"""
5061 self._DoReadFileRealDtb('207_fip_ls.dts')
5062 image_fname = tools.get_output_filename('image.bin')
5063 fname = os.path.join(self._indir, 'output.extact')
5064 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
5065 data = tools.read_file(fname)
5066 self.assertEqual(U_BOOT_DATA, data)
5068 def testFipReplace(self):
5069 """Test replacing a single file in a FIP"""
5070 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
5071 data = self._DoReadFileRealDtb('208_fip_replace.dts')
5072 updated_fname = tools.get_output_filename('image-updated.bin')
5073 tools.write_file(updated_fname, data)
5074 entry_name = 'atf-fip/u-boot'
5075 control.WriteEntry(updated_fname, entry_name, expected,
5077 actual = control.ReadEntry(updated_fname, entry_name)
5078 self.assertEqual(expected, actual)
5080 new_data = tools.read_file(updated_fname)
5081 hdr, fents = fip_util.decode_fip(new_data)
5083 self.assertEqual(2, len(fents))
5085 # Check that the FIP entry is updated
5087 self.assertEqual(0x8c, fent.offset)
5088 self.assertEqual(len(expected), fent.size)
5089 self.assertEqual(0, fent.flags)
5090 self.assertEqual(expected, fent.data)
5091 self.assertEqual(True, fent.valid)
5093 def testFipMissing(self):
5094 with test_util.capture_sys_output() as (stdout, stderr):
5095 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5096 err = stderr.getvalue()
5097 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5099 def testFipSize(self):
5100 """Test a FIP with a size property"""
5101 data = self._DoReadFile('210_fip_size.dts')
5102 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5103 hdr, fents = fip_util.decode_fip(data)
5104 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5105 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5107 self.assertEqual(1, len(fents))
5110 self.assertEqual('soc-fw', fent.fip_type)
5111 self.assertEqual(0x60, fent.offset)
5112 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5113 self.assertEqual(ATF_BL31_DATA, fent.data)
5114 self.assertEqual(True, fent.valid)
5116 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
5117 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
5119 def testFipBadAlign(self):
5120 """Test that an invalid alignment value in a FIP is detected"""
5121 with self.assertRaises(ValueError) as e:
5122 self._DoTestFile('211_fip_bad_align.dts')
5124 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5127 def testFipCollection(self):
5128 """Test using a FIP in a collection"""
5129 data = self._DoReadFile('212_fip_collection.dts')
5130 entry1 = control.images['image'].GetEntries()['collection']
5131 data1 = data[:entry1.size]
5132 hdr1, fents2 = fip_util.decode_fip(data1)
5134 entry2 = control.images['image'].GetEntries()['atf-fip']
5135 data2 = data[entry2.offset:entry2.offset + entry2.size]
5136 hdr1, fents2 = fip_util.decode_fip(data2)
5138 # The 'collection' entry should have U-Boot included at the end
5139 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5140 self.assertEqual(data1, data2 + U_BOOT_DATA)
5141 self.assertEqual(U_BOOT_DATA, data1[-4:])
5143 # There should be a U-Boot after the final FIP
5144 self.assertEqual(U_BOOT_DATA, data[-4:])
5146 def testFakeBlob(self):
5147 """Test handling of faking an external blob"""
5148 with test_util.capture_sys_output() as (stdout, stderr):
5149 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5150 allow_fake_blobs=True)
5151 err = stderr.getvalue()
5154 "Image '.*' has faked external blobs and is non-functional: .*")
5156 def testExtblobListFaked(self):
5157 """Test an extblob with missing external blob that are faked"""
5158 with test_util.capture_sys_output() as (stdout, stderr):
5159 self._DoTestFile('216_blob_ext_list_missing.dts',
5160 allow_fake_blobs=True)
5161 err = stderr.getvalue()
5162 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5164 def testListBintools(self):
5165 args = ['tool', '--list']
5166 with test_util.capture_sys_output() as (stdout, _):
5167 self._DoBinman(*args)
5168 out = stdout.getvalue().splitlines()
5169 self.assertTrue(len(out) >= 2)
5171 def testFetchBintools(self):
5172 def fail_download(url):
5173 """Take the tools.download() function by raising an exception"""
5174 raise urllib.error.URLError('my error')
5177 with self.assertRaises(ValueError) as e:
5178 self._DoBinman(*args)
5179 self.assertIn("Invalid arguments to 'tool' subcommand",
5182 args = ['tool', '--fetch']
5183 with self.assertRaises(ValueError) as e:
5184 self._DoBinman(*args)
5185 self.assertIn('Please specify bintools to fetch', str(e.exception))
5187 args = ['tool', '--fetch', '_testing']
5188 with unittest.mock.patch.object(tools, 'download',
5189 side_effect=fail_download):
5190 with test_util.capture_sys_output() as (stdout, _):
5191 self._DoBinman(*args)
5192 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5194 def testInvalidCompress(self):
5195 with self.assertRaises(ValueError) as e:
5196 comp_util.compress(b'', 'invalid')
5197 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5199 with self.assertRaises(ValueError) as e:
5200 comp_util.decompress(b'1234', 'invalid')
5201 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5203 def testBintoolDocs(self):
5204 """Test for creation of bintool documentation"""
5205 with test_util.capture_sys_output() as (stdout, stderr):
5206 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5207 self.assertTrue(len(stdout.getvalue()) > 0)
5209 def testBintoolDocsMissing(self):
5210 """Test handling of missing bintool documentation"""
5211 with self.assertRaises(ValueError) as e:
5212 with test_util.capture_sys_output() as (stdout, stderr):
5213 control.write_bintool_docs(
5214 control.bintool.Bintool.get_tool_list(), 'mkimage')
5215 self.assertIn('Documentation is missing for modules: mkimage',
5218 def testListWithGenNode(self):
5219 """Check handling of an FDT map when the section cannot be found"""
5221 'of-list': 'test-fdt1 test-fdt2',
5223 data = self._DoReadFileDtb(
5224 '219_fit_gennode.dts',
5225 entry_args=entry_args,
5227 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5230 tmpdir, updated_fname = self._SetupImageInTmpdir()
5231 with test_util.capture_sys_output() as (stdout, stderr):
5232 self._RunBinman('ls', '-i', updated_fname)
5234 shutil.rmtree(tmpdir)
5236 def testFitSubentryUsesBintool(self):
5237 """Test that binman FIT subentries can use bintools"""
5238 command.test_result = self._HandleGbbCommand
5240 'keydir': 'devkeys',
5241 'bmpblk': 'bmpblk.bin',
5243 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5244 entry_args=entry_args)
5246 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5247 tools.get_bytes(0, 0x2180 - 16))
5248 self.assertIn(expected, data)
5250 def testFitSubentryMissingBintool(self):
5251 """Test that binman reports missing bintools for FIT subentries"""
5253 'keydir': 'devkeys',
5255 with test_util.capture_sys_output() as (_, stderr):
5256 self._DoTestFile('220_fit_subentry_bintool.dts',
5257 force_missing_bintools='futility', entry_args=entry_args)
5258 err = stderr.getvalue()
5259 self.assertRegex(err,
5260 "Image 'main-section'.*missing bintools.*: futility")
5262 def testFitSubentryHashSubnode(self):
5263 """Test an image with a FIT inside"""
5264 data, _, _, out_dtb_name = self._DoReadFileDtb(
5265 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5267 mkimage_dtb = fdt.Fdt.FromData(data)
5269 binman_dtb = fdt.Fdt(out_dtb_name)
5272 # Check that binman didn't add hash values
5273 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5274 self.assertNotIn('value', fnode.props)
5276 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5277 self.assertNotIn('value', fnode.props)
5279 # Check that mkimage added hash values
5280 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5281 self.assertIn('value', fnode.props)
5283 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5284 self.assertIn('value', fnode.props)
5286 def testPackTeeOs(self):
5287 """Test that an image with an TEE binary can be created"""
5288 data = self._DoReadFile('222_tee_os.dts')
5289 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5291 def testFitFdtOper(self):
5292 """Check handling of a specified FIT operation"""
5294 'of-list': 'test-fdt1 test-fdt2',
5295 'default-dt': 'test-fdt2',
5297 self._DoReadFileDtb(
5298 '223_fit_fdt_oper.dts',
5299 entry_args=entry_args,
5300 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5302 def testFitFdtBadOper(self):
5303 """Check handling of an FDT map when the section cannot be found"""
5304 with self.assertRaises(ValueError) as exc:
5305 self._DoReadFileDtb('224_fit_bad_oper.dts')
5306 self.assertIn("Node '/binman/fit': Unknown operation 'unknown'",
5309 def test_uses_expand_size(self):
5310 """Test that the 'expand-size' property cannot be used anymore"""
5311 with self.assertRaises(ValueError) as e:
5312 data = self._DoReadFile('225_expand_size_bad.dts')
5314 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5317 def testMkimageMissingBlob(self):
5318 """Test using mkimage to build an image"""
5319 with test_util.capture_sys_output() as (stdout, stderr):
5320 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5321 allow_fake_blobs=True)
5322 err = stderr.getvalue()
5325 "Image '.*' has faked external blobs and is non-functional: .*")
5328 if __name__ == "__main__":