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 control
27 from binman import elf
28 from binman import elf_test
29 from binman import fip_util
30 from binman import fmap_util
31 from binman import state
33 from dtoc import fdt_util
34 from binman.etype import fdtmap
35 from binman.etype import image_header
36 from binman.image import Image
37 from u_boot_pylib import command
38 from u_boot_pylib import test_util
39 from u_boot_pylib import tools
40 from u_boot_pylib import tout
42 # Contents of test files, corresponding to different entry types
44 U_BOOT_IMG_DATA = b'img'
45 U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
47 U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
51 U_BOOT_DTB_DATA = b'udtb'
52 U_BOOT_SPL_DTB_DATA = b'spldtb'
53 U_BOOT_TPL_DTB_DATA = b'tpldtb'
54 U_BOOT_VPL_DTB_DATA = b'vpldtb'
55 X86_START16_DATA = b'start16'
56 X86_START16_SPL_DATA = b'start16spl'
57 X86_START16_TPL_DATA = b'start16tpl'
58 X86_RESET16_DATA = b'reset16'
59 X86_RESET16_SPL_DATA = b'reset16spl'
60 X86_RESET16_TPL_DATA = b'reset16tpl'
61 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
62 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
63 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
64 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
65 U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
66 U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
67 U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
68 U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
76 CROS_EC_RW_DATA = b'ecrw'
80 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
81 b"sorry you're alive\n")
82 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
83 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
84 REFCODE_DATA = b'refcode'
88 ATF_BL31_DATA = b'bl31'
89 TEE_OS_DATA = b'this is some tee OS data'
90 ATF_BL2U_DATA = b'bl2u'
91 OPENSBI_DATA = b'opensbi'
93 ROCKCHIP_TPL_DATA = b'rockchip-tpl'
94 TEST_FDT1_DATA = b'fdt1'
95 TEST_FDT2_DATA = b'test-fdt2'
96 ENV_DATA = b'var1=1\nvar2="2"'
97 ENCRYPTED_IV_DATA = b'123456'
98 ENCRYPTED_KEY_DATA = b'abcde'
99 PRE_LOAD_MAGIC = b'UBSH'
100 PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
101 PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
102 TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
103 TI_UNSECURE_DATA = b'unsecuredata'
105 # Subdirectory of the input dir to use to put test FDTs
106 TEST_FDT_SUBDIR = 'fdts'
108 # The expected size for the device tree in some tests
109 EXTRACT_DTB_SIZE = 0x3c9
111 # Properties expected to be in the device tree when update_dtb is used
112 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
114 # Extra properties expected to be in the device tree when allow-repack is used
115 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
117 # Supported compression bintools
118 COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
122 class TestFunctional(unittest.TestCase):
123 """Functional tests for binman
125 Most of these use a sample .dts file to build an image and then check
126 that it looks correct. The sample files are in the test/ subdirectory
129 For each entry type a very small test file is created using fixed
130 string contents. This makes it easy to test that things look right, and
133 In some cases a 'real' file must be used - these are also supplied in
134 the test/ diurectory.
139 from binman import entry
141 # Handle the case where argv[0] is 'python'
142 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
143 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
145 # Create a temporary directory for input files
146 cls._indir = tempfile.mkdtemp(prefix='binmant.')
148 # Create some test files
149 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
150 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
151 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
152 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
153 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
154 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
155 TestFunctional._MakeInputFile('me.bin', ME_DATA)
156 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
159 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
161 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
162 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
163 X86_START16_SPL_DATA)
164 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
165 X86_START16_TPL_DATA)
167 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
169 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
170 X86_RESET16_SPL_DATA)
171 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
172 X86_RESET16_TPL_DATA)
174 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
176 U_BOOT_SPL_NODTB_DATA)
177 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
178 U_BOOT_TPL_NODTB_DATA)
179 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
180 U_BOOT_VPL_NODTB_DATA)
181 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
182 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
183 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
184 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
185 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
186 TestFunctional._MakeInputDir('devkeys')
187 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
188 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
189 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
190 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
191 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
193 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
194 elf_test.BuildElfTestFiles(cls._elf_testdir)
196 # ELF file with a '_dt_ucode_base_size' symbol
197 TestFunctional._MakeInputFile('u-boot',
198 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
200 # Intel flash descriptor file
201 cls._SetupDescriptor()
203 shutil.copytree(cls.TestFile('files'),
204 os.path.join(cls._indir, 'files'))
206 shutil.copytree(cls.TestFile('yaml'),
207 os.path.join(cls._indir, 'yaml'))
209 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
210 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
211 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
212 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
213 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
214 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
215 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
216 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
217 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
219 # Add a few .dtb files for testing
220 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
222 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
225 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
227 # ELF file with two sections in different parts of memory, used for both
229 TestFunctional._MakeInputFile('bl31.elf',
230 tools.read_file(cls.ElfTestFile('elf_sections')))
231 TestFunctional._MakeInputFile('tee.elf',
232 tools.read_file(cls.ElfTestFile('elf_sections')))
234 # Newer OP_TEE file in v1 binary format
235 cls.make_tee_bin('tee.bin')
237 # test files for encrypted tests
238 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
239 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
241 cls.comp_bintools = {}
242 for name in COMP_BINTOOLS:
243 cls.comp_bintools[name] = bintool.Bintool.create(name)
246 def tearDownClass(cls):
247 """Remove the temporary input directory and its contents"""
248 if cls.preserve_indir:
249 print('Preserving input dir: %s' % cls._indir)
252 shutil.rmtree(cls._indir)
256 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
257 toolpath=None, verbosity=None):
258 """Accept arguments controlling test execution
261 preserve_indir: Preserve the shared input directory used by all
263 preserve_outdir: Preserve the output directories used by tests. Each
264 test has its own, so this is normally only useful when running a
266 toolpath: ist of paths to use for tools
268 cls.preserve_indir = preserve_indir
269 cls.preserve_outdirs = preserve_outdirs
270 cls.toolpath = toolpath
271 cls.verbosity = verbosity
273 def _CheckBintool(self, bintool):
274 if not bintool.is_present():
275 self.skipTest('%s not available' % bintool.name)
278 bintool = self.comp_bintools['lz4']
279 self._CheckBintool(bintool)
281 def _CleanupOutputDir(self):
282 """Remove the temporary output directory"""
283 if self.preserve_outdirs:
284 print('Preserving output dir: %s' % tools.outdir)
286 tools._finalise_for_test()
289 # Enable this to turn on debugging output
290 # tout.init(tout.DEBUG)
291 command.test_result = None
294 """Remove the temporary output directory"""
295 self._CleanupOutputDir()
297 def _SetupImageInTmpdir(self):
298 """Set up the output image in a new temporary directory
300 This is used when an image has been generated in the output directory,
301 but we want to run binman again. This will create a new output
302 directory and fail to delete the original one.
304 This creates a new temporary directory, copies the image to it (with a
305 new name) and removes the old output directory.
309 Temporary directory to use
312 image_fname = tools.get_output_filename('image.bin')
313 tmpdir = tempfile.mkdtemp(prefix='binman.')
314 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
315 tools.write_file(updated_fname, tools.read_file(image_fname))
316 self._CleanupOutputDir()
317 return tmpdir, updated_fname
321 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
322 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
323 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
324 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
326 def _RunBinman(self, *args, **kwargs):
327 """Run binman using the command line
330 Arguments to pass, as a list of strings
331 kwargs: Arguments to pass to Command.RunPipe()
333 result = command.run_pipe([[self._binman_pathname] + list(args)],
334 capture=True, capture_stderr=True, raise_on_error=False)
335 if result.return_code and kwargs.get('raise_on_error', True):
336 raise Exception("Error running '%s': %s" % (' '.join(args),
337 result.stdout + result.stderr))
340 def _DoBinman(self, *argv):
341 """Run binman using directly (in the same process)
344 Arguments to pass, as a list of strings
346 Return value (0 for success)
349 args = cmdline.ParseArgs(argv)
350 args.pager = 'binman-invalid-pager'
351 args.build_dir = self._indir
353 # For testing, you can force an increase in verbosity here
354 # args.verbosity = tout.DEBUG
355 return control.Binman(args)
357 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
358 entry_args=None, images=None, use_real_dtb=False,
359 use_expanded=False, verbosity=None, allow_missing=False,
360 allow_fake_blobs=False, extra_indirs=None, threads=None,
361 test_section_timeout=False, update_fdt_in_elf=None,
362 force_missing_bintools='', ignore_missing=False, output_dir=None):
363 """Run binman with a given test file
366 fname: Device-tree source filename to use (e.g. 005_simple.dts)
367 debug: True to enable debugging output
368 map: True to output map files for the images
369 update_dtb: Update the offset and size of each entry in the device
370 tree before packing it into the image
371 entry_args: Dict of entry args to supply to binman
373 value: value of that arg
374 images: List of image names to build
375 use_real_dtb: True to use the test file as the contents of
376 the u-boot-dtb entry. Normally this is not needed and the
377 test contents (the U_BOOT_DTB_DATA string) can be used.
378 But in some test we need the real contents.
379 use_expanded: True to use expanded entries where available, e.g.
380 'u-boot-expanded' instead of 'u-boot'
381 verbosity: Verbosity level to use (0-3, None=don't set it)
382 allow_missing: Set the '--allow-missing' flag so that missing
383 external binaries just produce a warning instead of an error
384 allow_fake_blobs: Set the '--fake-ext-blobs' flag
385 extra_indirs: Extra input directories to add using -I
386 threads: Number of threads to use (None for default, 0 for
388 test_section_timeout: True to force the first time to timeout, as
389 used in testThreadTimeout()
390 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
391 force_missing_tools (str): comma-separated list of bintools to
393 output_dir: Specific output directory to use for image using -O
396 int return code, 0 on success
401 if verbosity is not None:
402 args.append('-v%d' % verbosity)
404 args.append('-v%d' % self.verbosity)
406 for path in self.toolpath:
407 args += ['--toolpath', path]
408 if threads is not None:
409 args.append('-T%d' % threads)
410 if test_section_timeout:
411 args.append('--test-section-timeout')
412 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
418 args.append('--fake-dtb')
420 args.append('--no-expanded')
422 for arg, value in entry_args.items():
423 args.append('-a%s=%s' % (arg, value))
429 args.append('--fake-ext-blobs')
430 if force_missing_bintools:
431 args += ['--force-missing-bintools', force_missing_bintools]
432 if update_fdt_in_elf:
433 args += ['--update-fdt-in-elf', update_fdt_in_elf]
436 args += ['-i', image]
438 for indir in extra_indirs:
439 args += ['-I', indir]
441 args += ['-O', output_dir]
442 return self._DoBinman(*args)
444 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
445 """Set up a new test device-tree file
447 The given file is compiled and set up as the device tree to be used
451 fname: Filename of .dts file to read
452 outfile: Output filename for compiled device-tree binary
455 Contents of device-tree binary
457 tmpdir = tempfile.mkdtemp(prefix='binmant.')
458 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
459 with open(dtb, 'rb') as fd:
461 TestFunctional._MakeInputFile(outfile, data)
462 shutil.rmtree(tmpdir)
465 def _GetDtbContentsForSpls(self, dtb_data, name):
466 """Create a version of the main DTB for SPL / TPL / VPL
468 For testing we don't actually have different versions of the DTB. With
469 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
470 we don't normally have any unwanted nodes.
472 We still want the DTBs for SPL and TPL to be different though, since
473 otherwise it is confusing to know which one we are looking at. So add
474 an 'spl' or 'tpl' property to the top-level node.
477 dtb_data: dtb data to modify (this should be a value devicetree)
478 name: Name of a new property to add
481 New dtb data with the property added
483 dtb = fdt.Fdt.FromData(dtb_data)
485 dtb.GetNode('/binman').AddZeroProp(name)
486 dtb.Sync(auto_resize=True)
488 return dtb.GetContents()
490 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
491 map=False, update_dtb=False, entry_args=None,
492 reset_dtbs=True, extra_indirs=None, threads=None):
493 """Run binman and return the resulting image
495 This runs binman with a given test file and then reads the resulting
496 output file. It is a shortcut function since most tests need to do
499 Raises an assertion failure if binman returns a non-zero exit code.
502 fname: Device-tree source filename to use (e.g. 005_simple.dts)
503 use_real_dtb: True to use the test file as the contents of
504 the u-boot-dtb entry. Normally this is not needed and the
505 test contents (the U_BOOT_DTB_DATA string) can be used.
506 But in some test we need the real contents.
507 use_expanded: True to use expanded entries where available, e.g.
508 'u-boot-expanded' instead of 'u-boot'
509 map: True to output map files for the images
510 update_dtb: Update the offset and size of each entry in the device
511 tree before packing it into the image
512 entry_args: Dict of entry args to supply to binman
514 value: value of that arg
515 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
516 function. If reset_dtbs is True, then the original test dtb
517 is written back before this function finishes
518 extra_indirs: Extra input directories to add using -I
519 threads: Number of threads to use (None for default, 0 for
524 Resulting image contents
526 Map data showing contents of image (or None if none)
527 Output device tree binary filename ('u-boot.dtb' path)
530 # Use the compiled test file as the u-boot-dtb input
532 dtb_data = self._SetupDtb(fname)
534 # For testing purposes, make a copy of the DT for SPL and TPL. Add
535 # a node indicating which it is, so aid verification.
536 for name in ['spl', 'tpl', 'vpl']:
537 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
538 outfile = os.path.join(self._indir, dtb_fname)
539 TestFunctional._MakeInputFile(dtb_fname,
540 self._GetDtbContentsForSpls(dtb_data, name))
543 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
544 entry_args=entry_args, use_real_dtb=use_real_dtb,
545 use_expanded=use_expanded, extra_indirs=extra_indirs,
547 self.assertEqual(0, retcode)
548 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
550 # Find the (only) image, read it and return its contents
551 image = control.images['image']
552 image_fname = tools.get_output_filename('image.bin')
553 self.assertTrue(os.path.exists(image_fname))
555 map_fname = tools.get_output_filename('image.map')
556 with open(map_fname) as fd:
560 with open(image_fname, 'rb') as fd:
561 return fd.read(), dtb_data, map_data, out_dtb_fname
563 # Put the test file back
564 if reset_dtbs and use_real_dtb:
567 def _DoReadFileRealDtb(self, fname):
568 """Run binman with a real .dtb file and return the resulting data
571 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
574 Resulting image contents
576 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
578 def _DoReadFile(self, fname, use_real_dtb=False):
579 """Helper function which discards the device-tree binary
582 fname: Device-tree source filename to use (e.g. 005_simple.dts)
583 use_real_dtb: True to use the test file as the contents of
584 the u-boot-dtb entry. Normally this is not needed and the
585 test contents (the U_BOOT_DTB_DATA string) can be used.
586 But in some test we need the real contents.
589 Resulting image contents
591 return self._DoReadFileDtb(fname, use_real_dtb)[0]
594 def _MakeInputFile(cls, fname, contents):
595 """Create a new test input file, creating directories as needed
598 fname: Filename to create
599 contents: File contents to write in to the file
601 Full pathname of file created
603 pathname = os.path.join(cls._indir, fname)
604 dirname = os.path.dirname(pathname)
605 if dirname and not os.path.exists(dirname):
607 with open(pathname, 'wb') as fd:
612 def _MakeInputDir(cls, dirname):
613 """Create a new test input directory, creating directories as needed
616 dirname: Directory name to create
619 Full pathname of directory created
621 pathname = os.path.join(cls._indir, dirname)
622 if not os.path.exists(pathname):
623 os.makedirs(pathname)
627 def _SetupSplElf(cls, src_fname='bss_data'):
628 """Set up an ELF file with a '_dt_ucode_base_size' symbol
631 Filename of ELF file to use as SPL
633 TestFunctional._MakeInputFile('spl/u-boot-spl',
634 tools.read_file(cls.ElfTestFile(src_fname)))
637 def _SetupTplElf(cls, src_fname='bss_data'):
638 """Set up an ELF file with a '_dt_ucode_base_size' symbol
641 Filename of ELF file to use as TPL
643 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
644 tools.read_file(cls.ElfTestFile(src_fname)))
647 def _SetupVplElf(cls, src_fname='bss_data'):
648 """Set up an ELF file with a '_dt_ucode_base_size' symbol
651 Filename of ELF file to use as VPL
653 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
654 tools.read_file(cls.ElfTestFile(src_fname)))
657 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
658 """Set up an ELF file with a '_dt_ucode_base_size' symbol
661 Filename of ELF file to use as VPL
663 TestFunctional._MakeInputFile('pmu-firmware.elf',
664 tools.read_file(cls.ElfTestFile(src_fname)))
667 def _SetupDescriptor(cls):
668 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
669 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
672 def TestFile(cls, fname):
673 return os.path.join(cls._binman_dir, 'test', fname)
676 def ElfTestFile(cls, fname):
677 return os.path.join(cls._elf_testdir, fname)
680 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
681 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
682 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
683 dummy, paged_sz) + U_BOOT_DATA
685 TestFunctional._MakeInputFile(fname, data)
687 def AssertInList(self, grep_list, target):
688 """Assert that at least one of a list of things is in a target
691 grep_list: List of strings to check
692 target: Target string
694 for grep in grep_list:
697 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
699 def CheckNoGaps(self, entries):
700 """Check that all entries fit together without gaps
703 entries: List of entries to check
706 for entry in entries.values():
707 self.assertEqual(offset, entry.offset)
710 def GetFdtLen(self, dtb):
711 """Get the totalsize field from a device-tree binary
714 dtb: Device-tree binary contents
717 Total size of device-tree binary, from the header
719 return struct.unpack('>L', dtb[4:8])[0]
721 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
722 def AddNode(node, path):
724 path += '/' + node.name
725 for prop in node.props.values():
726 if prop.name in prop_names:
727 prop_path = path + ':' + prop.name
728 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
730 for subnode in node.subnodes:
731 AddNode(subnode, path)
734 AddNode(dtb.GetRoot(), '')
737 def _CheckSign(self, fit, key):
739 tools.run('fit_check_sign', '-k', key, '-f', fit)
741 self.fail('Expected signed FIT container')
746 """Test a basic run with valid args"""
747 result = self._RunBinman('-h')
749 def testFullHelp(self):
750 """Test that the full help is displayed with -H"""
751 result = self._RunBinman('-H')
752 help_file = os.path.join(self._binman_dir, 'README.rst')
753 # Remove possible extraneous strings
754 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
755 gothelp = result.stdout.replace(extra, '')
756 self.assertEqual(len(gothelp), os.path.getsize(help_file))
757 self.assertEqual(0, len(result.stderr))
758 self.assertEqual(0, result.return_code)
760 def testFullHelpInternal(self):
761 """Test that the full help is displayed with -H"""
763 command.test_result = command.CommandResult()
764 result = self._DoBinman('-H')
765 help_file = os.path.join(self._binman_dir, 'README.rst')
767 command.test_result = None
770 """Test that the basic help is displayed with -h"""
771 result = self._RunBinman('-h')
772 self.assertTrue(len(result.stdout) > 200)
773 self.assertEqual(0, len(result.stderr))
774 self.assertEqual(0, result.return_code)
777 """Test that we can run it with a specific board"""
778 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
779 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
780 result = self._DoBinman('build', '-n', '-b', 'sandbox')
781 self.assertEqual(0, result)
783 def testNeedBoard(self):
784 """Test that we get an error when no board ius supplied"""
785 with self.assertRaises(ValueError) as e:
786 result = self._DoBinman('build')
787 self.assertIn("Must provide a board to process (use -b <board>)",
790 def testMissingDt(self):
791 """Test that an invalid device-tree file generates an error"""
792 with self.assertRaises(Exception) as e:
793 self._RunBinman('build', '-d', 'missing_file')
794 # We get one error from libfdt, and a different one from fdtget.
795 self.AssertInList(["Couldn't open blob from 'missing_file'",
796 'No such file or directory'], str(e.exception))
798 def testBrokenDt(self):
799 """Test that an invalid device-tree source file generates an error
801 Since this is a source file it should be compiled and the error
802 will come from the device-tree compiler (dtc).
804 with self.assertRaises(Exception) as e:
805 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
806 self.assertIn("FATAL ERROR: Unable to parse input tree",
809 def testMissingNode(self):
810 """Test that a device tree without a 'binman' node generates an error"""
811 with self.assertRaises(Exception) as e:
812 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
813 self.assertIn("does not have a 'binman' node", str(e.exception))
816 """Test that an empty binman node works OK (i.e. does nothing)"""
817 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
818 self.assertEqual(0, len(result.stderr))
819 self.assertEqual(0, result.return_code)
821 def testInvalidEntry(self):
822 """Test that an invalid entry is flagged"""
823 with self.assertRaises(Exception) as e:
824 result = self._RunBinman('build', '-d',
825 self.TestFile('004_invalid_entry.dts'))
826 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
827 "'/binman/not-a-valid-type'", str(e.exception))
829 def testSimple(self):
830 """Test a simple binman with a single file"""
831 data = self._DoReadFile('005_simple.dts')
832 self.assertEqual(U_BOOT_DATA, data)
834 def testSimpleDebug(self):
835 """Test a simple binman run with debugging enabled"""
836 self._DoTestFile('005_simple.dts', debug=True)
839 """Test that we can handle creating two images
841 This also tests image padding.
843 retcode = self._DoTestFile('006_dual_image.dts')
844 self.assertEqual(0, retcode)
846 image = control.images['image1']
847 self.assertEqual(len(U_BOOT_DATA), image.size)
848 fname = tools.get_output_filename('image1.bin')
849 self.assertTrue(os.path.exists(fname))
850 with open(fname, 'rb') as fd:
852 self.assertEqual(U_BOOT_DATA, data)
854 image = control.images['image2']
855 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
856 fname = tools.get_output_filename('image2.bin')
857 self.assertTrue(os.path.exists(fname))
858 with open(fname, 'rb') as fd:
860 self.assertEqual(U_BOOT_DATA, data[3:7])
861 self.assertEqual(tools.get_bytes(0, 3), data[:3])
862 self.assertEqual(tools.get_bytes(0, 5), data[7:])
864 def testBadAlign(self):
865 """Test that an invalid alignment value is detected"""
866 with self.assertRaises(ValueError) as e:
867 self._DoTestFile('007_bad_align.dts')
868 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
869 "of two", str(e.exception))
871 def testPackSimple(self):
872 """Test that packing works as expected"""
873 retcode = self._DoTestFile('008_pack.dts')
874 self.assertEqual(0, retcode)
875 self.assertIn('image', control.images)
876 image = control.images['image']
877 entries = image.GetEntries()
878 self.assertEqual(5, len(entries))
881 self.assertIn('u-boot', entries)
882 entry = entries['u-boot']
883 self.assertEqual(0, entry.offset)
884 self.assertEqual(len(U_BOOT_DATA), entry.size)
886 # Second u-boot, aligned to 16-byte boundary
887 self.assertIn('u-boot-align', entries)
888 entry = entries['u-boot-align']
889 self.assertEqual(16, entry.offset)
890 self.assertEqual(len(U_BOOT_DATA), entry.size)
892 # Third u-boot, size 23 bytes
893 self.assertIn('u-boot-size', entries)
894 entry = entries['u-boot-size']
895 self.assertEqual(20, entry.offset)
896 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
897 self.assertEqual(23, entry.size)
899 # Fourth u-boot, placed immediate after the above
900 self.assertIn('u-boot-next', entries)
901 entry = entries['u-boot-next']
902 self.assertEqual(43, entry.offset)
903 self.assertEqual(len(U_BOOT_DATA), entry.size)
905 # Fifth u-boot, placed at a fixed offset
906 self.assertIn('u-boot-fixed', entries)
907 entry = entries['u-boot-fixed']
908 self.assertEqual(61, entry.offset)
909 self.assertEqual(len(U_BOOT_DATA), entry.size)
911 self.assertEqual(65, image.size)
913 def testPackExtra(self):
914 """Test that extra packing feature works as expected"""
915 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
918 self.assertIn('image', control.images)
919 image = control.images['image']
920 entries = image.GetEntries()
921 self.assertEqual(6, len(entries))
923 # First u-boot with padding before and after (included in minimum size)
924 self.assertIn('u-boot', entries)
925 entry = entries['u-boot']
926 self.assertEqual(0, entry.offset)
927 self.assertEqual(3, entry.pad_before)
928 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
929 self.assertEqual(U_BOOT_DATA, entry.data)
930 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
931 tools.get_bytes(0, 5), data[:entry.size])
934 # Second u-boot has an aligned size, but it has no effect
935 self.assertIn('u-boot-align-size-nop', entries)
936 entry = entries['u-boot-align-size-nop']
937 self.assertEqual(pos, entry.offset)
938 self.assertEqual(len(U_BOOT_DATA), entry.size)
939 self.assertEqual(U_BOOT_DATA, entry.data)
940 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
943 # Third u-boot has an aligned size too
944 self.assertIn('u-boot-align-size', entries)
945 entry = entries['u-boot-align-size']
946 self.assertEqual(pos, entry.offset)
947 self.assertEqual(32, entry.size)
948 self.assertEqual(U_BOOT_DATA, entry.data)
949 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
950 data[pos:pos + entry.size])
953 # Fourth u-boot has an aligned end
954 self.assertIn('u-boot-align-end', entries)
955 entry = entries['u-boot-align-end']
956 self.assertEqual(48, entry.offset)
957 self.assertEqual(16, entry.size)
958 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
959 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
960 data[pos:pos + entry.size])
963 # Fifth u-boot immediately afterwards
964 self.assertIn('u-boot-align-both', entries)
965 entry = entries['u-boot-align-both']
966 self.assertEqual(64, entry.offset)
967 self.assertEqual(64, entry.size)
968 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
969 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
970 data[pos:pos + entry.size])
972 # Sixth u-boot with both minimum size and aligned size
973 self.assertIn('u-boot-min-size', entries)
974 entry = entries['u-boot-min-size']
975 self.assertEqual(128, entry.offset)
976 self.assertEqual(32, entry.size)
977 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
978 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
979 data[pos:pos + entry.size])
981 self.CheckNoGaps(entries)
982 self.assertEqual(160, image.size)
984 dtb = fdt.Fdt(out_dtb_fname)
986 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
992 'u-boot:image-pos': 0,
994 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
996 'u-boot-align-size-nop:image-pos': 12,
997 'u-boot-align-size-nop:offset': 12,
998 'u-boot-align-size-nop:size': 4,
1000 'u-boot-align-size:image-pos': 16,
1001 'u-boot-align-size:offset': 16,
1002 'u-boot-align-size:size': 32,
1004 'u-boot-align-end:image-pos': 48,
1005 'u-boot-align-end:offset': 48,
1006 'u-boot-align-end:size': 16,
1008 'u-boot-align-both:image-pos': 64,
1009 'u-boot-align-both:offset': 64,
1010 'u-boot-align-both:size': 64,
1012 'u-boot-min-size:image-pos': 128,
1013 'u-boot-min-size:offset': 128,
1014 'u-boot-min-size:size': 32,
1016 self.assertEqual(expected, props)
1018 def testPackAlignPowerOf2(self):
1019 """Test that invalid entry alignment is detected"""
1020 with self.assertRaises(ValueError) as e:
1021 self._DoTestFile('010_pack_align_power2.dts')
1022 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1023 "of two", str(e.exception))
1025 def testPackAlignSizePowerOf2(self):
1026 """Test that invalid entry size alignment is detected"""
1027 with self.assertRaises(ValueError) as e:
1028 self._DoTestFile('011_pack_align_size_power2.dts')
1029 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1030 "power of two", str(e.exception))
1032 def testPackInvalidAlign(self):
1033 """Test detection of an offset that does not match its alignment"""
1034 with self.assertRaises(ValueError) as e:
1035 self._DoTestFile('012_pack_inv_align.dts')
1036 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
1037 "align 0x4 (4)", str(e.exception))
1039 def testPackInvalidSizeAlign(self):
1040 """Test that invalid entry size alignment is detected"""
1041 with self.assertRaises(ValueError) as e:
1042 self._DoTestFile('013_pack_inv_size_align.dts')
1043 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1044 "align-size 0x4 (4)", str(e.exception))
1046 def testPackOverlap(self):
1047 """Test that overlapping regions are detected"""
1048 with self.assertRaises(ValueError) as e:
1049 self._DoTestFile('014_pack_overlap.dts')
1050 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
1051 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1054 def testPackEntryOverflow(self):
1055 """Test that entries that overflow their size are detected"""
1056 with self.assertRaises(ValueError) as e:
1057 self._DoTestFile('015_pack_overflow.dts')
1058 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1059 "but entry size is 0x3 (3)", str(e.exception))
1061 def testPackImageOverflow(self):
1062 """Test that entries which overflow the image size are detected"""
1063 with self.assertRaises(ValueError) as e:
1064 self._DoTestFile('016_pack_image_overflow.dts')
1065 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
1066 "size 0x3 (3)", str(e.exception))
1068 def testPackImageSize(self):
1069 """Test that the image size can be set"""
1070 retcode = self._DoTestFile('017_pack_image_size.dts')
1071 self.assertEqual(0, retcode)
1072 self.assertIn('image', control.images)
1073 image = control.images['image']
1074 self.assertEqual(7, image.size)
1076 def testPackImageSizeAlign(self):
1077 """Test that image size alignemnt works as expected"""
1078 retcode = self._DoTestFile('018_pack_image_align.dts')
1079 self.assertEqual(0, retcode)
1080 self.assertIn('image', control.images)
1081 image = control.images['image']
1082 self.assertEqual(16, image.size)
1084 def testPackInvalidImageAlign(self):
1085 """Test that invalid image alignment is detected"""
1086 with self.assertRaises(ValueError) as e:
1087 self._DoTestFile('019_pack_inv_image_align.dts')
1088 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
1089 "align-size 0x8 (8)", str(e.exception))
1091 def testPackAlignPowerOf2Inv(self):
1092 """Test that invalid image alignment is detected"""
1093 with self.assertRaises(ValueError) as e:
1094 self._DoTestFile('020_pack_inv_image_align_power2.dts')
1095 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
1096 "two", str(e.exception))
1098 def testImagePadByte(self):
1099 """Test that the image pad byte can be specified"""
1101 data = self._DoReadFile('021_image_pad.dts')
1102 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
1105 def testImageName(self):
1106 """Test that image files can be named"""
1107 retcode = self._DoTestFile('022_image_name.dts')
1108 self.assertEqual(0, retcode)
1109 image = control.images['image1']
1110 fname = tools.get_output_filename('test-name')
1111 self.assertTrue(os.path.exists(fname))
1113 image = control.images['image2']
1114 fname = tools.get_output_filename('test-name.xx')
1115 self.assertTrue(os.path.exists(fname))
1117 def testBlobFilename(self):
1118 """Test that generic blobs can be provided by filename"""
1119 data = self._DoReadFile('023_blob.dts')
1120 self.assertEqual(BLOB_DATA, data)
1122 def testPackSorted(self):
1123 """Test that entries can be sorted"""
1125 data = self._DoReadFile('024_sorted.dts')
1126 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1127 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
1129 def testPackZeroOffset(self):
1130 """Test that an entry at offset 0 is not given a new offset"""
1132 with self.assertRaises(ValueError) as e:
1133 self._DoTestFile('025_pack_zero_size.dts')
1134 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1135 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1138 def testPackUbootDtb(self):
1139 """Test that a device tree can be added to U-Boot"""
1140 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1141 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1143 def testPackX86RomNoSize(self):
1144 """Test that the end-at-4gb property requires a size property"""
1146 with self.assertRaises(ValueError) as e:
1147 self._DoTestFile('027_pack_4gb_no_size.dts')
1148 self.assertIn("Image '/binman': Section size must be provided when "
1149 "using end-at-4gb", str(e.exception))
1151 def test4gbAndSkipAtStartTogether(self):
1152 """Test that the end-at-4gb and skip-at-size property can't be used
1155 with self.assertRaises(ValueError) as e:
1156 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1157 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1158 "'skip-at-start'", str(e.exception))
1160 def testPackX86RomOutside(self):
1161 """Test that the end-at-4gb property checks for offset boundaries"""
1163 with self.assertRaises(ValueError) as e:
1164 self._DoTestFile('028_pack_4gb_outside.dts')
1165 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1166 "is outside the section '/binman' starting at "
1167 '0xffffffe0 (4294967264) of size 0x20 (32)',
1170 def testPackX86Rom(self):
1171 """Test that a basic x86 ROM can be created"""
1173 data = self._DoReadFile('029_x86_rom.dts')
1174 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1175 tools.get_bytes(0, 2), data)
1177 def testPackX86RomMeNoDesc(self):
1178 """Test that an invalid Intel descriptor entry is detected"""
1180 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1181 with self.assertRaises(ValueError) as e:
1182 self._DoTestFile('163_x86_rom_me_empty.dts')
1183 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1186 self._SetupDescriptor()
1188 def testPackX86RomBadDesc(self):
1189 """Test that the Intel requires a descriptor entry"""
1190 with self.assertRaises(ValueError) as e:
1191 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1192 self.assertIn("Node '/binman/intel-me': No offset set with "
1193 "offset-unset: should another entry provide this correct "
1194 "offset?", str(e.exception))
1196 def testPackX86RomMe(self):
1197 """Test that an x86 ROM with an ME region can be created"""
1198 data = self._DoReadFile('031_x86_rom_me.dts')
1199 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
1200 if data[:0x1000] != expected_desc:
1201 self.fail('Expected descriptor binary at start of image')
1202 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1204 def testPackVga(self):
1205 """Test that an image with a VGA binary can be created"""
1206 data = self._DoReadFile('032_intel_vga.dts')
1207 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1209 def testPackStart16(self):
1210 """Test that an image with an x86 start16 region can be created"""
1211 data = self._DoReadFile('033_x86_start16.dts')
1212 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1214 def testPackPowerpcMpc85xxBootpgResetvec(self):
1215 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1217 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1218 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1220 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1221 """Handle running a test for insertion of microcode
1224 dts_fname: Name of test .dts file
1225 nodtb_data: Data that we expect in the first section
1226 ucode_second: True if the microsecond entry is second instead of
1231 Contents of first region (U-Boot or SPL)
1232 Offset and size components of microcode pointer, as inserted
1233 in the above (two 4-byte words)
1235 data = self._DoReadFile(dts_fname, True)
1237 # Now check the device tree has no microcode
1239 ucode_content = data[len(nodtb_data):]
1240 ucode_pos = len(nodtb_data)
1241 dtb_with_ucode = ucode_content[16:]
1242 fdt_len = self.GetFdtLen(dtb_with_ucode)
1244 dtb_with_ucode = data[len(nodtb_data):]
1245 fdt_len = self.GetFdtLen(dtb_with_ucode)
1246 ucode_content = dtb_with_ucode[fdt_len:]
1247 ucode_pos = len(nodtb_data) + fdt_len
1248 fname = tools.get_output_filename('test.dtb')
1249 with open(fname, 'wb') as fd:
1250 fd.write(dtb_with_ucode)
1251 dtb = fdt.FdtScan(fname)
1252 ucode = dtb.GetNode('/microcode')
1253 self.assertTrue(ucode)
1254 for node in ucode.subnodes:
1255 self.assertFalse(node.props.get('data'))
1257 # Check that the microcode appears immediately after the Fdt
1258 # This matches the concatenation of the data properties in
1259 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1260 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1262 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1264 # Check that the microcode pointer was inserted. It should match the
1265 # expected offset and size
1266 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1268 u_boot = data[:len(nodtb_data)]
1269 return u_boot, pos_and_size
1271 def testPackUbootMicrocode(self):
1272 """Test that x86 microcode can be handled correctly
1274 We expect to see the following in the image, in order:
1275 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1277 u-boot.dtb with the microcode removed
1280 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1282 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1283 b' somewhere in here', first)
1285 def _RunPackUbootSingleMicrocode(self):
1286 """Test that x86 microcode can be handled correctly
1288 We expect to see the following in the image, in order:
1289 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1291 u-boot.dtb with the microcode
1292 an empty microcode region
1294 # We need the libfdt library to run this test since only that allows
1295 # finding the offset of a property. This is required by
1296 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1297 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1299 second = data[len(U_BOOT_NODTB_DATA):]
1301 fdt_len = self.GetFdtLen(second)
1302 third = second[fdt_len:]
1303 second = second[:fdt_len]
1305 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1306 self.assertIn(ucode_data, second)
1307 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1309 # Check that the microcode pointer was inserted. It should match the
1310 # expected offset and size
1311 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1313 first = data[:len(U_BOOT_NODTB_DATA)]
1314 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1315 b' somewhere in here', first)
1317 def testPackUbootSingleMicrocode(self):
1318 """Test that x86 microcode can be handled correctly with fdt_normal.
1320 self._RunPackUbootSingleMicrocode()
1322 def testUBootImg(self):
1323 """Test that u-boot.img can be put in a file"""
1324 data = self._DoReadFile('036_u_boot_img.dts')
1325 self.assertEqual(U_BOOT_IMG_DATA, data)
1327 def testNoMicrocode(self):
1328 """Test that a missing microcode region is detected"""
1329 with self.assertRaises(ValueError) as e:
1330 self._DoReadFile('037_x86_no_ucode.dts', True)
1331 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1332 "node found in ", str(e.exception))
1334 def testMicrocodeWithoutNode(self):
1335 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1336 with self.assertRaises(ValueError) as e:
1337 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1338 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1339 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1341 def testMicrocodeWithoutNode2(self):
1342 """Test that a missing u-boot-ucode node is detected"""
1343 with self.assertRaises(ValueError) as e:
1344 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1345 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1346 "microcode region u-boot-ucode", str(e.exception))
1348 def testMicrocodeWithoutPtrInElf(self):
1349 """Test that a U-Boot binary without the microcode symbol is detected"""
1350 # ELF file without a '_dt_ucode_base_size' symbol
1352 TestFunctional._MakeInputFile('u-boot',
1353 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1355 with self.assertRaises(ValueError) as e:
1356 self._RunPackUbootSingleMicrocode()
1357 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1358 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1361 # Put the original file back
1362 TestFunctional._MakeInputFile('u-boot',
1363 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
1365 def testMicrocodeNotInImage(self):
1366 """Test that microcode must be placed within the image"""
1367 with self.assertRaises(ValueError) as e:
1368 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1369 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1370 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1371 "section ranging from 00000000 to 0000002e", str(e.exception))
1373 def testWithoutMicrocode(self):
1374 """Test that we can cope with an image without microcode (e.g. qemu)"""
1375 TestFunctional._MakeInputFile('u-boot',
1376 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1377 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1379 # Now check the device tree has no microcode
1380 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1381 second = data[len(U_BOOT_NODTB_DATA):]
1383 fdt_len = self.GetFdtLen(second)
1384 self.assertEqual(dtb, second[:fdt_len])
1386 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1387 third = data[used_len:]
1388 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
1390 def testUnknownPosSize(self):
1391 """Test that microcode must be placed within the image"""
1392 with self.assertRaises(ValueError) as e:
1393 self._DoReadFile('041_unknown_pos_size.dts', True)
1394 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1395 "entry 'invalid-entry'", str(e.exception))
1397 def testPackFsp(self):
1398 """Test that an image with a FSP binary can be created"""
1399 data = self._DoReadFile('042_intel_fsp.dts')
1400 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1402 def testPackCmc(self):
1403 """Test that an image with a CMC binary can be created"""
1404 data = self._DoReadFile('043_intel_cmc.dts')
1405 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1407 def testPackVbt(self):
1408 """Test that an image with a VBT binary can be created"""
1409 data = self._DoReadFile('046_intel_vbt.dts')
1410 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1412 def testSplBssPad(self):
1413 """Test that we can pad SPL's BSS with zeros"""
1414 # ELF file with a '__bss_size' symbol
1416 data = self._DoReadFile('047_spl_bss_pad.dts')
1417 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
1420 def testSplBssPadMissing(self):
1421 """Test that a missing symbol is detected"""
1422 self._SetupSplElf('u_boot_ucode_ptr')
1423 with self.assertRaises(ValueError) as e:
1424 self._DoReadFile('047_spl_bss_pad.dts')
1425 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1428 def testPackStart16Spl(self):
1429 """Test that an image with an x86 start16 SPL region can be created"""
1430 data = self._DoReadFile('048_x86_start16_spl.dts')
1431 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1433 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1434 """Helper function for microcode tests
1436 We expect to see the following in the image, in order:
1437 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1439 u-boot.dtb with the microcode removed
1443 dts: Device tree file to use for test
1444 ucode_second: True if the microsecond entry is second instead of
1447 self._SetupSplElf('u_boot_ucode_ptr')
1448 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1449 ucode_second=ucode_second)
1450 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1451 b'ter somewhere in here', first)
1453 def testPackUbootSplMicrocode(self):
1454 """Test that x86 microcode can be handled correctly in SPL"""
1456 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1458 def testPackUbootSplMicrocodeReorder(self):
1459 """Test that order doesn't matter for microcode entries
1461 This is the same as testPackUbootSplMicrocode but when we process the
1462 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1463 entry, so we reply on binman to try later.
1465 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1468 def testPackMrc(self):
1469 """Test that an image with an MRC binary can be created"""
1470 data = self._DoReadFile('050_intel_mrc.dts')
1471 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1473 def testSplDtb(self):
1474 """Test that an image with spl/u-boot-spl.dtb can be created"""
1476 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1477 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1479 def testSplNoDtb(self):
1480 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1482 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1483 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1485 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1486 use_expanded=False, no_write_symbols=False):
1487 """Check the image contains the expected symbol values
1490 dts: Device tree file to use for test
1491 base_data: Data before and after 'u-boot' section
1492 u_boot_offset: Offset of 'u-boot' section in image
1493 entry_args: Dict of entry args to supply to binman
1495 value: value of that arg
1496 use_expanded: True to use expanded entries where available, e.g.
1497 'u-boot-expanded' instead of 'u-boot'
1499 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1500 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1501 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1502 self.assertEqual(syms['_binman_sym_magic'].address, addr)
1503 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1506 self._SetupSplElf('u_boot_binman_syms')
1507 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1508 use_expanded=use_expanded)[0]
1509 # The image should contain the symbols from u_boot_binman_syms.c
1510 # Note that image_pos is adjusted by the base address of the image,
1511 # which is 0x10 in our test image
1512 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1513 0x00, u_boot_offset + len(U_BOOT_DATA),
1514 0x10 + u_boot_offset, 0x04)
1515 if no_write_symbols:
1516 expected = (base_data +
1517 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1518 U_BOOT_DATA + base_data)
1520 expected = (sym_values + base_data[24:] +
1521 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1523 self.assertEqual(expected, data)
1525 def testSymbols(self):
1526 """Test binman can assign symbols embedded in U-Boot"""
1527 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
1529 def testSymbolsNoDtb(self):
1530 """Test binman can assign symbols embedded in U-Boot SPL"""
1531 self.checkSymbols('196_symbols_nodtb.dts',
1532 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1535 def testPackUnitAddress(self):
1536 """Test that we support multiple binaries with the same name"""
1537 data = self._DoReadFile('054_unit_address.dts')
1538 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1540 def testSections(self):
1541 """Basic test of sections"""
1542 data = self._DoReadFile('055_sections.dts')
1543 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1544 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1545 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
1546 self.assertEqual(expected, data)
1549 """Tests outputting a map of the images"""
1550 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1551 self.assertEqual('''ImagePos Offset Size Name
1552 00000000 00000000 00000028 image
1553 00000000 00000000 00000010 section@0
1554 00000000 00000000 00000004 u-boot
1555 00000010 00000010 00000010 section@1
1556 00000010 00000000 00000004 u-boot
1557 00000020 00000020 00000004 section@2
1558 00000020 00000000 00000004 u-boot
1561 def testNamePrefix(self):
1562 """Tests that name prefixes are used"""
1563 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1564 self.assertEqual('''ImagePos Offset Size Name
1565 00000000 00000000 00000028 image
1566 00000000 00000000 00000010 section@0
1567 00000000 00000000 00000004 ro-u-boot
1568 00000010 00000010 00000010 section@1
1569 00000010 00000000 00000004 rw-u-boot
1572 def testUnknownContents(self):
1573 """Test that obtaining the contents works as expected"""
1574 with self.assertRaises(ValueError) as e:
1575 self._DoReadFile('057_unknown_contents.dts', True)
1576 self.assertIn("Image '/binman': Internal error: Could not complete "
1577 "processing of contents: remaining ["
1578 "<binman.etype._testing.Entry__testing ", str(e.exception))
1580 def testBadChangeSize(self):
1581 """Test that trying to change the size of an entry fails"""
1583 state.SetAllowEntryExpansion(False)
1584 with self.assertRaises(ValueError) as e:
1585 self._DoReadFile('059_change_size.dts', True)
1586 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1589 state.SetAllowEntryExpansion(True)
1591 def testUpdateFdt(self):
1592 """Test that we can update the device tree with offset/size info"""
1593 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1595 dtb = fdt.Fdt(out_dtb_fname)
1597 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1601 '_testing:offset': 32,
1603 '_testing:image-pos': 32,
1604 'section@0/u-boot:offset': 0,
1605 'section@0/u-boot:size': len(U_BOOT_DATA),
1606 'section@0/u-boot:image-pos': 0,
1607 'section@0:offset': 0,
1608 'section@0:size': 16,
1609 'section@0:image-pos': 0,
1611 'section@1/u-boot:offset': 0,
1612 'section@1/u-boot:size': len(U_BOOT_DATA),
1613 'section@1/u-boot:image-pos': 16,
1614 'section@1:offset': 16,
1615 'section@1:size': 16,
1616 'section@1:image-pos': 16,
1620 def testUpdateFdtBad(self):
1621 """Test that we detect when ProcessFdt never completes"""
1622 with self.assertRaises(ValueError) as e:
1623 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1624 self.assertIn('Could not complete processing of Fdt: remaining '
1625 '[<binman.etype._testing.Entry__testing',
1628 def testEntryArgs(self):
1629 """Test passing arguments to entries from the command line"""
1631 'test-str-arg': 'test1',
1632 'test-int-arg': '456',
1634 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1635 self.assertIn('image', control.images)
1636 entry = control.images['image'].GetEntries()['_testing']
1637 self.assertEqual('test0', entry.test_str_fdt)
1638 self.assertEqual('test1', entry.test_str_arg)
1639 self.assertEqual(123, entry.test_int_fdt)
1640 self.assertEqual(456, entry.test_int_arg)
1642 def testEntryArgsMissing(self):
1643 """Test missing arguments and properties"""
1645 'test-int-arg': '456',
1647 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1648 entry = control.images['image'].GetEntries()['_testing']
1649 self.assertEqual('test0', entry.test_str_fdt)
1650 self.assertEqual(None, entry.test_str_arg)
1651 self.assertEqual(None, entry.test_int_fdt)
1652 self.assertEqual(456, entry.test_int_arg)
1654 def testEntryArgsRequired(self):
1655 """Test missing arguments and properties"""
1657 'test-int-arg': '456',
1659 with self.assertRaises(ValueError) as e:
1660 self._DoReadFileDtb('064_entry_args_required.dts')
1661 self.assertIn("Node '/binman/_testing': "
1662 'Missing required properties/entry args: test-str-arg, '
1663 'test-int-fdt, test-int-arg',
1666 def testEntryArgsInvalidFormat(self):
1667 """Test that an invalid entry-argument format is detected"""
1668 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1670 with self.assertRaises(ValueError) as e:
1671 self._DoBinman(*args)
1672 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1674 def testEntryArgsInvalidInteger(self):
1675 """Test that an invalid entry-argument integer is detected"""
1677 'test-int-arg': 'abc',
1679 with self.assertRaises(ValueError) as e:
1680 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1681 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1682 "'test-int-arg' (value 'abc') to integer",
1685 def testEntryArgsInvalidDatatype(self):
1686 """Test that an invalid entry-argument datatype is detected
1688 This test could be written in entry_test.py except that it needs
1689 access to control.entry_args, which seems more than that module should
1693 'test-bad-datatype-arg': '12',
1695 with self.assertRaises(ValueError) as e:
1696 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1697 entry_args=entry_args)
1698 self.assertIn('GetArg() internal error: Unknown data type ',
1702 """Test for a text entry type"""
1704 'test-id': TEXT_DATA,
1705 'test-id2': TEXT_DATA2,
1706 'test-id3': TEXT_DATA3,
1708 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1709 entry_args=entry_args)
1710 expected = (tools.to_bytes(TEXT_DATA) +
1711 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1712 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
1713 b'some text' + b'more text')
1714 self.assertEqual(expected, data)
1716 def testEntryDocs(self):
1717 """Test for creation of entry documentation"""
1718 with test_util.capture_sys_output() as (stdout, stderr):
1719 control.WriteEntryDocs(control.GetEntryModules())
1720 self.assertTrue(len(stdout.getvalue()) > 0)
1722 def testEntryDocsMissing(self):
1723 """Test handling of missing entry documentation"""
1724 with self.assertRaises(ValueError) as e:
1725 with test_util.capture_sys_output() as (stdout, stderr):
1726 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1727 self.assertIn('Documentation is missing for modules: u_boot',
1731 """Basic test of generation of a flashrom fmap"""
1732 data = self._DoReadFile('067_fmap.dts')
1733 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1734 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1735 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
1736 self.assertEqual(expected, data[:32])
1737 self.assertEqual(b'__FMAP__', fhdr.signature)
1738 self.assertEqual(1, fhdr.ver_major)
1739 self.assertEqual(0, fhdr.ver_minor)
1740 self.assertEqual(0, fhdr.base)
1741 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1742 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1743 self.assertEqual(b'FMAP', fhdr.name)
1744 self.assertEqual(5, fhdr.nareas)
1745 fiter = iter(fentries)
1747 fentry = next(fiter)
1748 self.assertEqual(b'SECTION0', fentry.name)
1749 self.assertEqual(0, fentry.offset)
1750 self.assertEqual(16, fentry.size)
1751 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
1753 fentry = next(fiter)
1754 self.assertEqual(b'RO_U_BOOT', fentry.name)
1755 self.assertEqual(0, fentry.offset)
1756 self.assertEqual(4, fentry.size)
1757 self.assertEqual(0, fentry.flags)
1759 fentry = next(fiter)
1760 self.assertEqual(b'SECTION1', fentry.name)
1761 self.assertEqual(16, fentry.offset)
1762 self.assertEqual(16, fentry.size)
1763 self.assertEqual(0, fentry.flags)
1765 fentry = next(fiter)
1766 self.assertEqual(b'RW_U_BOOT', fentry.name)
1767 self.assertEqual(16, fentry.offset)
1768 self.assertEqual(4, fentry.size)
1769 self.assertEqual(0, fentry.flags)
1771 fentry = next(fiter)
1772 self.assertEqual(b'FMAP', fentry.name)
1773 self.assertEqual(32, fentry.offset)
1774 self.assertEqual(expect_size, fentry.size)
1775 self.assertEqual(0, fentry.flags)
1777 def testBlobNamedByArg(self):
1778 """Test we can add a blob with the filename coming from an entry arg"""
1780 'cros-ec-rw-path': 'ecrw.bin',
1782 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1785 """Test for an fill entry type"""
1786 data = self._DoReadFile('069_fill.dts')
1787 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
1788 self.assertEqual(expected, data)
1790 def testFillNoSize(self):
1791 """Test for an fill entry type with no size"""
1792 with self.assertRaises(ValueError) as e:
1793 self._DoReadFile('070_fill_no_size.dts')
1794 self.assertIn("'fill' entry is missing properties: size",
1797 def _HandleGbbCommand(self, pipe_list):
1798 """Fake calls to the futility utility"""
1799 if 'futility' in pipe_list[0][0]:
1800 fname = pipe_list[0][-1]
1801 # Append our GBB data to the file, which will happen every time the
1802 # futility command is called.
1803 with open(fname, 'ab') as fd:
1805 return command.CommandResult()
1808 """Test for the Chromium OS Google Binary Block"""
1809 command.test_result = self._HandleGbbCommand
1811 'keydir': 'devkeys',
1812 'bmpblk': 'bmpblk.bin',
1814 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1817 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1818 tools.get_bytes(0, 0x2180 - 16))
1819 self.assertEqual(expected, data)
1821 def testGbbTooSmall(self):
1822 """Test for the Chromium OS Google Binary Block being large enough"""
1823 with self.assertRaises(ValueError) as e:
1824 self._DoReadFileDtb('072_gbb_too_small.dts')
1825 self.assertIn("Node '/binman/gbb': GBB is too small",
1828 def testGbbNoSize(self):
1829 """Test for the Chromium OS Google Binary Block having a size"""
1830 with self.assertRaises(ValueError) as e:
1831 self._DoReadFileDtb('073_gbb_no_size.dts')
1832 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1835 def testGbbMissing(self):
1836 """Test that binman still produces an image if futility is missing"""
1838 'keydir': 'devkeys',
1840 with test_util.capture_sys_output() as (_, stderr):
1841 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1842 entry_args=entry_args)
1843 err = stderr.getvalue()
1844 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
1846 def _HandleVblockCommand(self, pipe_list):
1847 """Fake calls to the futility utility
1849 The expected pipe is:
1851 [('futility', 'vbutil_firmware', '--vblock',
1852 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1853 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1854 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1855 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1857 This writes to the output file (here, 'vblock.vblock'). If
1858 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1859 of the input data (here, 'input.vblock').
1861 if 'futility' in pipe_list[0][0]:
1862 fname = pipe_list[0][3]
1863 with open(fname, 'wb') as fd:
1865 infile = pipe_list[0][11]
1866 m = hashlib.sha256()
1867 data = tools.read_file(infile)
1869 fd.write(m.digest())
1871 fd.write(VBLOCK_DATA)
1873 return command.CommandResult()
1875 def testVblock(self):
1876 """Test for the Chromium OS Verified Boot Block"""
1877 self._hash_data = False
1878 command.test_result = self._HandleVblockCommand
1880 'keydir': 'devkeys',
1882 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1883 entry_args=entry_args)
1884 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1885 self.assertEqual(expected, data)
1887 def testVblockNoContent(self):
1888 """Test we detect a vblock which has no content to sign"""
1889 with self.assertRaises(ValueError) as e:
1890 self._DoReadFile('075_vblock_no_content.dts')
1891 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1892 'property', str(e.exception))
1894 def testVblockBadPhandle(self):
1895 """Test that we detect a vblock with an invalid phandle in contents"""
1896 with self.assertRaises(ValueError) as e:
1897 self._DoReadFile('076_vblock_bad_phandle.dts')
1898 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1899 '1000', str(e.exception))
1901 def testVblockBadEntry(self):
1902 """Test that we detect an entry that points to a non-entry"""
1903 with self.assertRaises(ValueError) as e:
1904 self._DoReadFile('077_vblock_bad_entry.dts')
1905 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1906 "'other'", str(e.exception))
1908 def testVblockContent(self):
1909 """Test that the vblock signs the right data"""
1910 self._hash_data = True
1911 command.test_result = self._HandleVblockCommand
1913 'keydir': 'devkeys',
1915 data = self._DoReadFileDtb(
1916 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1917 entry_args=entry_args)[0]
1918 hashlen = 32 # SHA256 hash is 32 bytes
1919 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1920 hashval = data[-hashlen:]
1921 dtb = data[len(U_BOOT_DATA):-hashlen]
1923 expected_data = U_BOOT_DATA + dtb
1925 # The hashval should be a hash of the dtb
1926 m = hashlib.sha256()
1927 m.update(expected_data)
1928 expected_hashval = m.digest()
1929 self.assertEqual(expected_hashval, hashval)
1931 def testVblockMissing(self):
1932 """Test that binman still produces an image if futility is missing"""
1934 'keydir': 'devkeys',
1936 with test_util.capture_sys_output() as (_, stderr):
1937 self._DoTestFile('074_vblock.dts',
1938 force_missing_bintools='futility',
1939 entry_args=entry_args)
1940 err = stderr.getvalue()
1941 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
1944 """Test that an image with TPL and its device tree can be created"""
1945 # ELF file with a '__bss_size' symbol
1947 data = self._DoReadFile('078_u_boot_tpl.dts')
1948 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1950 def testUsesPos(self):
1951 """Test that the 'pos' property cannot be used anymore"""
1952 with self.assertRaises(ValueError) as e:
1953 data = self._DoReadFile('079_uses_pos.dts')
1954 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1955 "'pos'", str(e.exception))
1957 def testFillZero(self):
1958 """Test for an fill entry type with a size of 0"""
1959 data = self._DoReadFile('080_fill_empty.dts')
1960 self.assertEqual(tools.get_bytes(0, 16), data)
1962 def testTextMissing(self):
1963 """Test for a text entry type where there is no text"""
1964 with self.assertRaises(ValueError) as e:
1965 self._DoReadFileDtb('066_text.dts',)
1966 self.assertIn("Node '/binman/text': No value provided for text label "
1967 "'test-id'", str(e.exception))
1969 def testPackStart16Tpl(self):
1970 """Test that an image with an x86 start16 TPL region can be created"""
1971 data = self._DoReadFile('081_x86_start16_tpl.dts')
1972 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1974 def testSelectImage(self):
1975 """Test that we can select which images to build"""
1976 expected = 'Skipping images: image1'
1978 # We should only get the expected message in verbose mode
1979 for verbosity in (0, 2):
1980 with test_util.capture_sys_output() as (stdout, stderr):
1981 retcode = self._DoTestFile('006_dual_image.dts',
1982 verbosity=verbosity,
1984 self.assertEqual(0, retcode)
1986 self.assertIn(expected, stdout.getvalue())
1988 self.assertNotIn(expected, stdout.getvalue())
1990 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1991 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
1992 self._CleanupOutputDir()
1994 def testUpdateFdtAll(self):
1995 """Test that all device trees are updated with offset/size info"""
1998 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
2004 'section:offset': 0,
2005 'section:image-pos': 0,
2006 'section:size': 565,
2007 'section/u-boot-dtb:offset': 0,
2008 'section/u-boot-dtb:image-pos': 0,
2009 'section/u-boot-dtb:size': 565,
2010 'u-boot-spl-dtb:offset': 565,
2011 'u-boot-spl-dtb:image-pos': 565,
2012 'u-boot-spl-dtb:size': 585,
2013 'u-boot-tpl-dtb:offset': 1150,
2014 'u-boot-tpl-dtb:image-pos': 1150,
2015 'u-boot-tpl-dtb:size': 585,
2016 'u-boot-vpl-dtb:image-pos': 1735,
2017 'u-boot-vpl-dtb:offset': 1735,
2018 'u-boot-vpl-dtb:size': 585,
2021 # We expect three device-tree files in the output, one after the other.
2022 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2023 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2024 # main U-Boot tree. All three should have the same postions and offset.
2027 for item in ['', 'spl', 'tpl', 'vpl']:
2028 dtb = fdt.Fdt.FromData(data[start:])
2030 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
2031 ['spl', 'tpl', 'vpl'])
2032 expected = dict(base_expected)
2035 self.assertEqual(expected, props)
2036 start += dtb._fdt_obj.totalsize()
2038 def testUpdateFdtOutput(self):
2039 """Test that output DTB files are updated"""
2041 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
2042 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2044 # Unfortunately, compiling a source file always results in a file
2045 # called source.dtb (see fdt_util.EnsureCompiled()). The test
2046 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
2047 # binman as a file called u-boot.dtb. To fix this, copy the file
2048 # over to the expected place.
2050 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
2051 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
2052 dtb = fdt.Fdt.FromData(data[start:])
2053 size = dtb._fdt_obj.totalsize()
2054 pathname = tools.get_output_filename(os.path.split(fname)[1])
2055 outdata = tools.read_file(pathname)
2056 name = os.path.split(fname)[0]
2059 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
2061 orig_indata = dtb_data
2062 self.assertNotEqual(outdata, orig_indata,
2063 "Expected output file '%s' be updated" % pathname)
2064 self.assertEqual(outdata, data[start:start + size],
2065 "Expected output file '%s' to match output image" %
2071 def _decompress(self, data):
2072 bintool = self.comp_bintools['lz4']
2073 return bintool.decompress(data)
2075 def testCompress(self):
2076 """Test compression of blobs"""
2078 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
2079 use_real_dtb=True, update_dtb=True)
2080 dtb = fdt.Fdt(out_dtb_fname)
2082 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2083 orig = self._decompress(data)
2084 self.assertEquals(COMPRESS_DATA, orig)
2086 # Do a sanity check on various fields
2087 image = control.images['image']
2088 entries = image.GetEntries()
2089 self.assertEqual(1, len(entries))
2091 entry = entries['blob']
2092 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2093 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2094 orig = self._decompress(entry.data)
2095 self.assertEqual(orig, entry.uncomp_data)
2097 self.assertEqual(image.data, entry.data)
2100 'blob:uncomp-size': len(COMPRESS_DATA),
2101 'blob:size': len(data),
2104 self.assertEqual(expected, props)
2106 def testFiles(self):
2107 """Test bringing in multiple files"""
2108 data = self._DoReadFile('084_files.dts')
2109 self.assertEqual(FILES_DATA, data)
2111 def testFilesCompress(self):
2112 """Test bringing in multiple files and compressing them"""
2114 data = self._DoReadFile('085_files_compress.dts')
2116 image = control.images['image']
2117 entries = image.GetEntries()
2118 files = entries['files']
2119 entries = files._entries
2122 for i in range(1, 3):
2124 start = entries[key].image_pos
2125 len = entries[key].size
2126 chunk = data[start:start + len]
2127 orig += self._decompress(chunk)
2129 self.assertEqual(FILES_DATA, orig)
2131 def testFilesMissing(self):
2132 """Test missing files"""
2133 with self.assertRaises(ValueError) as e:
2134 data = self._DoReadFile('086_files_none.dts')
2135 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2136 'no files', str(e.exception))
2138 def testFilesNoPattern(self):
2139 """Test missing files"""
2140 with self.assertRaises(ValueError) as e:
2141 data = self._DoReadFile('087_files_no_pattern.dts')
2142 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2145 def testExtendSize(self):
2146 """Test an extending entry"""
2147 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
2149 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2150 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2151 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2152 tools.get_bytes(ord('d'), 8))
2153 self.assertEqual(expect, data)
2154 self.assertEqual('''ImagePos Offset Size Name
2155 00000000 00000000 00000028 image
2156 00000000 00000000 00000008 fill
2157 00000008 00000008 00000004 u-boot
2158 0000000c 0000000c 00000004 section
2159 0000000c 00000000 00000003 intel-mrc
2160 00000010 00000010 00000004 u-boot2
2161 00000014 00000014 0000000c section2
2162 00000014 00000000 00000008 fill
2163 0000001c 00000008 00000004 u-boot
2164 00000020 00000020 00000008 fill2
2167 def testExtendSizeBad(self):
2168 """Test an extending entry which fails to provide contents"""
2169 with test_util.capture_sys_output() as (stdout, stderr):
2170 with self.assertRaises(ValueError) as e:
2171 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
2172 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2173 'expanding entry', str(e.exception))
2176 """Test hashing of the contents of an entry"""
2177 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2178 use_real_dtb=True, update_dtb=True)
2179 dtb = fdt.Fdt(out_dtb_fname)
2181 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2182 m = hashlib.sha256()
2183 m.update(U_BOOT_DATA)
2184 self.assertEqual(m.digest(), b''.join(hash_node.value))
2186 def testHashNoAlgo(self):
2187 with self.assertRaises(ValueError) as e:
2188 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2189 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2190 'hash node', str(e.exception))
2192 def testHashBadAlgo(self):
2193 with self.assertRaises(ValueError) as e:
2194 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2195 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
2198 def testHashSection(self):
2199 """Test hashing of the contents of an entry"""
2200 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2201 use_real_dtb=True, update_dtb=True)
2202 dtb = fdt.Fdt(out_dtb_fname)
2204 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2205 m = hashlib.sha256()
2206 m.update(U_BOOT_DATA)
2207 m.update(tools.get_bytes(ord('a'), 16))
2208 self.assertEqual(m.digest(), b''.join(hash_node.value))
2210 def testPackUBootTplMicrocode(self):
2211 """Test that x86 microcode can be handled correctly in TPL
2213 We expect to see the following in the image, in order:
2214 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2216 u-boot-tpl.dtb with the microcode removed
2219 self._SetupTplElf('u_boot_ucode_ptr')
2220 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2221 U_BOOT_TPL_NODTB_DATA)
2222 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2223 b'ter somewhere in here', first)
2225 def testFmapX86(self):
2226 """Basic test of generation of a flashrom fmap"""
2227 data = self._DoReadFile('094_fmap_x86.dts')
2228 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2229 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
2230 self.assertEqual(expected, data[:32])
2231 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2233 self.assertEqual(0x100, fhdr.image_size)
2235 self.assertEqual(0, fentries[0].offset)
2236 self.assertEqual(4, fentries[0].size)
2237 self.assertEqual(b'U_BOOT', fentries[0].name)
2239 self.assertEqual(4, fentries[1].offset)
2240 self.assertEqual(3, fentries[1].size)
2241 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2243 self.assertEqual(32, fentries[2].offset)
2244 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2245 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2246 self.assertEqual(b'FMAP', fentries[2].name)
2248 def testFmapX86Section(self):
2249 """Basic test of generation of a flashrom fmap"""
2250 data = self._DoReadFile('095_fmap_x86_section.dts')
2251 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
2252 self.assertEqual(expected, data[:32])
2253 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2255 self.assertEqual(0x180, fhdr.image_size)
2256 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2257 fiter = iter(fentries)
2259 fentry = next(fiter)
2260 self.assertEqual(b'U_BOOT', fentry.name)
2261 self.assertEqual(0, fentry.offset)
2262 self.assertEqual(4, fentry.size)
2264 fentry = next(fiter)
2265 self.assertEqual(b'SECTION', fentry.name)
2266 self.assertEqual(4, fentry.offset)
2267 self.assertEqual(0x20 + expect_size, fentry.size)
2269 fentry = next(fiter)
2270 self.assertEqual(b'INTEL_MRC', fentry.name)
2271 self.assertEqual(4, fentry.offset)
2272 self.assertEqual(3, fentry.size)
2274 fentry = next(fiter)
2275 self.assertEqual(b'FMAP', fentry.name)
2276 self.assertEqual(36, fentry.offset)
2277 self.assertEqual(expect_size, fentry.size)
2280 """Basic test of ELF entries"""
2283 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2284 TestFunctional._MakeInputFile('-boot', fd.read())
2285 data = self._DoReadFile('096_elf.dts')
2287 def testElfStrip(self):
2288 """Basic test of ELF entries"""
2290 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2291 TestFunctional._MakeInputFile('-boot', fd.read())
2292 data = self._DoReadFile('097_elf_strip.dts')
2294 def testPackOverlapMap(self):
2295 """Test that overlapping regions are detected"""
2296 with test_util.capture_sys_output() as (stdout, stderr):
2297 with self.assertRaises(ValueError) as e:
2298 self._DoTestFile('014_pack_overlap.dts', map=True)
2299 map_fname = tools.get_output_filename('image.map')
2300 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2303 # We should not get an inmage, but there should be a map file
2304 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
2305 self.assertTrue(os.path.exists(map_fname))
2306 map_data = tools.read_file(map_fname, binary=False)
2307 self.assertEqual('''ImagePos Offset Size Name
2308 <none> 00000000 00000008 image
2309 <none> 00000000 00000004 u-boot
2310 <none> 00000003 00000004 u-boot-align
2313 def testPackRefCode(self):
2314 """Test that an image with an Intel Reference code binary works"""
2315 data = self._DoReadFile('100_intel_refcode.dts')
2316 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2318 def testSectionOffset(self):
2319 """Tests use of a section with an offset"""
2320 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2322 self.assertEqual('''ImagePos Offset Size Name
2323 00000000 00000000 00000038 image
2324 00000004 00000004 00000010 section@0
2325 00000004 00000000 00000004 u-boot
2326 00000018 00000018 00000010 section@1
2327 00000018 00000000 00000004 u-boot
2328 0000002c 0000002c 00000004 section@2
2329 0000002c 00000000 00000004 u-boot
2331 self.assertEqual(data,
2332 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2333 tools.get_bytes(0x21, 12) +
2334 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2335 tools.get_bytes(0x61, 12) +
2336 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2337 tools.get_bytes(0x26, 8))
2339 def testCbfsRaw(self):
2340 """Test base handling of a Coreboot Filesystem (CBFS)
2342 The exact contents of the CBFS is verified by similar tests in
2343 cbfs_util_test.py. The tests here merely check that the files added to
2344 the CBFS can be found in the final image.
2346 data = self._DoReadFile('102_cbfs_raw.dts')
2349 cbfs = cbfs_util.CbfsReader(data)
2350 self.assertEqual(size, cbfs.rom_size)
2352 self.assertIn('u-boot-dtb', cbfs.files)
2353 cfile = cbfs.files['u-boot-dtb']
2354 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2356 def testCbfsArch(self):
2357 """Test on non-x86 architecture"""
2358 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2361 cbfs = cbfs_util.CbfsReader(data)
2362 self.assertEqual(size, cbfs.rom_size)
2364 self.assertIn('u-boot-dtb', cbfs.files)
2365 cfile = cbfs.files['u-boot-dtb']
2366 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2368 def testCbfsStage(self):
2369 """Tests handling of a Coreboot Filesystem (CBFS)"""
2370 if not elf.ELF_TOOLS:
2371 self.skipTest('Python elftools not available')
2372 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2373 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2376 data = self._DoReadFile('104_cbfs_stage.dts')
2377 cbfs = cbfs_util.CbfsReader(data)
2378 self.assertEqual(size, cbfs.rom_size)
2380 self.assertIn('u-boot', cbfs.files)
2381 cfile = cbfs.files['u-boot']
2382 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2384 def testCbfsRawCompress(self):
2385 """Test handling of compressing raw files"""
2387 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2390 cbfs = cbfs_util.CbfsReader(data)
2391 self.assertIn('u-boot', cbfs.files)
2392 cfile = cbfs.files['u-boot']
2393 self.assertEqual(COMPRESS_DATA, cfile.data)
2395 def testCbfsBadArch(self):
2396 """Test handling of a bad architecture"""
2397 with self.assertRaises(ValueError) as e:
2398 self._DoReadFile('106_cbfs_bad_arch.dts')
2399 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2401 def testCbfsNoSize(self):
2402 """Test handling of a missing size property"""
2403 with self.assertRaises(ValueError) as e:
2404 self._DoReadFile('107_cbfs_no_size.dts')
2405 self.assertIn('entry must have a size property', str(e.exception))
2407 def testCbfsNoContents(self):
2408 """Test handling of a CBFS entry which does not provide contentsy"""
2409 with self.assertRaises(ValueError) as e:
2410 self._DoReadFile('108_cbfs_no_contents.dts')
2411 self.assertIn('Could not complete processing of contents',
2414 def testCbfsBadCompress(self):
2415 """Test handling of a bad architecture"""
2416 with self.assertRaises(ValueError) as e:
2417 self._DoReadFile('109_cbfs_bad_compress.dts')
2418 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2421 def testCbfsNamedEntries(self):
2422 """Test handling of named entries"""
2423 data = self._DoReadFile('110_cbfs_name.dts')
2425 cbfs = cbfs_util.CbfsReader(data)
2426 self.assertIn('FRED', cbfs.files)
2427 cfile1 = cbfs.files['FRED']
2428 self.assertEqual(U_BOOT_DATA, cfile1.data)
2430 self.assertIn('hello', cbfs.files)
2431 cfile2 = cbfs.files['hello']
2432 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2434 def _SetupIfwi(self, fname):
2435 """Set up to run an IFWI test
2438 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2443 # Intel Integrated Firmware Image (IFWI) file
2444 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2446 TestFunctional._MakeInputFile(fname,data)
2448 def _CheckIfwi(self, data):
2449 """Check that an image with an IFWI contains the correct output
2452 data: Conents of output file
2454 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
2455 if data[:0x1000] != expected_desc:
2456 self.fail('Expected descriptor binary at start of image')
2458 # We expect to find the TPL wil in subpart IBBP entry IBBL
2459 image_fname = tools.get_output_filename('image.bin')
2460 tpl_fname = tools.get_output_filename('tpl.out')
2461 ifwitool = bintool.Bintool.create('ifwitool')
2462 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
2464 tpl_data = tools.read_file(tpl_fname)
2465 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2467 def testPackX86RomIfwi(self):
2468 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2469 self._SetupIfwi('fitimage.bin')
2470 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2471 self._CheckIfwi(data)
2473 def testPackX86RomIfwiNoDesc(self):
2474 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2475 self._SetupIfwi('ifwi.bin')
2476 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2477 self._CheckIfwi(data)
2479 def testPackX86RomIfwiNoData(self):
2480 """Test that an x86 ROM with IFWI handles missing data"""
2481 self._SetupIfwi('ifwi.bin')
2482 with self.assertRaises(ValueError) as e:
2483 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2484 self.assertIn('Could not complete processing of contents',
2487 def testIfwiMissing(self):
2488 """Test that binman still produces an image if ifwitool is missing"""
2489 self._SetupIfwi('fitimage.bin')
2490 with test_util.capture_sys_output() as (_, stderr):
2491 self._DoTestFile('111_x86_rom_ifwi.dts',
2492 force_missing_bintools='ifwitool')
2493 err = stderr.getvalue()
2494 self.assertRegex(err,
2495 "Image 'image'.*missing bintools.*: ifwitool")
2497 def testCbfsOffset(self):
2498 """Test a CBFS with files at particular offsets
2500 Like all CFBS tests, this is just checking the logic that calls
2501 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2503 data = self._DoReadFile('114_cbfs_offset.dts')
2506 cbfs = cbfs_util.CbfsReader(data)
2507 self.assertEqual(size, cbfs.rom_size)
2509 self.assertIn('u-boot', cbfs.files)
2510 cfile = cbfs.files['u-boot']
2511 self.assertEqual(U_BOOT_DATA, cfile.data)
2512 self.assertEqual(0x40, cfile.cbfs_offset)
2514 self.assertIn('u-boot-dtb', cbfs.files)
2515 cfile2 = cbfs.files['u-boot-dtb']
2516 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2517 self.assertEqual(0x140, cfile2.cbfs_offset)
2519 def testFdtmap(self):
2520 """Test an FDT map can be inserted in the image"""
2521 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2522 fdtmap_data = data[len(U_BOOT_DATA):]
2523 magic = fdtmap_data[:8]
2524 self.assertEqual(b'_FDTMAP_', magic)
2525 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
2527 fdt_data = fdtmap_data[16:]
2528 dtb = fdt.Fdt.FromData(fdt_data)
2530 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2535 'u-boot:size': len(U_BOOT_DATA),
2536 'u-boot:image-pos': 0,
2537 'fdtmap:image-pos': 4,
2539 'fdtmap:size': len(fdtmap_data),
2543 def testFdtmapNoMatch(self):
2544 """Check handling of an FDT map when the section cannot be found"""
2545 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2547 # Mangle the section name, which should cause a mismatch between the
2548 # correct FDT path and the one expected by the section
2549 image = control.images['image']
2550 image._node.path += '-suffix'
2551 entries = image.GetEntries()
2552 fdtmap = entries['fdtmap']
2553 with self.assertRaises(ValueError) as e:
2555 self.assertIn("Cannot locate node for path '/binman-suffix'",
2558 def testFdtmapHeader(self):
2559 """Test an FDT map and image header can be inserted in the image"""
2560 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2561 fdtmap_pos = len(U_BOOT_DATA)
2562 fdtmap_data = data[fdtmap_pos:]
2563 fdt_data = fdtmap_data[16:]
2564 dtb = fdt.Fdt.FromData(fdt_data)
2565 fdt_size = dtb.GetFdtObj().totalsize()
2566 hdr_data = data[-8:]
2567 self.assertEqual(b'BinM', hdr_data[:4])
2568 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2569 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2571 def testFdtmapHeaderStart(self):
2572 """Test an image header can be inserted at the image start"""
2573 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2574 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2576 self.assertEqual(b'BinM', hdr_data[:4])
2577 offset = struct.unpack('<I', hdr_data[4:])[0]
2578 self.assertEqual(fdtmap_pos, offset)
2580 def testFdtmapHeaderPos(self):
2581 """Test an image header can be inserted at a chosen position"""
2582 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2583 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2584 hdr_data = data[0x80:0x88]
2585 self.assertEqual(b'BinM', hdr_data[:4])
2586 offset = struct.unpack('<I', hdr_data[4:])[0]
2587 self.assertEqual(fdtmap_pos, offset)
2589 def testHeaderMissingFdtmap(self):
2590 """Test an image header requires an fdtmap"""
2591 with self.assertRaises(ValueError) as e:
2592 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2593 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2596 def testHeaderNoLocation(self):
2597 """Test an image header with a no specified location is detected"""
2598 with self.assertRaises(ValueError) as e:
2599 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2600 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2603 def testEntryExpand(self):
2604 """Test extending an entry after it is packed"""
2605 data = self._DoReadFile('121_entry_extend.dts')
2606 self.assertEqual(b'aaa', data[:3])
2607 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2608 self.assertEqual(b'aaa', data[-3:])
2610 def testEntryExtendBad(self):
2611 """Test extending an entry after it is packed, twice"""
2612 with self.assertRaises(ValueError) as e:
2613 self._DoReadFile('122_entry_extend_twice.dts')
2614 self.assertIn("Image '/binman': Entries changed size after packing",
2617 def testEntryExtendSection(self):
2618 """Test extending an entry within a section after it is packed"""
2619 data = self._DoReadFile('123_entry_extend_section.dts')
2620 self.assertEqual(b'aaa', data[:3])
2621 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2622 self.assertEqual(b'aaa', data[-3:])
2624 def testCompressDtb(self):
2625 """Test that compress of device-tree files is supported"""
2627 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2628 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2629 comp_data = data[len(U_BOOT_DATA):]
2630 orig = self._decompress(comp_data)
2631 dtb = fdt.Fdt.FromData(orig)
2633 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2635 'u-boot:size': len(U_BOOT_DATA),
2636 'u-boot-dtb:uncomp-size': len(orig),
2637 'u-boot-dtb:size': len(comp_data),
2640 self.assertEqual(expected, props)
2642 def testCbfsUpdateFdt(self):
2643 """Test that we can update the device tree with CBFS offset/size info"""
2645 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2647 dtb = fdt.Fdt(out_dtb_fname)
2649 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2650 del props['cbfs/u-boot:size']
2656 'cbfs:size': len(data),
2657 'cbfs:image-pos': 0,
2658 'cbfs/u-boot:offset': 0x38,
2659 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2660 'cbfs/u-boot:image-pos': 0x38,
2661 'cbfs/u-boot-dtb:offset': 0xb8,
2662 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2663 'cbfs/u-boot-dtb:image-pos': 0xb8,
2666 def testCbfsBadType(self):
2667 """Test an image header with a no specified location is detected"""
2668 with self.assertRaises(ValueError) as e:
2669 self._DoReadFile('126_cbfs_bad_type.dts')
2670 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2673 """Test listing the files in an image"""
2675 data = self._DoReadFile('127_list.dts')
2676 image = control.images['image']
2677 entries = image.BuildEntryList()
2678 self.assertEqual(7, len(entries))
2681 self.assertEqual(0, ent.indent)
2682 self.assertEqual('image', ent.name)
2683 self.assertEqual('section', ent.etype)
2684 self.assertEqual(len(data), ent.size)
2685 self.assertEqual(0, ent.image_pos)
2686 self.assertEqual(None, ent.uncomp_size)
2687 self.assertEqual(0, ent.offset)
2690 self.assertEqual(1, ent.indent)
2691 self.assertEqual('u-boot', ent.name)
2692 self.assertEqual('u-boot', ent.etype)
2693 self.assertEqual(len(U_BOOT_DATA), ent.size)
2694 self.assertEqual(0, ent.image_pos)
2695 self.assertEqual(None, ent.uncomp_size)
2696 self.assertEqual(0, ent.offset)
2699 self.assertEqual(1, ent.indent)
2700 self.assertEqual('section', ent.name)
2701 self.assertEqual('section', ent.etype)
2702 section_size = ent.size
2703 self.assertEqual(0x100, ent.image_pos)
2704 self.assertEqual(None, ent.uncomp_size)
2705 self.assertEqual(0x100, ent.offset)
2708 self.assertEqual(2, ent.indent)
2709 self.assertEqual('cbfs', ent.name)
2710 self.assertEqual('cbfs', ent.etype)
2711 self.assertEqual(0x400, ent.size)
2712 self.assertEqual(0x100, ent.image_pos)
2713 self.assertEqual(None, ent.uncomp_size)
2714 self.assertEqual(0, ent.offset)
2717 self.assertEqual(3, ent.indent)
2718 self.assertEqual('u-boot', ent.name)
2719 self.assertEqual('u-boot', ent.etype)
2720 self.assertEqual(len(U_BOOT_DATA), ent.size)
2721 self.assertEqual(0x138, ent.image_pos)
2722 self.assertEqual(None, ent.uncomp_size)
2723 self.assertEqual(0x38, ent.offset)
2726 self.assertEqual(3, ent.indent)
2727 self.assertEqual('u-boot-dtb', ent.name)
2728 self.assertEqual('text', ent.etype)
2729 self.assertGreater(len(COMPRESS_DATA), ent.size)
2730 self.assertEqual(0x178, ent.image_pos)
2731 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2732 self.assertEqual(0x78, ent.offset)
2735 self.assertEqual(2, ent.indent)
2736 self.assertEqual('u-boot-dtb', ent.name)
2737 self.assertEqual('u-boot-dtb', ent.etype)
2738 self.assertEqual(0x500, ent.image_pos)
2739 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2741 # Compressing this data expands it since headers are added
2742 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2743 self.assertEqual(0x400, ent.offset)
2745 self.assertEqual(len(data), 0x100 + section_size)
2746 self.assertEqual(section_size, 0x400 + dtb_size)
2748 def testFindFdtmap(self):
2749 """Test locating an FDT map in an image"""
2751 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2752 image = control.images['image']
2753 entries = image.GetEntries()
2754 entry = entries['fdtmap']
2755 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2757 def testFindFdtmapMissing(self):
2758 """Test failing to locate an FDP map"""
2759 data = self._DoReadFile('005_simple.dts')
2760 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2762 def testFindImageHeader(self):
2763 """Test locating a image header"""
2765 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2766 image = control.images['image']
2767 entries = image.GetEntries()
2768 entry = entries['fdtmap']
2769 # The header should point to the FDT map
2770 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2772 def testFindImageHeaderStart(self):
2773 """Test locating a image header located at the start of an image"""
2774 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2775 image = control.images['image']
2776 entries = image.GetEntries()
2777 entry = entries['fdtmap']
2778 # The header should point to the FDT map
2779 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2781 def testFindImageHeaderMissing(self):
2782 """Test failing to locate an image header"""
2783 data = self._DoReadFile('005_simple.dts')
2784 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2786 def testReadImage(self):
2787 """Test reading an image and accessing its FDT map"""
2789 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2790 image_fname = tools.get_output_filename('image.bin')
2791 orig_image = control.images['image']
2792 image = Image.FromFile(image_fname)
2793 self.assertEqual(orig_image.GetEntries().keys(),
2794 image.GetEntries().keys())
2796 orig_entry = orig_image.GetEntries()['fdtmap']
2797 entry = image.GetEntries()['fdtmap']
2798 self.assertEquals(orig_entry.offset, entry.offset)
2799 self.assertEquals(orig_entry.size, entry.size)
2800 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2802 def testReadImageNoHeader(self):
2803 """Test accessing an image's FDT map without an image header"""
2805 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2806 image_fname = tools.get_output_filename('image.bin')
2807 image = Image.FromFile(image_fname)
2808 self.assertTrue(isinstance(image, Image))
2809 self.assertEqual('image', image.image_name[-5:])
2811 def testReadImageFail(self):
2812 """Test failing to read an image image's FDT map"""
2813 self._DoReadFile('005_simple.dts')
2814 image_fname = tools.get_output_filename('image.bin')
2815 with self.assertRaises(ValueError) as e:
2816 image = Image.FromFile(image_fname)
2817 self.assertIn("Cannot find FDT map in image", str(e.exception))
2819 def testListCmd(self):
2820 """Test listing the files in an image using an Fdtmap"""
2822 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2824 # lz4 compression size differs depending on the version
2825 image = control.images['image']
2826 entries = image.GetEntries()
2827 section_size = entries['section'].size
2828 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2829 fdtmap_offset = entries['fdtmap'].offset
2832 tmpdir, updated_fname = self._SetupImageInTmpdir()
2833 with test_util.capture_sys_output() as (stdout, stderr):
2834 self._DoBinman('ls', '-i', updated_fname)
2836 shutil.rmtree(tmpdir)
2837 lines = stdout.getvalue().splitlines()
2839 'Name Image-pos Size Entry-type Offset Uncomp-size',
2840 '----------------------------------------------------------------------',
2841 'image 0 c00 section 0',
2842 ' u-boot 0 4 u-boot 0',
2843 ' section 100 %x section 100' % section_size,
2844 ' cbfs 100 400 cbfs 0',
2845 ' u-boot 138 4 u-boot 38',
2846 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2847 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2848 ' fdtmap %x 3bd fdtmap %x' %
2849 (fdtmap_offset, fdtmap_offset),
2850 ' image-header bf8 8 image-header bf8',
2852 self.assertEqual(expected, lines)
2854 def testListCmdFail(self):
2855 """Test failing to list an image"""
2856 self._DoReadFile('005_simple.dts')
2858 tmpdir, updated_fname = self._SetupImageInTmpdir()
2859 with self.assertRaises(ValueError) as e:
2860 self._DoBinman('ls', '-i', updated_fname)
2862 shutil.rmtree(tmpdir)
2863 self.assertIn("Cannot find FDT map in image", str(e.exception))
2865 def _RunListCmd(self, paths, expected):
2866 """List out entries and check the result
2869 paths: List of paths to pass to the list command
2870 expected: Expected list of filenames to be returned, in order
2873 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2874 image_fname = tools.get_output_filename('image.bin')
2875 image = Image.FromFile(image_fname)
2876 lines = image.GetListEntries(paths)[1]
2877 files = [line[0].strip() for line in lines[1:]]
2878 self.assertEqual(expected, files)
2880 def testListCmdSection(self):
2881 """Test listing the files in a section"""
2882 self._RunListCmd(['section'],
2883 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2885 def testListCmdFile(self):
2886 """Test listing a particular file"""
2887 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2889 def testListCmdWildcard(self):
2890 """Test listing a wildcarded file"""
2891 self._RunListCmd(['*boot*'],
2892 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2894 def testListCmdWildcardMulti(self):
2895 """Test listing a wildcarded file"""
2896 self._RunListCmd(['*cb*', '*head*'],
2897 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2899 def testListCmdEmpty(self):
2900 """Test listing a wildcarded file"""
2901 self._RunListCmd(['nothing'], [])
2903 def testListCmdPath(self):
2904 """Test listing the files in a sub-entry of a section"""
2905 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2907 def _RunExtractCmd(self, entry_name, decomp=True):
2908 """Extract an entry from an image
2911 entry_name: Entry name to extract
2912 decomp: True to decompress the data if compressed, False to leave
2913 it in its raw uncompressed format
2919 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2920 image_fname = tools.get_output_filename('image.bin')
2921 return control.ReadEntry(image_fname, entry_name, decomp)
2923 def testExtractSimple(self):
2924 """Test extracting a single file"""
2925 data = self._RunExtractCmd('u-boot')
2926 self.assertEqual(U_BOOT_DATA, data)
2928 def testExtractSection(self):
2929 """Test extracting the files in a section"""
2930 data = self._RunExtractCmd('section')
2931 cbfs_data = data[:0x400]
2932 cbfs = cbfs_util.CbfsReader(cbfs_data)
2933 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2934 dtb_data = data[0x400:]
2935 dtb = self._decompress(dtb_data)
2936 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2938 def testExtractCompressed(self):
2939 """Test extracting compressed data"""
2940 data = self._RunExtractCmd('section/u-boot-dtb')
2941 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2943 def testExtractRaw(self):
2944 """Test extracting compressed data without decompressing it"""
2945 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2946 dtb = self._decompress(data)
2947 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2949 def testExtractCbfs(self):
2950 """Test extracting CBFS data"""
2951 data = self._RunExtractCmd('section/cbfs/u-boot')
2952 self.assertEqual(U_BOOT_DATA, data)
2954 def testExtractCbfsCompressed(self):
2955 """Test extracting CBFS compressed data"""
2956 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2957 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2959 def testExtractCbfsRaw(self):
2960 """Test extracting CBFS compressed data without decompressing it"""
2961 bintool = self.comp_bintools['lzma_alone']
2962 self._CheckBintool(bintool)
2963 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2964 dtb = bintool.decompress(data)
2965 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2967 def testExtractBadEntry(self):
2968 """Test extracting a bad section path"""
2969 with self.assertRaises(ValueError) as e:
2970 self._RunExtractCmd('section/does-not-exist')
2971 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2974 def testExtractMissingFile(self):
2975 """Test extracting file that does not exist"""
2976 with self.assertRaises(IOError) as e:
2977 control.ReadEntry('missing-file', 'name')
2979 def testExtractBadFile(self):
2980 """Test extracting an invalid file"""
2981 fname = os.path.join(self._indir, 'badfile')
2982 tools.write_file(fname, b'')
2983 with self.assertRaises(ValueError) as e:
2984 control.ReadEntry(fname, 'name')
2986 def testExtractCmd(self):
2987 """Test extracting a file fron an image on the command line"""
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2990 fname = os.path.join(self._indir, 'output.extact')
2992 tmpdir, updated_fname = self._SetupImageInTmpdir()
2993 with test_util.capture_sys_output() as (stdout, stderr):
2994 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2997 shutil.rmtree(tmpdir)
2998 data = tools.read_file(fname)
2999 self.assertEqual(U_BOOT_DATA, data)
3001 def testExtractOneEntry(self):
3002 """Test extracting a single entry fron an image """
3004 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3005 image_fname = tools.get_output_filename('image.bin')
3006 fname = os.path.join(self._indir, 'output.extact')
3007 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
3008 data = tools.read_file(fname)
3009 self.assertEqual(U_BOOT_DATA, data)
3011 def _CheckExtractOutput(self, decomp):
3012 """Helper to test file output with and without decompression
3015 decomp: True to decompress entry data, False to output it raw
3017 def _CheckPresent(entry_path, expect_data, expect_size=None):
3018 """Check and remove expected file
3020 This checks the data/size of a file and removes the file both from
3021 the outfiles set and from the output directory. Once all files are
3022 processed, both the set and directory should be empty.
3025 entry_path: Entry path
3026 expect_data: Data to expect in file, or None to skip check
3027 expect_size: Size of data to expect in file, or None to skip
3029 path = os.path.join(outdir, entry_path)
3030 data = tools.read_file(path)
3033 self.assertEqual(expect_data, data)
3035 self.assertEqual(expect_size, len(data))
3036 outfiles.remove(path)
3038 def _CheckDirPresent(name):
3039 """Remove expected directory
3041 This gives an error if the directory does not exist as expected
3044 name: Name of directory to remove
3046 path = os.path.join(outdir, name)
3049 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3050 image_fname = tools.get_output_filename('image.bin')
3051 outdir = os.path.join(self._indir, 'extract')
3052 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3054 # Create a set of all file that were output (should be 9)
3056 for root, dirs, files in os.walk(outdir):
3057 outfiles |= set([os.path.join(root, fname) for fname in files])
3058 self.assertEqual(9, len(outfiles))
3059 self.assertEqual(9, len(einfos))
3061 image = control.images['image']
3062 entries = image.GetEntries()
3064 # Check the 9 files in various ways
3065 section = entries['section']
3066 section_entries = section.GetEntries()
3067 cbfs_entries = section_entries['cbfs'].GetEntries()
3068 _CheckPresent('u-boot', U_BOOT_DATA)
3069 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3070 dtb_len = EXTRACT_DTB_SIZE
3072 dtb_len = cbfs_entries['u-boot-dtb'].size
3073 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3075 dtb_len = section_entries['u-boot-dtb'].size
3076 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3078 fdtmap = entries['fdtmap']
3079 _CheckPresent('fdtmap', fdtmap.data)
3080 hdr = entries['image-header']
3081 _CheckPresent('image-header', hdr.data)
3083 _CheckPresent('section/root', section.data)
3084 cbfs = section_entries['cbfs']
3085 _CheckPresent('section/cbfs/root', cbfs.data)
3086 data = tools.read_file(image_fname)
3087 _CheckPresent('root', data)
3089 # There should be no files left. Remove all the directories to check.
3090 # If there are any files/dirs remaining, one of these checks will fail.
3091 self.assertEqual(0, len(outfiles))
3092 _CheckDirPresent('section/cbfs')
3093 _CheckDirPresent('section')
3094 _CheckDirPresent('')
3095 self.assertFalse(os.path.exists(outdir))
3097 def testExtractAllEntries(self):
3098 """Test extracting all entries"""
3100 self._CheckExtractOutput(decomp=True)
3102 def testExtractAllEntriesRaw(self):
3103 """Test extracting all entries without decompressing them"""
3105 self._CheckExtractOutput(decomp=False)
3107 def testExtractSelectedEntries(self):
3108 """Test extracting some entries"""
3110 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3111 image_fname = tools.get_output_filename('image.bin')
3112 outdir = os.path.join(self._indir, 'extract')
3113 einfos = control.ExtractEntries(image_fname, None, outdir,
3116 # File output is tested by testExtractAllEntries(), so just check that
3117 # the expected entries are selected
3118 names = [einfo.name for einfo in einfos]
3119 self.assertEqual(names,
3120 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3122 def testExtractNoEntryPaths(self):
3123 """Test extracting some entries"""
3125 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3126 image_fname = tools.get_output_filename('image.bin')
3127 with self.assertRaises(ValueError) as e:
3128 control.ExtractEntries(image_fname, 'fname', None, [])
3129 self.assertIn('Must specify an entry path to write with -f',
3132 def testExtractTooManyEntryPaths(self):
3133 """Test extracting some entries"""
3135 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3136 image_fname = tools.get_output_filename('image.bin')
3137 with self.assertRaises(ValueError) as e:
3138 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
3139 self.assertIn('Must specify exactly one entry path to write with -f',
3142 def testPackAlignSection(self):
3143 """Test that sections can have alignment"""
3144 self._DoReadFile('131_pack_align_section.dts')
3146 self.assertIn('image', control.images)
3147 image = control.images['image']
3148 entries = image.GetEntries()
3149 self.assertEqual(3, len(entries))
3152 self.assertIn('u-boot', entries)
3153 entry = entries['u-boot']
3154 self.assertEqual(0, entry.offset)
3155 self.assertEqual(0, entry.image_pos)
3156 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3157 self.assertEqual(len(U_BOOT_DATA), entry.size)
3160 self.assertIn('section0', entries)
3161 section0 = entries['section0']
3162 self.assertEqual(0x10, section0.offset)
3163 self.assertEqual(0x10, section0.image_pos)
3164 self.assertEqual(len(U_BOOT_DATA), section0.size)
3167 section_entries = section0.GetEntries()
3168 self.assertIn('u-boot', section_entries)
3169 entry = section_entries['u-boot']
3170 self.assertEqual(0, entry.offset)
3171 self.assertEqual(0x10, entry.image_pos)
3172 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3173 self.assertEqual(len(U_BOOT_DATA), entry.size)
3176 self.assertIn('section1', entries)
3177 section1 = entries['section1']
3178 self.assertEqual(0x14, section1.offset)
3179 self.assertEqual(0x14, section1.image_pos)
3180 self.assertEqual(0x20, section1.size)
3183 section_entries = section1.GetEntries()
3184 self.assertIn('u-boot', section_entries)
3185 entry = section_entries['u-boot']
3186 self.assertEqual(0, entry.offset)
3187 self.assertEqual(0x14, entry.image_pos)
3188 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3189 self.assertEqual(len(U_BOOT_DATA), entry.size)
3192 self.assertIn('section2', section_entries)
3193 section2 = section_entries['section2']
3194 self.assertEqual(0x4, section2.offset)
3195 self.assertEqual(0x18, section2.image_pos)
3196 self.assertEqual(4, section2.size)
3199 section_entries = section2.GetEntries()
3200 self.assertIn('u-boot', section_entries)
3201 entry = section_entries['u-boot']
3202 self.assertEqual(0, entry.offset)
3203 self.assertEqual(0x18, entry.image_pos)
3204 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3205 self.assertEqual(len(U_BOOT_DATA), entry.size)
3207 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3208 dts='132_replace.dts'):
3209 """Replace an entry in an image
3211 This writes the entry data to update it, then opens the updated file and
3212 returns the value that it now finds there.
3215 entry_name: Entry name to replace
3216 data: Data to replace it with
3217 decomp: True to compress the data if needed, False if data is
3218 already compressed so should be used as is
3219 allow_resize: True to allow entries to change size, False to raise
3225 data from fdtmap (excluding header)
3226 Image object that was modified
3228 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3231 self.assertIn('image', control.images)
3232 image = control.images['image']
3233 entries = image.GetEntries()
3234 orig_dtb_data = entries['u-boot-dtb'].data
3235 orig_fdtmap_data = entries['fdtmap'].data
3237 image_fname = tools.get_output_filename('image.bin')
3238 updated_fname = tools.get_output_filename('image-updated.bin')
3239 tools.write_file(updated_fname, tools.read_file(image_fname))
3240 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3242 data = control.ReadEntry(updated_fname, entry_name, decomp)
3244 # The DT data should not change unless resized:
3245 if not allow_resize:
3246 new_dtb_data = entries['u-boot-dtb'].data
3247 self.assertEqual(new_dtb_data, orig_dtb_data)
3248 new_fdtmap_data = entries['fdtmap'].data
3249 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3251 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3253 def testReplaceSimple(self):
3254 """Test replacing a single file"""
3255 expected = b'x' * len(U_BOOT_DATA)
3256 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3258 self.assertEqual(expected, data)
3260 # Test that the state looks right. There should be an FDT for the fdtmap
3261 # that we jsut read back in, and it should match what we find in the
3262 # 'control' tables. Checking for an FDT that does not exist should
3264 path, fdtmap = state.GetFdtContents('fdtmap')
3265 self.assertIsNotNone(path)
3266 self.assertEqual(expected_fdtmap, fdtmap)
3268 dtb = state.GetFdtForEtype('fdtmap')
3269 self.assertEqual(dtb.GetContents(), fdtmap)
3271 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3272 self.assertIsNone(missing_path)
3273 self.assertIsNone(missing_fdtmap)
3275 missing_dtb = state.GetFdtForEtype('missing')
3276 self.assertIsNone(missing_dtb)
3278 self.assertEqual('/binman', state.fdt_path_prefix)
3280 def testReplaceResizeFail(self):
3281 """Test replacing a file by something larger"""
3282 expected = U_BOOT_DATA + b'x'
3283 with self.assertRaises(ValueError) as e:
3284 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3285 dts='139_replace_repack.dts')
3286 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3289 def testReplaceMulti(self):
3290 """Test replacing entry data where multiple images are generated"""
3291 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3293 expected = b'x' * len(U_BOOT_DATA)
3294 updated_fname = tools.get_output_filename('image-updated.bin')
3295 tools.write_file(updated_fname, data)
3296 entry_name = 'u-boot'
3297 control.WriteEntry(updated_fname, entry_name, expected,
3299 data = control.ReadEntry(updated_fname, entry_name)
3300 self.assertEqual(expected, data)
3302 # Check the state looks right.
3303 self.assertEqual('/binman/image', state.fdt_path_prefix)
3305 # Now check we can write the first image
3306 image_fname = tools.get_output_filename('first-image.bin')
3307 updated_fname = tools.get_output_filename('first-updated.bin')
3308 tools.write_file(updated_fname, tools.read_file(image_fname))
3309 entry_name = 'u-boot'
3310 control.WriteEntry(updated_fname, entry_name, expected,
3312 data = control.ReadEntry(updated_fname, entry_name)
3313 self.assertEqual(expected, data)
3315 # Check the state looks right.
3316 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3318 def testUpdateFdtAllRepack(self):
3319 """Test that all device trees are updated with offset/size info"""
3322 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3323 SECTION_SIZE = 0x300
3328 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3330 'section:offset': 0,
3331 'section:size': SECTION_SIZE,
3332 'section:image-pos': 0,
3333 'section/u-boot-dtb:offset': 4,
3334 'section/u-boot-dtb:size': 636,
3335 'section/u-boot-dtb:image-pos': 4,
3336 'u-boot-spl-dtb:offset': SECTION_SIZE,
3337 'u-boot-spl-dtb:size': DTB_SIZE,
3338 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3339 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3340 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3341 'u-boot-tpl-dtb:size': DTB_SIZE,
3342 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3343 'fdtmap:size': FDTMAP_SIZE,
3344 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3347 'section:orig-size': SECTION_SIZE,
3348 'section/u-boot-dtb:orig-offset': 4,
3351 # We expect three device-tree files in the output, with the first one
3352 # within a fixed-size section.
3353 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3354 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3355 # main U-Boot tree. All three should have the same positions and offset
3356 # except that the main tree should include the main_expected properties
3358 for item in ['', 'spl', 'tpl', None]:
3360 start += 16 # Move past fdtmap header
3361 dtb = fdt.Fdt.FromData(data[start:])
3363 props = self._GetPropTree(dtb,
3364 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3365 prefix='/' if item is None else '/binman/')
3366 expected = dict(base_expected)
3370 # Main DTB and fdtdec should include the 'orig-' properties
3371 expected.update(main_expected)
3372 # Helpful for debugging:
3373 #for prop in sorted(props):
3374 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3375 self.assertEqual(expected, props)
3377 start = SECTION_SIZE
3379 start += dtb._fdt_obj.totalsize()
3381 def testFdtmapHeaderMiddle(self):
3382 """Test an FDT map in the middle of an image when it should be at end"""
3383 with self.assertRaises(ValueError) as e:
3384 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3385 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3388 def testFdtmapHeaderStartBad(self):
3389 """Test an FDT map in middle of an image when it should be at start"""
3390 with self.assertRaises(ValueError) as e:
3391 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3392 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3395 def testFdtmapHeaderEndBad(self):
3396 """Test an FDT map at the start of an image when it should be at end"""
3397 with self.assertRaises(ValueError) as e:
3398 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3399 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3402 def testFdtmapHeaderNoSize(self):
3403 """Test an image header at the end of an image with undefined size"""
3404 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3406 def testReplaceResize(self):
3407 """Test replacing a single file in an entry with a larger file"""
3408 expected = U_BOOT_DATA + b'x'
3409 data, _, image = self._RunReplaceCmd('u-boot', expected,
3410 dts='139_replace_repack.dts')
3411 self.assertEqual(expected, data)
3413 entries = image.GetEntries()
3414 dtb_data = entries['u-boot-dtb'].data
3415 dtb = fdt.Fdt.FromData(dtb_data)
3418 # The u-boot section should now be larger in the dtb
3419 node = dtb.GetNode('/binman/u-boot')
3420 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3422 # Same for the fdtmap
3423 fdata = entries['fdtmap'].data
3424 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3426 fnode = fdtb.GetNode('/u-boot')
3427 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3429 def testReplaceResizeNoRepack(self):
3430 """Test replacing an entry with a larger file when not allowed"""
3431 expected = U_BOOT_DATA + b'x'
3432 with self.assertRaises(ValueError) as e:
3433 self._RunReplaceCmd('u-boot', expected)
3434 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3437 def testEntryShrink(self):
3438 """Test contracting an entry after it is packed"""
3440 state.SetAllowEntryContraction(True)
3441 data = self._DoReadFileDtb('140_entry_shrink.dts',
3444 state.SetAllowEntryContraction(False)
3445 self.assertEqual(b'a', data[:1])
3446 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3447 self.assertEqual(b'a', data[-1:])
3449 def testEntryShrinkFail(self):
3450 """Test not being allowed to contract an entry after it is packed"""
3451 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3453 # In this case there is a spare byte at the end of the data. The size of
3454 # the contents is only 1 byte but we still have the size before it
3456 self.assertEqual(b'a\0', data[:2])
3457 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3458 self.assertEqual(b'a\0', data[-2:])
3460 def testDescriptorOffset(self):
3461 """Test that the Intel descriptor is always placed at at the start"""
3462 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3463 image = control.images['image']
3464 entries = image.GetEntries()
3465 desc = entries['intel-descriptor']
3466 self.assertEqual(0xff800000, desc.offset);
3467 self.assertEqual(0xff800000, desc.image_pos);
3469 def testReplaceCbfs(self):
3470 """Test replacing a single file in CBFS without changing the size"""
3472 expected = b'x' * len(U_BOOT_DATA)
3473 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3474 updated_fname = tools.get_output_filename('image-updated.bin')
3475 tools.write_file(updated_fname, data)
3476 entry_name = 'section/cbfs/u-boot'
3477 control.WriteEntry(updated_fname, entry_name, expected,
3479 data = control.ReadEntry(updated_fname, entry_name)
3480 self.assertEqual(expected, data)
3482 def testReplaceResizeCbfs(self):
3483 """Test replacing a single file in CBFS with one of a different size"""
3485 expected = U_BOOT_DATA + b'x'
3486 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3487 updated_fname = tools.get_output_filename('image-updated.bin')
3488 tools.write_file(updated_fname, data)
3489 entry_name = 'section/cbfs/u-boot'
3490 control.WriteEntry(updated_fname, entry_name, expected,
3492 data = control.ReadEntry(updated_fname, entry_name)
3493 self.assertEqual(expected, data)
3495 def _SetupForReplace(self):
3496 """Set up some files to use to replace entries
3498 This generates an image, copies it to a new file, extracts all the files
3499 in it and updates some of them
3505 Expected values for updated entries, each a string
3507 data = self._DoReadFileRealDtb('143_replace_all.dts')
3509 updated_fname = tools.get_output_filename('image-updated.bin')
3510 tools.write_file(updated_fname, data)
3512 outdir = os.path.join(self._indir, 'extract')
3513 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3515 expected1 = b'x' + U_BOOT_DATA + b'y'
3516 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3517 tools.write_file(u_boot_fname1, expected1)
3519 expected2 = b'a' + U_BOOT_DATA + b'b'
3520 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3521 tools.write_file(u_boot_fname2, expected2)
3523 expected_text = b'not the same text'
3524 text_fname = os.path.join(outdir, 'text')
3525 tools.write_file(text_fname, expected_text)
3527 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3528 dtb = fdt.FdtScan(dtb_fname)
3529 node = dtb.GetNode('/binman/text')
3530 node.AddString('my-property', 'the value')
3531 dtb.Sync(auto_resize=True)
3534 return updated_fname, outdir, expected1, expected2, expected_text
3536 def _CheckReplaceMultiple(self, entry_paths):
3537 """Handle replacing the contents of multiple entries
3540 entry_paths: List of entry paths to replace
3544 Dict of entries in the image:
3547 Expected values for updated entries, each a string
3549 updated_fname, outdir, expected1, expected2, expected_text = (
3550 self._SetupForReplace())
3551 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3553 image = Image.FromFile(updated_fname)
3555 return image.GetEntries(), expected1, expected2, expected_text
3557 def testReplaceAll(self):
3558 """Test replacing the contents of all entries"""
3559 entries, expected1, expected2, expected_text = (
3560 self._CheckReplaceMultiple([]))
3561 data = entries['u-boot'].data
3562 self.assertEqual(expected1, data)
3564 data = entries['u-boot2'].data
3565 self.assertEqual(expected2, data)
3567 data = entries['text'].data
3568 self.assertEqual(expected_text, data)
3570 # Check that the device tree is updated
3571 data = entries['u-boot-dtb'].data
3572 dtb = fdt.Fdt.FromData(data)
3574 node = dtb.GetNode('/binman/text')
3575 self.assertEqual('the value', node.props['my-property'].value)
3577 def testReplaceSome(self):
3578 """Test replacing the contents of a few entries"""
3579 entries, expected1, expected2, expected_text = (
3580 self._CheckReplaceMultiple(['u-boot2', 'text']))
3582 # This one should not change
3583 data = entries['u-boot'].data
3584 self.assertEqual(U_BOOT_DATA, data)
3586 data = entries['u-boot2'].data
3587 self.assertEqual(expected2, data)
3589 data = entries['text'].data
3590 self.assertEqual(expected_text, data)
3592 def testReplaceCmd(self):
3593 """Test replacing a file fron an image on the command line"""
3594 self._DoReadFileRealDtb('143_replace_all.dts')
3597 tmpdir, updated_fname = self._SetupImageInTmpdir()
3599 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3600 expected = b'x' * len(U_BOOT_DATA)
3601 tools.write_file(fname, expected)
3603 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3604 data = tools.read_file(updated_fname)
3605 self.assertEqual(expected, data[:len(expected)])
3606 map_fname = os.path.join(tmpdir, 'image-updated.map')
3607 self.assertFalse(os.path.exists(map_fname))
3609 shutil.rmtree(tmpdir)
3611 def testReplaceCmdSome(self):
3612 """Test replacing some files fron an image on the command line"""
3613 updated_fname, outdir, expected1, expected2, expected_text = (
3614 self._SetupForReplace())
3616 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3619 tools.prepare_output_dir(None)
3620 image = Image.FromFile(updated_fname)
3622 entries = image.GetEntries()
3624 # This one should not change
3625 data = entries['u-boot'].data
3626 self.assertEqual(U_BOOT_DATA, data)
3628 data = entries['u-boot2'].data
3629 self.assertEqual(expected2, data)
3631 data = entries['text'].data
3632 self.assertEqual(expected_text, data)
3634 def testReplaceMissing(self):
3635 """Test replacing entries where the file is missing"""
3636 updated_fname, outdir, expected1, expected2, expected_text = (
3637 self._SetupForReplace())
3639 # Remove one of the files, to generate a warning
3640 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3641 os.remove(u_boot_fname1)
3643 with test_util.capture_sys_output() as (stdout, stderr):
3644 control.ReplaceEntries(updated_fname, None, outdir, [])
3645 self.assertIn("Skipping entry '/u-boot' from missing file",
3648 def testReplaceCmdMap(self):
3649 """Test replacing a file fron an image on the command line"""
3650 self._DoReadFileRealDtb('143_replace_all.dts')
3653 tmpdir, updated_fname = self._SetupImageInTmpdir()
3655 fname = os.path.join(self._indir, 'update-u-boot.bin')
3656 expected = b'x' * len(U_BOOT_DATA)
3657 tools.write_file(fname, expected)
3659 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3661 map_fname = os.path.join(tmpdir, 'image-updated.map')
3662 self.assertTrue(os.path.exists(map_fname))
3664 shutil.rmtree(tmpdir)
3666 def testReplaceNoEntryPaths(self):
3667 """Test replacing an entry without an entry path"""
3668 self._DoReadFileRealDtb('143_replace_all.dts')
3669 image_fname = tools.get_output_filename('image.bin')
3670 with self.assertRaises(ValueError) as e:
3671 control.ReplaceEntries(image_fname, 'fname', None, [])
3672 self.assertIn('Must specify an entry path to read with -f',
3675 def testReplaceTooManyEntryPaths(self):
3676 """Test extracting some entries"""
3677 self._DoReadFileRealDtb('143_replace_all.dts')
3678 image_fname = tools.get_output_filename('image.bin')
3679 with self.assertRaises(ValueError) as e:
3680 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3681 self.assertIn('Must specify exactly one entry path to write with -f',
3684 def testPackReset16(self):
3685 """Test that an image with an x86 reset16 region can be created"""
3686 data = self._DoReadFile('144_x86_reset16.dts')
3687 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3689 def testPackReset16Spl(self):
3690 """Test that an image with an x86 reset16-spl region can be created"""
3691 data = self._DoReadFile('145_x86_reset16_spl.dts')
3692 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3694 def testPackReset16Tpl(self):
3695 """Test that an image with an x86 reset16-tpl region can be created"""
3696 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3697 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3699 def testPackIntelFit(self):
3700 """Test that an image with an Intel FIT and pointer can be created"""
3701 data = self._DoReadFile('147_intel_fit.dts')
3702 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3704 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3705 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3707 image = control.images['image']
3708 entries = image.GetEntries()
3709 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3710 self.assertEqual(expected_ptr, ptr)
3712 def testPackIntelFitMissing(self):
3713 """Test detection of a FIT pointer with not FIT region"""
3714 with self.assertRaises(ValueError) as e:
3715 self._DoReadFile('148_intel_fit_missing.dts')
3716 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3719 def _CheckSymbolsTplSection(self, dts, expected_vals):
3720 data = self._DoReadFile(dts)
3721 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
3722 upto1 = 4 + len(U_BOOT_SPL_DATA)
3723 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
3724 self.assertEqual(expected1, data[:upto1])
3726 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3727 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
3728 self.assertEqual(expected2, data[upto1:upto2])
3730 upto3 = 0x3c + len(U_BOOT_DATA)
3731 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
3732 self.assertEqual(expected3, data[upto2:upto3])
3734 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
3735 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3737 def testSymbolsTplSection(self):
3738 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3739 self._SetupSplElf('u_boot_binman_syms')
3740 self._SetupTplElf('u_boot_binman_syms')
3741 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3742 [0x04, 0x20, 0x10 + 0x3c, 0x04])
3744 def testSymbolsTplSectionX86(self):
3745 """Test binman can assign symbols in a section with end-at-4gb"""
3746 self._SetupSplElf('u_boot_binman_syms_x86')
3747 self._SetupTplElf('u_boot_binman_syms_x86')
3748 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3749 [0xffffff04, 0xffffff20, 0xffffff3c,
3752 def testPackX86RomIfwiSectiom(self):
3753 """Test that a section can be placed in an IFWI region"""
3754 self._SetupIfwi('fitimage.bin')
3755 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3756 self._CheckIfwi(data)
3758 def testPackFspM(self):
3759 """Test that an image with a FSP memory-init binary can be created"""
3760 data = self._DoReadFile('152_intel_fsp_m.dts')
3761 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3763 def testPackFspS(self):
3764 """Test that an image with a FSP silicon-init binary can be created"""
3765 data = self._DoReadFile('153_intel_fsp_s.dts')
3766 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3768 def testPackFspT(self):
3769 """Test that an image with a FSP temp-ram-init binary can be created"""
3770 data = self._DoReadFile('154_intel_fsp_t.dts')
3771 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3773 def testMkimage(self):
3774 """Test using mkimage to build an image"""
3776 data = self._DoReadFile('156_mkimage.dts')
3778 # Just check that the data appears in the file somewhere
3779 self.assertIn(U_BOOT_SPL_DATA, data)
3781 def testMkimageMissing(self):
3782 """Test that binman still produces an image if mkimage is missing"""
3784 with test_util.capture_sys_output() as (_, stderr):
3785 self._DoTestFile('156_mkimage.dts',
3786 force_missing_bintools='mkimage')
3787 err = stderr.getvalue()
3788 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
3790 def testExtblob(self):
3791 """Test an image with an external blob"""
3792 data = self._DoReadFile('157_blob_ext.dts')
3793 self.assertEqual(REFCODE_DATA, data)
3795 def testExtblobMissing(self):
3796 """Test an image with a missing external blob"""
3797 with self.assertRaises(ValueError) as e:
3798 self._DoReadFile('158_blob_ext_missing.dts')
3799 self.assertIn("Filename 'missing-file' not found in input path",
3802 def testExtblobMissingOk(self):
3803 """Test an image with an missing external blob that is allowed"""
3804 with test_util.capture_sys_output() as (stdout, stderr):
3805 ret = self._DoTestFile('158_blob_ext_missing.dts',
3807 self.assertEqual(103, ret)
3808 err = stderr.getvalue()
3809 self.assertIn('(missing-file)', err)
3810 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
3811 self.assertIn('Some images are invalid', err)
3813 def testExtblobMissingOkFlag(self):
3814 """Test an image with an missing external blob allowed with -W"""
3815 with test_util.capture_sys_output() as (stdout, stderr):
3816 ret = self._DoTestFile('158_blob_ext_missing.dts',
3817 allow_missing=True, ignore_missing=True)
3818 self.assertEqual(0, ret)
3819 err = stderr.getvalue()
3820 self.assertIn('(missing-file)', err)
3821 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
3822 self.assertIn('Some images are invalid', err)
3824 def testExtblobMissingOkSect(self):
3825 """Test an image with an missing external blob that is allowed"""
3826 with test_util.capture_sys_output() as (stdout, stderr):
3827 self._DoTestFile('159_blob_ext_missing_sect.dts',
3829 err = stderr.getvalue()
3830 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
3832 def testPackX86RomMeMissingDesc(self):
3833 """Test that an missing Intel descriptor entry is allowed"""
3834 with test_util.capture_sys_output() as (stdout, stderr):
3835 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3836 err = stderr.getvalue()
3837 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
3839 def testPackX86RomMissingIfwi(self):
3840 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3841 self._SetupIfwi('fitimage.bin')
3842 pathname = os.path.join(self._indir, 'fitimage.bin')
3844 with test_util.capture_sys_output() as (stdout, stderr):
3845 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3846 err = stderr.getvalue()
3847 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
3849 def testPackOverlapZero(self):
3850 """Test that zero-size overlapping regions are ignored"""
3851 self._DoTestFile('160_pack_overlap_zero.dts')
3853 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
3854 # The data should be inside the FIT
3855 dtb = fdt.Fdt.FromData(fit_data)
3857 fnode = dtb.GetNode('/images/kernel')
3858 self.assertIn('data', fnode.props)
3860 fname = os.path.join(self._indir, 'fit_data.fit')
3861 tools.write_file(fname, fit_data)
3862 out = tools.run('dumpimage', '-l', fname)
3864 # Check a few features to make sure the plumbing works. We don't need
3865 # to test the operation of mkimage or dumpimage here. First convert the
3866 # output into a dict where the keys are the fields printed by dumpimage
3867 # and the values are a list of values for each field
3868 lines = out.splitlines()
3870 # Converts "Compression: gzip compressed" into two groups:
3871 # 'Compression' and 'gzip compressed'
3872 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3873 vals = collections.defaultdict(list)
3875 mat = re_line.match(line)
3876 vals[mat.group(1)].append(mat.group(2))
3878 self.assertEquals('FIT description: test-desc', lines[0])
3879 self.assertIn('Created:', lines[1])
3880 self.assertIn('Image 0 (kernel)', vals)
3881 self.assertIn('Hash value', vals)
3882 data_sizes = vals.get('Data Size')
3883 self.assertIsNotNone(data_sizes)
3884 self.assertEqual(2, len(data_sizes))
3885 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3886 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3887 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3889 # Check if entry listing correctly omits /images/
3890 image = control.images['image']
3891 fit_entry = image.GetEntries()['fit']
3892 subentries = list(fit_entry.GetEntries().keys())
3893 expected = ['kernel', 'fdt-1']
3894 self.assertEqual(expected, subentries)
3896 def testSimpleFit(self):
3897 """Test an image with a FIT inside"""
3899 data = self._DoReadFile('161_fit.dts')
3900 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3901 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3902 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3904 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3906 def testSimpleFitExpandsSubentries(self):
3907 """Test that FIT images expand their subentries"""
3908 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3909 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3910 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3911 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3913 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
3915 def testSimpleFitImagePos(self):
3916 """Test that we have correct image-pos for FIT subentries"""
3917 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3919 dtb = fdt.Fdt(out_dtb_fname)
3921 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3929 'u-boot:image-pos': 0,
3937 'fit/images/kernel:image-pos': 304,
3938 'fit/images/kernel:offset': 300,
3939 'fit/images/kernel:size': 4,
3941 'fit/images/kernel/u-boot:image-pos': 304,
3942 'fit/images/kernel/u-boot:offset': 0,
3943 'fit/images/kernel/u-boot:size': 4,
3945 'fit/images/fdt-1:image-pos': 552,
3946 'fit/images/fdt-1:offset': 548,
3947 'fit/images/fdt-1:size': 6,
3949 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
3950 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3951 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3953 'u-boot-nodtb:image-pos': 1844,
3954 'u-boot-nodtb:offset': 1844,
3955 'u-boot-nodtb:size': 46,
3958 # Actually check the data is where we think it is
3959 for node, expected in [
3960 ("u-boot", U_BOOT_DATA),
3961 ("fit/images/kernel", U_BOOT_DATA),
3962 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3963 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3964 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3965 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3967 image_pos = props[f"{node}:image-pos"]
3968 size = props[f"{node}:size"]
3969 self.assertEqual(len(expected), size)
3970 self.assertEqual(expected, data[image_pos:image_pos+size])
3972 def testFitExternal(self):
3973 """Test an image with an FIT with external images"""
3974 data = self._DoReadFile('162_fit_external.dts')
3975 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3977 # Size of the external-data region as set up by mkimage
3978 external_data_size = len(U_BOOT_DATA) + 2
3979 expected_size = (len(U_BOOT_DATA) + 0x400 +
3980 tools.align(external_data_size, 4) +
3981 len(U_BOOT_NODTB_DATA))
3983 # The data should be outside the FIT
3984 dtb = fdt.Fdt.FromData(fit_data)
3986 fnode = dtb.GetNode('/images/kernel')
3987 self.assertNotIn('data', fnode.props)
3988 self.assertEqual(len(U_BOOT_DATA),
3989 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3993 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3995 self.assertEquals(expected_size, len(data))
3996 actual_pos = len(U_BOOT_DATA) + fit_pos
3997 self.assertEqual(U_BOOT_DATA + b'aa',
3998 data[actual_pos:actual_pos + external_data_size])
4000 def testFitExternalImagePos(self):
4001 """Test that we have correct image-pos for external FIT subentries"""
4002 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4004 dtb = fdt.Fdt(out_dtb_fname)
4006 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4013 'u-boot:image-pos': 0,
4021 'fit/images/kernel:size': 4,
4022 'fit/images/kernel:offset': 1024,
4023 'fit/images/kernel:image-pos': 1028,
4025 'fit/images/kernel/u-boot:size': 4,
4026 'fit/images/kernel/u-boot:offset': 0,
4027 'fit/images/kernel/u-boot:image-pos': 1028,
4029 'fit/images/fdt-1:size': 2,
4030 'fit/images/fdt-1:offset': 1028,
4031 'fit/images/fdt-1:image-pos': 1032,
4033 'fit/images/fdt-1/_testing:size': 2,
4034 'fit/images/fdt-1/_testing:offset': 0,
4035 'fit/images/fdt-1/_testing:image-pos': 1032,
4037 'u-boot-nodtb:image-pos': 1036,
4038 'u-boot-nodtb:offset': 1036,
4039 'u-boot-nodtb:size': 46,
4042 # Actually check the data is where we think it is
4043 for node, expected in [
4044 ("u-boot", U_BOOT_DATA),
4045 ("fit/images/kernel", U_BOOT_DATA),
4046 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4047 ("fit/images/fdt-1", b'aa'),
4048 ("fit/images/fdt-1/_testing", b'aa'),
4049 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4051 image_pos = props[f"{node}:image-pos"]
4052 size = props[f"{node}:size"]
4053 self.assertEqual(len(expected), size)
4054 self.assertEqual(expected, data[image_pos:image_pos+size])
4056 def testFitMissing(self):
4057 """Test that binman complains if mkimage is missing"""
4058 with self.assertRaises(ValueError) as e:
4059 self._DoTestFile('162_fit_external.dts',
4060 force_missing_bintools='mkimage')
4061 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4064 def testFitMissingOK(self):
4065 """Test that binman still produces a FIT image if mkimage is missing"""
4066 with test_util.capture_sys_output() as (_, stderr):
4067 self._DoTestFile('162_fit_external.dts', allow_missing=True,
4068 force_missing_bintools='mkimage')
4069 err = stderr.getvalue()
4070 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
4072 def testSectionIgnoreHashSignature(self):
4073 """Test that sections ignore hash, signature nodes for its data"""
4074 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4075 expected = (U_BOOT_DATA + U_BOOT_DATA)
4076 self.assertEqual(expected, data)
4078 def testPadInSections(self):
4079 """Test pad-before, pad-after for entries in sections"""
4080 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4081 '166_pad_in_sections.dts', update_dtb=True)
4082 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4083 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
4085 self.assertEqual(expected, data)
4087 dtb = fdt.Fdt(out_dtb_fname)
4089 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4093 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4095 'section:image-pos': 0,
4096 'section:offset': 0,
4097 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4099 'section/before:image-pos': 0,
4100 'section/before:offset': 0,
4101 'section/before:size': len(U_BOOT_DATA),
4103 'section/u-boot:image-pos': 4,
4104 'section/u-boot:offset': 4,
4105 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4107 'section/after:image-pos': 26,
4108 'section/after:offset': 26,
4109 'section/after:size': len(U_BOOT_DATA),
4111 self.assertEqual(expected, props)
4113 def testFitImageSubentryAlignment(self):
4114 """Test relative alignability of FIT image subentries"""
4117 'test-id': TEXT_DATA,
4119 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4120 entry_args=entry_args)
4121 dtb = fdt.Fdt.FromData(data)
4124 node = dtb.GetNode('/images/kernel')
4125 data = dtb.GetProps(node)["data"].bytes
4126 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
4127 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4128 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
4129 self.assertEqual(expected, data)
4131 node = dtb.GetNode('/images/fdt-1')
4132 data = dtb.GetProps(node)["data"].bytes
4133 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4134 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
4136 self.assertEqual(expected, data)
4138 def testFitExtblobMissingOk(self):
4139 """Test a FIT with a missing external blob that is allowed"""
4140 with test_util.capture_sys_output() as (stdout, stderr):
4141 self._DoTestFile('168_fit_missing_blob.dts',
4143 err = stderr.getvalue()
4144 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
4146 def testBlobNamedByArgMissing(self):
4147 """Test handling of a missing entry arg"""
4148 with self.assertRaises(ValueError) as e:
4149 self._DoReadFile('068_blob_named_by_arg.dts')
4150 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4153 def testPackBl31(self):
4154 """Test that an image with an ATF BL31 binary can be created"""
4155 data = self._DoReadFile('169_atf_bl31.dts')
4156 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4158 def testPackScp(self):
4159 """Test that an image with an SCP binary can be created"""
4160 data = self._DoReadFile('172_scp.dts')
4161 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4163 def testFitFdt(self):
4164 """Test an image with an FIT with multiple FDT images"""
4165 def _CheckFdt(seq, expected_data):
4166 """Check the FDT nodes
4169 seq: Sequence number to check (0 or 1)
4170 expected_data: Expected contents of 'data' property
4172 name = 'fdt-%d' % seq
4173 fnode = dtb.GetNode('/images/%s' % name)
4174 self.assertIsNotNone(fnode)
4175 self.assertEqual({'description','type', 'compression', 'data'},
4176 set(fnode.props.keys()))
4177 self.assertEqual(expected_data, fnode.props['data'].bytes)
4178 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4179 fnode.props['description'].value)
4180 self.assertEqual(fnode.subnodes[0].name, 'hash')
4182 def _CheckConfig(seq, expected_data):
4183 """Check the configuration nodes
4186 seq: Sequence number to check (0 or 1)
4187 expected_data: Expected contents of 'data' property
4189 cnode = dtb.GetNode('/configurations')
4190 self.assertIn('default', cnode.props)
4191 self.assertEqual('config-2', cnode.props['default'].value)
4193 name = 'config-%d' % seq
4194 fnode = dtb.GetNode('/configurations/%s' % name)
4195 self.assertIsNotNone(fnode)
4196 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4197 set(fnode.props.keys()))
4198 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4199 fnode.props['description'].value)
4200 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4203 'of-list': 'test-fdt1 test-fdt2',
4204 'default-dt': 'test-fdt2',
4206 data = self._DoReadFileDtb(
4208 entry_args=entry_args,
4209 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4210 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4211 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4213 dtb = fdt.Fdt.FromData(fit_data)
4215 fnode = dtb.GetNode('/images/kernel')
4216 self.assertIn('data', fnode.props)
4218 # Check all the properties in fdt-1 and fdt-2
4219 _CheckFdt(1, TEST_FDT1_DATA)
4220 _CheckFdt(2, TEST_FDT2_DATA)
4222 # Check configurations
4223 _CheckConfig(1, TEST_FDT1_DATA)
4224 _CheckConfig(2, TEST_FDT2_DATA)
4226 def testFitFdtMissingList(self):
4227 """Test handling of a missing 'of-list' entry arg"""
4228 with self.assertRaises(ValueError) as e:
4229 self._DoReadFile('170_fit_fdt.dts')
4230 self.assertIn("Generator node requires 'of-list' entry argument",
4233 def testFitFdtEmptyList(self):
4234 """Test handling of an empty 'of-list' entry arg"""
4238 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4240 def testFitFdtMissingProp(self):
4241 """Test handling of a missing 'fit,fdt-list' property"""
4242 with self.assertRaises(ValueError) as e:
4243 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4244 self.assertIn("Generator node requires 'fit,fdt-list' property",
4247 def testFitFdtMissing(self):
4248 """Test handling of a missing 'default-dt' entry arg"""
4250 'of-list': 'test-fdt1 test-fdt2',
4252 with self.assertRaises(ValueError) as e:
4253 self._DoReadFileDtb(
4255 entry_args=entry_args,
4256 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4257 self.assertIn("Generated 'default' node requires default-dt entry argument",
4260 def testFitFdtNotInList(self):
4261 """Test handling of a default-dt that is not in the of-list"""
4263 'of-list': 'test-fdt1 test-fdt2',
4264 'default-dt': 'test-fdt3',
4266 with self.assertRaises(ValueError) as e:
4267 self._DoReadFileDtb(
4269 entry_args=entry_args,
4270 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4271 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4274 def testFitExtblobMissingHelp(self):
4275 """Test display of help messages when an external blob is missing"""
4276 control.missing_blob_help = control._ReadMissingBlobHelp()
4277 control.missing_blob_help['wibble'] = 'Wibble test'
4278 control.missing_blob_help['another'] = 'Another test'
4279 with test_util.capture_sys_output() as (stdout, stderr):
4280 self._DoTestFile('168_fit_missing_blob.dts',
4282 err = stderr.getvalue()
4284 # We can get the tag from the name, the type or the missing-msg
4285 # property. Check all three.
4286 self.assertIn('You may need to build ARM Trusted', err)
4287 self.assertIn('Wibble test', err)
4288 self.assertIn('Another test', err)
4290 def testMissingBlob(self):
4291 """Test handling of a blob containing a missing file"""
4292 with self.assertRaises(ValueError) as e:
4293 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4294 self.assertIn("Filename 'missing' not found in input path",
4297 def testEnvironment(self):
4298 """Test adding a U-Boot environment"""
4299 data = self._DoReadFile('174_env.dts')
4300 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4301 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4302 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4303 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4306 def testEnvironmentNoSize(self):
4307 """Test that a missing 'size' property is detected"""
4308 with self.assertRaises(ValueError) as e:
4309 self._DoTestFile('175_env_no_size.dts')
4310 self.assertIn("'u-boot-env' entry must have a size property",
4313 def testEnvironmentTooSmall(self):
4314 """Test handling of an environment that does not fit"""
4315 with self.assertRaises(ValueError) as e:
4316 self._DoTestFile('176_env_too_small.dts')
4318 # checksum, start byte, environment with \0 terminator, final \0
4319 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4321 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4324 def testSkipAtStart(self):
4325 """Test handling of skip-at-start section"""
4326 data = self._DoReadFile('177_skip_at_start.dts')
4327 self.assertEqual(U_BOOT_DATA, data)
4329 image = control.images['image']
4330 entries = image.GetEntries()
4331 section = entries['section']
4332 self.assertEqual(0, section.offset)
4333 self.assertEqual(len(U_BOOT_DATA), section.size)
4334 self.assertEqual(U_BOOT_DATA, section.GetData())
4336 entry = section.GetEntries()['u-boot']
4337 self.assertEqual(16, entry.offset)
4338 self.assertEqual(len(U_BOOT_DATA), entry.size)
4339 self.assertEqual(U_BOOT_DATA, entry.data)
4341 def testSkipAtStartPad(self):
4342 """Test handling of skip-at-start section with padded entry"""
4343 data = self._DoReadFile('178_skip_at_start_pad.dts')
4344 before = tools.get_bytes(0, 8)
4345 after = tools.get_bytes(0, 4)
4346 all = before + U_BOOT_DATA + after
4347 self.assertEqual(all, data)
4349 image = control.images['image']
4350 entries = image.GetEntries()
4351 section = entries['section']
4352 self.assertEqual(0, section.offset)
4353 self.assertEqual(len(all), section.size)
4354 self.assertEqual(all, section.GetData())
4356 entry = section.GetEntries()['u-boot']
4357 self.assertEqual(16, entry.offset)
4358 self.assertEqual(len(all), entry.size)
4359 self.assertEqual(U_BOOT_DATA, entry.data)
4361 def testSkipAtStartSectionPad(self):
4362 """Test handling of skip-at-start section with padding"""
4363 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4364 before = tools.get_bytes(0, 8)
4365 after = tools.get_bytes(0, 4)
4366 all = before + U_BOOT_DATA + after
4367 self.assertEqual(all, data)
4369 image = control.images['image']
4370 entries = image.GetEntries()
4371 section = entries['section']
4372 self.assertEqual(0, section.offset)
4373 self.assertEqual(len(all), section.size)
4374 self.assertEqual(U_BOOT_DATA, section.data)
4375 self.assertEqual(all, section.GetPaddedData())
4377 entry = section.GetEntries()['u-boot']
4378 self.assertEqual(16, entry.offset)
4379 self.assertEqual(len(U_BOOT_DATA), entry.size)
4380 self.assertEqual(U_BOOT_DATA, entry.data)
4382 def testSectionPad(self):
4383 """Testing padding with sections"""
4384 data = self._DoReadFile('180_section_pad.dts')
4385 expected = (tools.get_bytes(ord('&'), 3) +
4386 tools.get_bytes(ord('!'), 5) +
4388 tools.get_bytes(ord('!'), 1) +
4389 tools.get_bytes(ord('&'), 2))
4390 self.assertEqual(expected, data)
4392 def testSectionAlign(self):
4393 """Testing alignment with sections"""
4394 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4395 expected = (b'\0' + # fill section
4396 tools.get_bytes(ord('&'), 1) + # padding to section align
4397 b'\0' + # fill section
4398 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
4400 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4401 tools.get_bytes(ord('!'), 4)) # padding to section size
4402 self.assertEqual(expected, data)
4404 def testCompressImage(self):
4405 """Test compression of the entire image"""
4407 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4408 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4409 dtb = fdt.Fdt(out_dtb_fname)
4411 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4413 orig = self._decompress(data)
4414 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4416 # Do a sanity check on various fields
4417 image = control.images['image']
4418 entries = image.GetEntries()
4419 self.assertEqual(2, len(entries))
4421 entry = entries['blob']
4422 self.assertEqual(COMPRESS_DATA, entry.data)
4423 self.assertEqual(len(COMPRESS_DATA), entry.size)
4425 entry = entries['u-boot']
4426 self.assertEqual(U_BOOT_DATA, entry.data)
4427 self.assertEqual(len(U_BOOT_DATA), entry.size)
4429 self.assertEqual(len(data), image.size)
4430 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4431 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4432 orig = self._decompress(image.data)
4433 self.assertEqual(orig, image.uncomp_data)
4437 'blob:size': len(COMPRESS_DATA),
4438 'u-boot:offset': len(COMPRESS_DATA),
4439 'u-boot:size': len(U_BOOT_DATA),
4440 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4445 self.assertEqual(expected, props)
4447 def testCompressImageLess(self):
4448 """Test compression where compression reduces the image size"""
4450 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4451 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4452 dtb = fdt.Fdt(out_dtb_fname)
4454 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4456 orig = self._decompress(data)
4458 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4460 # Do a sanity check on various fields
4461 image = control.images['image']
4462 entries = image.GetEntries()
4463 self.assertEqual(2, len(entries))
4465 entry = entries['blob']
4466 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4467 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4469 entry = entries['u-boot']
4470 self.assertEqual(U_BOOT_DATA, entry.data)
4471 self.assertEqual(len(U_BOOT_DATA), entry.size)
4473 self.assertEqual(len(data), image.size)
4474 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4475 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4477 orig = self._decompress(image.data)
4478 self.assertEqual(orig, image.uncomp_data)
4482 'blob:size': len(COMPRESS_DATA_BIG),
4483 'u-boot:offset': len(COMPRESS_DATA_BIG),
4484 'u-boot:size': len(U_BOOT_DATA),
4485 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4490 self.assertEqual(expected, props)
4492 def testCompressSectionSize(self):
4493 """Test compression of a section with a fixed size"""
4495 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4496 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4497 dtb = fdt.Fdt(out_dtb_fname)
4499 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4501 orig = self._decompress(data)
4502 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4504 'section/blob:offset': 0,
4505 'section/blob:size': len(COMPRESS_DATA),
4506 'section/u-boot:offset': len(COMPRESS_DATA),
4507 'section/u-boot:size': len(U_BOOT_DATA),
4508 'section:offset': 0,
4509 'section:image-pos': 0,
4510 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4511 'section:size': 0x30,
4516 self.assertEqual(expected, props)
4518 def testCompressSection(self):
4519 """Test compression of a section with no fixed size"""
4521 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4522 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4523 dtb = fdt.Fdt(out_dtb_fname)
4525 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4527 orig = self._decompress(data)
4528 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4530 'section/blob:offset': 0,
4531 'section/blob:size': len(COMPRESS_DATA),
4532 'section/u-boot:offset': len(COMPRESS_DATA),
4533 'section/u-boot:size': len(U_BOOT_DATA),
4534 'section:offset': 0,
4535 'section:image-pos': 0,
4536 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4537 'section:size': len(data),
4542 self.assertEqual(expected, props)
4544 def testLz4Missing(self):
4545 """Test that binman still produces an image if lz4 is missing"""
4546 with test_util.capture_sys_output() as (_, stderr):
4547 self._DoTestFile('185_compress_section.dts',
4548 force_missing_bintools='lz4')
4549 err = stderr.getvalue()
4550 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
4552 def testCompressExtra(self):
4553 """Test compression of a section with no fixed size"""
4555 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4556 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4557 dtb = fdt.Fdt(out_dtb_fname)
4559 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4562 base = data[len(U_BOOT_DATA):]
4563 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4564 rest = base[len(U_BOOT_DATA):]
4566 # Check compressed data
4567 bintool = self.comp_bintools['lz4']
4568 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
4569 data1 = rest[:len(expect1)]
4570 section1 = self._decompress(data1)
4571 self.assertEquals(expect1, data1)
4572 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4573 rest1 = rest[len(expect1):]
4575 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
4576 data2 = rest1[:len(expect2)]
4577 section2 = self._decompress(data2)
4578 self.assertEquals(expect2, data2)
4579 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4580 rest2 = rest1[len(expect2):]
4582 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4583 len(expect2) + len(U_BOOT_DATA))
4584 #self.assertEquals(expect_size, len(data))
4586 #self.assertEquals(U_BOOT_DATA, rest2)
4591 'u-boot:image-pos': 0,
4592 'u-boot:size': len(U_BOOT_DATA),
4594 'base:offset': len(U_BOOT_DATA),
4595 'base:image-pos': len(U_BOOT_DATA),
4596 'base:size': len(data) - len(U_BOOT_DATA),
4597 'base/u-boot:offset': 0,
4598 'base/u-boot:image-pos': len(U_BOOT_DATA),
4599 'base/u-boot:size': len(U_BOOT_DATA),
4600 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4602 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4604 'base/u-boot2:size': len(U_BOOT_DATA),
4606 'base/section:offset': len(U_BOOT_DATA),
4607 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4608 'base/section:size': len(expect1),
4609 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4610 'base/section/blob:offset': 0,
4611 'base/section/blob:size': len(COMPRESS_DATA),
4612 'base/section/u-boot:offset': len(COMPRESS_DATA),
4613 'base/section/u-boot:size': len(U_BOOT_DATA),
4615 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4616 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4617 'base/section2:size': len(expect2),
4618 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4619 'base/section2/blob:offset': 0,
4620 'base/section2/blob:size': len(COMPRESS_DATA),
4621 'base/section2/blob2:offset': len(COMPRESS_DATA),
4622 'base/section2/blob2:size': len(COMPRESS_DATA),
4628 self.assertEqual(expected, props)
4630 def testSymbolsSubsection(self):
4631 """Test binman can assign symbols from a subsection"""
4632 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
4634 def testReadImageEntryArg(self):
4635 """Test reading an image that would need an entry arg to generate"""
4637 'cros-ec-rw-path': 'ecrw.bin',
4639 data = self.data = self._DoReadFileDtb(
4640 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4641 entry_args=entry_args)
4643 image_fname = tools.get_output_filename('image.bin')
4644 orig_image = control.images['image']
4646 # This should not generate an error about the missing 'cros-ec-rw-path'
4647 # since we are reading the image from a file. Compare with
4648 # testEntryArgsRequired()
4649 image = Image.FromFile(image_fname)
4650 self.assertEqual(orig_image.GetEntries().keys(),
4651 image.GetEntries().keys())
4653 def testFilesAlign(self):
4654 """Test alignment with files"""
4655 data = self._DoReadFile('190_files_align.dts')
4657 # The first string is 15 bytes so will align to 16
4658 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4659 self.assertEqual(expect, data)
4661 def testReadImageSkip(self):
4662 """Test reading an image and accessing its FDT map"""
4663 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4664 image_fname = tools.get_output_filename('image.bin')
4665 orig_image = control.images['image']
4666 image = Image.FromFile(image_fname)
4667 self.assertEqual(orig_image.GetEntries().keys(),
4668 image.GetEntries().keys())
4670 orig_entry = orig_image.GetEntries()['fdtmap']
4671 entry = image.GetEntries()['fdtmap']
4672 self.assertEqual(orig_entry.offset, entry.offset)
4673 self.assertEqual(orig_entry.size, entry.size)
4674 self.assertEqual(16, entry.image_pos)
4676 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4678 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4680 def testTplNoDtb(self):
4681 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4683 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4684 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4685 data[:len(U_BOOT_TPL_NODTB_DATA)])
4687 def testTplBssPad(self):
4688 """Test that we can pad TPL's BSS with zeros"""
4689 # ELF file with a '__bss_size' symbol
4691 data = self._DoReadFile('193_tpl_bss_pad.dts')
4692 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
4695 def testTplBssPadMissing(self):
4696 """Test that a missing symbol is detected"""
4697 self._SetupTplElf('u_boot_ucode_ptr')
4698 with self.assertRaises(ValueError) as e:
4699 self._DoReadFile('193_tpl_bss_pad.dts')
4700 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4703 def checkDtbSizes(self, data, pad_len, start):
4704 """Check the size arguments in a dtb embedded in an image
4707 data: The image data
4708 pad_len: Length of the pad section in the image, in bytes
4709 start: Start offset of the devicetree to examine, within the image
4712 Size of the devicetree in bytes
4714 dtb_data = data[start:]
4715 dtb = fdt.Fdt.FromData(dtb_data)
4716 fdt_size = dtb.GetFdtObj().totalsize()
4718 props = self._GetPropTree(dtb, 'size')
4721 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4722 'u-boot-spl/u-boot-spl-dtb:size': 801,
4723 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4724 'u-boot-spl:size': 860,
4725 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4726 'u-boot/u-boot-dtb:size': 781,
4727 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4732 def testExpanded(self):
4733 """Test that an expanded entry type is selected when needed"""
4737 # SPL has a devicetree, TPL does not
4743 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4744 entry_args=entry_args)
4745 image = control.images['image']
4746 entries = image.GetEntries()
4747 self.assertEqual(3, len(entries))
4749 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4750 self.assertIn('u-boot', entries)
4751 entry = entries['u-boot']
4752 self.assertEqual('u-boot-expanded', entry.etype)
4753 subent = entry.GetEntries()
4754 self.assertEqual(2, len(subent))
4755 self.assertIn('u-boot-nodtb', subent)
4756 self.assertIn('u-boot-dtb', subent)
4758 # Second, u-boot-spl, which should be expanded into three parts
4759 self.assertIn('u-boot-spl', entries)
4760 entry = entries['u-boot-spl']
4761 self.assertEqual('u-boot-spl-expanded', entry.etype)
4762 subent = entry.GetEntries()
4763 self.assertEqual(3, len(subent))
4764 self.assertIn('u-boot-spl-nodtb', subent)
4765 self.assertIn('u-boot-spl-bss-pad', subent)
4766 self.assertIn('u-boot-spl-dtb', subent)
4768 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4770 self.assertIn('u-boot-tpl', entries)
4771 entry = entries['u-boot-tpl']
4772 self.assertEqual('u-boot-tpl', entry.etype)
4773 self.assertEqual(None, entry.GetEntries())
4775 def testExpandedTpl(self):
4776 """Test that an expanded entry type is selected for TPL when needed"""
4783 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4784 entry_args=entry_args)
4785 image = control.images['image']
4786 entries = image.GetEntries()
4787 self.assertEqual(1, len(entries))
4789 # We only have u-boot-tpl, which be expanded
4790 self.assertIn('u-boot-tpl', entries)
4791 entry = entries['u-boot-tpl']
4792 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4793 subent = entry.GetEntries()
4794 self.assertEqual(3, len(subent))
4795 self.assertIn('u-boot-tpl-nodtb', subent)
4796 self.assertIn('u-boot-tpl-bss-pad', subent)
4797 self.assertIn('u-boot-tpl-dtb', subent)
4799 def testExpandedNoPad(self):
4800 """Test an expanded entry without BSS pad enabled"""
4804 # SPL has a devicetree, TPL does not
4806 'spl-dtb': 'something',
4810 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4811 entry_args=entry_args)
4812 image = control.images['image']
4813 entries = image.GetEntries()
4815 # Just check u-boot-spl, which should be expanded into two parts
4816 self.assertIn('u-boot-spl', entries)
4817 entry = entries['u-boot-spl']
4818 self.assertEqual('u-boot-spl-expanded', entry.etype)
4819 subent = entry.GetEntries()
4820 self.assertEqual(2, len(subent))
4821 self.assertIn('u-boot-spl-nodtb', subent)
4822 self.assertIn('u-boot-spl-dtb', subent)
4824 def testExpandedTplNoPad(self):
4825 """Test that an expanded entry type with padding disabled in TPL"""
4832 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4833 entry_args=entry_args)
4834 image = control.images['image']
4835 entries = image.GetEntries()
4836 self.assertEqual(1, len(entries))
4838 # We only have u-boot-tpl, which be expanded
4839 self.assertIn('u-boot-tpl', entries)
4840 entry = entries['u-boot-tpl']
4841 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4842 subent = entry.GetEntries()
4843 self.assertEqual(2, len(subent))
4844 self.assertIn('u-boot-tpl-nodtb', subent)
4845 self.assertIn('u-boot-tpl-dtb', subent)
4847 def testFdtInclude(self):
4848 """Test that an Fdt is update within all binaries"""
4852 # SPL has a devicetree, TPL does not
4859 # Build the image. It includes two separate devicetree binaries, each
4860 # with their own contents, but all contain the binman definition.
4861 data = self._DoReadFileDtb(
4862 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4863 update_dtb=True, entry_args=entry_args)[0]
4866 # Check the U-Boot dtb
4867 start = len(U_BOOT_NODTB_DATA)
4868 fdt_size = self.checkDtbSizes(data, pad_len, start)
4871 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4872 fdt_size = self.checkDtbSizes(data, pad_len, start)
4874 # TPL has no devicetree
4875 start += fdt_size + len(U_BOOT_TPL_DATA)
4876 self.assertEqual(len(data), start)
4878 def testSymbolsExpanded(self):
4879 """Test binman can assign symbols in expanded entries"""
4883 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4884 U_BOOT_SPL_DTB_DATA, 0x38,
4885 entry_args=entry_args, use_expanded=True)
4887 def testCollection(self):
4888 """Test a collection"""
4889 data = self._DoReadFile('198_collection.dts')
4890 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4891 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4892 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
4895 def testCollectionSection(self):
4896 """Test a collection where a section must be built first"""
4897 # Sections never have their contents when GetData() is called, but when
4898 # BuildSectionData() is called with required=True, a section will force
4899 # building the contents, producing an error is anything is still
4901 data = self._DoReadFile('199_collection_section.dts')
4902 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4903 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4904 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
4907 def testAlignDefault(self):
4908 """Test that default alignment works on sections"""
4909 data = self._DoReadFile('200_align_default.dts')
4910 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
4912 # Special alignment for section
4913 expected += tools.get_bytes(0, 32 - len(expected))
4914 # No alignment within the nested section
4915 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4916 # Now the final piece, which should be default-aligned
4917 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4918 self.assertEqual(expected, data)
4920 def testPackOpenSBI(self):
4921 """Test that an image with an OpenSBI binary can be created"""
4922 data = self._DoReadFile('201_opensbi.dts')
4923 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4925 def testSectionsSingleThread(self):
4926 """Test sections without multithreading"""
4927 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4928 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4929 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4930 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
4931 self.assertEqual(expected, data)
4933 def testThreadTimeout(self):
4934 """Test handling a thread that takes too long"""
4935 with self.assertRaises(ValueError) as e:
4936 self._DoTestFile('202_section_timeout.dts',
4937 test_section_timeout=True)
4938 self.assertIn("Timed out obtaining contents", str(e.exception))
4940 def testTiming(self):
4941 """Test output of timing information"""
4942 data = self._DoReadFile('055_sections.dts')
4943 with test_util.capture_sys_output() as (stdout, stderr):
4945 self.assertIn('read:', stdout.getvalue())
4946 self.assertIn('compress:', stdout.getvalue())
4948 def testUpdateFdtInElf(self):
4949 """Test that we can update the devicetree in an ELF file"""
4950 if not elf.ELF_TOOLS:
4951 self.skipTest('Python elftools not available')
4952 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4953 outfile = os.path.join(self._indir, 'u-boot.out')
4954 begin_sym = 'dtb_embed_begin'
4955 end_sym = 'dtb_embed_end'
4956 retcode = self._DoTestFile(
4957 '060_fdt_update.dts', update_dtb=True,
4958 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4959 self.assertEqual(0, retcode)
4961 # Check that the output file does in fact contact a dtb with the binman
4962 # definition in the correct place
4963 syms = elf.GetSymbolFileOffset(infile,
4964 ['dtb_embed_begin', 'dtb_embed_end'])
4965 data = tools.read_file(outfile)
4966 dtb_data = data[syms['dtb_embed_begin'].offset:
4967 syms['dtb_embed_end'].offset]
4969 dtb = fdt.Fdt.FromData(dtb_data)
4971 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4975 '_testing:offset': 32,
4977 '_testing:image-pos': 32,
4978 'section@0/u-boot:offset': 0,
4979 'section@0/u-boot:size': len(U_BOOT_DATA),
4980 'section@0/u-boot:image-pos': 0,
4981 'section@0:offset': 0,
4982 'section@0:size': 16,
4983 'section@0:image-pos': 0,
4985 'section@1/u-boot:offset': 0,
4986 'section@1/u-boot:size': len(U_BOOT_DATA),
4987 'section@1/u-boot:image-pos': 16,
4988 'section@1:offset': 16,
4989 'section@1:size': 16,
4990 'section@1:image-pos': 16,
4994 def testUpdateFdtInElfInvalid(self):
4995 """Test that invalid args are detected with --update-fdt-in-elf"""
4996 with self.assertRaises(ValueError) as e:
4997 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4998 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5001 def testUpdateFdtInElfNoSyms(self):
5002 """Test that missing symbols are detected with --update-fdt-in-elf"""
5003 if not elf.ELF_TOOLS:
5004 self.skipTest('Python elftools not available')
5005 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5007 begin_sym = 'wrong_begin'
5008 end_sym = 'wrong_end'
5009 with self.assertRaises(ValueError) as e:
5011 '060_fdt_update.dts',
5012 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5013 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5016 def testUpdateFdtInElfTooSmall(self):
5017 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
5018 if not elf.ELF_TOOLS:
5019 self.skipTest('Python elftools not available')
5020 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5021 outfile = os.path.join(self._indir, 'u-boot.out')
5022 begin_sym = 'dtb_embed_begin'
5023 end_sym = 'dtb_embed_end'
5024 with self.assertRaises(ValueError) as e:
5026 '060_fdt_update.dts', update_dtb=True,
5027 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5030 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5032 def testVersion(self):
5033 """Test we can get the binman version"""
5034 version = '(unreleased)'
5035 self.assertEqual(version, state.GetVersion(self._indir))
5037 with self.assertRaises(SystemExit):
5038 with test_util.capture_sys_output() as (_, stderr):
5039 self._DoBinman('-V')
5040 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5042 # Try running the tool too, just to be safe
5043 result = self._RunBinman('-V')
5044 self.assertEqual('Binman %s\n' % version, result.stderr)
5046 # Set up a version file to make sure that works
5047 version = 'v2025.01-rc2'
5048 tools.write_file(os.path.join(self._indir, 'version'), version,
5050 self.assertEqual(version, state.GetVersion(self._indir))
5052 def testAltFormat(self):
5053 """Test that alternative formats can be used to extract"""
5054 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5057 tmpdir, updated_fname = self._SetupImageInTmpdir()
5058 with test_util.capture_sys_output() as (stdout, _):
5059 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5061 '''Flag (-F) Entry type Description
5062 fdt fdtmap Extract the devicetree blob from the fdtmap
5066 dtb = os.path.join(tmpdir, 'fdt.dtb')
5067 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5070 # Check that we can read it and it can be scanning, meaning it does
5071 # not have a 16-byte fdtmap header
5072 data = tools.read_file(dtb)
5073 dtb = fdt.Fdt.FromData(data)
5076 # Now check u-boot which has no alt_format
5077 fname = os.path.join(tmpdir, 'fdt.dtb')
5078 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5079 '-f', fname, 'u-boot')
5080 data = tools.read_file(fname)
5081 self.assertEqual(U_BOOT_DATA, data)
5084 shutil.rmtree(tmpdir)
5086 def testExtblobList(self):
5087 """Test an image with an external blob list"""
5088 data = self._DoReadFile('215_blob_ext_list.dts')
5089 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5091 def testExtblobListMissing(self):
5092 """Test an image with a missing external blob"""
5093 with self.assertRaises(ValueError) as e:
5094 self._DoReadFile('216_blob_ext_list_missing.dts')
5095 self.assertIn("Filename 'missing-file' not found in input path",
5098 def testExtblobListMissingOk(self):
5099 """Test an image with an missing external blob that is allowed"""
5100 with test_util.capture_sys_output() as (stdout, stderr):
5101 self._DoTestFile('216_blob_ext_list_missing.dts',
5103 err = stderr.getvalue()
5104 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
5107 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5108 data = self._DoReadFile('203_fip.dts')
5109 hdr, fents = fip_util.decode_fip(data)
5110 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5111 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5112 self.assertEqual(0x123, hdr.flags)
5114 self.assertEqual(2, len(fents))
5118 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5119 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5120 self.assertEqual('soc-fw', fent.fip_type)
5121 self.assertEqual(0x88, fent.offset)
5122 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5123 self.assertEqual(0x123456789abcdef, fent.flags)
5124 self.assertEqual(ATF_BL31_DATA, fent.data)
5125 self.assertEqual(True, fent.valid)
5129 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5130 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5131 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5132 self.assertEqual(0x8c, fent.offset)
5133 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5134 self.assertEqual(0, fent.flags)
5135 self.assertEqual(ATF_BL2U_DATA, fent.data)
5136 self.assertEqual(True, fent.valid)
5138 def testFipOther(self):
5139 """Basic FIP with something that isn't a external blob"""
5140 data = self._DoReadFile('204_fip_other.dts')
5141 hdr, fents = fip_util.decode_fip(data)
5143 self.assertEqual(2, len(fents))
5145 self.assertEqual('rot-cert', fent.fip_type)
5146 self.assertEqual(b'aa', fent.data)
5148 def testFipNoType(self):
5149 """FIP with an entry of an unknown type"""
5150 with self.assertRaises(ValueError) as e:
5151 self._DoReadFile('205_fip_no_type.dts')
5152 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5155 def testFipUuid(self):
5156 """Basic FIP with a manual uuid"""
5157 data = self._DoReadFile('206_fip_uuid.dts')
5158 hdr, fents = fip_util.decode_fip(data)
5160 self.assertEqual(2, len(fents))
5162 self.assertEqual(None, fent.fip_type)
5164 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5165 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5167 self.assertEqual(U_BOOT_DATA, fent.data)
5169 def testFipLs(self):
5170 """Test listing a FIP"""
5171 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5172 hdr, fents = fip_util.decode_fip(data)
5175 tmpdir, updated_fname = self._SetupImageInTmpdir()
5176 with test_util.capture_sys_output() as (stdout, stderr):
5177 self._DoBinman('ls', '-i', updated_fname)
5179 shutil.rmtree(tmpdir)
5180 lines = stdout.getvalue().splitlines()
5182 'Name Image-pos Size Entry-type Offset Uncomp-size',
5183 '--------------------------------------------------------------',
5184 'image 0 2d3 section 0',
5185 ' atf-fip 0 90 atf-fip 0',
5186 ' soc-fw 88 4 blob-ext 88',
5187 ' u-boot 8c 4 u-boot 8c',
5188 ' fdtmap 90 243 fdtmap 90',
5190 self.assertEqual(expected, lines)
5192 image = control.images['image']
5193 entries = image.GetEntries()
5194 fdtmap = entries['fdtmap']
5196 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5197 magic = fdtmap_data[:8]
5198 self.assertEqual(b'_FDTMAP_', magic)
5199 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
5201 fdt_data = fdtmap_data[16:]
5202 dtb = fdt.Fdt.FromData(fdt_data)
5204 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5206 'atf-fip/soc-fw:image-pos': 136,
5207 'atf-fip/soc-fw:offset': 136,
5208 'atf-fip/soc-fw:size': 4,
5209 'atf-fip/u-boot:image-pos': 140,
5210 'atf-fip/u-boot:offset': 140,
5211 'atf-fip/u-boot:size': 4,
5212 'atf-fip:image-pos': 0,
5213 'atf-fip:offset': 0,
5214 'atf-fip:size': 144,
5217 'fdtmap:image-pos': fdtmap.image_pos,
5218 'fdtmap:offset': fdtmap.offset,
5219 'fdtmap:size': len(fdtmap_data),
5223 def testFipExtractOneEntry(self):
5224 """Test extracting a single entry fron an FIP"""
5225 self._DoReadFileRealDtb('207_fip_ls.dts')
5226 image_fname = tools.get_output_filename('image.bin')
5227 fname = os.path.join(self._indir, 'output.extact')
5228 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
5229 data = tools.read_file(fname)
5230 self.assertEqual(U_BOOT_DATA, data)
5232 def testFipReplace(self):
5233 """Test replacing a single file in a FIP"""
5234 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
5235 data = self._DoReadFileRealDtb('208_fip_replace.dts')
5236 updated_fname = tools.get_output_filename('image-updated.bin')
5237 tools.write_file(updated_fname, data)
5238 entry_name = 'atf-fip/u-boot'
5239 control.WriteEntry(updated_fname, entry_name, expected,
5241 actual = control.ReadEntry(updated_fname, entry_name)
5242 self.assertEqual(expected, actual)
5244 new_data = tools.read_file(updated_fname)
5245 hdr, fents = fip_util.decode_fip(new_data)
5247 self.assertEqual(2, len(fents))
5249 # Check that the FIP entry is updated
5251 self.assertEqual(0x8c, fent.offset)
5252 self.assertEqual(len(expected), fent.size)
5253 self.assertEqual(0, fent.flags)
5254 self.assertEqual(expected, fent.data)
5255 self.assertEqual(True, fent.valid)
5257 def testFipMissing(self):
5258 with test_util.capture_sys_output() as (stdout, stderr):
5259 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5260 err = stderr.getvalue()
5261 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
5263 def testFipSize(self):
5264 """Test a FIP with a size property"""
5265 data = self._DoReadFile('210_fip_size.dts')
5266 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5267 hdr, fents = fip_util.decode_fip(data)
5268 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5269 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5271 self.assertEqual(1, len(fents))
5274 self.assertEqual('soc-fw', fent.fip_type)
5275 self.assertEqual(0x60, fent.offset)
5276 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5277 self.assertEqual(ATF_BL31_DATA, fent.data)
5278 self.assertEqual(True, fent.valid)
5280 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
5281 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
5283 def testFipBadAlign(self):
5284 """Test that an invalid alignment value in a FIP is detected"""
5285 with self.assertRaises(ValueError) as e:
5286 self._DoTestFile('211_fip_bad_align.dts')
5288 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5291 def testFipCollection(self):
5292 """Test using a FIP in a collection"""
5293 data = self._DoReadFile('212_fip_collection.dts')
5294 entry1 = control.images['image'].GetEntries()['collection']
5295 data1 = data[:entry1.size]
5296 hdr1, fents2 = fip_util.decode_fip(data1)
5298 entry2 = control.images['image'].GetEntries()['atf-fip']
5299 data2 = data[entry2.offset:entry2.offset + entry2.size]
5300 hdr1, fents2 = fip_util.decode_fip(data2)
5302 # The 'collection' entry should have U-Boot included at the end
5303 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5304 self.assertEqual(data1, data2 + U_BOOT_DATA)
5305 self.assertEqual(U_BOOT_DATA, data1[-4:])
5307 # There should be a U-Boot after the final FIP
5308 self.assertEqual(U_BOOT_DATA, data[-4:])
5310 def testFakeBlob(self):
5311 """Test handling of faking an external blob"""
5312 with test_util.capture_sys_output() as (stdout, stderr):
5313 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5314 allow_fake_blobs=True)
5315 err = stderr.getvalue()
5318 "Image '.*' has faked external blobs and is non-functional: .*")
5320 def testExtblobListFaked(self):
5321 """Test an extblob with missing external blob that are faked"""
5322 with test_util.capture_sys_output() as (stdout, stderr):
5323 self._DoTestFile('216_blob_ext_list_missing.dts',
5324 allow_fake_blobs=True)
5325 err = stderr.getvalue()
5326 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
5328 def testListBintools(self):
5329 args = ['tool', '--list']
5330 with test_util.capture_sys_output() as (stdout, _):
5331 self._DoBinman(*args)
5332 out = stdout.getvalue().splitlines()
5333 self.assertTrue(len(out) >= 2)
5335 def testFetchBintools(self):
5336 def fail_download(url):
5337 """Take the tools.download() function by raising an exception"""
5338 raise urllib.error.URLError('my error')
5341 with self.assertRaises(ValueError) as e:
5342 self._DoBinman(*args)
5343 self.assertIn("Invalid arguments to 'tool' subcommand",
5346 args = ['tool', '--fetch']
5347 with self.assertRaises(ValueError) as e:
5348 self._DoBinman(*args)
5349 self.assertIn('Please specify bintools to fetch', str(e.exception))
5351 args = ['tool', '--fetch', '_testing']
5352 with unittest.mock.patch.object(tools, 'download',
5353 side_effect=fail_download):
5354 with test_util.capture_sys_output() as (stdout, _):
5355 self._DoBinman(*args)
5356 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5358 def testBintoolDocs(self):
5359 """Test for creation of bintool documentation"""
5360 with test_util.capture_sys_output() as (stdout, stderr):
5361 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5362 self.assertTrue(len(stdout.getvalue()) > 0)
5364 def testBintoolDocsMissing(self):
5365 """Test handling of missing bintool documentation"""
5366 with self.assertRaises(ValueError) as e:
5367 with test_util.capture_sys_output() as (stdout, stderr):
5368 control.write_bintool_docs(
5369 control.bintool.Bintool.get_tool_list(), 'mkimage')
5370 self.assertIn('Documentation is missing for modules: mkimage',
5373 def testListWithGenNode(self):
5374 """Check handling of an FDT map when the section cannot be found"""
5376 'of-list': 'test-fdt1 test-fdt2',
5378 data = self._DoReadFileDtb(
5379 '219_fit_gennode.dts',
5380 entry_args=entry_args,
5382 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5385 tmpdir, updated_fname = self._SetupImageInTmpdir()
5386 with test_util.capture_sys_output() as (stdout, stderr):
5387 self._RunBinman('ls', '-i', updated_fname)
5389 shutil.rmtree(tmpdir)
5391 def testFitSubentryUsesBintool(self):
5392 """Test that binman FIT subentries can use bintools"""
5393 command.test_result = self._HandleGbbCommand
5395 'keydir': 'devkeys',
5396 'bmpblk': 'bmpblk.bin',
5398 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5399 entry_args=entry_args)
5401 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5402 tools.get_bytes(0, 0x2180 - 16))
5403 self.assertIn(expected, data)
5405 def testFitSubentryMissingBintool(self):
5406 """Test that binman reports missing bintools for FIT subentries"""
5408 'keydir': 'devkeys',
5410 with test_util.capture_sys_output() as (_, stderr):
5411 self._DoTestFile('220_fit_subentry_bintool.dts',
5412 force_missing_bintools='futility', entry_args=entry_args)
5413 err = stderr.getvalue()
5414 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
5416 def testFitSubentryHashSubnode(self):
5417 """Test an image with a FIT inside"""
5419 data, _, _, out_dtb_name = self._DoReadFileDtb(
5420 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5422 mkimage_dtb = fdt.Fdt.FromData(data)
5424 binman_dtb = fdt.Fdt(out_dtb_name)
5427 # Check that binman didn't add hash values
5428 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5429 self.assertNotIn('value', fnode.props)
5431 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5432 self.assertNotIn('value', fnode.props)
5434 # Check that mkimage added hash values
5435 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5436 self.assertIn('value', fnode.props)
5438 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5439 self.assertIn('value', fnode.props)
5441 def testPackTeeOs(self):
5442 """Test that an image with an TEE binary can be created"""
5443 data = self._DoReadFile('222_tee_os.dts')
5444 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5446 def testFitFdtOper(self):
5447 """Check handling of a specified FIT operation"""
5449 'of-list': 'test-fdt1 test-fdt2',
5450 'default-dt': 'test-fdt2',
5452 self._DoReadFileDtb(
5453 '223_fit_fdt_oper.dts',
5454 entry_args=entry_args,
5455 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5457 def testFitFdtBadOper(self):
5458 """Check handling of an FDT map when the section cannot be found"""
5459 with self.assertRaises(ValueError) as exc:
5460 self._DoReadFileDtb('224_fit_bad_oper.dts')
5461 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
5464 def test_uses_expand_size(self):
5465 """Test that the 'expand-size' property cannot be used anymore"""
5466 with self.assertRaises(ValueError) as e:
5467 data = self._DoReadFile('225_expand_size_bad.dts')
5469 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5472 def testFitSplitElf(self):
5473 """Test an image with an FIT with an split-elf operation"""
5474 if not elf.ELF_TOOLS:
5475 self.skipTest('Python elftools not available')
5477 'of-list': 'test-fdt1 test-fdt2',
5478 'default-dt': 'test-fdt2',
5479 'atf-bl31-path': 'bl31.elf',
5480 'tee-os-path': 'tee.elf',
5482 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5483 data = self._DoReadFileDtb(
5484 '226_fit_split_elf.dts',
5485 entry_args=entry_args,
5486 extra_indirs=[test_subdir])[0]
5488 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5489 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5491 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5493 dtb = fdt.Fdt.FromData(fit_data)
5496 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5497 segments, entry = elf.read_loadable_segments(elf_data)
5499 # We assume there are two segments
5500 self.assertEquals(2, len(segments))
5502 atf1 = dtb.GetNode('/images/atf-1')
5503 _, start, data = segments[0]
5504 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5505 self.assertEqual(entry,
5506 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5507 self.assertEqual(start,
5508 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5509 self.assertEqual(data, atf1.props['data'].bytes)
5511 hash_node = atf1.FindNode('hash')
5512 self.assertIsNotNone(hash_node)
5513 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5515 atf2 = dtb.GetNode('/images/atf-2')
5516 self.assertEqual(base_keys, atf2.props.keys())
5517 _, start, data = segments[1]
5518 self.assertEqual(start,
5519 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5520 self.assertEqual(data, atf2.props['data'].bytes)
5522 hash_node = atf2.FindNode('hash')
5523 self.assertIsNotNone(hash_node)
5524 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5526 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5527 self.assertIsNotNone(hash_node)
5528 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5530 conf = dtb.GetNode('/configurations')
5531 self.assertEqual({'default'}, conf.props.keys())
5533 for subnode in conf.subnodes:
5534 self.assertEqual({'description', 'fdt', 'loadables'},
5535 subnode.props.keys())
5537 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5538 fdt_util.GetStringList(subnode, 'loadables'))
5540 def _check_bad_fit(self, dts):
5543 This runs with the given dts and returns the assertion raised
5546 dts (str): dts filename to use
5549 str: Assertion string raised
5552 'of-list': 'test-fdt1 test-fdt2',
5553 'default-dt': 'test-fdt2',
5554 'atf-bl31-path': 'bl31.elf',
5555 'tee-os-path': 'tee.elf',
5557 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5558 with self.assertRaises(ValueError) as exc:
5559 self._DoReadFileDtb(dts, entry_args=entry_args,
5560 extra_indirs=[test_subdir])[0]
5561 return str(exc.exception)
5563 def testFitSplitElfBadElf(self):
5564 """Test a FIT split-elf operation with an invalid ELF file"""
5565 if not elf.ELF_TOOLS:
5566 self.skipTest('Python elftools not available')
5567 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5569 'of-list': 'test-fdt1 test-fdt2',
5570 'default-dt': 'test-fdt2',
5571 'atf-bl31-path': 'bad.elf',
5572 'tee-os-path': 'tee.elf',
5574 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5575 with self.assertRaises(ValueError) as exc:
5576 self._DoReadFileDtb(
5577 '226_fit_split_elf.dts',
5578 entry_args=entry_args,
5579 extra_indirs=[test_subdir])[0]
5581 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5584 def checkFitSplitElf(self, **kwargs):
5585 """Test an split-elf FIT with a missing ELF file
5588 kwargs (dict of str): Arguments to pass to _DoTestFile()
5596 'of-list': 'test-fdt1 test-fdt2',
5597 'default-dt': 'test-fdt2',
5598 'atf-bl31-path': 'bl31.elf',
5599 'tee-os-path': 'missing.elf',
5601 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5602 with test_util.capture_sys_output() as (stdout, stderr):
5604 '226_fit_split_elf.dts', entry_args=entry_args,
5605 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5606 out = stdout.getvalue()
5607 err = stderr.getvalue()
5610 def testFitSplitElfBadDirective(self):
5611 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5612 if not elf.ELF_TOOLS:
5613 self.skipTest('Python elftools not available')
5614 err = self._check_bad_fit('227_fit_bad_dir.dts')
5616 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5619 def testFitSplitElfBadDirectiveConfig(self):
5620 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5621 if not elf.ELF_TOOLS:
5622 self.skipTest('Python elftools not available')
5623 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5625 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5629 def testFitSplitElfMissing(self):
5630 """Test an split-elf FIT with a missing ELF file"""
5631 if not elf.ELF_TOOLS:
5632 self.skipTest('Python elftools not available')
5633 out, err = self.checkFitSplitElf(allow_missing=True)
5636 "Image '.*' is missing external blobs and is non-functional: .*")
5637 self.assertNotRegex(out, '.*Faked blob.*')
5638 fname = tools.get_output_filename('binman-fake/missing.elf')
5639 self.assertFalse(os.path.exists(fname))
5641 def testFitSplitElfFaked(self):
5642 """Test an split-elf FIT with faked ELF file"""
5643 if not elf.ELF_TOOLS:
5644 self.skipTest('Python elftools not available')
5645 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
5648 "Image '.*' is missing external blobs and is non-functional: .*")
5651 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5652 fname = tools.get_output_filename('binman-fake/missing.elf')
5653 self.assertTrue(os.path.exists(fname))
5655 def testMkimageMissingBlob(self):
5656 """Test using mkimage to build an image"""
5657 with test_util.capture_sys_output() as (stdout, stderr):
5658 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5659 allow_fake_blobs=True)
5660 err = stderr.getvalue()
5663 "Image '.*' has faked external blobs and is non-functional: .*")
5665 def testPreLoad(self):
5666 """Test an image with a pre-load header"""
5668 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5670 data = self._DoReadFileDtb(
5671 '230_pre_load.dts', entry_args=entry_args,
5672 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
5673 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5674 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5675 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5677 def testPreLoadNoKey(self):
5678 """Test an image with a pre-load heade0r with missing key"""
5679 with self.assertRaises(FileNotFoundError) as exc:
5680 self._DoReadFile('230_pre_load.dts')
5681 self.assertIn("No such file or directory: 'dev.key'",
5684 def testPreLoadPkcs(self):
5685 """Test an image with a pre-load header with padding pkcs"""
5687 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5689 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5690 entry_args=entry_args)[0]
5691 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5692 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5693 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5695 def testPreLoadPss(self):
5696 """Test an image with a pre-load header with padding pss"""
5698 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5700 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5701 entry_args=entry_args)[0]
5702 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5703 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5704 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5706 def testPreLoadInvalidPadding(self):
5707 """Test an image with a pre-load header with an invalid padding"""
5709 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5711 with self.assertRaises(ValueError) as e:
5712 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5713 entry_args=entry_args)
5715 def testPreLoadInvalidSha(self):
5716 """Test an image with a pre-load header with an invalid hash"""
5718 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5720 with self.assertRaises(ValueError) as e:
5721 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5722 entry_args=entry_args)
5724 def testPreLoadInvalidAlgo(self):
5725 """Test an image with a pre-load header with an invalid algo"""
5726 with self.assertRaises(ValueError) as e:
5727 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
5729 def testPreLoadInvalidKey(self):
5730 """Test an image with a pre-load header with an invalid key"""
5732 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5734 with self.assertRaises(ValueError) as e:
5735 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5736 entry_args=entry_args)
5738 def _CheckSafeUniqueNames(self, *images):
5739 """Check all entries of given images for unsafe unique names"""
5740 for image in images:
5742 image._CollectEntries(entries, {}, image)
5743 for entry in entries.values():
5744 uniq = entry.GetUniqueName()
5746 # Used as part of a filename, so must not be absolute paths.
5747 self.assertFalse(os.path.isabs(uniq))
5749 def testSafeUniqueNames(self):
5750 """Test entry unique names are safe in single image configuration"""
5751 data = self._DoReadFileRealDtb('237_unique_names.dts')
5753 orig_image = control.images['image']
5754 image_fname = tools.get_output_filename('image.bin')
5755 image = Image.FromFile(image_fname)
5757 self._CheckSafeUniqueNames(orig_image, image)
5759 def testSafeUniqueNamesMulti(self):
5760 """Test entry unique names are safe with multiple images"""
5761 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
5763 orig_image = control.images['image']
5764 image_fname = tools.get_output_filename('image.bin')
5765 image = Image.FromFile(image_fname)
5767 self._CheckSafeUniqueNames(orig_image, image)
5769 def testReplaceCmdWithBintool(self):
5770 """Test replacing an entry that needs a bintool to pack"""
5771 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
5772 expected = U_BOOT_DATA + b'aa'
5773 self.assertEqual(expected, data[:len(expected)])
5776 tmpdir, updated_fname = self._SetupImageInTmpdir()
5777 fname = os.path.join(tmpdir, 'update-testing.bin')
5778 tools.write_file(fname, b'zz')
5779 self._DoBinman('replace', '-i', updated_fname,
5780 '_testing', '-f', fname)
5782 data = tools.read_file(updated_fname)
5783 expected = U_BOOT_DATA + b'zz'
5784 self.assertEqual(expected, data[:len(expected)])
5786 shutil.rmtree(tmpdir)
5788 def testReplaceCmdOtherWithBintool(self):
5789 """Test replacing an entry when another needs a bintool to pack"""
5790 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
5791 expected = U_BOOT_DATA + b'aa'
5792 self.assertEqual(expected, data[:len(expected)])
5795 tmpdir, updated_fname = self._SetupImageInTmpdir()
5796 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5797 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5798 self._DoBinman('replace', '-i', updated_fname,
5799 'u-boot', '-f', fname)
5801 data = tools.read_file(updated_fname)
5802 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5803 self.assertEqual(expected, data[:len(expected)])
5805 shutil.rmtree(tmpdir)
5807 def testReplaceResizeNoRepackSameSize(self):
5808 """Test replacing entries with same-size data without repacking"""
5809 expected = b'x' * len(U_BOOT_DATA)
5810 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5811 self.assertEqual(expected, data)
5813 path, fdtmap = state.GetFdtContents('fdtmap')
5814 self.assertIsNotNone(path)
5815 self.assertEqual(expected_fdtmap, fdtmap)
5817 def testReplaceResizeNoRepackSmallerSize(self):
5818 """Test replacing entries with smaller-size data without repacking"""
5820 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5821 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5822 self.assertEqual(expected, data)
5824 path, fdtmap = state.GetFdtContents('fdtmap')
5825 self.assertIsNotNone(path)
5826 self.assertEqual(expected_fdtmap, fdtmap)
5828 def testExtractFit(self):
5829 """Test extracting a FIT section"""
5830 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
5831 image_fname = tools.get_output_filename('image.bin')
5833 fit_data = control.ReadEntry(image_fname, 'fit')
5834 fit = fdt.Fdt.FromData(fit_data)
5837 # Check subentry data inside the extracted fit
5838 for node_path, expected in [
5839 ('/images/kernel', U_BOOT_DATA),
5840 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5841 ('/images/scr-1', COMPRESS_DATA),
5843 node = fit.GetNode(node_path)
5844 data = fit.GetProps(node)['data'].bytes
5845 self.assertEqual(expected, data)
5847 def testExtractFitSubentries(self):
5848 """Test extracting FIT section subentries"""
5849 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
5850 image_fname = tools.get_output_filename('image.bin')
5852 for entry_path, expected in [
5853 ('fit/kernel', U_BOOT_DATA),
5854 ('fit/kernel/u-boot', U_BOOT_DATA),
5855 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5856 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5857 ('fit/scr-1', COMPRESS_DATA),
5858 ('fit/scr-1/blob', COMPRESS_DATA),
5860 data = control.ReadEntry(image_fname, entry_path)
5861 self.assertEqual(expected, data)
5863 def testReplaceFitSubentryLeafSameSize(self):
5864 """Test replacing a FIT leaf subentry with same-size data"""
5865 new_data = b'x' * len(U_BOOT_DATA)
5866 data, expected_fdtmap, _ = self._RunReplaceCmd(
5867 'fit/kernel/u-boot', new_data,
5868 dts='240_fit_extract_replace.dts')
5869 self.assertEqual(new_data, data)
5871 path, fdtmap = state.GetFdtContents('fdtmap')
5872 self.assertIsNotNone(path)
5873 self.assertEqual(expected_fdtmap, fdtmap)
5875 def testReplaceFitSubentryLeafBiggerSize(self):
5876 """Test replacing a FIT leaf subentry with bigger-size data"""
5877 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5878 data, expected_fdtmap, _ = self._RunReplaceCmd(
5879 'fit/fdt-1/u-boot-nodtb', new_data,
5880 dts='240_fit_extract_replace.dts')
5881 self.assertEqual(new_data, data)
5883 # Will be repacked, so fdtmap must change
5884 path, fdtmap = state.GetFdtContents('fdtmap')
5885 self.assertIsNotNone(path)
5886 self.assertNotEqual(expected_fdtmap, fdtmap)
5888 def testReplaceFitSubentryLeafSmallerSize(self):
5889 """Test replacing a FIT leaf subentry with smaller-size data"""
5891 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5892 data, expected_fdtmap, _ = self._RunReplaceCmd(
5893 'fit/fdt-1/u-boot-nodtb', new_data,
5894 dts='240_fit_extract_replace.dts')
5895 self.assertEqual(expected, data)
5897 path, fdtmap = state.GetFdtContents('fdtmap')
5898 self.assertIsNotNone(path)
5899 self.assertEqual(expected_fdtmap, fdtmap)
5901 def testReplaceSectionSimple(self):
5902 """Test replacing a simple section with same-sized data"""
5903 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
5904 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5905 new_data, dts='241_replace_section_simple.dts')
5906 self.assertEqual(new_data, data)
5908 entries = image.GetEntries()
5909 self.assertIn('section', entries)
5910 entry = entries['section']
5911 self.assertEqual(len(new_data), entry.size)
5913 def testReplaceSectionLarger(self):
5914 """Test replacing a simple section with larger data"""
5915 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5916 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5917 new_data, dts='241_replace_section_simple.dts')
5918 self.assertEqual(new_data, data)
5920 entries = image.GetEntries()
5921 self.assertIn('section', entries)
5922 entry = entries['section']
5923 self.assertEqual(len(new_data), entry.size)
5924 fentry = entries['fdtmap']
5925 self.assertEqual(entry.offset + entry.size, fentry.offset)
5927 def testReplaceSectionSmaller(self):
5928 """Test replacing a simple section with smaller data"""
5929 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5930 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5931 new_data, dts='241_replace_section_simple.dts')
5932 self.assertEqual(new_data, data)
5934 # The new size is the same as the old, just with a pad byte at the end
5935 entries = image.GetEntries()
5936 self.assertIn('section', entries)
5937 entry = entries['section']
5938 self.assertEqual(len(new_data), entry.size)
5940 def testReplaceSectionSmallerAllow(self):
5941 """Test failing to replace a simple section with smaller data"""
5942 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5944 state.SetAllowEntryContraction(True)
5945 with self.assertRaises(ValueError) as exc:
5946 self._RunReplaceCmd('section', new_data,
5947 dts='241_replace_section_simple.dts')
5949 state.SetAllowEntryContraction(False)
5951 # Since we have no information about the position of things within the
5952 # section, we cannot adjust the position of /section-u-boot so it ends
5953 # up outside the section
5955 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5956 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
5959 def testMkimageImagename(self):
5960 """Test using mkimage with -n holding the data too"""
5962 data = self._DoReadFile('242_mkimage_name.dts')
5964 # Check that the data appears in the file somewhere
5965 self.assertIn(U_BOOT_SPL_DATA, data)
5967 # Get struct legacy_img_hdr -> ih_name
5968 name = data[0x20:0x40]
5970 # Build the filename that we expect to be placed in there, by virtue of
5972 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5974 # Check that the image name is set to the temporary filename used
5975 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5977 def testMkimageImage(self):
5978 """Test using mkimage with -n holding the data too"""
5980 data = self._DoReadFile('243_mkimage_image.dts')
5982 # Check that the data appears in the file somewhere
5983 self.assertIn(U_BOOT_SPL_DATA, data)
5985 # Get struct legacy_img_hdr -> ih_name
5986 name = data[0x20:0x40]
5988 # Build the filename that we expect to be placed in there, by virtue of
5990 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5992 # Check that the image name is set to the temporary filename used
5993 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5995 # Check the corect data is in the imagename file
5996 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5998 def testMkimageImageNoContent(self):
5999 """Test using mkimage with -n and no data"""
6001 with self.assertRaises(ValueError) as exc:
6002 self._DoReadFile('244_mkimage_image_no_content.dts')
6003 self.assertIn('Could not complete processing of contents',
6006 def testMkimageImageBad(self):
6007 """Test using mkimage with imagename node and data-to-imagename"""
6009 with self.assertRaises(ValueError) as exc:
6010 self._DoReadFile('245_mkimage_image_bad.dts')
6011 self.assertIn('Cannot use both imagename node and data-to-imagename',
6014 def testCollectionOther(self):
6015 """Test a collection where the data comes from another section"""
6016 data = self._DoReadFile('246_collection_other.dts')
6017 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6018 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6019 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6022 def testMkimageCollection(self):
6023 """Test using a collection referring to an entry in a mkimage entry"""
6025 data = self._DoReadFile('247_mkimage_coll.dts')
6026 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6027 self.assertEqual(expect, data[:len(expect)])
6029 def testCompressDtbPrependInvalid(self):
6030 """Test that invalid header is detected"""
6031 with self.assertRaises(ValueError) as e:
6032 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
6033 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6034 "'u-boot-dtb': 'invalid'", str(e.exception))
6036 def testCompressDtbPrependLength(self):
6037 """Test that compress with length header works as expected"""
6038 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
6039 image = control.images['image']
6040 entries = image.GetEntries()
6041 self.assertIn('u-boot-dtb', entries)
6042 u_boot_dtb = entries['u-boot-dtb']
6043 self.assertIn('fdtmap', entries)
6044 fdtmap = entries['fdtmap']
6046 image_fname = tools.get_output_filename('image.bin')
6047 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6048 dtb = fdt.Fdt.FromData(orig)
6050 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6052 'u-boot:size': len(U_BOOT_DATA),
6053 'u-boot-dtb:uncomp-size': len(orig),
6054 'u-boot-dtb:size': u_boot_dtb.size,
6055 'fdtmap:size': fdtmap.size,
6058 self.assertEqual(expected, props)
6060 # Check implementation
6061 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6062 rest = data[len(U_BOOT_DATA):]
6063 comp_data_len = struct.unpack('<I', rest[:4])[0]
6064 comp_data = rest[4:4 + comp_data_len]
6065 orig2 = self._decompress(comp_data)
6066 self.assertEqual(orig, orig2)
6068 def testInvalidCompress(self):
6069 """Test that invalid compress algorithm is detected"""
6070 with self.assertRaises(ValueError) as e:
6071 self._DoTestFile('250_compress_dtb_invalid.dts')
6072 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6074 def testCompUtilCompressions(self):
6075 """Test compression algorithms"""
6076 for bintool in self.comp_bintools.values():
6077 self._CheckBintool(bintool)
6078 data = bintool.compress(COMPRESS_DATA)
6079 self.assertNotEqual(COMPRESS_DATA, data)
6080 orig = bintool.decompress(data)
6081 self.assertEquals(COMPRESS_DATA, orig)
6083 def testCompUtilVersions(self):
6084 """Test tool version of compression algorithms"""
6085 for bintool in self.comp_bintools.values():
6086 self._CheckBintool(bintool)
6087 version = bintool.version()
6088 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6090 def testCompUtilPadding(self):
6091 """Test padding of compression algorithms"""
6092 # Skip zstd because it doesn't support padding
6093 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
6094 self._CheckBintool(bintool)
6095 data = bintool.compress(COMPRESS_DATA)
6096 self.assertNotEqual(COMPRESS_DATA, data)
6097 data += tools.get_bytes(0, 64)
6098 orig = bintool.decompress(data)
6099 self.assertEquals(COMPRESS_DATA, orig)
6101 def testCompressDtbZstd(self):
6102 """Test that zstd compress of device-tree files failed"""
6103 with self.assertRaises(ValueError) as e:
6104 self._DoTestFile('251_compress_dtb_zstd.dts')
6105 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6106 "requires a length header", str(e.exception))
6108 def testMkimageMultipleDataFiles(self):
6109 """Test passing multiple files to mkimage in a mkimage entry"""
6112 data = self._DoReadFile('252_mkimage_mult_data.dts')
6113 # Size of files are packed in their 4B big-endian format
6114 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6115 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6116 # Size info is always followed by a 4B zero value.
6117 expect += tools.get_bytes(0, 4)
6118 expect += U_BOOT_TPL_DATA
6119 # All but last files are 4B-aligned
6120 align_pad = len(U_BOOT_TPL_DATA) % 4
6122 expect += tools.get_bytes(0, align_pad)
6123 expect += U_BOOT_SPL_DATA
6124 self.assertEqual(expect, data[-len(expect):])
6126 def testMkimageMultipleExpanded(self):
6127 """Test passing multiple files to mkimage in a mkimage entry"""
6134 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6135 use_expanded=True, entry_args=entry_args)[0]
6137 tpl_expect = U_BOOT_TPL_DATA
6138 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6139 spl_expect += U_BOOT_SPL_DTB_DATA
6141 content = data[0x40:]
6142 lens = struct.unpack('>III', content[:12])
6144 # Size of files are packed in their 4B big-endian format
6145 # Size info is always followed by a 4B zero value.
6146 self.assertEqual(len(tpl_expect), lens[0])
6147 self.assertEqual(len(spl_expect), lens[1])
6148 self.assertEqual(0, lens[2])
6151 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6153 rest = rest[len(tpl_expect):]
6154 align_pad = len(tpl_expect) % 4
6155 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6156 rest = rest[align_pad:]
6157 self.assertEqual(spl_expect, rest)
6159 def testMkimageMultipleNoContent(self):
6160 """Test passing multiple data files to mkimage with one data file having no content"""
6162 with self.assertRaises(ValueError) as exc:
6163 self._DoReadFile('253_mkimage_mult_no_content.dts')
6164 self.assertIn('Could not complete processing of contents',
6167 def testMkimageFilename(self):
6168 """Test using mkimage to build a binary with a filename"""
6170 retcode = self._DoTestFile('254_mkimage_filename.dts')
6171 self.assertEqual(0, retcode)
6172 fname = tools.get_output_filename('mkimage-test.bin')
6173 self.assertTrue(os.path.exists(fname))
6176 """Test that an image with VPL and its device tree can be created"""
6177 # ELF file with a '__bss_size' symbol
6179 data = self._DoReadFile('255_u_boot_vpl.dts')
6180 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6182 def testVplNoDtb(self):
6183 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6185 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6186 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6187 data[:len(U_BOOT_VPL_NODTB_DATA)])
6189 def testExpandedVpl(self):
6190 """Test that an expanded entry type is selected for TPL when needed"""
6197 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6198 entry_args=entry_args)
6199 image = control.images['image']
6200 entries = image.GetEntries()
6201 self.assertEqual(1, len(entries))
6203 # We only have u-boot-vpl, which be expanded
6204 self.assertIn('u-boot-vpl', entries)
6205 entry = entries['u-boot-vpl']
6206 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6207 subent = entry.GetEntries()
6208 self.assertEqual(3, len(subent))
6209 self.assertIn('u-boot-vpl-nodtb', subent)
6210 self.assertIn('u-boot-vpl-bss-pad', subent)
6211 self.assertIn('u-boot-vpl-dtb', subent)
6213 def testVplBssPadMissing(self):
6214 """Test that a missing symbol is detected"""
6215 self._SetupVplElf('u_boot_ucode_ptr')
6216 with self.assertRaises(ValueError) as e:
6217 self._DoReadFile('258_vpl_bss_pad.dts')
6218 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6221 def testSymlink(self):
6222 """Test that image files can be symlinked"""
6223 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6224 self.assertEqual(0, retcode)
6225 image = control.images['test_image']
6226 fname = tools.get_output_filename('test_image.bin')
6227 sname = tools.get_output_filename('symlink_to_test.bin')
6228 self.assertTrue(os.path.islink(sname))
6229 self.assertEqual(os.readlink(sname), fname)
6231 def testSymlinkOverwrite(self):
6232 """Test that symlinked images can be overwritten"""
6233 testdir = TestFunctional._MakeInputDir('symlinktest')
6234 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6235 # build the same image again in the same directory so that existing symlink is present
6236 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6237 fname = tools.get_output_filename('test_image.bin')
6238 sname = tools.get_output_filename('symlink_to_test.bin')
6239 self.assertTrue(os.path.islink(sname))
6240 self.assertEqual(os.readlink(sname), fname)
6242 def testSymbolsElf(self):
6243 """Test binman can assign symbols embedded in an ELF file"""
6244 if not elf.ELF_TOOLS:
6245 self.skipTest('Python elftools not available')
6246 self._SetupTplElf('u_boot_binman_syms')
6247 self._SetupVplElf('u_boot_binman_syms')
6248 self._SetupSplElf('u_boot_binman_syms')
6249 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6250 image_fname = tools.get_output_filename('image.bin')
6252 image = control.images['image']
6253 entries = image.GetEntries()
6255 for entry in entries.values():
6256 # No symbols in u-boot and it has faked contents anyway
6257 if entry.name == 'u-boot':
6259 edata = data[entry.image_pos:entry.image_pos + entry.size]
6260 efname = tools.get_output_filename(f'edata-{entry.name}')
6261 tools.write_file(efname, edata)
6263 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6264 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6265 for name, sym in syms.items():
6267 val = elf.GetSymbolValue(sym, edata, msg)
6268 entry_m = re_name.match(name)
6270 ename, prop = entry_m.group(1), entry_m.group(3)
6271 entry, entry_name, prop_name = image.LookupEntry(entries,
6273 if prop_name == 'offset':
6274 expect_val = entry.offset
6275 elif prop_name == 'image_pos':
6276 expect_val = entry.image_pos
6277 elif prop_name == 'size':
6278 expect_val = entry.size
6279 self.assertEqual(expect_val, val)
6281 def testSymbolsElfBad(self):
6282 """Check error when trying to write symbols without the elftools lib"""
6283 if not elf.ELF_TOOLS:
6284 self.skipTest('Python elftools not available')
6285 self._SetupTplElf('u_boot_binman_syms')
6286 self._SetupVplElf('u_boot_binman_syms')
6287 self._SetupSplElf('u_boot_binman_syms')
6289 elf.ELF_TOOLS = False
6290 with self.assertRaises(ValueError) as exc:
6291 self._DoReadFileDtb('260_symbols_elf.dts')
6293 elf.ELF_TOOLS = True
6295 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6296 'Cannot write symbols to an ELF file without Python elftools',
6299 def testSectionFilename(self):
6300 """Check writing of section contents to a file"""
6301 data = self._DoReadFile('261_section_fname.dts')
6302 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6303 tools.get_bytes(ord('!'), 7) +
6304 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6305 self.assertEqual(expected, data)
6307 sect_fname = tools.get_output_filename('outfile.bin')
6308 self.assertTrue(os.path.exists(sect_fname))
6309 sect_data = tools.read_file(sect_fname)
6310 self.assertEqual(U_BOOT_DATA, sect_data)
6312 def testAbsent(self):
6313 """Check handling of absent entries"""
6314 data = self._DoReadFile('262_absent.dts')
6315 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6317 def testPackTeeOsOptional(self):
6318 """Test that an image with an optional TEE binary can be created"""
6320 'tee-os-path': 'tee.elf',
6322 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6323 entry_args=entry_args)[0]
6324 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6326 def checkFitTee(self, dts, tee_fname):
6327 """Check that a tee-os entry works and returns data
6330 dts (str): Device tree filename to use
6331 tee_fname (str): filename containing tee-os
6334 bytes: Image contents
6336 if not elf.ELF_TOOLS:
6337 self.skipTest('Python elftools not available')
6339 'of-list': 'test-fdt1 test-fdt2',
6340 'default-dt': 'test-fdt2',
6341 'tee-os-path': tee_fname,
6343 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6344 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6345 extra_indirs=[test_subdir])[0]
6348 def testFitTeeOsOptionalFit(self):
6349 """Test an image with a FIT with an optional OP-TEE binary"""
6350 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6352 # There should be only one node, holding the data set up in SetUpClass()
6354 dtb = fdt.Fdt.FromData(data)
6356 node = dtb.GetNode('/images/tee-1')
6357 self.assertEqual(TEE_ADDR,
6358 fdt_util.fdt32_to_cpu(node.props['load'].value))
6359 self.assertEqual(TEE_ADDR,
6360 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6361 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6363 with test_util.capture_sys_output() as (stdout, stderr):
6364 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6365 err = stderr.getvalue()
6368 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6370 def testFitTeeOsOptionalFitBad(self):
6371 """Test an image with a FIT with an optional OP-TEE binary"""
6372 with self.assertRaises(ValueError) as exc:
6373 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6375 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6378 def testFitTeeOsBad(self):
6379 """Test an OP-TEE binary with wrong formats"""
6380 self.make_tee_bin('tee.bad1', 123)
6381 with self.assertRaises(ValueError) as exc:
6382 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6384 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6387 self.make_tee_bin('tee.bad2', 0, b'extra data')
6388 with self.assertRaises(ValueError) as exc:
6389 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6391 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6394 def testExtblobOptional(self):
6395 """Test an image with an external blob that is optional"""
6396 with test_util.capture_sys_output() as (stdout, stderr):
6397 data = self._DoReadFile('266_blob_ext_opt.dts')
6398 self.assertEqual(REFCODE_DATA, data)
6399 err = stderr.getvalue()
6402 "Image '.*' is missing optional external blobs but is still functional: missing")
6404 def testSectionInner(self):
6405 """Test an inner section with a size"""
6406 data = self._DoReadFile('267_section_inner.dts')
6407 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6408 self.assertEqual(expected, data)
6411 """Test an image with a null entry"""
6412 data = self._DoReadFile('268_null.dts')
6413 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6415 def testOverlap(self):
6416 """Test an image with a overlapping entry"""
6417 data = self._DoReadFile('269_overlap.dts')
6418 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6420 image = control.images['image']
6421 entries = image.GetEntries()
6423 self.assertIn('inset', entries)
6424 inset = entries['inset']
6425 self.assertEqual(1, inset.offset);
6426 self.assertEqual(1, inset.image_pos);
6427 self.assertEqual(2, inset.size);
6429 def testOverlapNull(self):
6430 """Test an image with a null overlap"""
6431 data = self._DoReadFile('270_overlap_null.dts')
6432 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6435 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6436 self.assertEqual(4, fhdr.nareas)
6437 fiter = iter(fentries)
6439 fentry = next(fiter)
6440 self.assertEqual(b'SECTION', fentry.name)
6441 self.assertEqual(0, fentry.offset)
6442 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6443 self.assertEqual(0, fentry.flags)
6445 fentry = next(fiter)
6446 self.assertEqual(b'U_BOOT', fentry.name)
6447 self.assertEqual(0, fentry.offset)
6448 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6449 self.assertEqual(0, fentry.flags)
6451 # Make sure that the NULL entry appears in the FMAP
6452 fentry = next(fiter)
6453 self.assertEqual(b'NULL', fentry.name)
6454 self.assertEqual(1, fentry.offset)
6455 self.assertEqual(2, fentry.size)
6456 self.assertEqual(0, fentry.flags)
6458 fentry = next(fiter)
6459 self.assertEqual(b'FMAP', fentry.name)
6460 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6462 def testOverlapBad(self):
6463 """Test an image with a bad overlapping entry"""
6464 with self.assertRaises(ValueError) as exc:
6465 self._DoReadFile('271_overlap_bad.dts')
6467 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6470 def testOverlapNoOffset(self):
6471 """Test an image with a bad overlapping entry"""
6472 with self.assertRaises(ValueError) as exc:
6473 self._DoReadFile('272_overlap_no_size.dts')
6475 "Node '/binman/inset': 'fill' entry is missing properties: size",
6478 def testBlobSymbol(self):
6479 """Test a blob with symbols read from an ELF file"""
6480 elf_fname = self.ElfTestFile('blob_syms')
6481 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6482 TestFunctional._MakeInputFile('blob_syms.bin',
6483 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6485 data = self._DoReadFile('273_blob_symbol.dts')
6487 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6488 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6489 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6490 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6491 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6493 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6494 expected = sym_values
6495 self.assertEqual(expected, data[:len(expected)])
6497 def testOffsetFromElf(self):
6498 """Test a blob with symbols read from an ELF file"""
6499 elf_fname = self.ElfTestFile('blob_syms')
6500 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6501 TestFunctional._MakeInputFile('blob_syms.bin',
6502 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6504 data = self._DoReadFile('274_offset_from_elf.dts')
6506 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6507 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6509 image = control.images['image']
6510 entries = image.GetEntries()
6512 self.assertIn('inset', entries)
6513 inset = entries['inset']
6515 self.assertEqual(base + 4, inset.offset);
6516 self.assertEqual(base + 4, inset.image_pos);
6517 self.assertEqual(4, inset.size);
6519 self.assertIn('inset2', entries)
6520 inset = entries['inset2']
6521 self.assertEqual(base + 8, inset.offset);
6522 self.assertEqual(base + 8, inset.image_pos);
6523 self.assertEqual(4, inset.size);
6525 def testFitAlign(self):
6526 """Test an image with an FIT with aligned external data"""
6527 data = self._DoReadFile('275_fit_align.dts')
6528 self.assertEqual(4096, len(data))
6530 dtb = fdt.Fdt.FromData(data)
6533 props = self._GetPropTree(dtb, ['data-position'])
6535 'u-boot:data-position': 1024,
6536 'fdt-1:data-position': 2048,
6537 'fdt-2:data-position': 3072,
6539 self.assertEqual(expected, props)
6541 def testFitFirmwareLoadables(self):
6542 """Test an image with an FIT that use fit,firmware"""
6543 if not elf.ELF_TOOLS:
6544 self.skipTest('Python elftools not available')
6546 'of-list': 'test-fdt1',
6547 'default-dt': 'test-fdt1',
6548 'atf-bl31-path': 'bl31.elf',
6549 'tee-os-path': 'missing.bin',
6551 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6552 with test_util.capture_sys_output() as (stdout, stderr):
6553 data = self._DoReadFileDtb(
6554 '276_fit_firmware_loadables.dts',
6555 entry_args=entry_args,
6556 extra_indirs=[test_subdir])[0]
6558 dtb = fdt.Fdt.FromData(data)
6561 node = dtb.GetNode('/configurations/conf-uboot-1')
6562 self.assertEqual('u-boot', node.props['firmware'].value)
6563 self.assertEqual(['atf-1', 'atf-2'],
6564 fdt_util.GetStringList(node, 'loadables'))
6566 node = dtb.GetNode('/configurations/conf-atf-1')
6567 self.assertEqual('atf-1', node.props['firmware'].value)
6568 self.assertEqual(['u-boot', 'atf-2'],
6569 fdt_util.GetStringList(node, 'loadables'))
6571 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6572 self.assertEqual('u-boot', node.props['firmware'].value)
6573 self.assertEqual(['atf-1', 'atf-2'],
6574 fdt_util.GetStringList(node, 'loadables'))
6576 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6577 self.assertEqual('atf-1', node.props['firmware'].value)
6578 self.assertEqual(['u-boot', 'atf-2'],
6579 fdt_util.GetStringList(node, 'loadables'))
6581 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6582 self.assertEqual('atf-1', node.props['firmware'].value)
6583 self.assertEqual(['u-boot', 'atf-2'],
6584 fdt_util.GetStringList(node, 'loadables'))
6586 def testTooldir(self):
6587 """Test that we can specify the tooldir"""
6588 with test_util.capture_sys_output() as (stdout, stderr):
6589 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6591 self.assertEqual('fred', bintool.Bintool.tooldir)
6593 # Check that the toolpath is updated correctly
6594 self.assertEqual(['fred'], tools.tool_search_paths)
6596 # Try with a few toolpaths; the tooldir should be at the end
6597 with test_util.capture_sys_output() as (stdout, stderr):
6598 self.assertEqual(0, self._DoBinman(
6599 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6601 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6603 def testReplaceSectionEntry(self):
6604 """Test replacing an entry in a section"""
6605 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6606 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6607 expect_data, dts='241_replace_section_simple.dts')
6608 self.assertEqual(expect_data, entry_data)
6610 entries = image.GetEntries()
6611 self.assertIn('section', entries)
6612 section = entries['section']
6614 sect_entries = section.GetEntries()
6615 self.assertIn('blob', sect_entries)
6616 entry = sect_entries['blob']
6617 self.assertEqual(len(expect_data), entry.size)
6619 fname = tools.get_output_filename('image-updated.bin')
6620 data = tools.read_file(fname)
6622 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6623 self.assertEqual(expect_data, new_blob_data)
6625 self.assertEqual(U_BOOT_DATA,
6626 data[entry.image_pos + len(expect_data):]
6627 [:len(U_BOOT_DATA)])
6629 def testReplaceSectionDeep(self):
6630 """Test replacing an entry in two levels of sections"""
6631 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6632 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6633 'section/section/blob', expect_data,
6634 dts='278_replace_section_deep.dts')
6635 self.assertEqual(expect_data, entry_data)
6637 entries = image.GetEntries()
6638 self.assertIn('section', entries)
6639 section = entries['section']
6641 subentries = section.GetEntries()
6642 self.assertIn('section', subentries)
6643 section = subentries['section']
6645 sect_entries = section.GetEntries()
6646 self.assertIn('blob', sect_entries)
6647 entry = sect_entries['blob']
6648 self.assertEqual(len(expect_data), entry.size)
6650 fname = tools.get_output_filename('image-updated.bin')
6651 data = tools.read_file(fname)
6653 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6654 self.assertEqual(expect_data, new_blob_data)
6656 self.assertEqual(U_BOOT_DATA,
6657 data[entry.image_pos + len(expect_data):]
6658 [:len(U_BOOT_DATA)])
6660 def testReplaceFitSibling(self):
6661 """Test an image with a FIT inside where we replace its sibling"""
6663 fname = TestFunctional._MakeInputFile('once', b'available once')
6664 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6668 tmpdir, updated_fname = self._SetupImageInTmpdir()
6670 fname = os.path.join(tmpdir, 'update-blob')
6671 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6672 tools.write_file(fname, expected)
6674 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6675 data = tools.read_file(updated_fname)
6676 start = len(U_BOOT_DTB_DATA)
6677 self.assertEqual(expected, data[start:start + len(expected)])
6678 map_fname = os.path.join(tmpdir, 'image-updated.map')
6679 self.assertFalse(os.path.exists(map_fname))
6681 shutil.rmtree(tmpdir)
6683 def testX509Cert(self):
6684 """Test creating an X509 certificate"""
6685 keyfile = self.TestFile('key.key')
6689 data = self._DoReadFileDtb('279_x509_cert.dts',
6690 entry_args=entry_args)[0]
6692 self.assertEqual(U_BOOT_DATA, data[-4:])
6694 # TODO: verify the signature
6696 def testX509CertMissing(self):
6697 """Test that binman still produces an image if openssl is missing"""
6698 keyfile = self.TestFile('key.key')
6700 'keyfile': 'keyfile',
6702 with test_util.capture_sys_output() as (_, stderr):
6703 self._DoTestFile('279_x509_cert.dts',
6704 force_missing_bintools='openssl',
6705 entry_args=entry_args)
6706 err = stderr.getvalue()
6707 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6709 def testPackRockchipTpl(self):
6710 """Test that an image with a Rockchip TPL binary can be created"""
6711 data = self._DoReadFile('291_rockchip_tpl.dts')
6712 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6714 def testMkimageMissingBlobMultiple(self):
6715 """Test missing blob with mkimage entry and multiple-data-files"""
6716 with test_util.capture_sys_output() as (stdout, stderr):
6717 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
6718 err = stderr.getvalue()
6719 self.assertIn("is missing external blobs and is non-functional", err)
6721 with self.assertRaises(ValueError) as e:
6722 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
6723 self.assertIn("not found in input path", str(e.exception))
6725 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6726 """Prepare sign environment
6728 Create private and public keys, add pubkey into dtb.
6738 data = self._DoReadFileRealDtb(dts)
6739 updated_fname = tools.get_output_filename('image-updated.bin')
6740 tools.write_file(updated_fname, data)
6741 dtb = tools.get_output_filename('source.dtb')
6742 private_key = tools.get_output_filename('test_key.key')
6743 public_key = tools.get_output_filename('test_key.crt')
6744 fit = tools.get_output_filename('fit.fit')
6745 key_dir = tools.get_output_dir()
6747 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6748 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6749 private_key, '-out', public_key)
6750 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6751 '-n', 'test_key', '-r', 'conf', dtb)
6753 return fit, updated_fname, private_key, dtb
6755 def testSignSimple(self):
6756 """Test that a FIT container can be signed in image"""
6758 fit, fname, private_key, dtb = self._PrepareSignEnv()
6760 # do sign with private key
6761 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6763 is_signed = self._CheckSign(fit, dtb)
6765 self.assertEqual(is_signed, True)
6767 def testSignExactFIT(self):
6768 """Test that a FIT container can be signed and replaced in image"""
6770 fit, fname, private_key, dtb = self._PrepareSignEnv()
6772 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6775 for path in self.toolpath:
6776 args += ['--toolpath', path]
6778 # do sign with private key
6779 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6780 'sha256,rsa4096', '-f', fit, 'fit')
6781 is_signed = self._CheckSign(fit, dtb)
6783 self.assertEqual(is_signed, True)
6785 def testSignNonFit(self):
6786 """Test a non-FIT entry cannot be signed"""
6788 fit, fname, private_key, _ = self._PrepareSignEnv(
6789 '281_sign_non_fit.dts')
6791 # do sign with private key
6792 with self.assertRaises(ValueError) as e:
6793 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6794 'sha256,rsa4096', '-f', fit, 'u-boot')
6796 "Node '/u-boot': Updating signatures is not supported with this entry type",
6799 def testSignMissingMkimage(self):
6800 """Test that FIT signing handles a missing mkimage tool"""
6801 fit, fname, private_key, _ = self._PrepareSignEnv()
6803 # try to sign with a missing mkimage tool
6804 bintool.Bintool.set_missing_list(['mkimage'])
6805 with self.assertRaises(ValueError) as e:
6806 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6808 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6810 def testSymbolNoWrite(self):
6811 """Test disabling of symbol writing"""
6813 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6814 no_write_symbols=True)
6816 def testSymbolNoWriteExpanded(self):
6817 """Test disabling of symbol writing in expanded entries"""
6821 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6822 U_BOOT_SPL_DTB_DATA, 0x38,
6823 entry_args=entry_args, use_expanded=True,
6824 no_write_symbols=True)
6826 def testMkimageSpecial(self):
6827 """Test mkimage ignores special hash-1 node"""
6828 data = self._DoReadFile('283_mkimage_special.dts')
6830 # Just check that the data appears in the file somewhere
6831 self.assertIn(U_BOOT_DATA, data)
6833 def testFitFdtList(self):
6834 """Test an image with an FIT with the fit,fdt-list-val option"""
6836 'default-dt': 'test-fdt2',
6838 data = self._DoReadFileDtb(
6839 '284_fit_fdt_list.dts',
6840 entry_args=entry_args,
6841 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6842 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6843 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6845 def testSplEmptyBss(self):
6846 """Test an expanded SPL with a zero-size BSS"""
6847 # ELF file with a '__bss_size' symbol
6848 self._SetupSplElf(src_fname='bss_data_zero')
6854 data = self._DoReadFileDtb('285_spl_expand.dts',
6855 use_expanded=True, entry_args=entry_args)[0]
6857 def testTemplate(self):
6858 """Test using a template"""
6859 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6860 data = self._DoReadFile('286_template.dts')
6861 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6862 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6863 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6865 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6866 self.assertTrue(os.path.exists(dtb_fname1))
6867 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6869 node1 = dtb.GetNode('/binman/template')
6870 self.assertTrue(node1)
6871 vga = dtb.GetNode('/binman/first/intel-vga')
6872 self.assertTrue(vga)
6874 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6875 self.assertTrue(os.path.exists(dtb_fname2))
6876 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6878 node2 = dtb2.GetNode('/binman/template')
6879 self.assertFalse(node2)
6881 def testTemplateBlobMulti(self):
6882 """Test using a template with 'multiple-images' enabled"""
6883 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6884 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6885 retcode = self._DoTestFile('287_template_multi.dts')
6887 self.assertEqual(0, retcode)
6888 image = control.images['image']
6889 image_fname = tools.get_output_filename('my-image.bin')
6890 data = tools.read_file(image_fname)
6891 self.assertEqual(b'blob@@@@other', data)
6893 def testTemplateFit(self):
6894 """Test using a template in a FIT"""
6895 fit_data = self._DoReadFile('288_template_fit.dts')
6896 fname = os.path.join(self._indir, 'fit_data.fit')
6897 tools.write_file(fname, fit_data)
6898 out = tools.run('dumpimage', '-l', fname)
6900 def testTemplateSection(self):
6901 """Test using a template in a section (not at top level)"""
6902 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6903 data = self._DoReadFile('289_template_section.dts')
6904 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6905 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6906 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6908 def testMkimageSymbols(self):
6909 """Test using mkimage to build an image with symbols in it"""
6910 self._SetupSplElf('u_boot_binman_syms')
6911 data = self._DoReadFile('290_mkimage_sym.dts')
6913 image = control.images['image']
6914 entries = image.GetEntries()
6915 self.assertIn('u-boot', entries)
6916 u_boot = entries['u-boot']
6918 mkim = entries['mkimage']
6919 mkim_entries = mkim.GetEntries()
6920 self.assertIn('u-boot-spl', mkim_entries)
6921 spl = mkim_entries['u-boot-spl']
6922 self.assertIn('u-boot-spl2', mkim_entries)
6923 spl2 = mkim_entries['u-boot-spl2']
6925 # skip the mkimage header and the area sizes
6926 mk_data = data[mkim.offset + 0x40:]
6927 size, term = struct.unpack('>LL', mk_data[:8])
6929 # There should be only one image, so check that the zero terminator is
6931 self.assertEqual(0, term)
6933 content = mk_data[8:8 + size]
6935 # The image should contain the symbols from u_boot_binman_syms.c
6936 # Note that image_pos is adjusted by the base address of the image,
6937 # which is 0x10 in our test image
6938 spl_data = content[:0x18]
6939 content = content[0x1b:]
6941 # After the header is a table of offsets for each image. There should
6942 # only be one image, then a 0 terminator, so figure out the real start
6946 # Check symbols in both u-boot-spl and u-boot-spl2
6948 vals = struct.unpack('<LLQLL', spl_data)
6950 # The image should contain the symbols from u_boot_binman_syms.c
6951 # Note that image_pos is adjusted by the base address of the image,
6952 # which is 0x10 in our 'u_boot_binman_syms' test image
6953 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6954 self.assertEqual(base, vals[1])
6955 self.assertEqual(spl2.offset, vals[2])
6956 # figure out the internal positions of its components
6957 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6959 # Check that spl and spl2 are actually at the indicated positions
6961 elf.BINMAN_SYM_MAGIC_VALUE,
6962 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6964 elf.BINMAN_SYM_MAGIC_VALUE,
6965 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6967 self.assertEqual(len(U_BOOT_DATA), vals[4])
6970 spl_data = content[:0x18]
6972 def testTemplatePhandle(self):
6973 """Test using a template in a node containing a phandle"""
6975 'atf-bl31-path': 'bl31.elf',
6977 data = self._DoReadFileDtb('309_template_phandle.dts',
6978 entry_args=entry_args)
6979 fname = tools.get_output_filename('image.bin')
6980 out = tools.run('dumpimage', '-l', fname)
6982 # We should see the FIT description and one for each of the two images
6983 lines = out.splitlines()
6984 descs = [line.split()[-1] for line in lines if 'escription' in line]
6985 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
6987 def testTemplatePhandleDup(self):
6988 """Test using a template in a node containing a phandle"""
6990 'atf-bl31-path': 'bl31.elf',
6992 with self.assertRaises(ValueError) as e:
6993 self._DoReadFileDtb('310_template_phandle_dup.dts',
6994 entry_args=entry_args)
6996 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
6999 def testTIBoardConfig(self):
7000 """Test that a schema validated board config file can be generated"""
7001 data = self._DoReadFile('293_ti_board_cfg.dts')
7002 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7004 def testTIBoardConfigCombined(self):
7005 """Test that a schema validated combined board config file can be generated"""
7006 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
7007 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7008 self.assertGreater(data, configlen_noheader)
7010 def testTIBoardConfigNoDataType(self):
7011 """Test that error is thrown when data type is not supported"""
7012 with self.assertRaises(ValueError) as e:
7013 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
7014 self.assertIn("Schema validation error", str(e.exception))
7016 def testPackTiSecure(self):
7017 """Test that an image with a TI secured binary can be created"""
7018 keyfile = self.TestFile('key.key')
7022 data = self._DoReadFileDtb('296_ti_secure.dts',
7023 entry_args=entry_args)[0]
7024 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7026 def testPackTiSecureMissingTool(self):
7027 """Test that an image with a TI secured binary (non-functional) can be created
7028 when openssl is missing"""
7029 keyfile = self.TestFile('key.key')
7033 with test_util.capture_sys_output() as (_, stderr):
7034 self._DoTestFile('296_ti_secure.dts',
7035 force_missing_bintools='openssl',
7036 entry_args=entry_args)
7037 err = stderr.getvalue()
7038 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7040 def testPackTiSecureROM(self):
7041 """Test that a ROM image with a TI secured binary can be created"""
7042 keyfile = self.TestFile('key.key')
7046 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
7047 entry_args=entry_args)[0]
7048 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
7049 entry_args=entry_args)[0]
7050 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
7051 entry_args=entry_args)[0]
7052 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7053 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7054 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7056 def testPackTiSecureROMCombined(self):
7057 """Test that a ROM image with a TI secured binary can be created"""
7058 keyfile = self.TestFile('key.key')
7062 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
7063 entry_args=entry_args)[0]
7064 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7066 def testEncryptedNoAlgo(self):
7067 """Test encrypted node with missing required properties"""
7068 with self.assertRaises(ValueError) as e:
7069 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7071 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7074 def testEncryptedInvalidIvfile(self):
7075 """Test encrypted node with invalid iv file"""
7076 with self.assertRaises(ValueError) as e:
7077 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7078 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7081 def testEncryptedMissingKey(self):
7082 """Test encrypted node with missing key properties"""
7083 with self.assertRaises(ValueError) as e:
7084 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7086 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7089 def testEncryptedKeySource(self):
7090 """Test encrypted node with key-source property"""
7091 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7093 dtb = fdt.Fdt.FromData(data)
7096 node = dtb.GetNode('/images/u-boot/cipher')
7097 self.assertEqual('algo-name', node.props['algo'].value)
7098 self.assertEqual('key-source-value', node.props['key-source'].value)
7099 self.assertEqual(ENCRYPTED_IV_DATA,
7100 tools.to_bytes(''.join(node.props['iv'].value)))
7101 self.assertNotIn('key', node.props)
7103 def testEncryptedKeyFile(self):
7104 """Test encrypted node with key-filename property"""
7105 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7107 dtb = fdt.Fdt.FromData(data)
7110 node = dtb.GetNode('/images/u-boot/cipher')
7111 self.assertEqual('algo-name', node.props['algo'].value)
7112 self.assertEqual(ENCRYPTED_IV_DATA,
7113 tools.to_bytes(''.join(node.props['iv'].value)))
7114 self.assertEqual(ENCRYPTED_KEY_DATA,
7115 tools.to_bytes(''.join(node.props['key'].value)))
7116 self.assertNotIn('key-source', node.props)
7119 def testSplPubkeyDtb(self):
7120 """Test u_boot_spl_pubkey_dtb etype"""
7121 data = tools.read_file(self.TestFile("key.pem"))
7122 self._MakeInputFile("key.crt", data)
7123 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7124 image = control.images['image']
7125 entries = image.GetEntries()
7126 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7127 dtb_data = dtb_entry.GetData()
7128 dtb = fdt.Fdt.FromData(dtb_data)
7131 signature_node = dtb.GetNode('/signature')
7132 self.assertIsNotNone(signature_node)
7133 key_node = signature_node.FindNode("key-key")
7134 self.assertIsNotNone(key_node)
7135 self.assertEqual(fdt_util.GetString(key_node, "required"),
7137 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7139 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7142 def testXilinxBootgenSigning(self):
7143 """Test xilinx-bootgen etype"""
7144 bootgen = bintool.Bintool.create('bootgen')
7145 self._CheckBintool(bootgen)
7146 data = tools.read_file(self.TestFile("key.key"))
7147 self._MakeInputFile("psk.pem", data)
7148 self._MakeInputFile("ssk.pem", data)
7149 self._SetupPmuFwlElf()
7151 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7152 image_fname = tools.get_output_filename('image.bin')
7154 # Read partition header table and check if authentication is enabled
7155 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7156 "-read", image_fname, "pht").splitlines()
7157 attributes = {"authentication": None,
7161 for l in bootgen_out:
7162 for a in attributes.keys():
7164 m = re.match(fr".*{a} \[([^]]+)\]", l)
7165 attributes[a] = m.group(1)
7167 self.assertTrue(attributes['authentication'] == "rsa")
7168 self.assertTrue(attributes['core'] == "a53-0")
7169 self.assertTrue(attributes['encryption'] == "no")
7171 def testXilinxBootgenSigningEncryption(self):
7172 """Test xilinx-bootgen etype"""
7173 bootgen = bintool.Bintool.create('bootgen')
7174 self._CheckBintool(bootgen)
7175 data = tools.read_file(self.TestFile("key.key"))
7176 self._MakeInputFile("psk.pem", data)
7177 self._MakeInputFile("ssk.pem", data)
7178 self._SetupPmuFwlElf()
7180 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7181 image_fname = tools.get_output_filename('image.bin')
7183 # Read boot header in order to verify encryption source and
7184 # encryption parameter
7185 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7186 "-read", image_fname, "bh").splitlines()
7187 attributes = {"auth_only":
7188 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7189 "encryption_keystore":
7190 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7194 for l in bootgen_out:
7195 for a in attributes.keys():
7197 m = re.match(attributes[a]['re'], l)
7198 attributes[a] = m.group(1)
7200 # Check if fsbl-attribute is set correctly
7201 self.assertTrue(attributes['auth_only'] == "true")
7202 # Check if key is stored in efuse
7203 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7205 def testXilinxBootgenMissing(self):
7206 """Test that binman still produces an image if bootgen is missing"""
7207 data = tools.read_file(self.TestFile("key.key"))
7208 self._MakeInputFile("psk.pem", data)
7209 self._MakeInputFile("ssk.pem", data)
7210 self._SetupPmuFwlElf()
7212 with test_util.capture_sys_output() as (_, stderr):
7213 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7214 force_missing_bintools='bootgen')
7215 err = stderr.getvalue()
7216 self.assertRegex(err,
7217 "Image 'image'.*missing bintools.*: bootgen")
7219 if __name__ == "__main__":