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 testExpandSize(self):
2032 """Test an expanding entry"""
2033 data, _, map_data, _ = self._DoReadFileDtb('088_expand_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 testExpandSizeBad(self):
2054 """Test an expanding 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_expand_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 expanding an entry after it is packed"""
2491 data = self._DoReadFile('121_entry_expand.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 testEntryExpandBad(self):
2497 """Test expanding an entry after it is packed, twice"""
2498 with self.assertRaises(ValueError) as e:
2499 self._DoReadFile('122_entry_expand_twice.dts')
2500 self.assertIn("Image '/binman': Entries changed size after packing",
2503 def testEntryExpandSection(self):
2504 """Test expanding an entry within a section after it is packed"""
2505 data = self._DoReadFile('123_entry_expand_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)
3788 'u-boot:image-pos': 0,
3796 'fit/images/kernel:image-pos': 160,
3797 'fit/images/kernel:offset': 156,
3798 'fit/images/kernel:size': 4,
3800 'fit/images/kernel/u-boot:image-pos': 160,
3801 'fit/images/kernel/u-boot:offset': 0,
3802 'fit/images/kernel/u-boot:size': 4,
3804 'fit/images/fdt-1:image-pos': 456,
3805 'fit/images/fdt-1:offset': 452,
3806 'fit/images/fdt-1:size': 6,
3808 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 456,
3809 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3810 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3812 'u-boot-nodtb:image-pos': 1844,
3813 'u-boot-nodtb:offset': 1844,
3814 'u-boot-nodtb:size': 46,
3817 # Actually check the data is where we think it is
3818 for node, expected in [
3819 ("u-boot", U_BOOT_DATA),
3820 ("fit/images/kernel", U_BOOT_DATA),
3821 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3822 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3823 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3824 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3826 image_pos = props[f"{node}:image-pos"]
3827 size = props[f"{node}:size"]
3828 self.assertEqual(len(expected), size)
3829 self.assertEqual(expected, data[image_pos:image_pos+size])
3831 def testFitExternal(self):
3832 """Test an image with an FIT with external images"""
3833 data = self._DoReadFile('162_fit_external.dts')
3834 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3836 # Size of the external-data region as set up by mkimage
3837 external_data_size = len(U_BOOT_DATA) + 2
3838 expected_size = (len(U_BOOT_DATA) + 0x400 +
3839 tools.align(external_data_size, 4) +
3840 len(U_BOOT_NODTB_DATA))
3842 # The data should be outside the FIT
3843 dtb = fdt.Fdt.FromData(fit_data)
3845 fnode = dtb.GetNode('/images/kernel')
3846 self.assertNotIn('data', fnode.props)
3847 self.assertEqual(len(U_BOOT_DATA),
3848 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3852 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3854 self.assertEquals(expected_size, len(data))
3855 actual_pos = len(U_BOOT_DATA) + fit_pos
3856 self.assertEqual(U_BOOT_DATA + b'aa',
3857 data[actual_pos:actual_pos + external_data_size])
3859 def testFitExternalImagePos(self):
3860 """Test that we have correct image-pos for external FIT subentries"""
3861 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3863 dtb = fdt.Fdt(out_dtb_fname)
3865 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3872 'u-boot:image-pos': 0,
3880 'fit/images/kernel:size': 4,
3881 'fit/images/kernel:offset': 1024,
3882 'fit/images/kernel:image-pos': 1028,
3884 'fit/images/kernel/u-boot:size': 4,
3885 'fit/images/kernel/u-boot:offset': 0,
3886 'fit/images/kernel/u-boot:image-pos': 1028,
3888 'fit/images/fdt-1:size': 2,
3889 'fit/images/fdt-1:offset': 1028,
3890 'fit/images/fdt-1:image-pos': 1032,
3892 'fit/images/fdt-1/_testing:size': 2,
3893 'fit/images/fdt-1/_testing:offset': 0,
3894 'fit/images/fdt-1/_testing:image-pos': 1032,
3896 'u-boot-nodtb:image-pos': 1036,
3897 'u-boot-nodtb:offset': 1036,
3898 'u-boot-nodtb:size': 46,
3901 # Actually check the data is where we think it is
3902 for node, expected in [
3903 ("u-boot", U_BOOT_DATA),
3904 ("fit/images/kernel", U_BOOT_DATA),
3905 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3906 ("fit/images/fdt-1", b'aa'),
3907 ("fit/images/fdt-1/_testing", b'aa'),
3908 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3910 image_pos = props[f"{node}:image-pos"]
3911 size = props[f"{node}:size"]
3912 self.assertEqual(len(expected), size)
3913 self.assertEqual(expected, data[image_pos:image_pos+size])
3915 def testFitMissing(self):
3916 """Test that binman still produces a FIT image if mkimage is missing"""
3917 with test_util.capture_sys_output() as (_, stderr):
3918 self._DoTestFile('162_fit_external.dts',
3919 force_missing_bintools='mkimage')
3920 err = stderr.getvalue()
3921 self.assertRegex(err,
3922 "Image 'main-section'.*missing bintools.*: mkimage")
3924 def testSectionIgnoreHashSignature(self):
3925 """Test that sections ignore hash, signature nodes for its data"""
3926 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3927 expected = (U_BOOT_DATA + U_BOOT_DATA)
3928 self.assertEqual(expected, data)
3930 def testPadInSections(self):
3931 """Test pad-before, pad-after for entries in sections"""
3932 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3933 '166_pad_in_sections.dts', update_dtb=True)
3934 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3935 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
3937 self.assertEqual(expected, data)
3939 dtb = fdt.Fdt(out_dtb_fname)
3941 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3945 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3947 'section:image-pos': 0,
3948 'section:offset': 0,
3949 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3951 'section/before:image-pos': 0,
3952 'section/before:offset': 0,
3953 'section/before:size': len(U_BOOT_DATA),
3955 'section/u-boot:image-pos': 4,
3956 'section/u-boot:offset': 4,
3957 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3959 'section/after:image-pos': 26,
3960 'section/after:offset': 26,
3961 'section/after:size': len(U_BOOT_DATA),
3963 self.assertEqual(expected, props)
3965 def testFitImageSubentryAlignment(self):
3966 """Test relative alignability of FIT image subentries"""
3969 'test-id': TEXT_DATA,
3971 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3972 entry_args=entry_args)
3973 dtb = fdt.Fdt.FromData(data)
3976 node = dtb.GetNode('/images/kernel')
3977 data = dtb.GetProps(node)["data"].bytes
3978 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3979 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3980 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
3981 self.assertEqual(expected, data)
3983 node = dtb.GetNode('/images/fdt-1')
3984 data = dtb.GetProps(node)["data"].bytes
3985 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
3986 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
3988 self.assertEqual(expected, data)
3990 def testFitExtblobMissingOk(self):
3991 """Test a FIT with a missing external blob that is allowed"""
3992 with test_util.capture_sys_output() as (stdout, stderr):
3993 self._DoTestFile('168_fit_missing_blob.dts',
3995 err = stderr.getvalue()
3996 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3998 def testBlobNamedByArgMissing(self):
3999 """Test handling of a missing entry arg"""
4000 with self.assertRaises(ValueError) as e:
4001 self._DoReadFile('068_blob_named_by_arg.dts')
4002 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4005 def testPackBl31(self):
4006 """Test that an image with an ATF BL31 binary can be created"""
4007 data = self._DoReadFile('169_atf_bl31.dts')
4008 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4010 def testPackScp(self):
4011 """Test that an image with an SCP binary can be created"""
4012 data = self._DoReadFile('172_scp.dts')
4013 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4015 def testFitFdt(self):
4016 """Test an image with an FIT with multiple FDT images"""
4017 def _CheckFdt(seq, expected_data):
4018 """Check the FDT nodes
4021 seq: Sequence number to check (0 or 1)
4022 expected_data: Expected contents of 'data' property
4024 name = 'fdt-%d' % seq
4025 fnode = dtb.GetNode('/images/%s' % name)
4026 self.assertIsNotNone(fnode)
4027 self.assertEqual({'description','type', 'compression', 'data'},
4028 set(fnode.props.keys()))
4029 self.assertEqual(expected_data, fnode.props['data'].bytes)
4030 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4031 fnode.props['description'].value)
4033 def _CheckConfig(seq, expected_data):
4034 """Check the configuration nodes
4037 seq: Sequence number to check (0 or 1)
4038 expected_data: Expected contents of 'data' property
4040 cnode = dtb.GetNode('/configurations')
4041 self.assertIn('default', cnode.props)
4042 self.assertEqual('config-2', cnode.props['default'].value)
4044 name = 'config-%d' % seq
4045 fnode = dtb.GetNode('/configurations/%s' % name)
4046 self.assertIsNotNone(fnode)
4047 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4048 set(fnode.props.keys()))
4049 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4050 fnode.props['description'].value)
4051 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4054 'of-list': 'test-fdt1 test-fdt2',
4055 'default-dt': 'test-fdt2',
4057 data = self._DoReadFileDtb(
4059 entry_args=entry_args,
4060 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4061 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4062 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4064 dtb = fdt.Fdt.FromData(fit_data)
4066 fnode = dtb.GetNode('/images/kernel')
4067 self.assertIn('data', fnode.props)
4069 # Check all the properties in fdt-1 and fdt-2
4070 _CheckFdt(1, TEST_FDT1_DATA)
4071 _CheckFdt(2, TEST_FDT2_DATA)
4073 # Check configurations
4074 _CheckConfig(1, TEST_FDT1_DATA)
4075 _CheckConfig(2, TEST_FDT2_DATA)
4077 def testFitFdtMissingList(self):
4078 """Test handling of a missing 'of-list' entry arg"""
4079 with self.assertRaises(ValueError) as e:
4080 self._DoReadFile('170_fit_fdt.dts')
4081 self.assertIn("Generator node requires 'of-list' entry argument",
4084 def testFitFdtEmptyList(self):
4085 """Test handling of an empty 'of-list' entry arg"""
4089 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4091 def testFitFdtMissingProp(self):
4092 """Test handling of a missing 'fit,fdt-list' property"""
4093 with self.assertRaises(ValueError) as e:
4094 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4095 self.assertIn("Generator node requires 'fit,fdt-list' property",
4098 def testFitFdtMissing(self):
4099 """Test handling of a missing 'default-dt' entry arg"""
4101 'of-list': 'test-fdt1 test-fdt2',
4103 with self.assertRaises(ValueError) as e:
4104 self._DoReadFileDtb(
4106 entry_args=entry_args,
4107 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4108 self.assertIn("Generated 'default' node requires default-dt entry argument",
4111 def testFitFdtNotInList(self):
4112 """Test handling of a default-dt that is not in the of-list"""
4114 'of-list': 'test-fdt1 test-fdt2',
4115 'default-dt': 'test-fdt3',
4117 with self.assertRaises(ValueError) as e:
4118 self._DoReadFileDtb(
4120 entry_args=entry_args,
4121 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4122 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4125 def testFitExtblobMissingHelp(self):
4126 """Test display of help messages when an external blob is missing"""
4127 control.missing_blob_help = control._ReadMissingBlobHelp()
4128 control.missing_blob_help['wibble'] = 'Wibble test'
4129 control.missing_blob_help['another'] = 'Another test'
4130 with test_util.capture_sys_output() as (stdout, stderr):
4131 self._DoTestFile('168_fit_missing_blob.dts',
4133 err = stderr.getvalue()
4135 # We can get the tag from the name, the type or the missing-msg
4136 # property. Check all three.
4137 self.assertIn('You may need to build ARM Trusted', err)
4138 self.assertIn('Wibble test', err)
4139 self.assertIn('Another test', err)
4141 def testMissingBlob(self):
4142 """Test handling of a blob containing a missing file"""
4143 with self.assertRaises(ValueError) as e:
4144 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4145 self.assertIn("Filename 'missing' not found in input path",
4148 def testEnvironment(self):
4149 """Test adding a U-Boot environment"""
4150 data = self._DoReadFile('174_env.dts')
4151 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4152 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4153 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4154 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4157 def testEnvironmentNoSize(self):
4158 """Test that a missing 'size' property is detected"""
4159 with self.assertRaises(ValueError) as e:
4160 self._DoTestFile('175_env_no_size.dts')
4161 self.assertIn("'u-boot-env' entry must have a size property",
4164 def testEnvironmentTooSmall(self):
4165 """Test handling of an environment that does not fit"""
4166 with self.assertRaises(ValueError) as e:
4167 self._DoTestFile('176_env_too_small.dts')
4169 # checksum, start byte, environment with \0 terminator, final \0
4170 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4172 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4175 def testSkipAtStart(self):
4176 """Test handling of skip-at-start section"""
4177 data = self._DoReadFile('177_skip_at_start.dts')
4178 self.assertEqual(U_BOOT_DATA, data)
4180 image = control.images['image']
4181 entries = image.GetEntries()
4182 section = entries['section']
4183 self.assertEqual(0, section.offset)
4184 self.assertEqual(len(U_BOOT_DATA), section.size)
4185 self.assertEqual(U_BOOT_DATA, section.GetData())
4187 entry = section.GetEntries()['u-boot']
4188 self.assertEqual(16, entry.offset)
4189 self.assertEqual(len(U_BOOT_DATA), entry.size)
4190 self.assertEqual(U_BOOT_DATA, entry.data)
4192 def testSkipAtStartPad(self):
4193 """Test handling of skip-at-start section with padded entry"""
4194 data = self._DoReadFile('178_skip_at_start_pad.dts')
4195 before = tools.get_bytes(0, 8)
4196 after = tools.get_bytes(0, 4)
4197 all = before + U_BOOT_DATA + after
4198 self.assertEqual(all, data)
4200 image = control.images['image']
4201 entries = image.GetEntries()
4202 section = entries['section']
4203 self.assertEqual(0, section.offset)
4204 self.assertEqual(len(all), section.size)
4205 self.assertEqual(all, section.GetData())
4207 entry = section.GetEntries()['u-boot']
4208 self.assertEqual(16, entry.offset)
4209 self.assertEqual(len(all), entry.size)
4210 self.assertEqual(U_BOOT_DATA, entry.data)
4212 def testSkipAtStartSectionPad(self):
4213 """Test handling of skip-at-start section with padding"""
4214 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4215 before = tools.get_bytes(0, 8)
4216 after = tools.get_bytes(0, 4)
4217 all = before + U_BOOT_DATA + after
4218 self.assertEqual(all, data)
4220 image = control.images['image']
4221 entries = image.GetEntries()
4222 section = entries['section']
4223 self.assertEqual(0, section.offset)
4224 self.assertEqual(len(all), section.size)
4225 self.assertEqual(U_BOOT_DATA, section.data)
4226 self.assertEqual(all, section.GetPaddedData())
4228 entry = section.GetEntries()['u-boot']
4229 self.assertEqual(16, entry.offset)
4230 self.assertEqual(len(U_BOOT_DATA), entry.size)
4231 self.assertEqual(U_BOOT_DATA, entry.data)
4233 def testSectionPad(self):
4234 """Testing padding with sections"""
4235 data = self._DoReadFile('180_section_pad.dts')
4236 expected = (tools.get_bytes(ord('&'), 3) +
4237 tools.get_bytes(ord('!'), 5) +
4239 tools.get_bytes(ord('!'), 1) +
4240 tools.get_bytes(ord('&'), 2))
4241 self.assertEqual(expected, data)
4243 def testSectionAlign(self):
4244 """Testing alignment with sections"""
4245 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4246 expected = (b'\0' + # fill section
4247 tools.get_bytes(ord('&'), 1) + # padding to section align
4248 b'\0' + # fill section
4249 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
4251 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4252 tools.get_bytes(ord('!'), 4)) # padding to section size
4253 self.assertEqual(expected, data)
4255 def testCompressImage(self):
4256 """Test compression of the entire image"""
4258 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4259 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4260 dtb = fdt.Fdt(out_dtb_fname)
4262 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4264 orig = self._decompress(data)
4265 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4267 # Do a sanity check on various fields
4268 image = control.images['image']
4269 entries = image.GetEntries()
4270 self.assertEqual(2, len(entries))
4272 entry = entries['blob']
4273 self.assertEqual(COMPRESS_DATA, entry.data)
4274 self.assertEqual(len(COMPRESS_DATA), entry.size)
4276 entry = entries['u-boot']
4277 self.assertEqual(U_BOOT_DATA, entry.data)
4278 self.assertEqual(len(U_BOOT_DATA), entry.size)
4280 self.assertEqual(len(data), image.size)
4281 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4282 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4283 orig = self._decompress(image.data)
4284 self.assertEqual(orig, image.uncomp_data)
4288 'blob:size': len(COMPRESS_DATA),
4289 'u-boot:offset': len(COMPRESS_DATA),
4290 'u-boot:size': len(U_BOOT_DATA),
4291 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4296 self.assertEqual(expected, props)
4298 def testCompressImageLess(self):
4299 """Test compression where compression reduces the image size"""
4301 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4302 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4303 dtb = fdt.Fdt(out_dtb_fname)
4305 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4307 orig = self._decompress(data)
4309 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4311 # Do a sanity check on various fields
4312 image = control.images['image']
4313 entries = image.GetEntries()
4314 self.assertEqual(2, len(entries))
4316 entry = entries['blob']
4317 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4318 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4320 entry = entries['u-boot']
4321 self.assertEqual(U_BOOT_DATA, entry.data)
4322 self.assertEqual(len(U_BOOT_DATA), entry.size)
4324 self.assertEqual(len(data), image.size)
4325 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4326 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4328 orig = self._decompress(image.data)
4329 self.assertEqual(orig, image.uncomp_data)
4333 'blob:size': len(COMPRESS_DATA_BIG),
4334 'u-boot:offset': len(COMPRESS_DATA_BIG),
4335 'u-boot:size': len(U_BOOT_DATA),
4336 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4341 self.assertEqual(expected, props)
4343 def testCompressSectionSize(self):
4344 """Test compression of a section with a fixed size"""
4346 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4347 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4348 dtb = fdt.Fdt(out_dtb_fname)
4350 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4352 orig = self._decompress(data)
4353 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4355 'section/blob:offset': 0,
4356 'section/blob:size': len(COMPRESS_DATA),
4357 'section/u-boot:offset': len(COMPRESS_DATA),
4358 'section/u-boot:size': len(U_BOOT_DATA),
4359 'section:offset': 0,
4360 'section:image-pos': 0,
4361 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4362 'section:size': 0x30,
4367 self.assertEqual(expected, props)
4369 def testCompressSection(self):
4370 """Test compression of a section with no fixed size"""
4372 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4373 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4374 dtb = fdt.Fdt(out_dtb_fname)
4376 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4378 orig = self._decompress(data)
4379 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4381 'section/blob:offset': 0,
4382 'section/blob:size': len(COMPRESS_DATA),
4383 'section/u-boot:offset': len(COMPRESS_DATA),
4384 'section/u-boot:size': len(U_BOOT_DATA),
4385 'section:offset': 0,
4386 'section:image-pos': 0,
4387 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4388 'section:size': len(data),
4393 self.assertEqual(expected, props)
4395 def testCompressExtra(self):
4396 """Test compression of a section with no fixed size"""
4398 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4399 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4400 dtb = fdt.Fdt(out_dtb_fname)
4402 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4405 base = data[len(U_BOOT_DATA):]
4406 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4407 rest = base[len(U_BOOT_DATA):]
4409 # Check compressed data
4410 section1 = self._decompress(rest)
4411 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4412 self.assertEquals(expect1, rest[:len(expect1)])
4413 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4414 rest1 = rest[len(expect1):]
4416 section2 = self._decompress(rest1)
4417 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4418 self.assertEquals(expect2, rest1[:len(expect2)])
4419 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4420 rest2 = rest1[len(expect2):]
4422 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4423 len(expect2) + len(U_BOOT_DATA))
4424 #self.assertEquals(expect_size, len(data))
4426 #self.assertEquals(U_BOOT_DATA, rest2)
4431 'u-boot:image-pos': 0,
4432 'u-boot:size': len(U_BOOT_DATA),
4434 'base:offset': len(U_BOOT_DATA),
4435 'base:image-pos': len(U_BOOT_DATA),
4436 'base:size': len(data) - len(U_BOOT_DATA),
4437 'base/u-boot:offset': 0,
4438 'base/u-boot:image-pos': len(U_BOOT_DATA),
4439 'base/u-boot:size': len(U_BOOT_DATA),
4440 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4442 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4444 'base/u-boot2:size': len(U_BOOT_DATA),
4446 'base/section:offset': len(U_BOOT_DATA),
4447 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4448 'base/section:size': len(expect1),
4449 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4450 'base/section/blob:offset': 0,
4451 'base/section/blob:size': len(COMPRESS_DATA),
4452 'base/section/u-boot:offset': len(COMPRESS_DATA),
4453 'base/section/u-boot:size': len(U_BOOT_DATA),
4455 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4456 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4457 'base/section2:size': len(expect2),
4458 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4459 'base/section2/blob:offset': 0,
4460 'base/section2/blob:size': len(COMPRESS_DATA),
4461 'base/section2/blob2:offset': len(COMPRESS_DATA),
4462 'base/section2/blob2:size': len(COMPRESS_DATA),
4468 self.assertEqual(expected, props)
4470 def testSymbolsSubsection(self):
4471 """Test binman can assign symbols from a subsection"""
4472 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4474 def testReadImageEntryArg(self):
4475 """Test reading an image that would need an entry arg to generate"""
4477 'cros-ec-rw-path': 'ecrw.bin',
4479 data = self.data = self._DoReadFileDtb(
4480 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4481 entry_args=entry_args)
4483 image_fname = tools.get_output_filename('image.bin')
4484 orig_image = control.images['image']
4486 # This should not generate an error about the missing 'cros-ec-rw-path'
4487 # since we are reading the image from a file. Compare with
4488 # testEntryArgsRequired()
4489 image = Image.FromFile(image_fname)
4490 self.assertEqual(orig_image.GetEntries().keys(),
4491 image.GetEntries().keys())
4493 def testFilesAlign(self):
4494 """Test alignment with files"""
4495 data = self._DoReadFile('190_files_align.dts')
4497 # The first string is 15 bytes so will align to 16
4498 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4499 self.assertEqual(expect, data)
4501 def testReadImageSkip(self):
4502 """Test reading an image and accessing its FDT map"""
4503 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4504 image_fname = tools.get_output_filename('image.bin')
4505 orig_image = control.images['image']
4506 image = Image.FromFile(image_fname)
4507 self.assertEqual(orig_image.GetEntries().keys(),
4508 image.GetEntries().keys())
4510 orig_entry = orig_image.GetEntries()['fdtmap']
4511 entry = image.GetEntries()['fdtmap']
4512 self.assertEqual(orig_entry.offset, entry.offset)
4513 self.assertEqual(orig_entry.size, entry.size)
4514 self.assertEqual(16, entry.image_pos)
4516 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4518 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4520 def testTplNoDtb(self):
4521 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4523 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4524 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4525 data[:len(U_BOOT_TPL_NODTB_DATA)])
4527 def testTplBssPad(self):
4528 """Test that we can pad TPL's BSS with zeros"""
4529 # ELF file with a '__bss_size' symbol
4531 data = self._DoReadFile('193_tpl_bss_pad.dts')
4532 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
4535 def testTplBssPadMissing(self):
4536 """Test that a missing symbol is detected"""
4537 self._SetupTplElf('u_boot_ucode_ptr')
4538 with self.assertRaises(ValueError) as e:
4539 self._DoReadFile('193_tpl_bss_pad.dts')
4540 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4543 def checkDtbSizes(self, data, pad_len, start):
4544 """Check the size arguments in a dtb embedded in an image
4547 data: The image data
4548 pad_len: Length of the pad section in the image, in bytes
4549 start: Start offset of the devicetree to examine, within the image
4552 Size of the devicetree in bytes
4554 dtb_data = data[start:]
4555 dtb = fdt.Fdt.FromData(dtb_data)
4556 fdt_size = dtb.GetFdtObj().totalsize()
4558 props = self._GetPropTree(dtb, 'size')
4561 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4562 'u-boot-spl/u-boot-spl-dtb:size': 801,
4563 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4564 'u-boot-spl:size': 860,
4565 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4566 'u-boot/u-boot-dtb:size': 781,
4567 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4572 def testExpanded(self):
4573 """Test that an expanded entry type is selected when needed"""
4577 # SPL has a devicetree, TPL does not
4583 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4584 entry_args=entry_args)
4585 image = control.images['image']
4586 entries = image.GetEntries()
4587 self.assertEqual(3, len(entries))
4589 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4590 self.assertIn('u-boot', entries)
4591 entry = entries['u-boot']
4592 self.assertEqual('u-boot-expanded', entry.etype)
4593 subent = entry.GetEntries()
4594 self.assertEqual(2, len(subent))
4595 self.assertIn('u-boot-nodtb', subent)
4596 self.assertIn('u-boot-dtb', subent)
4598 # Second, u-boot-spl, which should be expanded into three parts
4599 self.assertIn('u-boot-spl', entries)
4600 entry = entries['u-boot-spl']
4601 self.assertEqual('u-boot-spl-expanded', entry.etype)
4602 subent = entry.GetEntries()
4603 self.assertEqual(3, len(subent))
4604 self.assertIn('u-boot-spl-nodtb', subent)
4605 self.assertIn('u-boot-spl-bss-pad', subent)
4606 self.assertIn('u-boot-spl-dtb', subent)
4608 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4610 self.assertIn('u-boot-tpl', entries)
4611 entry = entries['u-boot-tpl']
4612 self.assertEqual('u-boot-tpl', entry.etype)
4613 self.assertEqual(None, entry.GetEntries())
4615 def testExpandedTpl(self):
4616 """Test that an expanded entry type is selected for TPL when needed"""
4623 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4624 entry_args=entry_args)
4625 image = control.images['image']
4626 entries = image.GetEntries()
4627 self.assertEqual(1, len(entries))
4629 # We only have u-boot-tpl, which be expanded
4630 self.assertIn('u-boot-tpl', entries)
4631 entry = entries['u-boot-tpl']
4632 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4633 subent = entry.GetEntries()
4634 self.assertEqual(3, len(subent))
4635 self.assertIn('u-boot-tpl-nodtb', subent)
4636 self.assertIn('u-boot-tpl-bss-pad', subent)
4637 self.assertIn('u-boot-tpl-dtb', subent)
4639 def testExpandedNoPad(self):
4640 """Test an expanded entry without BSS pad enabled"""
4644 # SPL has a devicetree, TPL does not
4646 'spl-dtb': 'something',
4650 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4651 entry_args=entry_args)
4652 image = control.images['image']
4653 entries = image.GetEntries()
4655 # Just check u-boot-spl, which should be expanded into two parts
4656 self.assertIn('u-boot-spl', entries)
4657 entry = entries['u-boot-spl']
4658 self.assertEqual('u-boot-spl-expanded', entry.etype)
4659 subent = entry.GetEntries()
4660 self.assertEqual(2, len(subent))
4661 self.assertIn('u-boot-spl-nodtb', subent)
4662 self.assertIn('u-boot-spl-dtb', subent)
4664 def testExpandedTplNoPad(self):
4665 """Test that an expanded entry type with padding disabled in TPL"""
4672 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4673 entry_args=entry_args)
4674 image = control.images['image']
4675 entries = image.GetEntries()
4676 self.assertEqual(1, len(entries))
4678 # We only have u-boot-tpl, which be expanded
4679 self.assertIn('u-boot-tpl', entries)
4680 entry = entries['u-boot-tpl']
4681 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4682 subent = entry.GetEntries()
4683 self.assertEqual(2, len(subent))
4684 self.assertIn('u-boot-tpl-nodtb', subent)
4685 self.assertIn('u-boot-tpl-dtb', subent)
4687 def testFdtInclude(self):
4688 """Test that an Fdt is update within all binaries"""
4692 # SPL has a devicetree, TPL does not
4699 # Build the image. It includes two separate devicetree binaries, each
4700 # with their own contents, but all contain the binman definition.
4701 data = self._DoReadFileDtb(
4702 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4703 update_dtb=True, entry_args=entry_args)[0]
4706 # Check the U-Boot dtb
4707 start = len(U_BOOT_NODTB_DATA)
4708 fdt_size = self.checkDtbSizes(data, pad_len, start)
4711 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4712 fdt_size = self.checkDtbSizes(data, pad_len, start)
4714 # TPL has no devicetree
4715 start += fdt_size + len(U_BOOT_TPL_DATA)
4716 self.assertEqual(len(data), start)
4718 def testSymbolsExpanded(self):
4719 """Test binman can assign symbols in expanded entries"""
4723 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4724 U_BOOT_SPL_DTB_DATA, 0x38,
4725 entry_args=entry_args, use_expanded=True)
4727 def testCollection(self):
4728 """Test a collection"""
4729 data = self._DoReadFile('198_collection.dts')
4730 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4731 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4732 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
4735 def testCollectionSection(self):
4736 """Test a collection where a section must be built first"""
4737 # Sections never have their contents when GetData() is called, but when
4738 # BuildSectionData() is called with required=True, a section will force
4739 # building the contents, producing an error is anything is still
4741 data = self._DoReadFile('199_collection_section.dts')
4742 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4743 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4744 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
4747 def testAlignDefault(self):
4748 """Test that default alignment works on sections"""
4749 data = self._DoReadFile('200_align_default.dts')
4750 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
4752 # Special alignment for section
4753 expected += tools.get_bytes(0, 32 - len(expected))
4754 # No alignment within the nested section
4755 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4756 # Now the final piece, which should be default-aligned
4757 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4758 self.assertEqual(expected, data)
4760 def testPackOpenSBI(self):
4761 """Test that an image with an OpenSBI binary can be created"""
4762 data = self._DoReadFile('201_opensbi.dts')
4763 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4765 def testSectionsSingleThread(self):
4766 """Test sections without multithreading"""
4767 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4768 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4769 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4770 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
4771 self.assertEqual(expected, data)
4773 def testThreadTimeout(self):
4774 """Test handling a thread that takes too long"""
4775 with self.assertRaises(ValueError) as e:
4776 self._DoTestFile('202_section_timeout.dts',
4777 test_section_timeout=True)
4778 self.assertIn("Timed out obtaining contents", str(e.exception))
4780 def testTiming(self):
4781 """Test output of timing information"""
4782 data = self._DoReadFile('055_sections.dts')
4783 with test_util.capture_sys_output() as (stdout, stderr):
4785 self.assertIn('read:', stdout.getvalue())
4786 self.assertIn('compress:', stdout.getvalue())
4788 def testUpdateFdtInElf(self):
4789 """Test that we can update the devicetree in an ELF file"""
4790 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4791 outfile = os.path.join(self._indir, 'u-boot.out')
4792 begin_sym = 'dtb_embed_begin'
4793 end_sym = 'dtb_embed_end'
4794 retcode = self._DoTestFile(
4795 '060_fdt_update.dts', update_dtb=True,
4796 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4797 self.assertEqual(0, retcode)
4799 # Check that the output file does in fact contact a dtb with the binman
4800 # definition in the correct place
4801 syms = elf.GetSymbolFileOffset(infile,
4802 ['dtb_embed_begin', 'dtb_embed_end'])
4803 data = tools.read_file(outfile)
4804 dtb_data = data[syms['dtb_embed_begin'].offset:
4805 syms['dtb_embed_end'].offset]
4807 dtb = fdt.Fdt.FromData(dtb_data)
4809 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4813 '_testing:offset': 32,
4815 '_testing:image-pos': 32,
4816 'section@0/u-boot:offset': 0,
4817 'section@0/u-boot:size': len(U_BOOT_DATA),
4818 'section@0/u-boot:image-pos': 0,
4819 'section@0:offset': 0,
4820 'section@0:size': 16,
4821 'section@0:image-pos': 0,
4823 'section@1/u-boot:offset': 0,
4824 'section@1/u-boot:size': len(U_BOOT_DATA),
4825 'section@1/u-boot:image-pos': 16,
4826 'section@1:offset': 16,
4827 'section@1:size': 16,
4828 'section@1:image-pos': 16,
4832 def testUpdateFdtInElfInvalid(self):
4833 """Test that invalid args are detected with --update-fdt-in-elf"""
4834 with self.assertRaises(ValueError) as e:
4835 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4836 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4839 def testUpdateFdtInElfNoSyms(self):
4840 """Test that missing symbols are detected with --update-fdt-in-elf"""
4841 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4843 begin_sym = 'wrong_begin'
4844 end_sym = 'wrong_end'
4845 with self.assertRaises(ValueError) as e:
4847 '060_fdt_update.dts',
4848 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4849 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4852 def testUpdateFdtInElfTooSmall(self):
4853 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4854 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4855 outfile = os.path.join(self._indir, 'u-boot.out')
4856 begin_sym = 'dtb_embed_begin'
4857 end_sym = 'dtb_embed_end'
4858 with self.assertRaises(ValueError) as e:
4860 '060_fdt_update.dts', update_dtb=True,
4861 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4864 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4866 def testVersion(self):
4867 """Test we can get the binman version"""
4868 version = '(unreleased)'
4869 self.assertEqual(version, state.GetVersion(self._indir))
4871 with self.assertRaises(SystemExit):
4872 with test_util.capture_sys_output() as (_, stderr):
4873 self._DoBinman('-V')
4874 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4876 # Try running the tool too, just to be safe
4877 result = self._RunBinman('-V')
4878 self.assertEqual('Binman %s\n' % version, result.stderr)
4880 # Set up a version file to make sure that works
4881 version = 'v2025.01-rc2'
4882 tools.write_file(os.path.join(self._indir, 'version'), version,
4884 self.assertEqual(version, state.GetVersion(self._indir))
4886 def testAltFormat(self):
4887 """Test that alternative formats can be used to extract"""
4888 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4891 tmpdir, updated_fname = self._SetupImageInTmpdir()
4892 with test_util.capture_sys_output() as (stdout, _):
4893 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4895 '''Flag (-F) Entry type Description
4896 fdt fdtmap Extract the devicetree blob from the fdtmap
4900 dtb = os.path.join(tmpdir, 'fdt.dtb')
4901 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4904 # Check that we can read it and it can be scanning, meaning it does
4905 # not have a 16-byte fdtmap header
4906 data = tools.read_file(dtb)
4907 dtb = fdt.Fdt.FromData(data)
4910 # Now check u-boot which has no alt_format
4911 fname = os.path.join(tmpdir, 'fdt.dtb')
4912 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4913 '-f', fname, 'u-boot')
4914 data = tools.read_file(fname)
4915 self.assertEqual(U_BOOT_DATA, data)
4918 shutil.rmtree(tmpdir)
4920 def testExtblobList(self):
4921 """Test an image with an external blob list"""
4922 data = self._DoReadFile('215_blob_ext_list.dts')
4923 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4925 def testExtblobListMissing(self):
4926 """Test an image with a missing external blob"""
4927 with self.assertRaises(ValueError) as e:
4928 self._DoReadFile('216_blob_ext_list_missing.dts')
4929 self.assertIn("Filename 'missing-file' not found in input path",
4932 def testExtblobListMissingOk(self):
4933 """Test an image with an missing external blob that is allowed"""
4934 with test_util.capture_sys_output() as (stdout, stderr):
4935 self._DoTestFile('216_blob_ext_list_missing.dts',
4937 err = stderr.getvalue()
4938 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4941 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4942 data = self._DoReadFile('203_fip.dts')
4943 hdr, fents = fip_util.decode_fip(data)
4944 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4945 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4946 self.assertEqual(0x123, hdr.flags)
4948 self.assertEqual(2, len(fents))
4952 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4953 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4954 self.assertEqual('soc-fw', fent.fip_type)
4955 self.assertEqual(0x88, fent.offset)
4956 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4957 self.assertEqual(0x123456789abcdef, fent.flags)
4958 self.assertEqual(ATF_BL31_DATA, fent.data)
4959 self.assertEqual(True, fent.valid)
4963 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4964 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4965 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4966 self.assertEqual(0x8c, fent.offset)
4967 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4968 self.assertEqual(0, fent.flags)
4969 self.assertEqual(ATF_BL2U_DATA, fent.data)
4970 self.assertEqual(True, fent.valid)
4972 def testFipOther(self):
4973 """Basic FIP with something that isn't a external blob"""
4974 data = self._DoReadFile('204_fip_other.dts')
4975 hdr, fents = fip_util.decode_fip(data)
4977 self.assertEqual(2, len(fents))
4979 self.assertEqual('rot-cert', fent.fip_type)
4980 self.assertEqual(b'aa', fent.data)
4982 def testFipNoType(self):
4983 """FIP with an entry of an unknown type"""
4984 with self.assertRaises(ValueError) as e:
4985 self._DoReadFile('205_fip_no_type.dts')
4986 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4989 def testFipUuid(self):
4990 """Basic FIP with a manual uuid"""
4991 data = self._DoReadFile('206_fip_uuid.dts')
4992 hdr, fents = fip_util.decode_fip(data)
4994 self.assertEqual(2, len(fents))
4996 self.assertEqual(None, fent.fip_type)
4998 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4999 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5001 self.assertEqual(U_BOOT_DATA, fent.data)
5003 def testFipLs(self):
5004 """Test listing a FIP"""
5005 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5006 hdr, fents = fip_util.decode_fip(data)
5009 tmpdir, updated_fname = self._SetupImageInTmpdir()
5010 with test_util.capture_sys_output() as (stdout, stderr):
5011 self._DoBinman('ls', '-i', updated_fname)
5013 shutil.rmtree(tmpdir)
5014 lines = stdout.getvalue().splitlines()
5016 'Name Image-pos Size Entry-type Offset Uncomp-size',
5017 '----------------------------------------------------------------',
5018 'main-section 0 2d3 section 0',
5019 ' atf-fip 0 90 atf-fip 0',
5020 ' soc-fw 88 4 blob-ext 88',
5021 ' u-boot 8c 4 u-boot 8c',
5022 ' fdtmap 90 243 fdtmap 90',
5024 self.assertEqual(expected, lines)
5026 image = control.images['image']
5027 entries = image.GetEntries()
5028 fdtmap = entries['fdtmap']
5030 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5031 magic = fdtmap_data[:8]
5032 self.assertEqual(b'_FDTMAP_', magic)
5033 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
5035 fdt_data = fdtmap_data[16:]
5036 dtb = fdt.Fdt.FromData(fdt_data)
5038 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5040 'atf-fip/soc-fw:image-pos': 136,
5041 'atf-fip/soc-fw:offset': 136,
5042 'atf-fip/soc-fw:size': 4,
5043 'atf-fip/u-boot:image-pos': 140,
5044 'atf-fip/u-boot:offset': 140,
5045 'atf-fip/u-boot:size': 4,
5046 'atf-fip:image-pos': 0,
5047 'atf-fip:offset': 0,
5048 'atf-fip:size': 144,
5051 'fdtmap:image-pos': fdtmap.image_pos,
5052 'fdtmap:offset': fdtmap.offset,
5053 'fdtmap:size': len(fdtmap_data),
5057 def testFipExtractOneEntry(self):
5058 """Test extracting a single entry fron an FIP"""
5059 self._DoReadFileRealDtb('207_fip_ls.dts')
5060 image_fname = tools.get_output_filename('image.bin')
5061 fname = os.path.join(self._indir, 'output.extact')
5062 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
5063 data = tools.read_file(fname)
5064 self.assertEqual(U_BOOT_DATA, data)
5066 def testFipReplace(self):
5067 """Test replacing a single file in a FIP"""
5068 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
5069 data = self._DoReadFileRealDtb('208_fip_replace.dts')
5070 updated_fname = tools.get_output_filename('image-updated.bin')
5071 tools.write_file(updated_fname, data)
5072 entry_name = 'atf-fip/u-boot'
5073 control.WriteEntry(updated_fname, entry_name, expected,
5075 actual = control.ReadEntry(updated_fname, entry_name)
5076 self.assertEqual(expected, actual)
5078 new_data = tools.read_file(updated_fname)
5079 hdr, fents = fip_util.decode_fip(new_data)
5081 self.assertEqual(2, len(fents))
5083 # Check that the FIP entry is updated
5085 self.assertEqual(0x8c, fent.offset)
5086 self.assertEqual(len(expected), fent.size)
5087 self.assertEqual(0, fent.flags)
5088 self.assertEqual(expected, fent.data)
5089 self.assertEqual(True, fent.valid)
5091 def testFipMissing(self):
5092 with test_util.capture_sys_output() as (stdout, stderr):
5093 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5094 err = stderr.getvalue()
5095 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5097 def testFipSize(self):
5098 """Test a FIP with a size property"""
5099 data = self._DoReadFile('210_fip_size.dts')
5100 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5101 hdr, fents = fip_util.decode_fip(data)
5102 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5103 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5105 self.assertEqual(1, len(fents))
5108 self.assertEqual('soc-fw', fent.fip_type)
5109 self.assertEqual(0x60, fent.offset)
5110 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5111 self.assertEqual(ATF_BL31_DATA, fent.data)
5112 self.assertEqual(True, fent.valid)
5114 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
5115 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
5117 def testFipBadAlign(self):
5118 """Test that an invalid alignment value in a FIP is detected"""
5119 with self.assertRaises(ValueError) as e:
5120 self._DoTestFile('211_fip_bad_align.dts')
5122 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5125 def testFipCollection(self):
5126 """Test using a FIP in a collection"""
5127 data = self._DoReadFile('212_fip_collection.dts')
5128 entry1 = control.images['image'].GetEntries()['collection']
5129 data1 = data[:entry1.size]
5130 hdr1, fents2 = fip_util.decode_fip(data1)
5132 entry2 = control.images['image'].GetEntries()['atf-fip']
5133 data2 = data[entry2.offset:entry2.offset + entry2.size]
5134 hdr1, fents2 = fip_util.decode_fip(data2)
5136 # The 'collection' entry should have U-Boot included at the end
5137 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5138 self.assertEqual(data1, data2 + U_BOOT_DATA)
5139 self.assertEqual(U_BOOT_DATA, data1[-4:])
5141 # There should be a U-Boot after the final FIP
5142 self.assertEqual(U_BOOT_DATA, data[-4:])
5144 def testFakeBlob(self):
5145 """Test handling of faking an external blob"""
5146 with test_util.capture_sys_output() as (stdout, stderr):
5147 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5148 allow_fake_blobs=True)
5149 err = stderr.getvalue()
5152 "Image '.*' has faked external blobs and is non-functional: .*")
5154 def testExtblobListFaked(self):
5155 """Test an extblob with missing external blob that are faked"""
5156 with test_util.capture_sys_output() as (stdout, stderr):
5157 self._DoTestFile('216_blob_ext_list_missing.dts',
5158 allow_fake_blobs=True)
5159 err = stderr.getvalue()
5160 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5162 def testListBintools(self):
5163 args = ['tool', '--list']
5164 with test_util.capture_sys_output() as (stdout, _):
5165 self._DoBinman(*args)
5166 out = stdout.getvalue().splitlines()
5167 self.assertTrue(len(out) >= 2)
5169 def testFetchBintools(self):
5170 def fail_download(url):
5171 """Take the tools.download() function by raising an exception"""
5172 raise urllib.error.URLError('my error')
5175 with self.assertRaises(ValueError) as e:
5176 self._DoBinman(*args)
5177 self.assertIn("Invalid arguments to 'tool' subcommand",
5180 args = ['tool', '--fetch']
5181 with self.assertRaises(ValueError) as e:
5182 self._DoBinman(*args)
5183 self.assertIn('Please specify bintools to fetch', str(e.exception))
5185 args = ['tool', '--fetch', '_testing']
5186 with unittest.mock.patch.object(tools, 'download',
5187 side_effect=fail_download):
5188 with test_util.capture_sys_output() as (stdout, _):
5189 self._DoBinman(*args)
5190 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5192 def testInvalidCompress(self):
5193 with self.assertRaises(ValueError) as e:
5194 comp_util.compress(b'', 'invalid')
5195 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5197 with self.assertRaises(ValueError) as e:
5198 comp_util.decompress(b'1234', 'invalid')
5199 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5201 def testBintoolDocs(self):
5202 """Test for creation of bintool documentation"""
5203 with test_util.capture_sys_output() as (stdout, stderr):
5204 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5205 self.assertTrue(len(stdout.getvalue()) > 0)
5207 def testBintoolDocsMissing(self):
5208 """Test handling of missing bintool documentation"""
5209 with self.assertRaises(ValueError) as e:
5210 with test_util.capture_sys_output() as (stdout, stderr):
5211 control.write_bintool_docs(
5212 control.bintool.Bintool.get_tool_list(), 'mkimage')
5213 self.assertIn('Documentation is missing for modules: mkimage',
5216 def testListWithGenNode(self):
5217 """Check handling of an FDT map when the section cannot be found"""
5219 'of-list': 'test-fdt1 test-fdt2',
5221 data = self._DoReadFileDtb(
5222 '219_fit_gennode.dts',
5223 entry_args=entry_args,
5225 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5228 tmpdir, updated_fname = self._SetupImageInTmpdir()
5229 with test_util.capture_sys_output() as (stdout, stderr):
5230 self._RunBinman('ls', '-i', updated_fname)
5232 shutil.rmtree(tmpdir)
5234 def testFitSubentryUsesBintool(self):
5235 """Test that binman FIT subentries can use bintools"""
5236 command.test_result = self._HandleGbbCommand
5238 'keydir': 'devkeys',
5239 'bmpblk': 'bmpblk.bin',
5241 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5242 entry_args=entry_args)
5244 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5245 tools.get_bytes(0, 0x2180 - 16))
5246 self.assertIn(expected, data)
5248 def testFitSubentryMissingBintool(self):
5249 """Test that binman reports missing bintools for FIT subentries"""
5251 'keydir': 'devkeys',
5253 with test_util.capture_sys_output() as (_, stderr):
5254 self._DoTestFile('220_fit_subentry_bintool.dts',
5255 force_missing_bintools='futility', entry_args=entry_args)
5256 err = stderr.getvalue()
5257 self.assertRegex(err,
5258 "Image 'main-section'.*missing bintools.*: futility")
5260 def testFitSubentryHashSubnode(self):
5261 """Test an image with a FIT inside"""
5262 data, _, _, out_dtb_name = self._DoReadFileDtb(
5263 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5265 mkimage_dtb = fdt.Fdt.FromData(data)
5267 binman_dtb = fdt.Fdt(out_dtb_name)
5270 # Check that binman didn't add hash values
5271 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5272 self.assertNotIn('value', fnode.props)
5274 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5275 self.assertNotIn('value', fnode.props)
5277 # Check that mkimage added hash values
5278 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5279 self.assertIn('value', fnode.props)
5281 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5282 self.assertIn('value', fnode.props)
5284 def testPackTeeOs(self):
5285 """Test that an image with an TEE binary can be created"""
5286 data = self._DoReadFile('222_tee_os.dts')
5287 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5289 def testFitFdtOper(self):
5290 """Check handling of a specified FIT operation"""
5292 'of-list': 'test-fdt1 test-fdt2',
5293 'default-dt': 'test-fdt2',
5295 self._DoReadFileDtb(
5296 '223_fit_fdt_oper.dts',
5297 entry_args=entry_args,
5298 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5300 def testFitFdtBadOper(self):
5301 """Check handling of an FDT map when the section cannot be found"""
5302 with self.assertRaises(ValueError) as exc:
5303 self._DoReadFileDtb('224_fit_bad_oper.dts')
5304 self.assertIn("Node '/binman/fit': Unknown operation 'unknown'",
5308 if __name__ == "__main__":