1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
5 # To run a single test, change to this directory, and:
7 # python -m unittest func_test.TestFunctional.testHelp
13 from optparse import OptionParser
24 from binman import bintool
25 from binman import cbfs_util
26 from binman import cmdline
27 from binman import control
28 from binman import elf
29 from binman import elf_test
30 from binman import fip_util
31 from binman import fmap_util
32 from binman import state
34 from dtoc import fdt_util
35 from binman.etype import fdtmap
36 from binman.etype import image_header
37 from binman.image import Image
38 from u_boot_pylib import command
39 from u_boot_pylib import test_util
40 from u_boot_pylib import tools
41 from u_boot_pylib import tout
43 # Contents of test files, corresponding to different entry types
45 U_BOOT_IMG_DATA = b'img'
46 U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
48 U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
52 EFI_CAPSULE_DATA = b'efi'
53 U_BOOT_DTB_DATA = b'udtb'
54 U_BOOT_SPL_DTB_DATA = b'spldtb'
55 U_BOOT_TPL_DTB_DATA = b'tpldtb'
56 U_BOOT_VPL_DTB_DATA = b'vpldtb'
57 X86_START16_DATA = b'start16'
58 X86_START16_SPL_DATA = b'start16spl'
59 X86_START16_TPL_DATA = b'start16tpl'
60 X86_RESET16_DATA = b'reset16'
61 X86_RESET16_SPL_DATA = b'reset16spl'
62 X86_RESET16_TPL_DATA = b'reset16tpl'
63 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
67 U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
68 U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69 U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70 U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
78 CROS_EC_RW_DATA = b'ecrw'
82 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
84 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
85 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
86 REFCODE_DATA = b'refcode'
90 ATF_BL31_DATA = b'bl31'
91 TEE_OS_DATA = b'this is some tee OS data'
92 TI_DM_DATA = b'tidmtidm'
93 ATF_BL2U_DATA = b'bl2u'
94 OPENSBI_DATA = b'opensbi'
96 ROCKCHIP_TPL_DATA = b'rockchip-tpl'
97 TEST_FDT1_DATA = b'fdt1'
98 TEST_FDT2_DATA = b'test-fdt2'
99 ENV_DATA = b'var1=1\nvar2="2"'
100 ENCRYPTED_IV_DATA = b'123456'
101 ENCRYPTED_KEY_DATA = b'abcde'
102 PRE_LOAD_MAGIC = b'UBSH'
103 PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104 PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
105 TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
106 TI_UNSECURE_DATA = b'unsecuredata'
108 # Subdirectory of the input dir to use to put test FDTs
109 TEST_FDT_SUBDIR = 'fdts'
111 # The expected size for the device tree in some tests
112 EXTRACT_DTB_SIZE = 0x3c9
114 # Properties expected to be in the device tree when update_dtb is used
115 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
117 # Extra properties expected to be in the device tree when allow-repack is used
118 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
120 # Supported compression bintools
121 COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
125 # Firmware Management Protocol(FMP) GUID
126 FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
127 # Image GUID specified in the DTS
128 CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
130 WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
131 # Empty capsule GUIDs
132 EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133 EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
135 class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
152 from binman import entry
154 # Handle the case where argv[0] is 'python'
155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
158 # Create a temporary directory for input files
159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
176 X86_START16_SPL_DATA)
177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
178 X86_START16_TPL_DATA)
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
209 # ELF file with a '_dt_ucode_base_size' symbol
210 TestFunctional._MakeInputFile('u-boot',
211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
213 # Intel flash descriptor file
214 cls._SetupDescriptor()
216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
242 # ELF file with two sections in different parts of memory, used for both
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
261 def tearDownClass(cls):
262 """Remove the temporary input directory and its contents"""
263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
267 shutil.rmtree(cls._indir)
271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
272 toolpath=None, verbosity=None):
273 """Accept arguments controlling test execution
276 preserve_indir: Preserve the shared input directory used by all
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
281 toolpath: ist of paths to use for tools
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
285 cls.toolpath = toolpath
286 cls.verbosity = verbosity
288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
301 tools._finalise_for_test()
304 # Enable this to turn on debugging output
305 # tout.init(tout.DEBUG)
306 command.test_result = None
309 """Remove the temporary output directory"""
310 self._CleanupOutputDir()
312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
324 Temporary directory to use
327 image_fname = tools.get_output_filename('image.bin')
328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
330 tools.write_file(updated_fname, tools.read_file(image_fname))
331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
348 result = command.run_pipe([[self._binman_pathname] + list(args)],
349 capture=True, capture_stderr=True, raise_on_error=False)
350 if result.return_code and kwargs.get('raise_on_error', True):
351 raise Exception("Error running '%s': %s" % (' '.join(args),
352 result.stdout + result.stderr))
355 def _DoBinman(self, *argv):
356 """Run binman using directly (in the same process)
359 Arguments to pass, as a list of strings
361 Return value (0 for success)
364 args = cmdline.ParseArgs(argv)
365 args.pager = 'binman-invalid-pager'
366 args.build_dir = self._indir
368 # For testing, you can force an increase in verbosity here
369 # args.verbosity = tout.DEBUG
370 return control.Binman(args)
372 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
373 entry_args=None, images=None, use_real_dtb=False,
374 use_expanded=False, verbosity=None, allow_missing=False,
375 allow_fake_blobs=False, extra_indirs=None, threads=None,
376 test_section_timeout=False, update_fdt_in_elf=None,
377 force_missing_bintools='', ignore_missing=False, output_dir=None):
378 """Run binman with a given test file
381 fname: Device-tree source filename to use (e.g. 005_simple.dts)
382 debug: True to enable debugging output
383 map: True to output map files for the images
384 update_dtb: Update the offset and size of each entry in the device
385 tree before packing it into the image
386 entry_args: Dict of entry args to supply to binman
388 value: value of that arg
389 images: List of image names to build
390 use_real_dtb: True to use the test file as the contents of
391 the u-boot-dtb entry. Normally this is not needed and the
392 test contents (the U_BOOT_DTB_DATA string) can be used.
393 But in some test we need the real contents.
394 use_expanded: True to use expanded entries where available, e.g.
395 'u-boot-expanded' instead of 'u-boot'
396 verbosity: Verbosity level to use (0-3, None=don't set it)
397 allow_missing: Set the '--allow-missing' flag so that missing
398 external binaries just produce a warning instead of an error
399 allow_fake_blobs: Set the '--fake-ext-blobs' flag
400 extra_indirs: Extra input directories to add using -I
401 threads: Number of threads to use (None for default, 0 for
403 test_section_timeout: True to force the first time to timeout, as
404 used in testThreadTimeout()
405 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
406 force_missing_bintools (str): comma-separated list of bintools to
408 ignore_missing (bool): True to return success even if there are
409 missing blobs or bintools
410 output_dir: Specific output directory to use for image using -O
413 int return code, 0 on success
418 if verbosity is not None:
419 args.append('-v%d' % verbosity)
421 args.append('-v%d' % self.verbosity)
423 for path in self.toolpath:
424 args += ['--toolpath', path]
425 if threads is not None:
426 args.append('-T%d' % threads)
427 if test_section_timeout:
428 args.append('--test-section-timeout')
429 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
435 args.append('--fake-dtb')
437 args.append('--no-expanded')
439 for arg, value in entry_args.items():
440 args.append('-a%s=%s' % (arg, value))
446 args.append('--fake-ext-blobs')
447 if force_missing_bintools:
448 args += ['--force-missing-bintools', force_missing_bintools]
449 if update_fdt_in_elf:
450 args += ['--update-fdt-in-elf', update_fdt_in_elf]
453 args += ['-i', image]
455 for indir in extra_indirs:
456 args += ['-I', indir]
458 args += ['-O', output_dir]
459 return self._DoBinman(*args)
461 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
462 """Set up a new test device-tree file
464 The given file is compiled and set up as the device tree to be used
468 fname: Filename of .dts file to read
469 outfile: Output filename for compiled device-tree binary
472 Contents of device-tree binary
474 tmpdir = tempfile.mkdtemp(prefix='binmant.')
475 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
476 with open(dtb, 'rb') as fd:
478 TestFunctional._MakeInputFile(outfile, data)
479 shutil.rmtree(tmpdir)
482 def _GetDtbContentsForSpls(self, dtb_data, name):
483 """Create a version of the main DTB for SPL / TPL / VPL
485 For testing we don't actually have different versions of the DTB. With
486 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
487 we don't normally have any unwanted nodes.
489 We still want the DTBs for SPL and TPL to be different though, since
490 otherwise it is confusing to know which one we are looking at. So add
491 an 'spl' or 'tpl' property to the top-level node.
494 dtb_data: dtb data to modify (this should be a value devicetree)
495 name: Name of a new property to add
498 New dtb data with the property added
500 dtb = fdt.Fdt.FromData(dtb_data)
502 dtb.GetNode('/binman').AddZeroProp(name)
503 dtb.Sync(auto_resize=True)
505 return dtb.GetContents()
507 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
508 verbosity=None, map=False, update_dtb=False,
509 entry_args=None, reset_dtbs=True, extra_indirs=None,
511 """Run binman and return the resulting image
513 This runs binman with a given test file and then reads the resulting
514 output file. It is a shortcut function since most tests need to do
517 Raises an assertion failure if binman returns a non-zero exit code.
520 fname: Device-tree source filename to use (e.g. 005_simple.dts)
521 use_real_dtb: True to use the test file as the contents of
522 the u-boot-dtb entry. Normally this is not needed and the
523 test contents (the U_BOOT_DTB_DATA string) can be used.
524 But in some test we need the real contents.
525 use_expanded: True to use expanded entries where available, e.g.
526 'u-boot-expanded' instead of 'u-boot'
527 verbosity: Verbosity level to use (0-3, None=don't set it)
528 map: True to output map files for the images
529 update_dtb: Update the offset and size of each entry in the device
530 tree before packing it into the image
531 entry_args: Dict of entry args to supply to binman
533 value: value of that arg
534 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
535 function. If reset_dtbs is True, then the original test dtb
536 is written back before this function finishes
537 extra_indirs: Extra input directories to add using -I
538 threads: Number of threads to use (None for default, 0 for
543 Resulting image contents
545 Map data showing contents of image (or None if none)
546 Output device tree binary filename ('u-boot.dtb' path)
549 # Use the compiled test file as the u-boot-dtb input
551 dtb_data = self._SetupDtb(fname)
553 # For testing purposes, make a copy of the DT for SPL and TPL. Add
554 # a node indicating which it is, to aid verification.
555 for name in ['spl', 'tpl', 'vpl']:
556 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
557 outfile = os.path.join(self._indir, dtb_fname)
558 TestFunctional._MakeInputFile(dtb_fname,
559 self._GetDtbContentsForSpls(dtb_data, name))
562 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
563 entry_args=entry_args, use_real_dtb=use_real_dtb,
564 use_expanded=use_expanded, verbosity=verbosity,
565 extra_indirs=extra_indirs,
567 self.assertEqual(0, retcode)
568 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
570 # Find the (only) image, read it and return its contents
571 image = control.images['image']
572 image_fname = tools.get_output_filename('image.bin')
573 self.assertTrue(os.path.exists(image_fname))
575 map_fname = tools.get_output_filename('image.map')
576 with open(map_fname) as fd:
580 with open(image_fname, 'rb') as fd:
581 return fd.read(), dtb_data, map_data, out_dtb_fname
583 # Put the test file back
584 if reset_dtbs and use_real_dtb:
587 def _DoReadFileRealDtb(self, fname):
588 """Run binman with a real .dtb file and return the resulting data
591 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
594 Resulting image contents
596 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
598 def _DoReadFile(self, fname, use_real_dtb=False):
599 """Helper function which discards the device-tree binary
602 fname: Device-tree source filename to use (e.g. 005_simple.dts)
603 use_real_dtb: True to use the test file as the contents of
604 the u-boot-dtb entry. Normally this is not needed and the
605 test contents (the U_BOOT_DTB_DATA string) can be used.
606 But in some test we need the real contents.
609 Resulting image contents
611 return self._DoReadFileDtb(fname, use_real_dtb)[0]
614 def _MakeInputFile(cls, fname, contents):
615 """Create a new test input file, creating directories as needed
618 fname: Filename to create
619 contents: File contents to write in to the file
621 Full pathname of file created
623 pathname = os.path.join(cls._indir, fname)
624 dirname = os.path.dirname(pathname)
625 if dirname and not os.path.exists(dirname):
627 with open(pathname, 'wb') as fd:
632 def _MakeInputDir(cls, dirname):
633 """Create a new test input directory, creating directories as needed
636 dirname: Directory name to create
639 Full pathname of directory created
641 pathname = os.path.join(cls._indir, dirname)
642 if not os.path.exists(pathname):
643 os.makedirs(pathname)
647 def _SetupSplElf(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 SPL
653 TestFunctional._MakeInputFile('spl/u-boot-spl',
654 tools.read_file(cls.ElfTestFile(src_fname)))
657 def _SetupTplElf(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 TPL
663 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
664 tools.read_file(cls.ElfTestFile(src_fname)))
667 def _SetupVplElf(cls, src_fname='bss_data'):
668 """Set up an ELF file with a '_dt_ucode_base_size' symbol
671 Filename of ELF file to use as VPL
673 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
674 tools.read_file(cls.ElfTestFile(src_fname)))
677 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
678 """Set up an ELF file with a '_dt_ucode_base_size' symbol
681 Filename of ELF file to use as VPL
683 TestFunctional._MakeInputFile('pmu-firmware.elf',
684 tools.read_file(cls.ElfTestFile(src_fname)))
687 def _SetupDescriptor(cls):
688 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
689 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
692 def TestFile(cls, fname):
693 return os.path.join(cls._binman_dir, 'test', fname)
696 def ElfTestFile(cls, fname):
697 return os.path.join(cls._elf_testdir, fname)
700 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
701 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
702 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
703 dummy, paged_sz) + U_BOOT_DATA
705 TestFunctional._MakeInputFile(fname, data)
707 def AssertInList(self, grep_list, target):
708 """Assert that at least one of a list of things is in a target
711 grep_list: List of strings to check
712 target: Target string
714 for grep in grep_list:
717 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
719 def CheckNoGaps(self, entries):
720 """Check that all entries fit together without gaps
723 entries: List of entries to check
726 for entry in entries.values():
727 self.assertEqual(offset, entry.offset)
730 def GetFdtLen(self, dtb):
731 """Get the totalsize field from a device-tree binary
734 dtb: Device-tree binary contents
737 Total size of device-tree binary, from the header
739 return struct.unpack('>L', dtb[4:8])[0]
741 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
742 def AddNode(node, path):
744 path += '/' + node.name
745 for prop in node.props.values():
746 if prop.name in prop_names:
747 prop_path = path + ':' + prop.name
748 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
750 for subnode in node.subnodes:
751 AddNode(subnode, path)
754 AddNode(dtb.GetRoot(), '')
757 def _CheckSign(self, fit, key):
759 tools.run('fit_check_sign', '-k', key, '-f', fit)
761 self.fail('Expected signed FIT container')
766 """Test a basic run with valid args"""
767 result = self._RunBinman('-h')
769 def testFullHelp(self):
770 """Test that the full help is displayed with -H"""
771 result = self._RunBinman('-H')
772 help_file = os.path.join(self._binman_dir, 'README.rst')
773 # Remove possible extraneous strings
774 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
775 gothelp = result.stdout.replace(extra, '')
776 self.assertEqual(len(gothelp), os.path.getsize(help_file))
777 self.assertEqual(0, len(result.stderr))
778 self.assertEqual(0, result.return_code)
780 def testFullHelpInternal(self):
781 """Test that the full help is displayed with -H"""
783 command.test_result = command.CommandResult()
784 result = self._DoBinman('-H')
785 help_file = os.path.join(self._binman_dir, 'README.rst')
787 command.test_result = None
790 """Test that the basic help is displayed with -h"""
791 result = self._RunBinman('-h')
792 self.assertTrue(len(result.stdout) > 200)
793 self.assertEqual(0, len(result.stderr))
794 self.assertEqual(0, result.return_code)
797 """Test that we can run it with a specific board"""
798 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
799 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
800 result = self._DoBinman('build', '-n', '-b', 'sandbox')
801 self.assertEqual(0, result)
803 def testNeedBoard(self):
804 """Test that we get an error when no board ius supplied"""
805 with self.assertRaises(ValueError) as e:
806 result = self._DoBinman('build')
807 self.assertIn("Must provide a board to process (use -b <board>)",
810 def testMissingDt(self):
811 """Test that an invalid device-tree file generates an error"""
812 with self.assertRaises(Exception) as e:
813 self._RunBinman('build', '-d', 'missing_file')
814 # We get one error from libfdt, and a different one from fdtget.
815 self.AssertInList(["Couldn't open blob from 'missing_file'",
816 'No such file or directory'], str(e.exception))
818 def testBrokenDt(self):
819 """Test that an invalid device-tree source file generates an error
821 Since this is a source file it should be compiled and the error
822 will come from the device-tree compiler (dtc).
824 with self.assertRaises(Exception) as e:
825 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
826 self.assertIn("FATAL ERROR: Unable to parse input tree",
829 def testMissingNode(self):
830 """Test that a device tree without a 'binman' node generates an error"""
831 with self.assertRaises(Exception) as e:
832 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
833 self.assertIn("does not have a 'binman' node", str(e.exception))
836 """Test that an empty binman node works OK (i.e. does nothing)"""
837 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
838 self.assertEqual(0, len(result.stderr))
839 self.assertEqual(0, result.return_code)
841 def testInvalidEntry(self):
842 """Test that an invalid entry is flagged"""
843 with self.assertRaises(Exception) as e:
844 result = self._RunBinman('build', '-d',
845 self.TestFile('004_invalid_entry.dts'))
846 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
847 "'/binman/not-a-valid-type'", str(e.exception))
849 def testSimple(self):
850 """Test a simple binman with a single file"""
851 data = self._DoReadFile('005_simple.dts')
852 self.assertEqual(U_BOOT_DATA, data)
854 def testSimpleDebug(self):
855 """Test a simple binman run with debugging enabled"""
856 self._DoTestFile('005_simple.dts', debug=True)
859 """Test that we can handle creating two images
861 This also tests image padding.
863 retcode = self._DoTestFile('006_dual_image.dts')
864 self.assertEqual(0, retcode)
866 image = control.images['image1']
867 self.assertEqual(len(U_BOOT_DATA), image.size)
868 fname = tools.get_output_filename('image1.bin')
869 self.assertTrue(os.path.exists(fname))
870 with open(fname, 'rb') as fd:
872 self.assertEqual(U_BOOT_DATA, data)
874 image = control.images['image2']
875 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
876 fname = tools.get_output_filename('image2.bin')
877 self.assertTrue(os.path.exists(fname))
878 with open(fname, 'rb') as fd:
880 self.assertEqual(U_BOOT_DATA, data[3:7])
881 self.assertEqual(tools.get_bytes(0, 3), data[:3])
882 self.assertEqual(tools.get_bytes(0, 5), data[7:])
884 def testBadAlign(self):
885 """Test that an invalid alignment value is detected"""
886 with self.assertRaises(ValueError) as e:
887 self._DoTestFile('007_bad_align.dts')
888 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
889 "of two", str(e.exception))
891 def testPackSimple(self):
892 """Test that packing works as expected"""
893 retcode = self._DoTestFile('008_pack.dts')
894 self.assertEqual(0, retcode)
895 self.assertIn('image', control.images)
896 image = control.images['image']
897 entries = image.GetEntries()
898 self.assertEqual(5, len(entries))
901 self.assertIn('u-boot', entries)
902 entry = entries['u-boot']
903 self.assertEqual(0, entry.offset)
904 self.assertEqual(len(U_BOOT_DATA), entry.size)
906 # Second u-boot, aligned to 16-byte boundary
907 self.assertIn('u-boot-align', entries)
908 entry = entries['u-boot-align']
909 self.assertEqual(16, entry.offset)
910 self.assertEqual(len(U_BOOT_DATA), entry.size)
912 # Third u-boot, size 23 bytes
913 self.assertIn('u-boot-size', entries)
914 entry = entries['u-boot-size']
915 self.assertEqual(20, entry.offset)
916 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
917 self.assertEqual(23, entry.size)
919 # Fourth u-boot, placed immediate after the above
920 self.assertIn('u-boot-next', entries)
921 entry = entries['u-boot-next']
922 self.assertEqual(43, entry.offset)
923 self.assertEqual(len(U_BOOT_DATA), entry.size)
925 # Fifth u-boot, placed at a fixed offset
926 self.assertIn('u-boot-fixed', entries)
927 entry = entries['u-boot-fixed']
928 self.assertEqual(61, entry.offset)
929 self.assertEqual(len(U_BOOT_DATA), entry.size)
931 self.assertEqual(65, image.size)
933 def testPackExtra(self):
934 """Test that extra packing feature works as expected"""
935 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
938 self.assertIn('image', control.images)
939 image = control.images['image']
940 entries = image.GetEntries()
941 self.assertEqual(6, len(entries))
943 # First u-boot with padding before and after (included in minimum size)
944 self.assertIn('u-boot', entries)
945 entry = entries['u-boot']
946 self.assertEqual(0, entry.offset)
947 self.assertEqual(3, entry.pad_before)
948 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
949 self.assertEqual(U_BOOT_DATA, entry.data)
950 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
951 tools.get_bytes(0, 5), data[:entry.size])
954 # Second u-boot has an aligned size, but it has no effect
955 self.assertIn('u-boot-align-size-nop', entries)
956 entry = entries['u-boot-align-size-nop']
957 self.assertEqual(pos, entry.offset)
958 self.assertEqual(len(U_BOOT_DATA), entry.size)
959 self.assertEqual(U_BOOT_DATA, entry.data)
960 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
963 # Third u-boot has an aligned size too
964 self.assertIn('u-boot-align-size', entries)
965 entry = entries['u-boot-align-size']
966 self.assertEqual(pos, entry.offset)
967 self.assertEqual(32, entry.size)
968 self.assertEqual(U_BOOT_DATA, entry.data)
969 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
970 data[pos:pos + entry.size])
973 # Fourth u-boot has an aligned end
974 self.assertIn('u-boot-align-end', entries)
975 entry = entries['u-boot-align-end']
976 self.assertEqual(48, entry.offset)
977 self.assertEqual(16, entry.size)
978 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
979 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
980 data[pos:pos + entry.size])
983 # Fifth u-boot immediately afterwards
984 self.assertIn('u-boot-align-both', entries)
985 entry = entries['u-boot-align-both']
986 self.assertEqual(64, entry.offset)
987 self.assertEqual(64, entry.size)
988 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
989 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
990 data[pos:pos + entry.size])
992 # Sixth u-boot with both minimum size and aligned size
993 self.assertIn('u-boot-min-size', entries)
994 entry = entries['u-boot-min-size']
995 self.assertEqual(128, entry.offset)
996 self.assertEqual(32, entry.size)
997 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
998 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
999 data[pos:pos + entry.size])
1001 self.CheckNoGaps(entries)
1002 self.assertEqual(160, image.size)
1004 dtb = fdt.Fdt(out_dtb_fname)
1006 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1012 'u-boot:image-pos': 0,
1014 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1016 'u-boot-align-size-nop:image-pos': 12,
1017 'u-boot-align-size-nop:offset': 12,
1018 'u-boot-align-size-nop:size': 4,
1020 'u-boot-align-size:image-pos': 16,
1021 'u-boot-align-size:offset': 16,
1022 'u-boot-align-size:size': 32,
1024 'u-boot-align-end:image-pos': 48,
1025 'u-boot-align-end:offset': 48,
1026 'u-boot-align-end:size': 16,
1028 'u-boot-align-both:image-pos': 64,
1029 'u-boot-align-both:offset': 64,
1030 'u-boot-align-both:size': 64,
1032 'u-boot-min-size:image-pos': 128,
1033 'u-boot-min-size:offset': 128,
1034 'u-boot-min-size:size': 32,
1036 self.assertEqual(expected, props)
1038 def testPackAlignPowerOf2(self):
1039 """Test that invalid entry alignment is detected"""
1040 with self.assertRaises(ValueError) as e:
1041 self._DoTestFile('010_pack_align_power2.dts')
1042 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1043 "of two", str(e.exception))
1045 def testPackAlignSizePowerOf2(self):
1046 """Test that invalid entry size alignment is detected"""
1047 with self.assertRaises(ValueError) as e:
1048 self._DoTestFile('011_pack_align_size_power2.dts')
1049 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1050 "power of two", str(e.exception))
1052 def testPackInvalidAlign(self):
1053 """Test detection of an offset that does not match its alignment"""
1054 with self.assertRaises(ValueError) as e:
1055 self._DoTestFile('012_pack_inv_align.dts')
1056 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
1057 "align 0x4 (4)", str(e.exception))
1059 def testPackInvalidSizeAlign(self):
1060 """Test that invalid entry size alignment is detected"""
1061 with self.assertRaises(ValueError) as e:
1062 self._DoTestFile('013_pack_inv_size_align.dts')
1063 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1064 "align-size 0x4 (4)", str(e.exception))
1066 def testPackOverlap(self):
1067 """Test that overlapping regions are detected"""
1068 with self.assertRaises(ValueError) as e:
1069 self._DoTestFile('014_pack_overlap.dts')
1070 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
1071 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1074 def testPackEntryOverflow(self):
1075 """Test that entries that overflow their size are detected"""
1076 with self.assertRaises(ValueError) as e:
1077 self._DoTestFile('015_pack_overflow.dts')
1078 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1079 "but entry size is 0x3 (3)", str(e.exception))
1081 def testPackImageOverflow(self):
1082 """Test that entries which overflow the image size are detected"""
1083 with self.assertRaises(ValueError) as e:
1084 self._DoTestFile('016_pack_image_overflow.dts')
1085 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
1086 "size 0x3 (3)", str(e.exception))
1088 def testPackImageSize(self):
1089 """Test that the image size can be set"""
1090 retcode = self._DoTestFile('017_pack_image_size.dts')
1091 self.assertEqual(0, retcode)
1092 self.assertIn('image', control.images)
1093 image = control.images['image']
1094 self.assertEqual(7, image.size)
1096 def testPackImageSizeAlign(self):
1097 """Test that image size alignemnt works as expected"""
1098 retcode = self._DoTestFile('018_pack_image_align.dts')
1099 self.assertEqual(0, retcode)
1100 self.assertIn('image', control.images)
1101 image = control.images['image']
1102 self.assertEqual(16, image.size)
1104 def testPackInvalidImageAlign(self):
1105 """Test that invalid image alignment is detected"""
1106 with self.assertRaises(ValueError) as e:
1107 self._DoTestFile('019_pack_inv_image_align.dts')
1108 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
1109 "align-size 0x8 (8)", str(e.exception))
1111 def testPackAlignPowerOf2Inv(self):
1112 """Test that invalid image alignment is detected"""
1113 with self.assertRaises(ValueError) as e:
1114 self._DoTestFile('020_pack_inv_image_align_power2.dts')
1115 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
1116 "two", str(e.exception))
1118 def testImagePadByte(self):
1119 """Test that the image pad byte can be specified"""
1121 data = self._DoReadFile('021_image_pad.dts')
1122 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
1125 def testImageName(self):
1126 """Test that image files can be named"""
1127 retcode = self._DoTestFile('022_image_name.dts')
1128 self.assertEqual(0, retcode)
1129 image = control.images['image1']
1130 fname = tools.get_output_filename('test-name')
1131 self.assertTrue(os.path.exists(fname))
1133 image = control.images['image2']
1134 fname = tools.get_output_filename('test-name.xx')
1135 self.assertTrue(os.path.exists(fname))
1137 def testBlobFilename(self):
1138 """Test that generic blobs can be provided by filename"""
1139 data = self._DoReadFile('023_blob.dts')
1140 self.assertEqual(BLOB_DATA, data)
1142 def testPackSorted(self):
1143 """Test that entries can be sorted"""
1145 data = self._DoReadFile('024_sorted.dts')
1146 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1147 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
1149 def testPackZeroOffset(self):
1150 """Test that an entry at offset 0 is not given a new offset"""
1152 with self.assertRaises(ValueError) as e:
1153 self._DoTestFile('025_pack_zero_size.dts')
1154 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1155 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1158 def testPackUbootDtb(self):
1159 """Test that a device tree can be added to U-Boot"""
1160 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1161 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1163 def testPackX86RomNoSize(self):
1164 """Test that the end-at-4gb property requires a size property"""
1166 with self.assertRaises(ValueError) as e:
1167 self._DoTestFile('027_pack_4gb_no_size.dts')
1168 self.assertIn("Image '/binman': Section size must be provided when "
1169 "using end-at-4gb", str(e.exception))
1171 def test4gbAndSkipAtStartTogether(self):
1172 """Test that the end-at-4gb and skip-at-size property can't be used
1175 with self.assertRaises(ValueError) as e:
1176 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1177 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1178 "'skip-at-start'", str(e.exception))
1180 def testPackX86RomOutside(self):
1181 """Test that the end-at-4gb property checks for offset boundaries"""
1183 with self.assertRaises(ValueError) as e:
1184 self._DoTestFile('028_pack_4gb_outside.dts')
1185 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1186 "is outside the section '/binman' starting at "
1187 '0xffffffe0 (4294967264) of size 0x20 (32)',
1190 def testPackX86Rom(self):
1191 """Test that a basic x86 ROM can be created"""
1193 data = self._DoReadFile('029_x86_rom.dts')
1194 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1195 tools.get_bytes(0, 2), data)
1197 def testPackX86RomMeNoDesc(self):
1198 """Test that an invalid Intel descriptor entry is detected"""
1200 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1201 with self.assertRaises(ValueError) as e:
1202 self._DoTestFile('163_x86_rom_me_empty.dts')
1203 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1206 self._SetupDescriptor()
1208 def testPackX86RomBadDesc(self):
1209 """Test that the Intel requires a descriptor entry"""
1210 with self.assertRaises(ValueError) as e:
1211 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1212 self.assertIn("Node '/binman/intel-me': No offset set with "
1213 "offset-unset: should another entry provide this correct "
1214 "offset?", str(e.exception))
1216 def testPackX86RomMe(self):
1217 """Test that an x86 ROM with an ME region can be created"""
1218 data = self._DoReadFile('031_x86_rom_me.dts')
1219 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
1220 if data[:0x1000] != expected_desc:
1221 self.fail('Expected descriptor binary at start of image')
1222 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1224 def testPackVga(self):
1225 """Test that an image with a VGA binary can be created"""
1226 data = self._DoReadFile('032_intel_vga.dts')
1227 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1229 def testPackStart16(self):
1230 """Test that an image with an x86 start16 region can be created"""
1231 data = self._DoReadFile('033_x86_start16.dts')
1232 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1234 def testPackPowerpcMpc85xxBootpgResetvec(self):
1235 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1237 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1238 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1240 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1241 """Handle running a test for insertion of microcode
1244 dts_fname: Name of test .dts file
1245 nodtb_data: Data that we expect in the first section
1246 ucode_second: True if the microsecond entry is second instead of
1251 Contents of first region (U-Boot or SPL)
1252 Offset and size components of microcode pointer, as inserted
1253 in the above (two 4-byte words)
1255 data = self._DoReadFile(dts_fname, True)
1257 # Now check the device tree has no microcode
1259 ucode_content = data[len(nodtb_data):]
1260 ucode_pos = len(nodtb_data)
1261 dtb_with_ucode = ucode_content[16:]
1262 fdt_len = self.GetFdtLen(dtb_with_ucode)
1264 dtb_with_ucode = data[len(nodtb_data):]
1265 fdt_len = self.GetFdtLen(dtb_with_ucode)
1266 ucode_content = dtb_with_ucode[fdt_len:]
1267 ucode_pos = len(nodtb_data) + fdt_len
1268 fname = tools.get_output_filename('test.dtb')
1269 with open(fname, 'wb') as fd:
1270 fd.write(dtb_with_ucode)
1271 dtb = fdt.FdtScan(fname)
1272 ucode = dtb.GetNode('/microcode')
1273 self.assertTrue(ucode)
1274 for node in ucode.subnodes:
1275 self.assertFalse(node.props.get('data'))
1277 # Check that the microcode appears immediately after the Fdt
1278 # This matches the concatenation of the data properties in
1279 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1280 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1282 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1284 # Check that the microcode pointer was inserted. It should match the
1285 # expected offset and size
1286 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1288 u_boot = data[:len(nodtb_data)]
1289 return u_boot, pos_and_size
1291 def testPackUbootMicrocode(self):
1292 """Test that x86 microcode can be handled correctly
1294 We expect to see the following in the image, in order:
1295 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1297 u-boot.dtb with the microcode removed
1300 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1302 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1303 b' somewhere in here', first)
1305 def _RunPackUbootSingleMicrocode(self):
1306 """Test that x86 microcode can be handled correctly
1308 We expect to see the following in the image, in order:
1309 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1311 u-boot.dtb with the microcode
1312 an empty microcode region
1314 # We need the libfdt library to run this test since only that allows
1315 # finding the offset of a property. This is required by
1316 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1317 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1319 second = data[len(U_BOOT_NODTB_DATA):]
1321 fdt_len = self.GetFdtLen(second)
1322 third = second[fdt_len:]
1323 second = second[:fdt_len]
1325 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1326 self.assertIn(ucode_data, second)
1327 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1329 # Check that the microcode pointer was inserted. It should match the
1330 # expected offset and size
1331 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1333 first = data[:len(U_BOOT_NODTB_DATA)]
1334 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1335 b' somewhere in here', first)
1337 def testPackUbootSingleMicrocode(self):
1338 """Test that x86 microcode can be handled correctly with fdt_normal.
1340 self._RunPackUbootSingleMicrocode()
1342 def testUBootImg(self):
1343 """Test that u-boot.img can be put in a file"""
1344 data = self._DoReadFile('036_u_boot_img.dts')
1345 self.assertEqual(U_BOOT_IMG_DATA, data)
1347 def testNoMicrocode(self):
1348 """Test that a missing microcode region is detected"""
1349 with self.assertRaises(ValueError) as e:
1350 self._DoReadFile('037_x86_no_ucode.dts', True)
1351 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1352 "node found in ", str(e.exception))
1354 def testMicrocodeWithoutNode(self):
1355 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1356 with self.assertRaises(ValueError) as e:
1357 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1358 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1359 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1361 def testMicrocodeWithoutNode2(self):
1362 """Test that a missing u-boot-ucode node is detected"""
1363 with self.assertRaises(ValueError) as e:
1364 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1365 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1366 "microcode region u-boot-ucode", str(e.exception))
1368 def testMicrocodeWithoutPtrInElf(self):
1369 """Test that a U-Boot binary without the microcode symbol is detected"""
1370 # ELF file without a '_dt_ucode_base_size' symbol
1372 TestFunctional._MakeInputFile('u-boot',
1373 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1375 with self.assertRaises(ValueError) as e:
1376 self._RunPackUbootSingleMicrocode()
1377 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1378 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1381 # Put the original file back
1382 TestFunctional._MakeInputFile('u-boot',
1383 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
1385 def testMicrocodeNotInImage(self):
1386 """Test that microcode must be placed within the image"""
1387 with self.assertRaises(ValueError) as e:
1388 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1389 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1390 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1391 "section ranging from 00000000 to 0000002e", str(e.exception))
1393 def testWithoutMicrocode(self):
1394 """Test that we can cope with an image without microcode (e.g. qemu)"""
1395 TestFunctional._MakeInputFile('u-boot',
1396 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1397 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1399 # Now check the device tree has no microcode
1400 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1401 second = data[len(U_BOOT_NODTB_DATA):]
1403 fdt_len = self.GetFdtLen(second)
1404 self.assertEqual(dtb, second[:fdt_len])
1406 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1407 third = data[used_len:]
1408 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
1410 def testUnknownPosSize(self):
1411 """Test that microcode must be placed within the image"""
1412 with self.assertRaises(ValueError) as e:
1413 self._DoReadFile('041_unknown_pos_size.dts', True)
1414 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1415 "entry 'invalid-entry'", str(e.exception))
1417 def testPackFsp(self):
1418 """Test that an image with a FSP binary can be created"""
1419 data = self._DoReadFile('042_intel_fsp.dts')
1420 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1422 def testPackCmc(self):
1423 """Test that an image with a CMC binary can be created"""
1424 data = self._DoReadFile('043_intel_cmc.dts')
1425 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1427 def testPackVbt(self):
1428 """Test that an image with a VBT binary can be created"""
1429 data = self._DoReadFile('046_intel_vbt.dts')
1430 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1432 def testSplBssPad(self):
1433 """Test that we can pad SPL's BSS with zeros"""
1434 # ELF file with a '__bss_size' symbol
1436 data = self._DoReadFile('047_spl_bss_pad.dts')
1437 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
1440 def testSplBssPadMissing(self):
1441 """Test that a missing symbol is detected"""
1442 self._SetupSplElf('u_boot_ucode_ptr')
1443 with self.assertRaises(ValueError) as e:
1444 self._DoReadFile('047_spl_bss_pad.dts')
1445 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1448 def testPackStart16Spl(self):
1449 """Test that an image with an x86 start16 SPL region can be created"""
1450 data = self._DoReadFile('048_x86_start16_spl.dts')
1451 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1453 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1454 """Helper function for microcode tests
1456 We expect to see the following in the image, in order:
1457 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1459 u-boot.dtb with the microcode removed
1463 dts: Device tree file to use for test
1464 ucode_second: True if the microsecond entry is second instead of
1467 self._SetupSplElf('u_boot_ucode_ptr')
1468 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1469 ucode_second=ucode_second)
1470 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1471 b'ter somewhere in here', first)
1473 def testPackUbootSplMicrocode(self):
1474 """Test that x86 microcode can be handled correctly in SPL"""
1476 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1478 def testPackUbootSplMicrocodeReorder(self):
1479 """Test that order doesn't matter for microcode entries
1481 This is the same as testPackUbootSplMicrocode but when we process the
1482 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1483 entry, so we reply on binman to try later.
1485 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1488 def testPackMrc(self):
1489 """Test that an image with an MRC binary can be created"""
1490 data = self._DoReadFile('050_intel_mrc.dts')
1491 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1493 def testSplDtb(self):
1494 """Test that an image with spl/u-boot-spl.dtb can be created"""
1496 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1497 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1499 def testSplNoDtb(self):
1500 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1502 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1503 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1505 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1506 use_expanded=False, no_write_symbols=False,
1508 """Check the image contains the expected symbol values
1511 dts: Device tree file to use for test
1512 base_data: Data before and after 'u-boot' section
1513 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1514 the offset not available due to it being in a compressed section
1515 entry_args: Dict of entry args to supply to binman
1517 value: value of that arg
1518 use_expanded: True to use expanded entries where available, e.g.
1519 'u-boot-expanded' instead of 'u-boot'
1520 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1523 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1524 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1525 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1526 self.assertEqual(syms['_binman_sym_magic'].address, addr)
1527 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1530 self._SetupSplElf('u_boot_binman_syms')
1531 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1532 use_expanded=use_expanded,
1533 verbosity=None if u_boot_offset else 3)[0]
1535 # The lz4-compressed version of the U-Boot data is 19 bytes long
1538 # The image should contain the symbols from u_boot_binman_syms.c
1539 # Note that image_pos is adjusted by the base address of the image,
1540 # which is 0x10 in our test image
1541 # If u_boot_offset is None, Binman should write -1U into the image
1542 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
1543 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1544 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1545 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
1547 # u-boot-spl has a symbols-base property, so take that into account if
1548 # required. The caller must supply the value
1550 if symbols_base is not None:
1551 vals[3] = symbols_base + u_boot_offset
1554 sym_values = struct.pack('<LLQLL', *vals)
1555 sym_values2 = struct.pack('<LLQLL', *vals2)
1556 if no_write_symbols:
1559 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1560 U_BOOT_DATA + base_data, data)
1562 got_vals = struct.unpack('<LLQLL', data[:24])
1565 #print('expect:', list(f'{v:x}' for v in vals))
1566 #print(' got:', list(f'{v:x}' for v in got_vals))
1568 self.assertEqual(vals, got_vals)
1569 self.assertEqual(sym_values, data[:24])
1571 blen = len(base_data)
1572 self.assertEqual(base_data[24:], data[24:blen])
1573 self.assertEqual(0xff, data[blen])
1576 ofs = blen + 1 + len(U_BOOT_DATA)
1577 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1579 ofs = blen + 1 + comp_uboot_len
1581 self.assertEqual(sym_values2, data[ofs:ofs + 24])
1582 self.assertEqual(base_data[24:], data[ofs + 24:])
1584 # Just repeating the above asserts all at once, for clarity
1586 expected = (sym_values + base_data[24:] +
1587 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1588 sym_values2 + base_data[24:])
1589 self.assertEqual(expected, data)
1591 def testSymbols(self):
1592 """Test binman can assign symbols embedded in U-Boot"""
1593 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
1595 def testSymbolsNoDtb(self):
1596 """Test binman can assign symbols embedded in U-Boot SPL"""
1597 self.checkSymbols('196_symbols_nodtb.dts',
1598 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1601 def testPackUnitAddress(self):
1602 """Test that we support multiple binaries with the same name"""
1603 data = self._DoReadFile('054_unit_address.dts')
1604 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1606 def testSections(self):
1607 """Basic test of sections"""
1608 data = self._DoReadFile('055_sections.dts')
1609 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1610 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1611 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
1612 self.assertEqual(expected, data)
1615 """Tests outputting a map of the images"""
1616 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1617 self.assertEqual('''ImagePos Offset Size Name
1618 00000000 00000000 00000028 image
1619 00000000 00000000 00000010 section@0
1620 00000000 00000000 00000004 u-boot
1621 00000010 00000010 00000010 section@1
1622 00000010 00000000 00000004 u-boot
1623 00000020 00000020 00000004 section@2
1624 00000020 00000000 00000004 u-boot
1627 def testNamePrefix(self):
1628 """Tests that name prefixes are used"""
1629 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1630 self.assertEqual('''ImagePos Offset Size Name
1631 00000000 00000000 00000028 image
1632 00000000 00000000 00000010 section@0
1633 00000000 00000000 00000004 ro-u-boot
1634 00000010 00000010 00000010 section@1
1635 00000010 00000000 00000004 rw-u-boot
1638 def testUnknownContents(self):
1639 """Test that obtaining the contents works as expected"""
1640 with self.assertRaises(ValueError) as e:
1641 self._DoReadFile('057_unknown_contents.dts', True)
1642 self.assertIn("Image '/binman': Internal error: Could not complete "
1643 "processing of contents: remaining ["
1644 "<binman.etype._testing.Entry__testing ", str(e.exception))
1646 def testBadChangeSize(self):
1647 """Test that trying to change the size of an entry fails"""
1649 state.SetAllowEntryExpansion(False)
1650 with self.assertRaises(ValueError) as e:
1651 self._DoReadFile('059_change_size.dts', True)
1652 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1655 state.SetAllowEntryExpansion(True)
1657 def testUpdateFdt(self):
1658 """Test that we can update the device tree with offset/size info"""
1659 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1661 dtb = fdt.Fdt(out_dtb_fname)
1663 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1667 '_testing:offset': 32,
1669 '_testing:image-pos': 32,
1670 'section@0/u-boot:offset': 0,
1671 'section@0/u-boot:size': len(U_BOOT_DATA),
1672 'section@0/u-boot:image-pos': 0,
1673 'section@0:offset': 0,
1674 'section@0:size': 16,
1675 'section@0:image-pos': 0,
1677 'section@1/u-boot:offset': 0,
1678 'section@1/u-boot:size': len(U_BOOT_DATA),
1679 'section@1/u-boot:image-pos': 16,
1680 'section@1:offset': 16,
1681 'section@1:size': 16,
1682 'section@1:image-pos': 16,
1686 def testUpdateFdtBad(self):
1687 """Test that we detect when ProcessFdt never completes"""
1688 with self.assertRaises(ValueError) as e:
1689 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1690 self.assertIn('Could not complete processing of Fdt: remaining '
1691 '[<binman.etype._testing.Entry__testing',
1694 def testEntryArgs(self):
1695 """Test passing arguments to entries from the command line"""
1697 'test-str-arg': 'test1',
1698 'test-int-arg': '456',
1700 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1701 self.assertIn('image', control.images)
1702 entry = control.images['image'].GetEntries()['_testing']
1703 self.assertEqual('test0', entry.test_str_fdt)
1704 self.assertEqual('test1', entry.test_str_arg)
1705 self.assertEqual(123, entry.test_int_fdt)
1706 self.assertEqual(456, entry.test_int_arg)
1708 def testEntryArgsMissing(self):
1709 """Test missing arguments and properties"""
1711 'test-int-arg': '456',
1713 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1714 entry = control.images['image'].GetEntries()['_testing']
1715 self.assertEqual('test0', entry.test_str_fdt)
1716 self.assertEqual(None, entry.test_str_arg)
1717 self.assertEqual(None, entry.test_int_fdt)
1718 self.assertEqual(456, entry.test_int_arg)
1720 def testEntryArgsRequired(self):
1721 """Test missing arguments and properties"""
1723 'test-int-arg': '456',
1725 with self.assertRaises(ValueError) as e:
1726 self._DoReadFileDtb('064_entry_args_required.dts')
1727 self.assertIn("Node '/binman/_testing': "
1728 'Missing required properties/entry args: test-str-arg, '
1729 'test-int-fdt, test-int-arg',
1732 def testEntryArgsInvalidFormat(self):
1733 """Test that an invalid entry-argument format is detected"""
1734 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1736 with self.assertRaises(ValueError) as e:
1737 self._DoBinman(*args)
1738 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1740 def testEntryArgsInvalidInteger(self):
1741 """Test that an invalid entry-argument integer is detected"""
1743 'test-int-arg': 'abc',
1745 with self.assertRaises(ValueError) as e:
1746 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1747 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1748 "'test-int-arg' (value 'abc') to integer",
1751 def testEntryArgsInvalidDatatype(self):
1752 """Test that an invalid entry-argument datatype is detected
1754 This test could be written in entry_test.py except that it needs
1755 access to control.entry_args, which seems more than that module should
1759 'test-bad-datatype-arg': '12',
1761 with self.assertRaises(ValueError) as e:
1762 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1763 entry_args=entry_args)
1764 self.assertIn('GetArg() internal error: Unknown data type ',
1768 """Test for a text entry type"""
1770 'test-id': TEXT_DATA,
1771 'test-id2': TEXT_DATA2,
1772 'test-id3': TEXT_DATA3,
1774 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1775 entry_args=entry_args)
1776 expected = (tools.to_bytes(TEXT_DATA) +
1777 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1778 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
1779 b'some text' + b'more text')
1780 self.assertEqual(expected, data)
1782 def testEntryDocs(self):
1783 """Test for creation of entry documentation"""
1784 with test_util.capture_sys_output() as (stdout, stderr):
1785 control.WriteEntryDocs(control.GetEntryModules())
1786 self.assertTrue(len(stdout.getvalue()) > 0)
1788 def testEntryDocsMissing(self):
1789 """Test handling of missing entry documentation"""
1790 with self.assertRaises(ValueError) as e:
1791 with test_util.capture_sys_output() as (stdout, stderr):
1792 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1793 self.assertIn('Documentation is missing for modules: u_boot',
1797 """Basic test of generation of a flashrom fmap"""
1798 data = self._DoReadFile('067_fmap.dts')
1799 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1800 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1801 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
1802 self.assertEqual(expected, data[:32])
1803 self.assertEqual(b'__FMAP__', fhdr.signature)
1804 self.assertEqual(1, fhdr.ver_major)
1805 self.assertEqual(0, fhdr.ver_minor)
1806 self.assertEqual(0, fhdr.base)
1807 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1808 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1809 self.assertEqual(b'FMAP', fhdr.name)
1810 self.assertEqual(5, fhdr.nareas)
1811 fiter = iter(fentries)
1813 fentry = next(fiter)
1814 self.assertEqual(b'SECTION0', fentry.name)
1815 self.assertEqual(0, fentry.offset)
1816 self.assertEqual(16, fentry.size)
1817 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
1819 fentry = next(fiter)
1820 self.assertEqual(b'RO_U_BOOT', fentry.name)
1821 self.assertEqual(0, fentry.offset)
1822 self.assertEqual(4, fentry.size)
1823 self.assertEqual(0, fentry.flags)
1825 fentry = next(fiter)
1826 self.assertEqual(b'SECTION1', fentry.name)
1827 self.assertEqual(16, fentry.offset)
1828 self.assertEqual(16, fentry.size)
1829 self.assertEqual(0, fentry.flags)
1831 fentry = next(fiter)
1832 self.assertEqual(b'RW_U_BOOT', fentry.name)
1833 self.assertEqual(16, fentry.offset)
1834 self.assertEqual(4, fentry.size)
1835 self.assertEqual(0, fentry.flags)
1837 fentry = next(fiter)
1838 self.assertEqual(b'FMAP', fentry.name)
1839 self.assertEqual(32, fentry.offset)
1840 self.assertEqual(expect_size, fentry.size)
1841 self.assertEqual(0, fentry.flags)
1843 def testBlobNamedByArg(self):
1844 """Test we can add a blob with the filename coming from an entry arg"""
1846 'cros-ec-rw-path': 'ecrw.bin',
1848 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1851 """Test for an fill entry type"""
1852 data = self._DoReadFile('069_fill.dts')
1853 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
1854 self.assertEqual(expected, data)
1856 def testFillNoSize(self):
1857 """Test for an fill entry type with no size"""
1858 with self.assertRaises(ValueError) as e:
1859 self._DoReadFile('070_fill_no_size.dts')
1860 self.assertIn("'fill' entry is missing properties: size",
1863 def _HandleGbbCommand(self, pipe_list):
1864 """Fake calls to the futility utility"""
1865 if 'futility' in pipe_list[0][0]:
1866 fname = pipe_list[0][-1]
1867 # Append our GBB data to the file, which will happen every time the
1868 # futility command is called.
1869 with open(fname, 'ab') as fd:
1871 return command.CommandResult()
1874 """Test for the Chromium OS Google Binary Block"""
1875 command.test_result = self._HandleGbbCommand
1877 'keydir': 'devkeys',
1878 'bmpblk': 'bmpblk.bin',
1880 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1883 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1884 tools.get_bytes(0, 0x2180 - 16))
1885 self.assertEqual(expected, data)
1887 def testGbbTooSmall(self):
1888 """Test for the Chromium OS Google Binary Block being large enough"""
1889 with self.assertRaises(ValueError) as e:
1890 self._DoReadFileDtb('072_gbb_too_small.dts')
1891 self.assertIn("Node '/binman/gbb': GBB is too small",
1894 def testGbbNoSize(self):
1895 """Test for the Chromium OS Google Binary Block having a size"""
1896 with self.assertRaises(ValueError) as e:
1897 self._DoReadFileDtb('073_gbb_no_size.dts')
1898 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1901 def testGbbMissing(self):
1902 """Test that binman still produces an image if futility is missing"""
1904 'keydir': 'devkeys',
1906 with test_util.capture_sys_output() as (_, stderr):
1907 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1908 entry_args=entry_args)
1909 err = stderr.getvalue()
1910 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
1912 def _HandleVblockCommand(self, pipe_list):
1913 """Fake calls to the futility utility
1915 The expected pipe is:
1917 [('futility', 'vbutil_firmware', '--vblock',
1918 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1919 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1920 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1921 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1923 This writes to the output file (here, 'vblock.vblock'). If
1924 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1925 of the input data (here, 'input.vblock').
1927 if 'futility' in pipe_list[0][0]:
1928 fname = pipe_list[0][3]
1929 with open(fname, 'wb') as fd:
1931 infile = pipe_list[0][11]
1932 m = hashlib.sha256()
1933 data = tools.read_file(infile)
1935 fd.write(m.digest())
1937 fd.write(VBLOCK_DATA)
1939 return command.CommandResult()
1941 def testVblock(self):
1942 """Test for the Chromium OS Verified Boot Block"""
1943 self._hash_data = False
1944 command.test_result = self._HandleVblockCommand
1946 'keydir': 'devkeys',
1948 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1949 entry_args=entry_args)
1950 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1951 self.assertEqual(expected, data)
1953 def testVblockNoContent(self):
1954 """Test we detect a vblock which has no content to sign"""
1955 with self.assertRaises(ValueError) as e:
1956 self._DoReadFile('075_vblock_no_content.dts')
1957 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1958 'property', str(e.exception))
1960 def testVblockBadPhandle(self):
1961 """Test that we detect a vblock with an invalid phandle in contents"""
1962 with self.assertRaises(ValueError) as e:
1963 self._DoReadFile('076_vblock_bad_phandle.dts')
1964 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1965 '1000', str(e.exception))
1967 def testVblockBadEntry(self):
1968 """Test that we detect an entry that points to a non-entry"""
1969 with self.assertRaises(ValueError) as e:
1970 self._DoReadFile('077_vblock_bad_entry.dts')
1971 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1972 "'other'", str(e.exception))
1974 def testVblockContent(self):
1975 """Test that the vblock signs the right data"""
1976 self._hash_data = True
1977 command.test_result = self._HandleVblockCommand
1979 'keydir': 'devkeys',
1981 data = self._DoReadFileDtb(
1982 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1983 entry_args=entry_args)[0]
1984 hashlen = 32 # SHA256 hash is 32 bytes
1985 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1986 hashval = data[-hashlen:]
1987 dtb = data[len(U_BOOT_DATA):-hashlen]
1989 expected_data = U_BOOT_DATA + dtb
1991 # The hashval should be a hash of the dtb
1992 m = hashlib.sha256()
1993 m.update(expected_data)
1994 expected_hashval = m.digest()
1995 self.assertEqual(expected_hashval, hashval)
1997 def testVblockMissing(self):
1998 """Test that binman still produces an image if futility is missing"""
2000 'keydir': 'devkeys',
2002 with test_util.capture_sys_output() as (_, stderr):
2003 self._DoTestFile('074_vblock.dts',
2004 force_missing_bintools='futility',
2005 entry_args=entry_args)
2006 err = stderr.getvalue()
2007 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
2010 """Test that an image with TPL and its device tree can be created"""
2011 # ELF file with a '__bss_size' symbol
2013 data = self._DoReadFile('078_u_boot_tpl.dts')
2014 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2016 def testUsesPos(self):
2017 """Test that the 'pos' property cannot be used anymore"""
2018 with self.assertRaises(ValueError) as e:
2019 data = self._DoReadFile('079_uses_pos.dts')
2020 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2021 "'pos'", str(e.exception))
2023 def testFillZero(self):
2024 """Test for an fill entry type with a size of 0"""
2025 data = self._DoReadFile('080_fill_empty.dts')
2026 self.assertEqual(tools.get_bytes(0, 16), data)
2028 def testTextMissing(self):
2029 """Test for a text entry type where there is no text"""
2030 with self.assertRaises(ValueError) as e:
2031 self._DoReadFileDtb('066_text.dts',)
2032 self.assertIn("Node '/binman/text': No value provided for text label "
2033 "'test-id'", str(e.exception))
2035 def testPackStart16Tpl(self):
2036 """Test that an image with an x86 start16 TPL region can be created"""
2037 data = self._DoReadFile('081_x86_start16_tpl.dts')
2038 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2040 def testSelectImage(self):
2041 """Test that we can select which images to build"""
2042 expected = 'Skipping images: image1'
2044 # We should only get the expected message in verbose mode
2045 for verbosity in (0, 2):
2046 with test_util.capture_sys_output() as (stdout, stderr):
2047 retcode = self._DoTestFile('006_dual_image.dts',
2048 verbosity=verbosity,
2050 self.assertEqual(0, retcode)
2052 self.assertIn(expected, stdout.getvalue())
2054 self.assertNotIn(expected, stdout.getvalue())
2056 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2057 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
2058 self._CleanupOutputDir()
2060 def testUpdateFdtAll(self):
2061 """Test that all device trees are updated with offset/size info"""
2064 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
2070 'section:offset': 0,
2071 'section:image-pos': 0,
2072 'section:size': 565,
2073 'section/u-boot-dtb:offset': 0,
2074 'section/u-boot-dtb:image-pos': 0,
2075 'section/u-boot-dtb:size': 565,
2076 'u-boot-spl-dtb:offset': 565,
2077 'u-boot-spl-dtb:image-pos': 565,
2078 'u-boot-spl-dtb:size': 585,
2079 'u-boot-tpl-dtb:offset': 1150,
2080 'u-boot-tpl-dtb:image-pos': 1150,
2081 'u-boot-tpl-dtb:size': 585,
2082 'u-boot-vpl-dtb:image-pos': 1735,
2083 'u-boot-vpl-dtb:offset': 1735,
2084 'u-boot-vpl-dtb:size': 585,
2087 # We expect three device-tree files in the output, one after the other.
2088 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2089 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2090 # main U-Boot tree. All three should have the same postions and offset.
2093 for item in ['', 'spl', 'tpl', 'vpl']:
2094 dtb = fdt.Fdt.FromData(data[start:])
2096 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
2097 ['spl', 'tpl', 'vpl'])
2098 expected = dict(base_expected)
2101 self.assertEqual(expected, props)
2102 start += dtb._fdt_obj.totalsize()
2104 def testUpdateFdtOutput(self):
2105 """Test that output DTB files are updated"""
2107 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
2108 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2110 # Unfortunately, compiling a source file always results in a file
2111 # called source.dtb (see fdt_util.EnsureCompiled()). The test
2112 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
2113 # binman as a file called u-boot.dtb. To fix this, copy the file
2114 # over to the expected place.
2116 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
2117 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
2118 dtb = fdt.Fdt.FromData(data[start:])
2119 size = dtb._fdt_obj.totalsize()
2120 pathname = tools.get_output_filename(os.path.split(fname)[1])
2121 outdata = tools.read_file(pathname)
2122 name = os.path.split(fname)[0]
2125 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
2127 orig_indata = dtb_data
2128 self.assertNotEqual(outdata, orig_indata,
2129 "Expected output file '%s' be updated" % pathname)
2130 self.assertEqual(outdata, data[start:start + size],
2131 "Expected output file '%s' to match output image" %
2137 def _decompress(self, data):
2138 bintool = self.comp_bintools['lz4']
2139 return bintool.decompress(data)
2141 def testCompress(self):
2142 """Test compression of blobs"""
2144 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
2145 use_real_dtb=True, update_dtb=True)
2146 dtb = fdt.Fdt(out_dtb_fname)
2148 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2149 orig = self._decompress(data)
2150 self.assertEqual(COMPRESS_DATA, orig)
2152 # Do a sanity check on various fields
2153 image = control.images['image']
2154 entries = image.GetEntries()
2155 self.assertEqual(1, len(entries))
2157 entry = entries['blob']
2158 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2159 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2160 orig = self._decompress(entry.data)
2161 self.assertEqual(orig, entry.uncomp_data)
2163 self.assertEqual(image.data, entry.data)
2166 'blob:uncomp-size': len(COMPRESS_DATA),
2167 'blob:size': len(data),
2170 self.assertEqual(expected, props)
2172 def testFiles(self):
2173 """Test bringing in multiple files"""
2174 data = self._DoReadFile('084_files.dts')
2175 self.assertEqual(FILES_DATA, data)
2177 def testFilesCompress(self):
2178 """Test bringing in multiple files and compressing them"""
2180 data = self._DoReadFile('085_files_compress.dts')
2182 image = control.images['image']
2183 entries = image.GetEntries()
2184 files = entries['files']
2185 entries = files._entries
2188 for i in range(1, 3):
2190 start = entries[key].image_pos
2191 len = entries[key].size
2192 chunk = data[start:start + len]
2193 orig += self._decompress(chunk)
2195 self.assertEqual(FILES_DATA, orig)
2197 def testFilesMissing(self):
2198 """Test missing files"""
2199 with self.assertRaises(ValueError) as e:
2200 data = self._DoReadFile('086_files_none.dts')
2201 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2202 'no files', str(e.exception))
2204 def testFilesNoPattern(self):
2205 """Test missing files"""
2206 with self.assertRaises(ValueError) as e:
2207 data = self._DoReadFile('087_files_no_pattern.dts')
2208 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2211 def testExtendSize(self):
2212 """Test an extending entry"""
2213 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
2215 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2216 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2217 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2218 tools.get_bytes(ord('d'), 8))
2219 self.assertEqual(expect, data)
2220 self.assertEqual('''ImagePos Offset Size Name
2221 00000000 00000000 00000028 image
2222 00000000 00000000 00000008 fill
2223 00000008 00000008 00000004 u-boot
2224 0000000c 0000000c 00000004 section
2225 0000000c 00000000 00000003 intel-mrc
2226 00000010 00000010 00000004 u-boot2
2227 00000014 00000014 0000000c section2
2228 00000014 00000000 00000008 fill
2229 0000001c 00000008 00000004 u-boot
2230 00000020 00000020 00000008 fill2
2233 def testExtendSizeBad(self):
2234 """Test an extending entry which fails to provide contents"""
2235 with test_util.capture_sys_output() as (stdout, stderr):
2236 with self.assertRaises(ValueError) as e:
2237 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
2238 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2239 'expanding entry', str(e.exception))
2242 """Test hashing of the contents of an entry"""
2243 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2244 use_real_dtb=True, update_dtb=True)
2245 dtb = fdt.Fdt(out_dtb_fname)
2247 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2248 m = hashlib.sha256()
2249 m.update(U_BOOT_DATA)
2250 self.assertEqual(m.digest(), b''.join(hash_node.value))
2252 def testHashNoAlgo(self):
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2255 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2256 'hash node', str(e.exception))
2258 def testHashBadAlgo(self):
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2261 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
2264 def testHashSection(self):
2265 """Test hashing of the contents of an entry"""
2266 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2267 use_real_dtb=True, update_dtb=True)
2268 dtb = fdt.Fdt(out_dtb_fname)
2270 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2271 m = hashlib.sha256()
2272 m.update(U_BOOT_DATA)
2273 m.update(tools.get_bytes(ord('a'), 16))
2274 self.assertEqual(m.digest(), b''.join(hash_node.value))
2276 def testPackUBootTplMicrocode(self):
2277 """Test that x86 microcode can be handled correctly in TPL
2279 We expect to see the following in the image, in order:
2280 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2282 u-boot-tpl.dtb with the microcode removed
2285 self._SetupTplElf('u_boot_ucode_ptr')
2286 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2287 U_BOOT_TPL_NODTB_DATA)
2288 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2289 b'ter somewhere in here', first)
2291 def testFmapX86(self):
2292 """Basic test of generation of a flashrom fmap"""
2293 data = self._DoReadFile('094_fmap_x86.dts')
2294 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2295 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
2296 self.assertEqual(expected, data[:32])
2297 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2299 self.assertEqual(0x100, fhdr.image_size)
2301 self.assertEqual(0, fentries[0].offset)
2302 self.assertEqual(4, fentries[0].size)
2303 self.assertEqual(b'U_BOOT', fentries[0].name)
2305 self.assertEqual(4, fentries[1].offset)
2306 self.assertEqual(3, fentries[1].size)
2307 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2309 self.assertEqual(32, fentries[2].offset)
2310 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2311 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2312 self.assertEqual(b'FMAP', fentries[2].name)
2314 def testFmapX86Section(self):
2315 """Basic test of generation of a flashrom fmap"""
2316 data = self._DoReadFile('095_fmap_x86_section.dts')
2317 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
2318 self.assertEqual(expected, data[:32])
2319 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2321 self.assertEqual(0x180, fhdr.image_size)
2322 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2323 fiter = iter(fentries)
2325 fentry = next(fiter)
2326 self.assertEqual(b'U_BOOT', fentry.name)
2327 self.assertEqual(0, fentry.offset)
2328 self.assertEqual(4, fentry.size)
2330 fentry = next(fiter)
2331 self.assertEqual(b'SECTION', fentry.name)
2332 self.assertEqual(4, fentry.offset)
2333 self.assertEqual(0x20 + expect_size, fentry.size)
2335 fentry = next(fiter)
2336 self.assertEqual(b'INTEL_MRC', fentry.name)
2337 self.assertEqual(4, fentry.offset)
2338 self.assertEqual(3, fentry.size)
2340 fentry = next(fiter)
2341 self.assertEqual(b'FMAP', fentry.name)
2342 self.assertEqual(36, fentry.offset)
2343 self.assertEqual(expect_size, fentry.size)
2346 """Basic test of ELF entries"""
2349 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2350 TestFunctional._MakeInputFile('-boot', fd.read())
2351 data = self._DoReadFile('096_elf.dts')
2353 def testElfStrip(self):
2354 """Basic test of ELF entries"""
2356 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2357 TestFunctional._MakeInputFile('-boot', fd.read())
2358 data = self._DoReadFile('097_elf_strip.dts')
2360 def testPackOverlapMap(self):
2361 """Test that overlapping regions are detected"""
2362 with test_util.capture_sys_output() as (stdout, stderr):
2363 with self.assertRaises(ValueError) as e:
2364 self._DoTestFile('014_pack_overlap.dts', map=True)
2365 map_fname = tools.get_output_filename('image.map')
2366 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2369 # We should not get an inmage, but there should be a map file
2370 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
2371 self.assertTrue(os.path.exists(map_fname))
2372 map_data = tools.read_file(map_fname, binary=False)
2373 self.assertEqual('''ImagePos Offset Size Name
2374 <none> 00000000 00000008 image
2375 <none> 00000000 00000004 u-boot
2376 <none> 00000003 00000004 u-boot-align
2379 def testPackRefCode(self):
2380 """Test that an image with an Intel Reference code binary works"""
2381 data = self._DoReadFile('100_intel_refcode.dts')
2382 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2384 def testSectionOffset(self):
2385 """Tests use of a section with an offset"""
2386 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2388 self.assertEqual('''ImagePos Offset Size Name
2389 00000000 00000000 00000038 image
2390 00000004 00000004 00000010 section@0
2391 00000004 00000000 00000004 u-boot
2392 00000018 00000018 00000010 section@1
2393 00000018 00000000 00000004 u-boot
2394 0000002c 0000002c 00000004 section@2
2395 0000002c 00000000 00000004 u-boot
2397 self.assertEqual(data,
2398 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2399 tools.get_bytes(0x21, 12) +
2400 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2401 tools.get_bytes(0x61, 12) +
2402 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2403 tools.get_bytes(0x26, 8))
2405 def testCbfsRaw(self):
2406 """Test base handling of a Coreboot Filesystem (CBFS)
2408 The exact contents of the CBFS is verified by similar tests in
2409 cbfs_util_test.py. The tests here merely check that the files added to
2410 the CBFS can be found in the final image.
2412 data = self._DoReadFile('102_cbfs_raw.dts')
2415 cbfs = cbfs_util.CbfsReader(data)
2416 self.assertEqual(size, cbfs.rom_size)
2418 self.assertIn('u-boot-dtb', cbfs.files)
2419 cfile = cbfs.files['u-boot-dtb']
2420 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2422 def testCbfsArch(self):
2423 """Test on non-x86 architecture"""
2424 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2427 cbfs = cbfs_util.CbfsReader(data)
2428 self.assertEqual(size, cbfs.rom_size)
2430 self.assertIn('u-boot-dtb', cbfs.files)
2431 cfile = cbfs.files['u-boot-dtb']
2432 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2434 def testCbfsStage(self):
2435 """Tests handling of a Coreboot Filesystem (CBFS)"""
2436 if not elf.ELF_TOOLS:
2437 self.skipTest('Python elftools not available')
2438 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2439 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2442 data = self._DoReadFile('104_cbfs_stage.dts')
2443 cbfs = cbfs_util.CbfsReader(data)
2444 self.assertEqual(size, cbfs.rom_size)
2446 self.assertIn('u-boot', cbfs.files)
2447 cfile = cbfs.files['u-boot']
2448 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2450 def testCbfsRawCompress(self):
2451 """Test handling of compressing raw files"""
2453 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2456 cbfs = cbfs_util.CbfsReader(data)
2457 self.assertIn('u-boot', cbfs.files)
2458 cfile = cbfs.files['u-boot']
2459 self.assertEqual(COMPRESS_DATA, cfile.data)
2461 def testCbfsBadArch(self):
2462 """Test handling of a bad architecture"""
2463 with self.assertRaises(ValueError) as e:
2464 self._DoReadFile('106_cbfs_bad_arch.dts')
2465 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2467 def testCbfsNoSize(self):
2468 """Test handling of a missing size property"""
2469 with self.assertRaises(ValueError) as e:
2470 self._DoReadFile('107_cbfs_no_size.dts')
2471 self.assertIn('entry must have a size property', str(e.exception))
2473 def testCbfsNoContents(self):
2474 """Test handling of a CBFS entry which does not provide contentsy"""
2475 with self.assertRaises(ValueError) as e:
2476 self._DoReadFile('108_cbfs_no_contents.dts')
2477 self.assertIn('Could not complete processing of contents',
2480 def testCbfsBadCompress(self):
2481 """Test handling of a bad architecture"""
2482 with self.assertRaises(ValueError) as e:
2483 self._DoReadFile('109_cbfs_bad_compress.dts')
2484 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2487 def testCbfsNamedEntries(self):
2488 """Test handling of named entries"""
2489 data = self._DoReadFile('110_cbfs_name.dts')
2491 cbfs = cbfs_util.CbfsReader(data)
2492 self.assertIn('FRED', cbfs.files)
2493 cfile1 = cbfs.files['FRED']
2494 self.assertEqual(U_BOOT_DATA, cfile1.data)
2496 self.assertIn('hello', cbfs.files)
2497 cfile2 = cbfs.files['hello']
2498 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2500 def _SetupIfwi(self, fname):
2501 """Set up to run an IFWI test
2504 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2509 # Intel Integrated Firmware Image (IFWI) file
2510 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2512 TestFunctional._MakeInputFile(fname,data)
2514 def _CheckIfwi(self, data):
2515 """Check that an image with an IFWI contains the correct output
2518 data: Conents of output file
2520 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
2521 if data[:0x1000] != expected_desc:
2522 self.fail('Expected descriptor binary at start of image')
2524 # We expect to find the TPL wil in subpart IBBP entry IBBL
2525 image_fname = tools.get_output_filename('image.bin')
2526 tpl_fname = tools.get_output_filename('tpl.out')
2527 ifwitool = bintool.Bintool.create('ifwitool')
2528 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
2530 tpl_data = tools.read_file(tpl_fname)
2531 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2533 def testPackX86RomIfwi(self):
2534 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2535 self._SetupIfwi('fitimage.bin')
2536 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2537 self._CheckIfwi(data)
2539 def testPackX86RomIfwiNoDesc(self):
2540 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2541 self._SetupIfwi('ifwi.bin')
2542 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2543 self._CheckIfwi(data)
2545 def testPackX86RomIfwiNoData(self):
2546 """Test that an x86 ROM with IFWI handles missing data"""
2547 self._SetupIfwi('ifwi.bin')
2548 with self.assertRaises(ValueError) as e:
2549 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2550 self.assertIn('Could not complete processing of contents',
2553 def testIfwiMissing(self):
2554 """Test that binman still produces an image if ifwitool is missing"""
2555 self._SetupIfwi('fitimage.bin')
2556 with test_util.capture_sys_output() as (_, stderr):
2557 self._DoTestFile('111_x86_rom_ifwi.dts',
2558 force_missing_bintools='ifwitool')
2559 err = stderr.getvalue()
2560 self.assertRegex(err,
2561 "Image 'image'.*missing bintools.*: ifwitool")
2563 def testCbfsOffset(self):
2564 """Test a CBFS with files at particular offsets
2566 Like all CFBS tests, this is just checking the logic that calls
2567 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2569 data = self._DoReadFile('114_cbfs_offset.dts')
2572 cbfs = cbfs_util.CbfsReader(data)
2573 self.assertEqual(size, cbfs.rom_size)
2575 self.assertIn('u-boot', cbfs.files)
2576 cfile = cbfs.files['u-boot']
2577 self.assertEqual(U_BOOT_DATA, cfile.data)
2578 self.assertEqual(0x40, cfile.cbfs_offset)
2580 self.assertIn('u-boot-dtb', cbfs.files)
2581 cfile2 = cbfs.files['u-boot-dtb']
2582 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2583 self.assertEqual(0x140, cfile2.cbfs_offset)
2585 def testFdtmap(self):
2586 """Test an FDT map can be inserted in the image"""
2587 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2588 fdtmap_data = data[len(U_BOOT_DATA):]
2589 magic = fdtmap_data[:8]
2590 self.assertEqual(b'_FDTMAP_', magic)
2591 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
2593 fdt_data = fdtmap_data[16:]
2594 dtb = fdt.Fdt.FromData(fdt_data)
2596 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2601 'u-boot:size': len(U_BOOT_DATA),
2602 'u-boot:image-pos': 0,
2603 'fdtmap:image-pos': 4,
2605 'fdtmap:size': len(fdtmap_data),
2609 def testFdtmapNoMatch(self):
2610 """Check handling of an FDT map when the section cannot be found"""
2611 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2613 # Mangle the section name, which should cause a mismatch between the
2614 # correct FDT path and the one expected by the section
2615 image = control.images['image']
2616 image._node.path += '-suffix'
2617 entries = image.GetEntries()
2618 fdtmap = entries['fdtmap']
2619 with self.assertRaises(ValueError) as e:
2621 self.assertIn("Cannot locate node for path '/binman-suffix'",
2624 def testFdtmapHeader(self):
2625 """Test an FDT map and image header can be inserted in the image"""
2626 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2627 fdtmap_pos = len(U_BOOT_DATA)
2628 fdtmap_data = data[fdtmap_pos:]
2629 fdt_data = fdtmap_data[16:]
2630 dtb = fdt.Fdt.FromData(fdt_data)
2631 fdt_size = dtb.GetFdtObj().totalsize()
2632 hdr_data = data[-8:]
2633 self.assertEqual(b'BinM', hdr_data[:4])
2634 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2635 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2637 def testFdtmapHeaderStart(self):
2638 """Test an image header can be inserted at the image start"""
2639 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2640 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2642 self.assertEqual(b'BinM', hdr_data[:4])
2643 offset = struct.unpack('<I', hdr_data[4:])[0]
2644 self.assertEqual(fdtmap_pos, offset)
2646 def testFdtmapHeaderPos(self):
2647 """Test an image header can be inserted at a chosen position"""
2648 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2649 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2650 hdr_data = data[0x80:0x88]
2651 self.assertEqual(b'BinM', hdr_data[:4])
2652 offset = struct.unpack('<I', hdr_data[4:])[0]
2653 self.assertEqual(fdtmap_pos, offset)
2655 def testHeaderMissingFdtmap(self):
2656 """Test an image header requires an fdtmap"""
2657 with self.assertRaises(ValueError) as e:
2658 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2659 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2662 def testHeaderNoLocation(self):
2663 """Test an image header with a no specified location is detected"""
2664 with self.assertRaises(ValueError) as e:
2665 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2666 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2669 def testEntryExpand(self):
2670 """Test extending an entry after it is packed"""
2671 data = self._DoReadFile('121_entry_extend.dts')
2672 self.assertEqual(b'aaa', data[:3])
2673 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2674 self.assertEqual(b'aaa', data[-3:])
2676 def testEntryExtendBad(self):
2677 """Test extending an entry after it is packed, twice"""
2678 with self.assertRaises(ValueError) as e:
2679 self._DoReadFile('122_entry_extend_twice.dts')
2680 self.assertIn("Image '/binman': Entries changed size after packing",
2683 def testEntryExtendSection(self):
2684 """Test extending an entry within a section after it is packed"""
2685 data = self._DoReadFile('123_entry_extend_section.dts')
2686 self.assertEqual(b'aaa', data[:3])
2687 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2688 self.assertEqual(b'aaa', data[-3:])
2690 def testCompressDtb(self):
2691 """Test that compress of device-tree files is supported"""
2693 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2694 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2695 comp_data = data[len(U_BOOT_DATA):]
2696 orig = self._decompress(comp_data)
2697 dtb = fdt.Fdt.FromData(orig)
2699 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2701 'u-boot:size': len(U_BOOT_DATA),
2702 'u-boot-dtb:uncomp-size': len(orig),
2703 'u-boot-dtb:size': len(comp_data),
2706 self.assertEqual(expected, props)
2708 def testCbfsUpdateFdt(self):
2709 """Test that we can update the device tree with CBFS offset/size info"""
2711 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2713 dtb = fdt.Fdt(out_dtb_fname)
2715 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2716 del props['cbfs/u-boot:size']
2722 'cbfs:size': len(data),
2723 'cbfs:image-pos': 0,
2724 'cbfs/u-boot:offset': 0x30,
2725 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2726 'cbfs/u-boot:image-pos': 0x30,
2727 'cbfs/u-boot-dtb:offset': 0xa4,
2728 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2729 'cbfs/u-boot-dtb:image-pos': 0xa4,
2732 def testCbfsBadType(self):
2733 """Test an image header with a no specified location is detected"""
2734 with self.assertRaises(ValueError) as e:
2735 self._DoReadFile('126_cbfs_bad_type.dts')
2736 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2739 """Test listing the files in an image"""
2741 data = self._DoReadFile('127_list.dts')
2742 image = control.images['image']
2743 entries = image.BuildEntryList()
2744 self.assertEqual(7, len(entries))
2747 self.assertEqual(0, ent.indent)
2748 self.assertEqual('image', ent.name)
2749 self.assertEqual('section', ent.etype)
2750 self.assertEqual(len(data), ent.size)
2751 self.assertEqual(0, ent.image_pos)
2752 self.assertEqual(None, ent.uncomp_size)
2753 self.assertEqual(0, ent.offset)
2756 self.assertEqual(1, ent.indent)
2757 self.assertEqual('u-boot', ent.name)
2758 self.assertEqual('u-boot', ent.etype)
2759 self.assertEqual(len(U_BOOT_DATA), ent.size)
2760 self.assertEqual(0, ent.image_pos)
2761 self.assertEqual(None, ent.uncomp_size)
2762 self.assertEqual(0, ent.offset)
2765 self.assertEqual(1, ent.indent)
2766 self.assertEqual('section', ent.name)
2767 self.assertEqual('section', ent.etype)
2768 section_size = ent.size
2769 self.assertEqual(0x100, ent.image_pos)
2770 self.assertEqual(None, ent.uncomp_size)
2771 self.assertEqual(0x100, ent.offset)
2774 self.assertEqual(2, ent.indent)
2775 self.assertEqual('cbfs', ent.name)
2776 self.assertEqual('cbfs', ent.etype)
2777 self.assertEqual(0x400, ent.size)
2778 self.assertEqual(0x100, ent.image_pos)
2779 self.assertEqual(None, ent.uncomp_size)
2780 self.assertEqual(0, ent.offset)
2783 self.assertEqual(3, ent.indent)
2784 self.assertEqual('u-boot', ent.name)
2785 self.assertEqual('u-boot', ent.etype)
2786 self.assertEqual(len(U_BOOT_DATA), ent.size)
2787 self.assertEqual(0x138, ent.image_pos)
2788 self.assertEqual(None, ent.uncomp_size)
2789 self.assertEqual(0x38, ent.offset)
2792 self.assertEqual(3, ent.indent)
2793 self.assertEqual('u-boot-dtb', ent.name)
2794 self.assertEqual('text', ent.etype)
2795 self.assertGreater(len(COMPRESS_DATA), ent.size)
2796 self.assertEqual(0x178, ent.image_pos)
2797 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2798 self.assertEqual(0x78, ent.offset)
2801 self.assertEqual(2, ent.indent)
2802 self.assertEqual('u-boot-dtb', ent.name)
2803 self.assertEqual('u-boot-dtb', ent.etype)
2804 self.assertEqual(0x500, ent.image_pos)
2805 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2807 # Compressing this data expands it since headers are added
2808 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2809 self.assertEqual(0x400, ent.offset)
2811 self.assertEqual(len(data), 0x100 + section_size)
2812 self.assertEqual(section_size, 0x400 + dtb_size)
2814 def testFindFdtmap(self):
2815 """Test locating an FDT map in an image"""
2817 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2818 image = control.images['image']
2819 entries = image.GetEntries()
2820 entry = entries['fdtmap']
2821 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2823 def testFindFdtmapMissing(self):
2824 """Test failing to locate an FDP map"""
2825 data = self._DoReadFile('005_simple.dts')
2826 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2828 def testFindImageHeader(self):
2829 """Test locating a image header"""
2831 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2832 image = control.images['image']
2833 entries = image.GetEntries()
2834 entry = entries['fdtmap']
2835 # The header should point to the FDT map
2836 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2838 def testFindImageHeaderStart(self):
2839 """Test locating a image header located at the start of an image"""
2840 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2841 image = control.images['image']
2842 entries = image.GetEntries()
2843 entry = entries['fdtmap']
2844 # The header should point to the FDT map
2845 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2847 def testFindImageHeaderMissing(self):
2848 """Test failing to locate an image header"""
2849 data = self._DoReadFile('005_simple.dts')
2850 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2852 def testReadImage(self):
2853 """Test reading an image and accessing its FDT map"""
2855 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2856 image_fname = tools.get_output_filename('image.bin')
2857 orig_image = control.images['image']
2858 image = Image.FromFile(image_fname)
2859 self.assertEqual(orig_image.GetEntries().keys(),
2860 image.GetEntries().keys())
2862 orig_entry = orig_image.GetEntries()['fdtmap']
2863 entry = image.GetEntries()['fdtmap']
2864 self.assertEqual(orig_entry.offset, entry.offset)
2865 self.assertEqual(orig_entry.size, entry.size)
2866 self.assertEqual(orig_entry.image_pos, entry.image_pos)
2868 def testReadImageNoHeader(self):
2869 """Test accessing an image's FDT map without an image header"""
2871 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2872 image_fname = tools.get_output_filename('image.bin')
2873 image = Image.FromFile(image_fname)
2874 self.assertTrue(isinstance(image, Image))
2875 self.assertEqual('image', image.image_name[-5:])
2877 def testReadImageFail(self):
2878 """Test failing to read an image image's FDT map"""
2879 self._DoReadFile('005_simple.dts')
2880 image_fname = tools.get_output_filename('image.bin')
2881 with self.assertRaises(ValueError) as e:
2882 image = Image.FromFile(image_fname)
2883 self.assertIn("Cannot find FDT map in image", str(e.exception))
2885 def testListCmd(self):
2886 """Test listing the files in an image using an Fdtmap"""
2888 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2890 # lz4 compression size differs depending on the version
2891 image = control.images['image']
2892 entries = image.GetEntries()
2893 section_size = entries['section'].size
2894 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2895 fdtmap_offset = entries['fdtmap'].offset
2899 tmpdir, updated_fname = self._SetupImageInTmpdir()
2900 with test_util.capture_sys_output() as (stdout, stderr):
2901 self._DoBinman('ls', '-i', updated_fname)
2904 shutil.rmtree(tmpdir)
2905 lines = stdout.getvalue().splitlines()
2907 'Name Image-pos Size Entry-type Offset Uncomp-size',
2908 '----------------------------------------------------------------------',
2909 'image 0 c00 section 0',
2910 ' u-boot 0 4 u-boot 0',
2911 ' section 100 %x section 100' % section_size,
2912 ' cbfs 100 400 cbfs 0',
2913 ' u-boot 120 4 u-boot 20',
2914 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2915 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2916 ' fdtmap %x 3bd fdtmap %x' %
2917 (fdtmap_offset, fdtmap_offset),
2918 ' image-header bf8 8 image-header bf8',
2920 self.assertEqual(expected, lines)
2922 def testListCmdFail(self):
2923 """Test failing to list an image"""
2924 self._DoReadFile('005_simple.dts')
2927 tmpdir, updated_fname = self._SetupImageInTmpdir()
2928 with self.assertRaises(ValueError) as e:
2929 self._DoBinman('ls', '-i', updated_fname)
2932 shutil.rmtree(tmpdir)
2933 self.assertIn("Cannot find FDT map in image", str(e.exception))
2935 def _RunListCmd(self, paths, expected):
2936 """List out entries and check the result
2939 paths: List of paths to pass to the list command
2940 expected: Expected list of filenames to be returned, in order
2943 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2944 image_fname = tools.get_output_filename('image.bin')
2945 image = Image.FromFile(image_fname)
2946 lines = image.GetListEntries(paths)[1]
2947 files = [line[0].strip() for line in lines[1:]]
2948 self.assertEqual(expected, files)
2950 def testListCmdSection(self):
2951 """Test listing the files in a section"""
2952 self._RunListCmd(['section'],
2953 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2955 def testListCmdFile(self):
2956 """Test listing a particular file"""
2957 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2959 def testListCmdWildcard(self):
2960 """Test listing a wildcarded file"""
2961 self._RunListCmd(['*boot*'],
2962 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2964 def testListCmdWildcardMulti(self):
2965 """Test listing a wildcarded file"""
2966 self._RunListCmd(['*cb*', '*head*'],
2967 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2969 def testListCmdEmpty(self):
2970 """Test listing a wildcarded file"""
2971 self._RunListCmd(['nothing'], [])
2973 def testListCmdPath(self):
2974 """Test listing the files in a sub-entry of a section"""
2975 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2977 def _RunExtractCmd(self, entry_name, decomp=True):
2978 """Extract an entry from an image
2981 entry_name: Entry name to extract
2982 decomp: True to decompress the data if compressed, False to leave
2983 it in its raw uncompressed format
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2990 image_fname = tools.get_output_filename('image.bin')
2991 return control.ReadEntry(image_fname, entry_name, decomp)
2993 def testExtractSimple(self):
2994 """Test extracting a single file"""
2995 data = self._RunExtractCmd('u-boot')
2996 self.assertEqual(U_BOOT_DATA, data)
2998 def testExtractSection(self):
2999 """Test extracting the files in a section"""
3000 data = self._RunExtractCmd('section')
3001 cbfs_data = data[:0x400]
3002 cbfs = cbfs_util.CbfsReader(cbfs_data)
3003 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
3004 dtb_data = data[0x400:]
3005 dtb = self._decompress(dtb_data)
3006 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3008 def testExtractCompressed(self):
3009 """Test extracting compressed data"""
3010 data = self._RunExtractCmd('section/u-boot-dtb')
3011 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3013 def testExtractRaw(self):
3014 """Test extracting compressed data without decompressing it"""
3015 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3016 dtb = self._decompress(data)
3017 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3019 def testExtractCbfs(self):
3020 """Test extracting CBFS data"""
3021 data = self._RunExtractCmd('section/cbfs/u-boot')
3022 self.assertEqual(U_BOOT_DATA, data)
3024 def testExtractCbfsCompressed(self):
3025 """Test extracting CBFS compressed data"""
3026 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3027 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3029 def testExtractCbfsRaw(self):
3030 """Test extracting CBFS compressed data without decompressing it"""
3031 bintool = self.comp_bintools['lzma_alone']
3032 self._CheckBintool(bintool)
3033 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
3034 dtb = bintool.decompress(data)
3035 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3037 def testExtractBadEntry(self):
3038 """Test extracting a bad section path"""
3039 with self.assertRaises(ValueError) as e:
3040 self._RunExtractCmd('section/does-not-exist')
3041 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3044 def testExtractMissingFile(self):
3045 """Test extracting file that does not exist"""
3046 with self.assertRaises(IOError) as e:
3047 control.ReadEntry('missing-file', 'name')
3049 def testExtractBadFile(self):
3050 """Test extracting an invalid file"""
3051 fname = os.path.join(self._indir, 'badfile')
3052 tools.write_file(fname, b'')
3053 with self.assertRaises(ValueError) as e:
3054 control.ReadEntry(fname, 'name')
3056 def testExtractCmd(self):
3057 """Test extracting a file fron an image on the command line"""
3059 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3060 fname = os.path.join(self._indir, 'output.extact')
3063 tmpdir, updated_fname = self._SetupImageInTmpdir()
3064 with test_util.capture_sys_output() as (stdout, stderr):
3065 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3069 shutil.rmtree(tmpdir)
3070 data = tools.read_file(fname)
3071 self.assertEqual(U_BOOT_DATA, data)
3073 def testExtractOneEntry(self):
3074 """Test extracting a single entry fron an image """
3076 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3077 image_fname = tools.get_output_filename('image.bin')
3078 fname = os.path.join(self._indir, 'output.extact')
3079 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
3080 data = tools.read_file(fname)
3081 self.assertEqual(U_BOOT_DATA, data)
3083 def _CheckExtractOutput(self, decomp):
3084 """Helper to test file output with and without decompression
3087 decomp: True to decompress entry data, False to output it raw
3089 def _CheckPresent(entry_path, expect_data, expect_size=None):
3090 """Check and remove expected file
3092 This checks the data/size of a file and removes the file both from
3093 the outfiles set and from the output directory. Once all files are
3094 processed, both the set and directory should be empty.
3097 entry_path: Entry path
3098 expect_data: Data to expect in file, or None to skip check
3099 expect_size: Size of data to expect in file, or None to skip
3101 path = os.path.join(outdir, entry_path)
3102 data = tools.read_file(path)
3105 self.assertEqual(expect_data, data)
3107 self.assertEqual(expect_size, len(data))
3108 outfiles.remove(path)
3110 def _CheckDirPresent(name):
3111 """Remove expected directory
3113 This gives an error if the directory does not exist as expected
3116 name: Name of directory to remove
3118 path = os.path.join(outdir, name)
3121 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3122 image_fname = tools.get_output_filename('image.bin')
3123 outdir = os.path.join(self._indir, 'extract')
3124 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3126 # Create a set of all file that were output (should be 9)
3128 for root, dirs, files in os.walk(outdir):
3129 outfiles |= set([os.path.join(root, fname) for fname in files])
3130 self.assertEqual(9, len(outfiles))
3131 self.assertEqual(9, len(einfos))
3133 image = control.images['image']
3134 entries = image.GetEntries()
3136 # Check the 9 files in various ways
3137 section = entries['section']
3138 section_entries = section.GetEntries()
3139 cbfs_entries = section_entries['cbfs'].GetEntries()
3140 _CheckPresent('u-boot', U_BOOT_DATA)
3141 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3142 dtb_len = EXTRACT_DTB_SIZE
3144 dtb_len = cbfs_entries['u-boot-dtb'].size
3145 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3147 dtb_len = section_entries['u-boot-dtb'].size
3148 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3150 fdtmap = entries['fdtmap']
3151 _CheckPresent('fdtmap', fdtmap.data)
3152 hdr = entries['image-header']
3153 _CheckPresent('image-header', hdr.data)
3155 _CheckPresent('section/root', section.data)
3156 cbfs = section_entries['cbfs']
3157 _CheckPresent('section/cbfs/root', cbfs.data)
3158 data = tools.read_file(image_fname)
3159 _CheckPresent('root', data)
3161 # There should be no files left. Remove all the directories to check.
3162 # If there are any files/dirs remaining, one of these checks will fail.
3163 self.assertEqual(0, len(outfiles))
3164 _CheckDirPresent('section/cbfs')
3165 _CheckDirPresent('section')
3166 _CheckDirPresent('')
3167 self.assertFalse(os.path.exists(outdir))
3169 def testExtractAllEntries(self):
3170 """Test extracting all entries"""
3172 self._CheckExtractOutput(decomp=True)
3174 def testExtractAllEntriesRaw(self):
3175 """Test extracting all entries without decompressing them"""
3177 self._CheckExtractOutput(decomp=False)
3179 def testExtractSelectedEntries(self):
3180 """Test extracting some entries"""
3182 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3183 image_fname = tools.get_output_filename('image.bin')
3184 outdir = os.path.join(self._indir, 'extract')
3185 einfos = control.ExtractEntries(image_fname, None, outdir,
3188 # File output is tested by testExtractAllEntries(), so just check that
3189 # the expected entries are selected
3190 names = [einfo.name for einfo in einfos]
3191 self.assertEqual(names,
3192 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3194 def testExtractNoEntryPaths(self):
3195 """Test extracting some entries"""
3197 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3198 image_fname = tools.get_output_filename('image.bin')
3199 with self.assertRaises(ValueError) as e:
3200 control.ExtractEntries(image_fname, 'fname', None, [])
3201 self.assertIn('Must specify an entry path to write with -f',
3204 def testExtractTooManyEntryPaths(self):
3205 """Test extracting some entries"""
3207 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3208 image_fname = tools.get_output_filename('image.bin')
3209 with self.assertRaises(ValueError) as e:
3210 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
3211 self.assertIn('Must specify exactly one entry path to write with -f',
3214 def testPackAlignSection(self):
3215 """Test that sections can have alignment"""
3216 self._DoReadFile('131_pack_align_section.dts')
3218 self.assertIn('image', control.images)
3219 image = control.images['image']
3220 entries = image.GetEntries()
3221 self.assertEqual(3, len(entries))
3224 self.assertIn('u-boot', entries)
3225 entry = entries['u-boot']
3226 self.assertEqual(0, entry.offset)
3227 self.assertEqual(0, entry.image_pos)
3228 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3229 self.assertEqual(len(U_BOOT_DATA), entry.size)
3232 self.assertIn('section0', entries)
3233 section0 = entries['section0']
3234 self.assertEqual(0x10, section0.offset)
3235 self.assertEqual(0x10, section0.image_pos)
3236 self.assertEqual(len(U_BOOT_DATA), section0.size)
3239 section_entries = section0.GetEntries()
3240 self.assertIn('u-boot', section_entries)
3241 entry = section_entries['u-boot']
3242 self.assertEqual(0, entry.offset)
3243 self.assertEqual(0x10, entry.image_pos)
3244 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3245 self.assertEqual(len(U_BOOT_DATA), entry.size)
3248 self.assertIn('section1', entries)
3249 section1 = entries['section1']
3250 self.assertEqual(0x14, section1.offset)
3251 self.assertEqual(0x14, section1.image_pos)
3252 self.assertEqual(0x20, section1.size)
3255 section_entries = section1.GetEntries()
3256 self.assertIn('u-boot', section_entries)
3257 entry = section_entries['u-boot']
3258 self.assertEqual(0, entry.offset)
3259 self.assertEqual(0x14, entry.image_pos)
3260 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3261 self.assertEqual(len(U_BOOT_DATA), entry.size)
3264 self.assertIn('section2', section_entries)
3265 section2 = section_entries['section2']
3266 self.assertEqual(0x4, section2.offset)
3267 self.assertEqual(0x18, section2.image_pos)
3268 self.assertEqual(4, section2.size)
3271 section_entries = section2.GetEntries()
3272 self.assertIn('u-boot', section_entries)
3273 entry = section_entries['u-boot']
3274 self.assertEqual(0, entry.offset)
3275 self.assertEqual(0x18, entry.image_pos)
3276 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3277 self.assertEqual(len(U_BOOT_DATA), entry.size)
3279 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3280 dts='132_replace.dts'):
3281 """Replace an entry in an image
3283 This writes the entry data to update it, then opens the updated file and
3284 returns the value that it now finds there.
3287 entry_name: Entry name to replace
3288 data: Data to replace it with
3289 decomp: True to compress the data if needed, False if data is
3290 already compressed so should be used as is
3291 allow_resize: True to allow entries to change size, False to raise
3297 data from fdtmap (excluding header)
3298 Image object that was modified
3300 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3303 self.assertIn('image', control.images)
3304 image = control.images['image']
3305 entries = image.GetEntries()
3306 orig_dtb_data = entries['u-boot-dtb'].data
3307 orig_fdtmap_data = entries['fdtmap'].data
3309 image_fname = tools.get_output_filename('image.bin')
3310 updated_fname = tools.get_output_filename('image-updated.bin')
3311 tools.write_file(updated_fname, tools.read_file(image_fname))
3312 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3314 data = control.ReadEntry(updated_fname, entry_name, decomp)
3316 # The DT data should not change unless resized:
3317 if not allow_resize:
3318 new_dtb_data = entries['u-boot-dtb'].data
3319 self.assertEqual(new_dtb_data, orig_dtb_data)
3320 new_fdtmap_data = entries['fdtmap'].data
3321 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3323 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3325 def testReplaceSimple(self):
3326 """Test replacing a single file"""
3327 expected = b'x' * len(U_BOOT_DATA)
3328 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3330 self.assertEqual(expected, data)
3332 # Test that the state looks right. There should be an FDT for the fdtmap
3333 # that we jsut read back in, and it should match what we find in the
3334 # 'control' tables. Checking for an FDT that does not exist should
3336 path, fdtmap = state.GetFdtContents('fdtmap')
3337 self.assertIsNotNone(path)
3338 self.assertEqual(expected_fdtmap, fdtmap)
3340 dtb = state.GetFdtForEtype('fdtmap')
3341 self.assertEqual(dtb.GetContents(), fdtmap)
3343 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3344 self.assertIsNone(missing_path)
3345 self.assertIsNone(missing_fdtmap)
3347 missing_dtb = state.GetFdtForEtype('missing')
3348 self.assertIsNone(missing_dtb)
3350 self.assertEqual('/binman', state.fdt_path_prefix)
3352 def testReplaceResizeFail(self):
3353 """Test replacing a file by something larger"""
3354 expected = U_BOOT_DATA + b'x'
3355 with self.assertRaises(ValueError) as e:
3356 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3357 dts='139_replace_repack.dts')
3358 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3361 def testReplaceMulti(self):
3362 """Test replacing entry data where multiple images are generated"""
3363 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3365 expected = b'x' * len(U_BOOT_DATA)
3366 updated_fname = tools.get_output_filename('image-updated.bin')
3367 tools.write_file(updated_fname, data)
3368 entry_name = 'u-boot'
3369 control.WriteEntry(updated_fname, entry_name, expected,
3371 data = control.ReadEntry(updated_fname, entry_name)
3372 self.assertEqual(expected, data)
3374 # Check the state looks right.
3375 self.assertEqual('/binman/image', state.fdt_path_prefix)
3377 # Now check we can write the first image
3378 image_fname = tools.get_output_filename('first-image.bin')
3379 updated_fname = tools.get_output_filename('first-updated.bin')
3380 tools.write_file(updated_fname, tools.read_file(image_fname))
3381 entry_name = 'u-boot'
3382 control.WriteEntry(updated_fname, entry_name, expected,
3384 data = control.ReadEntry(updated_fname, entry_name)
3385 self.assertEqual(expected, data)
3387 # Check the state looks right.
3388 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3390 def testUpdateFdtAllRepack(self):
3391 """Test that all device trees are updated with offset/size info"""
3394 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3395 SECTION_SIZE = 0x300
3400 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3402 'section:offset': 0,
3403 'section:size': SECTION_SIZE,
3404 'section:image-pos': 0,
3405 'section/u-boot-dtb:offset': 4,
3406 'section/u-boot-dtb:size': 636,
3407 'section/u-boot-dtb:image-pos': 4,
3408 'u-boot-spl-dtb:offset': SECTION_SIZE,
3409 'u-boot-spl-dtb:size': DTB_SIZE,
3410 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3411 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3412 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3413 'u-boot-tpl-dtb:size': DTB_SIZE,
3414 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3415 'fdtmap:size': FDTMAP_SIZE,
3416 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3419 'section:orig-size': SECTION_SIZE,
3420 'section/u-boot-dtb:orig-offset': 4,
3423 # We expect three device-tree files in the output, with the first one
3424 # within a fixed-size section.
3425 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3426 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3427 # main U-Boot tree. All three should have the same positions and offset
3428 # except that the main tree should include the main_expected properties
3430 for item in ['', 'spl', 'tpl', None]:
3432 start += 16 # Move past fdtmap header
3433 dtb = fdt.Fdt.FromData(data[start:])
3435 props = self._GetPropTree(dtb,
3436 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3437 prefix='/' if item is None else '/binman/')
3438 expected = dict(base_expected)
3442 # Main DTB and fdtdec should include the 'orig-' properties
3443 expected.update(main_expected)
3444 # Helpful for debugging:
3445 #for prop in sorted(props):
3446 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3447 self.assertEqual(expected, props)
3449 start = SECTION_SIZE
3451 start += dtb._fdt_obj.totalsize()
3453 def testFdtmapHeaderMiddle(self):
3454 """Test an FDT map in the middle of an image when it should be at end"""
3455 with self.assertRaises(ValueError) as e:
3456 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3457 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3460 def testFdtmapHeaderStartBad(self):
3461 """Test an FDT map in middle of an image when it should be at start"""
3462 with self.assertRaises(ValueError) as e:
3463 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3464 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3467 def testFdtmapHeaderEndBad(self):
3468 """Test an FDT map at the start of an image when it should be at end"""
3469 with self.assertRaises(ValueError) as e:
3470 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3471 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3474 def testFdtmapHeaderNoSize(self):
3475 """Test an image header at the end of an image with undefined size"""
3476 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3478 def testReplaceResize(self):
3479 """Test replacing a single file in an entry with a larger file"""
3480 expected = U_BOOT_DATA + b'x'
3481 data, _, image = self._RunReplaceCmd('u-boot', expected,
3482 dts='139_replace_repack.dts')
3483 self.assertEqual(expected, data)
3485 entries = image.GetEntries()
3486 dtb_data = entries['u-boot-dtb'].data
3487 dtb = fdt.Fdt.FromData(dtb_data)
3490 # The u-boot section should now be larger in the dtb
3491 node = dtb.GetNode('/binman/u-boot')
3492 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3494 # Same for the fdtmap
3495 fdata = entries['fdtmap'].data
3496 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3498 fnode = fdtb.GetNode('/u-boot')
3499 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3501 def testReplaceResizeNoRepack(self):
3502 """Test replacing an entry with a larger file when not allowed"""
3503 expected = U_BOOT_DATA + b'x'
3504 with self.assertRaises(ValueError) as e:
3505 self._RunReplaceCmd('u-boot', expected)
3506 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3509 def testEntryShrink(self):
3510 """Test contracting an entry after it is packed"""
3512 state.SetAllowEntryContraction(True)
3513 data = self._DoReadFileDtb('140_entry_shrink.dts',
3516 state.SetAllowEntryContraction(False)
3517 self.assertEqual(b'a', data[:1])
3518 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3519 self.assertEqual(b'a', data[-1:])
3521 def testEntryShrinkFail(self):
3522 """Test not being allowed to contract an entry after it is packed"""
3523 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3525 # In this case there is a spare byte at the end of the data. The size of
3526 # the contents is only 1 byte but we still have the size before it
3528 self.assertEqual(b'a\0', data[:2])
3529 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3530 self.assertEqual(b'a\0', data[-2:])
3532 def testDescriptorOffset(self):
3533 """Test that the Intel descriptor is always placed at at the start"""
3534 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3535 image = control.images['image']
3536 entries = image.GetEntries()
3537 desc = entries['intel-descriptor']
3538 self.assertEqual(0xff800000, desc.offset);
3539 self.assertEqual(0xff800000, desc.image_pos);
3541 def testReplaceCbfs(self):
3542 """Test replacing a single file in CBFS without changing the size"""
3544 expected = b'x' * len(U_BOOT_DATA)
3545 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3546 updated_fname = tools.get_output_filename('image-updated.bin')
3547 tools.write_file(updated_fname, data)
3548 entry_name = 'section/cbfs/u-boot'
3549 control.WriteEntry(updated_fname, entry_name, expected,
3551 data = control.ReadEntry(updated_fname, entry_name)
3552 self.assertEqual(expected, data)
3554 def testReplaceResizeCbfs(self):
3555 """Test replacing a single file in CBFS with one of a different size"""
3557 expected = U_BOOT_DATA + b'x'
3558 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3559 updated_fname = tools.get_output_filename('image-updated.bin')
3560 tools.write_file(updated_fname, data)
3561 entry_name = 'section/cbfs/u-boot'
3562 control.WriteEntry(updated_fname, entry_name, expected,
3564 data = control.ReadEntry(updated_fname, entry_name)
3565 self.assertEqual(expected, data)
3567 def _SetupForReplace(self):
3568 """Set up some files to use to replace entries
3570 This generates an image, copies it to a new file, extracts all the files
3571 in it and updates some of them
3577 Expected values for updated entries, each a string
3579 data = self._DoReadFileRealDtb('143_replace_all.dts')
3581 updated_fname = tools.get_output_filename('image-updated.bin')
3582 tools.write_file(updated_fname, data)
3584 outdir = os.path.join(self._indir, 'extract')
3585 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3587 expected1 = b'x' + U_BOOT_DATA + b'y'
3588 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3589 tools.write_file(u_boot_fname1, expected1)
3591 expected2 = b'a' + U_BOOT_DATA + b'b'
3592 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3593 tools.write_file(u_boot_fname2, expected2)
3595 expected_text = b'not the same text'
3596 text_fname = os.path.join(outdir, 'text')
3597 tools.write_file(text_fname, expected_text)
3599 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3600 dtb = fdt.FdtScan(dtb_fname)
3601 node = dtb.GetNode('/binman/text')
3602 node.AddString('my-property', 'the value')
3603 dtb.Sync(auto_resize=True)
3606 return updated_fname, outdir, expected1, expected2, expected_text
3608 def _CheckReplaceMultiple(self, entry_paths):
3609 """Handle replacing the contents of multiple entries
3612 entry_paths: List of entry paths to replace
3616 Dict of entries in the image:
3619 Expected values for updated entries, each a string
3621 updated_fname, outdir, expected1, expected2, expected_text = (
3622 self._SetupForReplace())
3623 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3625 image = Image.FromFile(updated_fname)
3627 return image.GetEntries(), expected1, expected2, expected_text
3629 def testReplaceAll(self):
3630 """Test replacing the contents of all entries"""
3631 entries, expected1, expected2, expected_text = (
3632 self._CheckReplaceMultiple([]))
3633 data = entries['u-boot'].data
3634 self.assertEqual(expected1, data)
3636 data = entries['u-boot2'].data
3637 self.assertEqual(expected2, data)
3639 data = entries['text'].data
3640 self.assertEqual(expected_text, data)
3642 # Check that the device tree is updated
3643 data = entries['u-boot-dtb'].data
3644 dtb = fdt.Fdt.FromData(data)
3646 node = dtb.GetNode('/binman/text')
3647 self.assertEqual('the value', node.props['my-property'].value)
3649 def testReplaceSome(self):
3650 """Test replacing the contents of a few entries"""
3651 entries, expected1, expected2, expected_text = (
3652 self._CheckReplaceMultiple(['u-boot2', 'text']))
3654 # This one should not change
3655 data = entries['u-boot'].data
3656 self.assertEqual(U_BOOT_DATA, data)
3658 data = entries['u-boot2'].data
3659 self.assertEqual(expected2, data)
3661 data = entries['text'].data
3662 self.assertEqual(expected_text, data)
3664 def testReplaceCmd(self):
3665 """Test replacing a file fron an image on the command line"""
3666 self._DoReadFileRealDtb('143_replace_all.dts')
3669 tmpdir, updated_fname = self._SetupImageInTmpdir()
3671 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3672 expected = b'x' * len(U_BOOT_DATA)
3673 tools.write_file(fname, expected)
3675 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3676 data = tools.read_file(updated_fname)
3677 self.assertEqual(expected, data[:len(expected)])
3678 map_fname = os.path.join(tmpdir, 'image-updated.map')
3679 self.assertFalse(os.path.exists(map_fname))
3681 shutil.rmtree(tmpdir)
3683 def testReplaceCmdSome(self):
3684 """Test replacing some files fron an image on the command line"""
3685 updated_fname, outdir, expected1, expected2, expected_text = (
3686 self._SetupForReplace())
3688 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3691 tools.prepare_output_dir(None)
3692 image = Image.FromFile(updated_fname)
3694 entries = image.GetEntries()
3696 # This one should not change
3697 data = entries['u-boot'].data
3698 self.assertEqual(U_BOOT_DATA, data)
3700 data = entries['u-boot2'].data
3701 self.assertEqual(expected2, data)
3703 data = entries['text'].data
3704 self.assertEqual(expected_text, data)
3706 def testReplaceMissing(self):
3707 """Test replacing entries where the file is missing"""
3708 updated_fname, outdir, expected1, expected2, expected_text = (
3709 self._SetupForReplace())
3711 # Remove one of the files, to generate a warning
3712 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3713 os.remove(u_boot_fname1)
3715 with test_util.capture_sys_output() as (stdout, stderr):
3716 control.ReplaceEntries(updated_fname, None, outdir, [])
3717 self.assertIn("Skipping entry '/u-boot' from missing file",
3720 def testReplaceCmdMap(self):
3721 """Test replacing a file fron an image on the command line"""
3722 self._DoReadFileRealDtb('143_replace_all.dts')
3725 tmpdir, updated_fname = self._SetupImageInTmpdir()
3727 fname = os.path.join(self._indir, 'update-u-boot.bin')
3728 expected = b'x' * len(U_BOOT_DATA)
3729 tools.write_file(fname, expected)
3731 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3733 map_fname = os.path.join(tmpdir, 'image-updated.map')
3734 self.assertTrue(os.path.exists(map_fname))
3736 shutil.rmtree(tmpdir)
3738 def testReplaceNoEntryPaths(self):
3739 """Test replacing an entry without an entry path"""
3740 self._DoReadFileRealDtb('143_replace_all.dts')
3741 image_fname = tools.get_output_filename('image.bin')
3742 with self.assertRaises(ValueError) as e:
3743 control.ReplaceEntries(image_fname, 'fname', None, [])
3744 self.assertIn('Must specify an entry path to read with -f',
3747 def testReplaceTooManyEntryPaths(self):
3748 """Test extracting some entries"""
3749 self._DoReadFileRealDtb('143_replace_all.dts')
3750 image_fname = tools.get_output_filename('image.bin')
3751 with self.assertRaises(ValueError) as e:
3752 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3753 self.assertIn('Must specify exactly one entry path to write with -f',
3756 def testPackReset16(self):
3757 """Test that an image with an x86 reset16 region can be created"""
3758 data = self._DoReadFile('144_x86_reset16.dts')
3759 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3761 def testPackReset16Spl(self):
3762 """Test that an image with an x86 reset16-spl region can be created"""
3763 data = self._DoReadFile('145_x86_reset16_spl.dts')
3764 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3766 def testPackReset16Tpl(self):
3767 """Test that an image with an x86 reset16-tpl region can be created"""
3768 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3769 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3771 def testPackIntelFit(self):
3772 """Test that an image with an Intel FIT and pointer can be created"""
3773 data = self._DoReadFile('147_intel_fit.dts')
3774 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3776 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3777 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3779 image = control.images['image']
3780 entries = image.GetEntries()
3781 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3782 self.assertEqual(expected_ptr, ptr)
3784 def testPackIntelFitMissing(self):
3785 """Test detection of a FIT pointer with not FIT region"""
3786 with self.assertRaises(ValueError) as e:
3787 self._DoReadFile('148_intel_fit_missing.dts')
3788 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3791 def _CheckSymbolsTplSection(self, dts, expected_vals):
3792 data = self._DoReadFile(dts)
3793 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
3794 upto1 = 4 + len(U_BOOT_SPL_DATA)
3795 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
3796 self.assertEqual(expected1, data[:upto1])
3798 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3799 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
3800 self.assertEqual(expected2, data[upto1:upto2])
3802 upto3 = 0x3c + len(U_BOOT_DATA)
3803 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
3804 self.assertEqual(expected3, data[upto2:upto3])
3806 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
3807 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3809 def testSymbolsTplSection(self):
3810 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3811 self._SetupSplElf('u_boot_binman_syms')
3812 self._SetupTplElf('u_boot_binman_syms')
3813 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3814 [0x04, 0x20, 0x10 + 0x3c, 0x04])
3816 def testSymbolsTplSectionX86(self):
3817 """Test binman can assign symbols in a section with end-at-4gb"""
3818 self._SetupSplElf('u_boot_binman_syms_x86')
3819 self._SetupTplElf('u_boot_binman_syms_x86')
3820 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3821 [0xffffff04, 0xffffff20, 0xffffff3c,
3824 def testPackX86RomIfwiSectiom(self):
3825 """Test that a section can be placed in an IFWI region"""
3826 self._SetupIfwi('fitimage.bin')
3827 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3828 self._CheckIfwi(data)
3830 def testPackFspM(self):
3831 """Test that an image with a FSP memory-init binary can be created"""
3832 data = self._DoReadFile('152_intel_fsp_m.dts')
3833 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3835 def testPackFspS(self):
3836 """Test that an image with a FSP silicon-init binary can be created"""
3837 data = self._DoReadFile('153_intel_fsp_s.dts')
3838 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3840 def testPackFspT(self):
3841 """Test that an image with a FSP temp-ram-init binary can be created"""
3842 data = self._DoReadFile('154_intel_fsp_t.dts')
3843 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3845 def testMkimage(self):
3846 """Test using mkimage to build an image"""
3848 data = self._DoReadFile('156_mkimage.dts')
3850 # Just check that the data appears in the file somewhere
3851 self.assertIn(U_BOOT_SPL_DATA, data)
3853 def testMkimageMissing(self):
3854 """Test that binman still produces an image if mkimage is missing"""
3856 with test_util.capture_sys_output() as (_, stderr):
3857 self._DoTestFile('156_mkimage.dts',
3858 force_missing_bintools='mkimage')
3859 err = stderr.getvalue()
3860 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
3862 def testExtblob(self):
3863 """Test an image with an external blob"""
3864 data = self._DoReadFile('157_blob_ext.dts')
3865 self.assertEqual(REFCODE_DATA, data)
3867 def testExtblobMissing(self):
3868 """Test an image with a missing external blob"""
3869 with self.assertRaises(ValueError) as e:
3870 self._DoReadFile('158_blob_ext_missing.dts')
3871 self.assertIn("Filename 'missing-file' not found in input path",
3874 def testExtblobMissingOk(self):
3875 """Test an image with an missing external blob that is allowed"""
3876 with test_util.capture_sys_output() as (stdout, stderr):
3877 ret = self._DoTestFile('158_blob_ext_missing.dts',
3879 self.assertEqual(103, ret)
3880 err = stderr.getvalue()
3881 self.assertIn('(missing-file)', err)
3882 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
3883 self.assertIn('Some images are invalid', err)
3885 def testExtblobMissingOkFlag(self):
3886 """Test an image with an missing external blob allowed with -W"""
3887 with test_util.capture_sys_output() as (stdout, stderr):
3888 ret = self._DoTestFile('158_blob_ext_missing.dts',
3889 allow_missing=True, ignore_missing=True)
3890 self.assertEqual(0, ret)
3891 err = stderr.getvalue()
3892 self.assertIn('(missing-file)', err)
3893 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
3894 self.assertIn('Some images are invalid', err)
3896 def testExtblobMissingOkSect(self):
3897 """Test an image with an missing external blob that is allowed"""
3898 with test_util.capture_sys_output() as (stdout, stderr):
3899 self._DoTestFile('159_blob_ext_missing_sect.dts',
3901 err = stderr.getvalue()
3902 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
3904 def testPackX86RomMeMissingDesc(self):
3905 """Test that an missing Intel descriptor entry is allowed"""
3906 with test_util.capture_sys_output() as (stdout, stderr):
3907 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3908 err = stderr.getvalue()
3909 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
3911 def testPackX86RomMissingIfwi(self):
3912 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3913 self._SetupIfwi('fitimage.bin')
3914 pathname = os.path.join(self._indir, 'fitimage.bin')
3916 with test_util.capture_sys_output() as (stdout, stderr):
3917 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3918 err = stderr.getvalue()
3919 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
3921 def testPackOverlapZero(self):
3922 """Test that zero-size overlapping regions are ignored"""
3923 self._DoTestFile('160_pack_overlap_zero.dts')
3925 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
3926 # The data should be inside the FIT
3927 dtb = fdt.Fdt.FromData(fit_data)
3929 fnode = dtb.GetNode('/images/kernel')
3930 self.assertIn('data', fnode.props)
3932 fname = os.path.join(self._indir, 'fit_data.fit')
3933 tools.write_file(fname, fit_data)
3934 out = tools.run('dumpimage', '-l', fname)
3936 # Check a few features to make sure the plumbing works. We don't need
3937 # to test the operation of mkimage or dumpimage here. First convert the
3938 # output into a dict where the keys are the fields printed by dumpimage
3939 # and the values are a list of values for each field
3940 lines = out.splitlines()
3942 # Converts "Compression: gzip compressed" into two groups:
3943 # 'Compression' and 'gzip compressed'
3944 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3945 vals = collections.defaultdict(list)
3947 mat = re_line.match(line)
3948 vals[mat.group(1)].append(mat.group(2))
3950 self.assertEqual('FIT description: test-desc', lines[0])
3951 self.assertIn('Created:', lines[1])
3952 self.assertIn('Image 0 (kernel)', vals)
3953 self.assertIn('Hash value', vals)
3954 data_sizes = vals.get('Data Size')
3955 self.assertIsNotNone(data_sizes)
3956 self.assertEqual(2, len(data_sizes))
3957 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3958 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3959 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3961 # Check if entry listing correctly omits /images/
3962 image = control.images['image']
3963 fit_entry = image.GetEntries()['fit']
3964 subentries = list(fit_entry.GetEntries().keys())
3965 expected = ['kernel', 'fdt-1']
3966 self.assertEqual(expected, subentries)
3968 def testSimpleFit(self):
3969 """Test an image with a FIT inside"""
3971 data = self._DoReadFile('161_fit.dts')
3972 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3973 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3974 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3976 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3978 def testSimpleFitExpandsSubentries(self):
3979 """Test that FIT images expand their subentries"""
3980 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3981 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3982 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3983 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3985 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
3987 def testSimpleFitImagePos(self):
3988 """Test that we have correct image-pos for FIT subentries"""
3989 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3991 dtb = fdt.Fdt(out_dtb_fname)
3993 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4001 'u-boot:image-pos': 0,
4009 'fit/images/kernel:image-pos': 304,
4010 'fit/images/kernel:offset': 300,
4011 'fit/images/kernel:size': 4,
4013 'fit/images/kernel/u-boot:image-pos': 304,
4014 'fit/images/kernel/u-boot:offset': 0,
4015 'fit/images/kernel/u-boot:size': 4,
4017 'fit/images/fdt-1:image-pos': 552,
4018 'fit/images/fdt-1:offset': 548,
4019 'fit/images/fdt-1:size': 6,
4021 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
4022 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4023 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4025 'u-boot-nodtb:image-pos': 1844,
4026 'u-boot-nodtb:offset': 1844,
4027 'u-boot-nodtb:size': 46,
4030 # Actually check the data is where we think it is
4031 for node, expected in [
4032 ("u-boot", U_BOOT_DATA),
4033 ("fit/images/kernel", U_BOOT_DATA),
4034 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4035 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4036 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4037 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4039 image_pos = props[f"{node}:image-pos"]
4040 size = props[f"{node}:size"]
4041 self.assertEqual(len(expected), size)
4042 self.assertEqual(expected, data[image_pos:image_pos+size])
4044 def testFitExternal(self):
4045 """Test an image with an FIT with external images"""
4046 data = self._DoReadFile('162_fit_external.dts')
4047 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4049 # Size of the external-data region as set up by mkimage
4050 external_data_size = len(U_BOOT_DATA) + 2
4051 expected_size = (len(U_BOOT_DATA) + 0x400 +
4052 tools.align(external_data_size, 4) +
4053 len(U_BOOT_NODTB_DATA))
4055 # The data should be outside the FIT
4056 dtb = fdt.Fdt.FromData(fit_data)
4058 fnode = dtb.GetNode('/images/kernel')
4059 self.assertNotIn('data', fnode.props)
4060 self.assertEqual(len(U_BOOT_DATA),
4061 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4065 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4067 self.assertEqual(expected_size, len(data))
4068 actual_pos = len(U_BOOT_DATA) + fit_pos
4069 self.assertEqual(U_BOOT_DATA + b'aa',
4070 data[actual_pos:actual_pos + external_data_size])
4072 def testFitExternalImagePos(self):
4073 """Test that we have correct image-pos for external FIT subentries"""
4074 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4076 dtb = fdt.Fdt(out_dtb_fname)
4078 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4085 'u-boot:image-pos': 0,
4093 'fit/images/kernel:size': 4,
4094 'fit/images/kernel:offset': 1024,
4095 'fit/images/kernel:image-pos': 1028,
4097 'fit/images/kernel/u-boot:size': 4,
4098 'fit/images/kernel/u-boot:offset': 0,
4099 'fit/images/kernel/u-boot:image-pos': 1028,
4101 'fit/images/fdt-1:size': 2,
4102 'fit/images/fdt-1:offset': 1028,
4103 'fit/images/fdt-1:image-pos': 1032,
4105 'fit/images/fdt-1/_testing:size': 2,
4106 'fit/images/fdt-1/_testing:offset': 0,
4107 'fit/images/fdt-1/_testing:image-pos': 1032,
4109 'u-boot-nodtb:image-pos': 1036,
4110 'u-boot-nodtb:offset': 1036,
4111 'u-boot-nodtb:size': 46,
4114 # Actually check the data is where we think it is
4115 for node, expected in [
4116 ("u-boot", U_BOOT_DATA),
4117 ("fit/images/kernel", U_BOOT_DATA),
4118 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4119 ("fit/images/fdt-1", b'aa'),
4120 ("fit/images/fdt-1/_testing", b'aa'),
4121 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4123 image_pos = props[f"{node}:image-pos"]
4124 size = props[f"{node}:size"]
4125 self.assertEqual(len(expected), size)
4126 self.assertEqual(expected, data[image_pos:image_pos+size])
4128 def testFitMissing(self):
4129 """Test that binman complains if mkimage is missing"""
4130 with self.assertRaises(ValueError) as e:
4131 self._DoTestFile('162_fit_external.dts',
4132 force_missing_bintools='mkimage')
4133 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4136 def testFitMissingOK(self):
4137 """Test that binman still produces a FIT image if mkimage is missing"""
4138 with test_util.capture_sys_output() as (_, stderr):
4139 self._DoTestFile('162_fit_external.dts', allow_missing=True,
4140 force_missing_bintools='mkimage')
4141 err = stderr.getvalue()
4142 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
4144 def testSectionIgnoreHashSignature(self):
4145 """Test that sections ignore hash, signature nodes for its data"""
4146 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4147 expected = (U_BOOT_DATA + U_BOOT_DATA)
4148 self.assertEqual(expected, data)
4150 def testPadInSections(self):
4151 """Test pad-before, pad-after for entries in sections"""
4152 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4153 '166_pad_in_sections.dts', update_dtb=True)
4154 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4155 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
4157 self.assertEqual(expected, data)
4159 dtb = fdt.Fdt(out_dtb_fname)
4161 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4165 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4167 'section:image-pos': 0,
4168 'section:offset': 0,
4169 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4171 'section/before:image-pos': 0,
4172 'section/before:offset': 0,
4173 'section/before:size': len(U_BOOT_DATA),
4175 'section/u-boot:image-pos': 4,
4176 'section/u-boot:offset': 4,
4177 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4179 'section/after:image-pos': 26,
4180 'section/after:offset': 26,
4181 'section/after:size': len(U_BOOT_DATA),
4183 self.assertEqual(expected, props)
4185 def testFitImageSubentryAlignment(self):
4186 """Test relative alignability of FIT image subentries"""
4189 'test-id': TEXT_DATA,
4191 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4192 entry_args=entry_args)
4193 dtb = fdt.Fdt.FromData(data)
4196 node = dtb.GetNode('/images/kernel')
4197 data = dtb.GetProps(node)["data"].bytes
4198 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
4199 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4200 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
4201 self.assertEqual(expected, data)
4203 node = dtb.GetNode('/images/fdt-1')
4204 data = dtb.GetProps(node)["data"].bytes
4205 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4206 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
4208 self.assertEqual(expected, data)
4210 def testFitExtblobMissingOk(self):
4211 """Test a FIT with a missing external blob that is allowed"""
4212 with test_util.capture_sys_output() as (stdout, stderr):
4213 self._DoTestFile('168_fit_missing_blob.dts',
4215 err = stderr.getvalue()
4216 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
4218 def testBlobNamedByArgMissing(self):
4219 """Test handling of a missing entry arg"""
4220 with self.assertRaises(ValueError) as e:
4221 self._DoReadFile('068_blob_named_by_arg.dts')
4222 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4225 def testPackBl31(self):
4226 """Test that an image with an ATF BL31 binary can be created"""
4227 data = self._DoReadFile('169_atf_bl31.dts')
4228 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4230 def testPackScp(self):
4231 """Test that an image with an SCP binary can be created"""
4232 data = self._DoReadFile('172_scp.dts')
4233 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4235 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
4236 default_dt=None, use_seq_num=True):
4237 """Check an image with an FIT with multiple FDT images"""
4238 def _CheckFdt(val, expected_data):
4239 """Check the FDT nodes
4242 val: Sequence number to check (0 or 1) or fdt name
4243 expected_data: Expected contents of 'data' property
4245 name = 'fdt-%s' % val
4246 fnode = dtb.GetNode('/images/%s' % name)
4247 self.assertIsNotNone(fnode)
4248 self.assertEqual({'description','type', 'compression', 'data'},
4249 set(fnode.props.keys()))
4250 self.assertEqual(expected_data, fnode.props['data'].bytes)
4252 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4255 self.assertEqual(description, fnode.props['description'].value)
4256 self.assertEqual(fnode.subnodes[0].name, 'hash')
4258 def _CheckConfig(val, expected_data):
4259 """Check the configuration nodes
4262 val: Sequence number to check (0 or 1) or fdt name
4263 expected_data: Expected contents of 'data' property
4265 cnode = dtb.GetNode('/configurations')
4266 self.assertIn('default', cnode.props)
4268 'config-2' if len(val) == 1 else
4271 self.assertEqual(default, cnode.props['default'].value)
4273 name = 'config-%s' % val
4274 fnode = dtb.GetNode('/configurations/%s' % name)
4275 self.assertIsNotNone(fnode)
4276 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4277 set(fnode.props.keys()))
4279 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4282 self.assertEqual(description, fnode.props['description'].value)
4283 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
4286 'default-dt': 'test-fdt2',
4290 entry_args['of-list'] = 'test-fdt1 test-fdt2'
4292 entry_args['default-dt'] = default_dt
4294 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
4295 data = self._DoReadFileDtb(
4297 entry_args=entry_args,
4298 extra_indirs=extra_indirs)[0]
4299 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4300 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4302 dtb = fdt.Fdt.FromData(fit_data)
4304 fnode = dtb.GetNode('/images/kernel')
4305 self.assertIn('data', fnode.props)
4307 if use_seq_num == True:
4308 # Check all the properties in fdt-1 and fdt-2
4309 _CheckFdt('1', TEST_FDT1_DATA)
4310 _CheckFdt('2', TEST_FDT2_DATA)
4312 # Check configurations
4313 _CheckConfig('1', TEST_FDT1_DATA)
4314 _CheckConfig('2', TEST_FDT2_DATA)
4316 # Check all the properties in fdt-1 and fdt-2
4317 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4318 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4320 # Check configurations
4321 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4322 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
4324 def testFitFdt(self):
4325 """Test an image with an FIT with multiple FDT images"""
4328 def testFitFdtMissingList(self):
4329 """Test handling of a missing 'of-list' entry arg"""
4330 with self.assertRaises(ValueError) as e:
4331 self._DoReadFile('170_fit_fdt.dts')
4332 self.assertIn("Generator node requires 'of-list' entry argument",
4335 def testFitFdtEmptyList(self):
4336 """Test handling of an empty 'of-list' entry arg"""
4340 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4342 def testFitFdtMissingProp(self):
4343 """Test handling of a missing 'fit,fdt-list' property"""
4344 with self.assertRaises(ValueError) as e:
4345 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4346 self.assertIn("Generator node requires 'fit,fdt-list' property",
4349 def testFitFdtMissing(self):
4350 """Test handling of a missing 'default-dt' entry arg"""
4352 'of-list': 'test-fdt1 test-fdt2',
4354 with self.assertRaises(ValueError) as e:
4355 self._DoReadFileDtb(
4357 entry_args=entry_args,
4358 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4359 self.assertIn("Generated 'default' node requires default-dt entry argument",
4362 def testFitFdtNotInList(self):
4363 """Test handling of a default-dt that is not in the of-list"""
4365 'of-list': 'test-fdt1 test-fdt2',
4366 'default-dt': 'test-fdt3',
4368 with self.assertRaises(ValueError) as e:
4369 self._DoReadFileDtb(
4371 entry_args=entry_args,
4372 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4373 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4376 def testFitExtblobMissingHelp(self):
4377 """Test display of help messages when an external blob is missing"""
4378 control.missing_blob_help = control._ReadMissingBlobHelp()
4379 control.missing_blob_help['wibble'] = 'Wibble test'
4380 control.missing_blob_help['another'] = 'Another test'
4381 with test_util.capture_sys_output() as (stdout, stderr):
4382 self._DoTestFile('168_fit_missing_blob.dts',
4384 err = stderr.getvalue()
4386 # We can get the tag from the name, the type or the missing-msg
4387 # property. Check all three.
4388 self.assertIn('You may need to build ARM Trusted', err)
4389 self.assertIn('Wibble test', err)
4390 self.assertIn('Another test', err)
4392 def testMissingBlob(self):
4393 """Test handling of a blob containing a missing file"""
4394 with self.assertRaises(ValueError) as e:
4395 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4396 self.assertIn("Filename 'missing' not found in input path",
4399 def testEnvironment(self):
4400 """Test adding a U-Boot environment"""
4401 data = self._DoReadFile('174_env.dts')
4402 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4403 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4404 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4405 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4408 def testEnvironmentNoSize(self):
4409 """Test that a missing 'size' property is detected"""
4410 with self.assertRaises(ValueError) as e:
4411 self._DoTestFile('175_env_no_size.dts')
4412 self.assertIn("'u-boot-env' entry must have a size property",
4415 def testEnvironmentTooSmall(self):
4416 """Test handling of an environment that does not fit"""
4417 with self.assertRaises(ValueError) as e:
4418 self._DoTestFile('176_env_too_small.dts')
4420 # checksum, start byte, environment with \0 terminator, final \0
4421 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4423 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4426 def testSkipAtStart(self):
4427 """Test handling of skip-at-start section"""
4428 data = self._DoReadFile('177_skip_at_start.dts')
4429 self.assertEqual(U_BOOT_DATA, data)
4431 image = control.images['image']
4432 entries = image.GetEntries()
4433 section = entries['section']
4434 self.assertEqual(0, section.offset)
4435 self.assertEqual(len(U_BOOT_DATA), section.size)
4436 self.assertEqual(U_BOOT_DATA, section.GetData())
4438 entry = section.GetEntries()['u-boot']
4439 self.assertEqual(16, entry.offset)
4440 self.assertEqual(len(U_BOOT_DATA), entry.size)
4441 self.assertEqual(U_BOOT_DATA, entry.data)
4443 def testSkipAtStartPad(self):
4444 """Test handling of skip-at-start section with padded entry"""
4445 data = self._DoReadFile('178_skip_at_start_pad.dts')
4446 before = tools.get_bytes(0, 8)
4447 after = tools.get_bytes(0, 4)
4448 all = before + U_BOOT_DATA + after
4449 self.assertEqual(all, data)
4451 image = control.images['image']
4452 entries = image.GetEntries()
4453 section = entries['section']
4454 self.assertEqual(0, section.offset)
4455 self.assertEqual(len(all), section.size)
4456 self.assertEqual(all, section.GetData())
4458 entry = section.GetEntries()['u-boot']
4459 self.assertEqual(16, entry.offset)
4460 self.assertEqual(len(all), entry.size)
4461 self.assertEqual(U_BOOT_DATA, entry.data)
4463 def testSkipAtStartSectionPad(self):
4464 """Test handling of skip-at-start section with padding"""
4465 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4466 before = tools.get_bytes(0, 8)
4467 after = tools.get_bytes(0, 4)
4468 all = before + U_BOOT_DATA + after
4469 self.assertEqual(all, data)
4471 image = control.images['image']
4472 entries = image.GetEntries()
4473 section = entries['section']
4474 self.assertEqual(0, section.offset)
4475 self.assertEqual(len(all), section.size)
4476 self.assertEqual(U_BOOT_DATA, section.data)
4477 self.assertEqual(all, section.GetPaddedData())
4479 entry = section.GetEntries()['u-boot']
4480 self.assertEqual(16, entry.offset)
4481 self.assertEqual(len(U_BOOT_DATA), entry.size)
4482 self.assertEqual(U_BOOT_DATA, entry.data)
4484 def testSectionPad(self):
4485 """Testing padding with sections"""
4486 data = self._DoReadFile('180_section_pad.dts')
4487 expected = (tools.get_bytes(ord('&'), 3) +
4488 tools.get_bytes(ord('!'), 5) +
4490 tools.get_bytes(ord('!'), 1) +
4491 tools.get_bytes(ord('&'), 2))
4492 self.assertEqual(expected, data)
4494 def testSectionAlign(self):
4495 """Testing alignment with sections"""
4496 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4497 expected = (b'\0' + # fill section
4498 tools.get_bytes(ord('&'), 1) + # padding to section align
4499 b'\0' + # fill section
4500 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
4502 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4503 tools.get_bytes(ord('!'), 4)) # padding to section size
4504 self.assertEqual(expected, data)
4506 def testCompressImage(self):
4507 """Test compression of the entire image"""
4509 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4510 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4511 dtb = fdt.Fdt(out_dtb_fname)
4513 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4515 orig = self._decompress(data)
4516 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
4518 # Do a sanity check on various fields
4519 image = control.images['image']
4520 entries = image.GetEntries()
4521 self.assertEqual(2, len(entries))
4523 entry = entries['blob']
4524 self.assertEqual(COMPRESS_DATA, entry.data)
4525 self.assertEqual(len(COMPRESS_DATA), entry.size)
4527 entry = entries['u-boot']
4528 self.assertEqual(U_BOOT_DATA, entry.data)
4529 self.assertEqual(len(U_BOOT_DATA), entry.size)
4531 self.assertEqual(len(data), image.size)
4532 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4533 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4534 orig = self._decompress(image.data)
4535 self.assertEqual(orig, image.uncomp_data)
4539 'blob:size': len(COMPRESS_DATA),
4540 'u-boot:offset': len(COMPRESS_DATA),
4541 'u-boot:size': len(U_BOOT_DATA),
4542 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4547 self.assertEqual(expected, props)
4549 def testCompressImageLess(self):
4550 """Test compression where compression reduces the image size"""
4552 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4553 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4554 dtb = fdt.Fdt(out_dtb_fname)
4556 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4558 orig = self._decompress(data)
4560 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4562 # Do a sanity check on various fields
4563 image = control.images['image']
4564 entries = image.GetEntries()
4565 self.assertEqual(2, len(entries))
4567 entry = entries['blob']
4568 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4569 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4571 entry = entries['u-boot']
4572 self.assertEqual(U_BOOT_DATA, entry.data)
4573 self.assertEqual(len(U_BOOT_DATA), entry.size)
4575 self.assertEqual(len(data), image.size)
4576 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4577 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4579 orig = self._decompress(image.data)
4580 self.assertEqual(orig, image.uncomp_data)
4584 'blob:size': len(COMPRESS_DATA_BIG),
4585 'u-boot:offset': len(COMPRESS_DATA_BIG),
4586 'u-boot:size': len(U_BOOT_DATA),
4587 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4592 self.assertEqual(expected, props)
4594 def testCompressSectionSize(self):
4595 """Test compression of a section with a fixed size"""
4597 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4598 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4599 dtb = fdt.Fdt(out_dtb_fname)
4601 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4603 orig = self._decompress(data)
4604 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
4606 'section/blob:offset': 0,
4607 'section/blob:size': len(COMPRESS_DATA),
4608 'section/u-boot:offset': len(COMPRESS_DATA),
4609 'section/u-boot:size': len(U_BOOT_DATA),
4610 'section:offset': 0,
4611 'section:image-pos': 0,
4612 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4613 'section:size': 0x30,
4618 self.assertEqual(expected, props)
4620 def testCompressSection(self):
4621 """Test compression of a section with no fixed size"""
4623 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4624 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4625 dtb = fdt.Fdt(out_dtb_fname)
4627 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4629 orig = self._decompress(data)
4630 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
4632 'section/blob:offset': 0,
4633 'section/blob:size': len(COMPRESS_DATA),
4634 'section/u-boot:offset': len(COMPRESS_DATA),
4635 'section/u-boot:size': len(U_BOOT_DATA),
4636 'section:offset': 0,
4637 'section:image-pos': 0,
4638 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4639 'section:size': len(data),
4644 self.assertEqual(expected, props)
4646 def testLz4Missing(self):
4647 """Test that binman still produces an image if lz4 is missing"""
4648 with test_util.capture_sys_output() as (_, stderr):
4649 self._DoTestFile('185_compress_section.dts',
4650 force_missing_bintools='lz4')
4651 err = stderr.getvalue()
4652 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
4654 def testCompressExtra(self):
4655 """Test compression of a section with no fixed size"""
4657 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4658 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4659 dtb = fdt.Fdt(out_dtb_fname)
4661 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4664 base = data[len(U_BOOT_DATA):]
4665 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4666 rest = base[len(U_BOOT_DATA):]
4668 # Check compressed data
4669 bintool = self.comp_bintools['lz4']
4670 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
4671 data1 = rest[:len(expect1)]
4672 section1 = self._decompress(data1)
4673 self.assertEqual(expect1, data1)
4674 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
4675 rest1 = rest[len(expect1):]
4677 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
4678 data2 = rest1[:len(expect2)]
4679 section2 = self._decompress(data2)
4680 self.assertEqual(expect2, data2)
4681 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
4682 rest2 = rest1[len(expect2):]
4684 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4685 len(expect2) + len(U_BOOT_DATA))
4686 #self.assertEqual(expect_size, len(data))
4688 #self.assertEqual(U_BOOT_DATA, rest2)
4693 'u-boot:image-pos': 0,
4694 'u-boot:size': len(U_BOOT_DATA),
4696 'base:offset': len(U_BOOT_DATA),
4697 'base:image-pos': len(U_BOOT_DATA),
4698 'base:size': len(data) - len(U_BOOT_DATA),
4699 'base/u-boot:offset': 0,
4700 'base/u-boot:image-pos': len(U_BOOT_DATA),
4701 'base/u-boot:size': len(U_BOOT_DATA),
4702 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4704 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4706 'base/u-boot2:size': len(U_BOOT_DATA),
4708 'base/section:offset': len(U_BOOT_DATA),
4709 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4710 'base/section:size': len(expect1),
4711 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4712 'base/section/blob:offset': 0,
4713 'base/section/blob:size': len(COMPRESS_DATA),
4714 'base/section/u-boot:offset': len(COMPRESS_DATA),
4715 'base/section/u-boot:size': len(U_BOOT_DATA),
4717 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4718 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4719 'base/section2:size': len(expect2),
4720 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4721 'base/section2/blob:offset': 0,
4722 'base/section2/blob:size': len(COMPRESS_DATA),
4723 'base/section2/blob2:offset': len(COMPRESS_DATA),
4724 'base/section2/blob2:size': len(COMPRESS_DATA),
4730 self.assertEqual(expected, props)
4732 def testSymbolsSubsection(self):
4733 """Test binman can assign symbols from a subsection"""
4734 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
4736 def testReadImageEntryArg(self):
4737 """Test reading an image that would need an entry arg to generate"""
4739 'cros-ec-rw-path': 'ecrw.bin',
4741 data = self.data = self._DoReadFileDtb(
4742 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4743 entry_args=entry_args)
4745 image_fname = tools.get_output_filename('image.bin')
4746 orig_image = control.images['image']
4748 # This should not generate an error about the missing 'cros-ec-rw-path'
4749 # since we are reading the image from a file. Compare with
4750 # testEntryArgsRequired()
4751 image = Image.FromFile(image_fname)
4752 self.assertEqual(orig_image.GetEntries().keys(),
4753 image.GetEntries().keys())
4755 def testFilesAlign(self):
4756 """Test alignment with files"""
4757 data = self._DoReadFile('190_files_align.dts')
4759 # The first string is 15 bytes so will align to 16
4760 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4761 self.assertEqual(expect, data)
4763 def testReadImageSkip(self):
4764 """Test reading an image and accessing its FDT map"""
4765 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4766 image_fname = tools.get_output_filename('image.bin')
4767 orig_image = control.images['image']
4768 image = Image.FromFile(image_fname)
4769 self.assertEqual(orig_image.GetEntries().keys(),
4770 image.GetEntries().keys())
4772 orig_entry = orig_image.GetEntries()['fdtmap']
4773 entry = image.GetEntries()['fdtmap']
4774 self.assertEqual(orig_entry.offset, entry.offset)
4775 self.assertEqual(orig_entry.size, entry.size)
4776 self.assertEqual(16, entry.image_pos)
4778 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4780 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
4782 def testTplNoDtb(self):
4783 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4785 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4786 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4787 data[:len(U_BOOT_TPL_NODTB_DATA)])
4789 def testTplBssPad(self):
4790 """Test that we can pad TPL's BSS with zeros"""
4791 # ELF file with a '__bss_size' symbol
4793 data = self._DoReadFile('193_tpl_bss_pad.dts')
4794 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
4797 def testTplBssPadMissing(self):
4798 """Test that a missing symbol is detected"""
4799 self._SetupTplElf('u_boot_ucode_ptr')
4800 with self.assertRaises(ValueError) as e:
4801 self._DoReadFile('193_tpl_bss_pad.dts')
4802 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4805 def checkDtbSizes(self, data, pad_len, start):
4806 """Check the size arguments in a dtb embedded in an image
4809 data: The image data
4810 pad_len: Length of the pad section in the image, in bytes
4811 start: Start offset of the devicetree to examine, within the image
4814 Size of the devicetree in bytes
4816 dtb_data = data[start:]
4817 dtb = fdt.Fdt.FromData(dtb_data)
4818 fdt_size = dtb.GetFdtObj().totalsize()
4820 props = self._GetPropTree(dtb, 'size')
4823 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4824 'u-boot-spl/u-boot-spl-dtb:size': 801,
4825 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4826 'u-boot-spl:size': 860,
4827 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4828 'u-boot/u-boot-dtb:size': 781,
4829 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4834 def testExpanded(self):
4835 """Test that an expanded entry type is selected when needed"""
4839 # SPL has a devicetree, TPL does not
4845 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4846 entry_args=entry_args)
4847 image = control.images['image']
4848 entries = image.GetEntries()
4849 self.assertEqual(3, len(entries))
4851 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4852 self.assertIn('u-boot', entries)
4853 entry = entries['u-boot']
4854 self.assertEqual('u-boot-expanded', entry.etype)
4855 subent = entry.GetEntries()
4856 self.assertEqual(2, len(subent))
4857 self.assertIn('u-boot-nodtb', subent)
4858 self.assertIn('u-boot-dtb', subent)
4860 # Second, u-boot-spl, which should be expanded into three parts
4861 self.assertIn('u-boot-spl', entries)
4862 entry = entries['u-boot-spl']
4863 self.assertEqual('u-boot-spl-expanded', entry.etype)
4864 subent = entry.GetEntries()
4865 self.assertEqual(3, len(subent))
4866 self.assertIn('u-boot-spl-nodtb', subent)
4867 self.assertIn('u-boot-spl-bss-pad', subent)
4868 self.assertIn('u-boot-spl-dtb', subent)
4870 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4872 self.assertIn('u-boot-tpl', entries)
4873 entry = entries['u-boot-tpl']
4874 self.assertEqual('u-boot-tpl', entry.etype)
4875 self.assertEqual(None, entry.GetEntries())
4877 def testExpandedTpl(self):
4878 """Test that an expanded entry type is selected for TPL when needed"""
4885 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4886 entry_args=entry_args)
4887 image = control.images['image']
4888 entries = image.GetEntries()
4889 self.assertEqual(1, len(entries))
4891 # We only have u-boot-tpl, which be expanded
4892 self.assertIn('u-boot-tpl', entries)
4893 entry = entries['u-boot-tpl']
4894 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4895 subent = entry.GetEntries()
4896 self.assertEqual(3, len(subent))
4897 self.assertIn('u-boot-tpl-nodtb', subent)
4898 self.assertIn('u-boot-tpl-bss-pad', subent)
4899 self.assertIn('u-boot-tpl-dtb', subent)
4901 def testExpandedNoPad(self):
4902 """Test an expanded entry without BSS pad enabled"""
4906 # SPL has a devicetree, TPL does not
4908 'spl-dtb': 'something',
4912 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4913 entry_args=entry_args)
4914 image = control.images['image']
4915 entries = image.GetEntries()
4917 # Just check u-boot-spl, which should be expanded into two parts
4918 self.assertIn('u-boot-spl', entries)
4919 entry = entries['u-boot-spl']
4920 self.assertEqual('u-boot-spl-expanded', entry.etype)
4921 subent = entry.GetEntries()
4922 self.assertEqual(2, len(subent))
4923 self.assertIn('u-boot-spl-nodtb', subent)
4924 self.assertIn('u-boot-spl-dtb', subent)
4926 def testExpandedTplNoPad(self):
4927 """Test that an expanded entry type with padding disabled in TPL"""
4934 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4935 entry_args=entry_args)
4936 image = control.images['image']
4937 entries = image.GetEntries()
4938 self.assertEqual(1, len(entries))
4940 # We only have u-boot-tpl, which be expanded
4941 self.assertIn('u-boot-tpl', entries)
4942 entry = entries['u-boot-tpl']
4943 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4944 subent = entry.GetEntries()
4945 self.assertEqual(2, len(subent))
4946 self.assertIn('u-boot-tpl-nodtb', subent)
4947 self.assertIn('u-boot-tpl-dtb', subent)
4949 def testFdtInclude(self):
4950 """Test that an Fdt is update within all binaries"""
4954 # SPL has a devicetree, TPL does not
4961 # Build the image. It includes two separate devicetree binaries, each
4962 # with their own contents, but all contain the binman definition.
4963 data = self._DoReadFileDtb(
4964 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4965 update_dtb=True, entry_args=entry_args)[0]
4968 # Check the U-Boot dtb
4969 start = len(U_BOOT_NODTB_DATA)
4970 fdt_size = self.checkDtbSizes(data, pad_len, start)
4973 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4974 fdt_size = self.checkDtbSizes(data, pad_len, start)
4976 # TPL has no devicetree
4977 start += fdt_size + len(U_BOOT_TPL_DATA)
4978 self.assertEqual(len(data), start)
4980 def testSymbolsExpanded(self):
4981 """Test binman can assign symbols in expanded entries"""
4985 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4986 U_BOOT_SPL_DTB_DATA, 0x38,
4987 entry_args=entry_args, use_expanded=True)
4989 def testCollection(self):
4990 """Test a collection"""
4991 data = self._DoReadFile('198_collection.dts')
4992 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4993 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4994 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
4997 def testCollectionSection(self):
4998 """Test a collection where a section must be built first"""
4999 # Sections never have their contents when GetData() is called, but when
5000 # BuildSectionData() is called with required=True, a section will force
5001 # building the contents, producing an error is anything is still
5003 data = self._DoReadFile('199_collection_section.dts')
5004 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
5005 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5006 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
5009 def testAlignDefault(self):
5010 """Test that default alignment works on sections"""
5011 data = self._DoReadFile('200_align_default.dts')
5012 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
5014 # Special alignment for section
5015 expected += tools.get_bytes(0, 32 - len(expected))
5016 # No alignment within the nested section
5017 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5018 # Now the final piece, which should be default-aligned
5019 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
5020 self.assertEqual(expected, data)
5022 def testPackOpenSBI(self):
5023 """Test that an image with an OpenSBI binary can be created"""
5024 data = self._DoReadFile('201_opensbi.dts')
5025 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5027 def testSectionsSingleThread(self):
5028 """Test sections without multithreading"""
5029 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
5030 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5031 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5032 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
5033 self.assertEqual(expected, data)
5035 def testThreadTimeout(self):
5036 """Test handling a thread that takes too long"""
5037 with self.assertRaises(ValueError) as e:
5038 self._DoTestFile('202_section_timeout.dts',
5039 test_section_timeout=True)
5040 self.assertIn("Timed out obtaining contents", str(e.exception))
5042 def testTiming(self):
5043 """Test output of timing information"""
5044 data = self._DoReadFile('055_sections.dts')
5045 with test_util.capture_sys_output() as (stdout, stderr):
5047 self.assertIn('read:', stdout.getvalue())
5048 self.assertIn('compress:', stdout.getvalue())
5050 def testUpdateFdtInElf(self):
5051 """Test that we can update the devicetree in an ELF file"""
5052 if not elf.ELF_TOOLS:
5053 self.skipTest('Python elftools not available')
5054 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5055 outfile = os.path.join(self._indir, 'u-boot.out')
5056 begin_sym = 'dtb_embed_begin'
5057 end_sym = 'dtb_embed_end'
5058 retcode = self._DoTestFile(
5059 '060_fdt_update.dts', update_dtb=True,
5060 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5061 self.assertEqual(0, retcode)
5063 # Check that the output file does in fact contact a dtb with the binman
5064 # definition in the correct place
5065 syms = elf.GetSymbolFileOffset(infile,
5066 ['dtb_embed_begin', 'dtb_embed_end'])
5067 data = tools.read_file(outfile)
5068 dtb_data = data[syms['dtb_embed_begin'].offset:
5069 syms['dtb_embed_end'].offset]
5071 dtb = fdt.Fdt.FromData(dtb_data)
5073 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5077 '_testing:offset': 32,
5079 '_testing:image-pos': 32,
5080 'section@0/u-boot:offset': 0,
5081 'section@0/u-boot:size': len(U_BOOT_DATA),
5082 'section@0/u-boot:image-pos': 0,
5083 'section@0:offset': 0,
5084 'section@0:size': 16,
5085 'section@0:image-pos': 0,
5087 'section@1/u-boot:offset': 0,
5088 'section@1/u-boot:size': len(U_BOOT_DATA),
5089 'section@1/u-boot:image-pos': 16,
5090 'section@1:offset': 16,
5091 'section@1:size': 16,
5092 'section@1:image-pos': 16,
5096 def testUpdateFdtInElfInvalid(self):
5097 """Test that invalid args are detected with --update-fdt-in-elf"""
5098 with self.assertRaises(ValueError) as e:
5099 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5100 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5103 def testUpdateFdtInElfNoSyms(self):
5104 """Test that missing symbols are detected with --update-fdt-in-elf"""
5105 if not elf.ELF_TOOLS:
5106 self.skipTest('Python elftools not available')
5107 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5109 begin_sym = 'wrong_begin'
5110 end_sym = 'wrong_end'
5111 with self.assertRaises(ValueError) as e:
5113 '060_fdt_update.dts',
5114 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5115 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5118 def testUpdateFdtInElfTooSmall(self):
5119 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
5120 if not elf.ELF_TOOLS:
5121 self.skipTest('Python elftools not available')
5122 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5123 outfile = os.path.join(self._indir, 'u-boot.out')
5124 begin_sym = 'dtb_embed_begin'
5125 end_sym = 'dtb_embed_end'
5126 with self.assertRaises(ValueError) as e:
5128 '060_fdt_update.dts', update_dtb=True,
5129 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5132 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5134 def testVersion(self):
5135 """Test we can get the binman version"""
5136 version = '(unreleased)'
5137 self.assertEqual(version, state.GetVersion(self._indir))
5139 with self.assertRaises(SystemExit):
5140 with test_util.capture_sys_output() as (_, stderr):
5141 self._DoBinman('-V')
5142 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5144 # Try running the tool too, just to be safe
5145 result = self._RunBinman('-V')
5146 self.assertEqual('Binman %s\n' % version, result.stderr)
5148 # Set up a version file to make sure that works
5149 version = 'v2025.01-rc2'
5150 tools.write_file(os.path.join(self._indir, 'version'), version,
5152 self.assertEqual(version, state.GetVersion(self._indir))
5154 def testAltFormat(self):
5155 """Test that alternative formats can be used to extract"""
5156 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5159 tmpdir, updated_fname = self._SetupImageInTmpdir()
5160 with test_util.capture_sys_output() as (stdout, _):
5161 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5163 '''Flag (-F) Entry type Description
5164 fdt fdtmap Extract the devicetree blob from the fdtmap
5168 dtb = os.path.join(tmpdir, 'fdt.dtb')
5169 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5172 # Check that we can read it and it can be scanning, meaning it does
5173 # not have a 16-byte fdtmap header
5174 data = tools.read_file(dtb)
5175 dtb = fdt.Fdt.FromData(data)
5178 # Now check u-boot which has no alt_format
5179 fname = os.path.join(tmpdir, 'fdt.dtb')
5180 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5181 '-f', fname, 'u-boot')
5182 data = tools.read_file(fname)
5183 self.assertEqual(U_BOOT_DATA, data)
5186 shutil.rmtree(tmpdir)
5188 def testExtblobList(self):
5189 """Test an image with an external blob list"""
5190 data = self._DoReadFile('215_blob_ext_list.dts')
5191 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5193 def testExtblobListMissing(self):
5194 """Test an image with a missing external blob"""
5195 with self.assertRaises(ValueError) as e:
5196 self._DoReadFile('216_blob_ext_list_missing.dts')
5197 self.assertIn("Filename 'missing-file' not found in input path",
5200 def testExtblobListMissingOk(self):
5201 """Test an image with an missing external blob that is allowed"""
5202 with test_util.capture_sys_output() as (stdout, stderr):
5203 self._DoTestFile('216_blob_ext_list_missing.dts',
5205 err = stderr.getvalue()
5206 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
5209 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5210 data = self._DoReadFile('203_fip.dts')
5211 hdr, fents = fip_util.decode_fip(data)
5212 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5213 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5214 self.assertEqual(0x123, hdr.flags)
5216 self.assertEqual(2, len(fents))
5220 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5221 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5222 self.assertEqual('soc-fw', fent.fip_type)
5223 self.assertEqual(0x88, fent.offset)
5224 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5225 self.assertEqual(0x123456789abcdef, fent.flags)
5226 self.assertEqual(ATF_BL31_DATA, fent.data)
5227 self.assertEqual(True, fent.valid)
5231 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5232 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5233 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5234 self.assertEqual(0x8c, fent.offset)
5235 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5236 self.assertEqual(0, fent.flags)
5237 self.assertEqual(ATF_BL2U_DATA, fent.data)
5238 self.assertEqual(True, fent.valid)
5240 def testFipOther(self):
5241 """Basic FIP with something that isn't a external blob"""
5242 data = self._DoReadFile('204_fip_other.dts')
5243 hdr, fents = fip_util.decode_fip(data)
5245 self.assertEqual(2, len(fents))
5247 self.assertEqual('rot-cert', fent.fip_type)
5248 self.assertEqual(b'aa', fent.data)
5250 def testFipNoType(self):
5251 """FIP with an entry of an unknown type"""
5252 with self.assertRaises(ValueError) as e:
5253 self._DoReadFile('205_fip_no_type.dts')
5254 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5257 def testFipUuid(self):
5258 """Basic FIP with a manual uuid"""
5259 data = self._DoReadFile('206_fip_uuid.dts')
5260 hdr, fents = fip_util.decode_fip(data)
5262 self.assertEqual(2, len(fents))
5264 self.assertEqual(None, fent.fip_type)
5266 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5267 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5269 self.assertEqual(U_BOOT_DATA, fent.data)
5271 def testFipLs(self):
5272 """Test listing a FIP"""
5273 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5274 hdr, fents = fip_util.decode_fip(data)
5278 tmpdir, updated_fname = self._SetupImageInTmpdir()
5279 with test_util.capture_sys_output() as (stdout, stderr):
5280 self._DoBinman('ls', '-i', updated_fname)
5283 shutil.rmtree(tmpdir)
5284 lines = stdout.getvalue().splitlines()
5286 'Name Image-pos Size Entry-type Offset Uncomp-size',
5287 '--------------------------------------------------------------',
5288 'image 0 2d3 section 0',
5289 ' atf-fip 0 90 atf-fip 0',
5290 ' soc-fw 88 4 blob-ext 88',
5291 ' u-boot 8c 4 u-boot 8c',
5292 ' fdtmap 90 243 fdtmap 90',
5294 self.assertEqual(expected, lines)
5296 image = control.images['image']
5297 entries = image.GetEntries()
5298 fdtmap = entries['fdtmap']
5300 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5301 magic = fdtmap_data[:8]
5302 self.assertEqual(b'_FDTMAP_', magic)
5303 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
5305 fdt_data = fdtmap_data[16:]
5306 dtb = fdt.Fdt.FromData(fdt_data)
5308 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5310 'atf-fip/soc-fw:image-pos': 136,
5311 'atf-fip/soc-fw:offset': 136,
5312 'atf-fip/soc-fw:size': 4,
5313 'atf-fip/u-boot:image-pos': 140,
5314 'atf-fip/u-boot:offset': 140,
5315 'atf-fip/u-boot:size': 4,
5316 'atf-fip:image-pos': 0,
5317 'atf-fip:offset': 0,
5318 'atf-fip:size': 144,
5321 'fdtmap:image-pos': fdtmap.image_pos,
5322 'fdtmap:offset': fdtmap.offset,
5323 'fdtmap:size': len(fdtmap_data),
5327 def testFipExtractOneEntry(self):
5328 """Test extracting a single entry fron an FIP"""
5329 self._DoReadFileRealDtb('207_fip_ls.dts')
5330 image_fname = tools.get_output_filename('image.bin')
5331 fname = os.path.join(self._indir, 'output.extact')
5332 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
5333 data = tools.read_file(fname)
5334 self.assertEqual(U_BOOT_DATA, data)
5336 def testFipReplace(self):
5337 """Test replacing a single file in a FIP"""
5338 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
5339 data = self._DoReadFileRealDtb('208_fip_replace.dts')
5340 updated_fname = tools.get_output_filename('image-updated.bin')
5341 tools.write_file(updated_fname, data)
5342 entry_name = 'atf-fip/u-boot'
5343 control.WriteEntry(updated_fname, entry_name, expected,
5345 actual = control.ReadEntry(updated_fname, entry_name)
5346 self.assertEqual(expected, actual)
5348 new_data = tools.read_file(updated_fname)
5349 hdr, fents = fip_util.decode_fip(new_data)
5351 self.assertEqual(2, len(fents))
5353 # Check that the FIP entry is updated
5355 self.assertEqual(0x8c, fent.offset)
5356 self.assertEqual(len(expected), fent.size)
5357 self.assertEqual(0, fent.flags)
5358 self.assertEqual(expected, fent.data)
5359 self.assertEqual(True, fent.valid)
5361 def testFipMissing(self):
5362 with test_util.capture_sys_output() as (stdout, stderr):
5363 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5364 err = stderr.getvalue()
5365 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
5367 def testFipSize(self):
5368 """Test a FIP with a size property"""
5369 data = self._DoReadFile('210_fip_size.dts')
5370 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5371 hdr, fents = fip_util.decode_fip(data)
5372 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5373 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5375 self.assertEqual(1, len(fents))
5378 self.assertEqual('soc-fw', fent.fip_type)
5379 self.assertEqual(0x60, fent.offset)
5380 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5381 self.assertEqual(ATF_BL31_DATA, fent.data)
5382 self.assertEqual(True, fent.valid)
5384 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
5385 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
5387 def testFipBadAlign(self):
5388 """Test that an invalid alignment value in a FIP is detected"""
5389 with self.assertRaises(ValueError) as e:
5390 self._DoTestFile('211_fip_bad_align.dts')
5392 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5395 def testFipCollection(self):
5396 """Test using a FIP in a collection"""
5397 data = self._DoReadFile('212_fip_collection.dts')
5398 entry1 = control.images['image'].GetEntries()['collection']
5399 data1 = data[:entry1.size]
5400 hdr1, fents2 = fip_util.decode_fip(data1)
5402 entry2 = control.images['image'].GetEntries()['atf-fip']
5403 data2 = data[entry2.offset:entry2.offset + entry2.size]
5404 hdr1, fents2 = fip_util.decode_fip(data2)
5406 # The 'collection' entry should have U-Boot included at the end
5407 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5408 self.assertEqual(data1, data2 + U_BOOT_DATA)
5409 self.assertEqual(U_BOOT_DATA, data1[-4:])
5411 # There should be a U-Boot after the final FIP
5412 self.assertEqual(U_BOOT_DATA, data[-4:])
5414 def testFakeBlob(self):
5415 """Test handling of faking an external blob"""
5416 with test_util.capture_sys_output() as (stdout, stderr):
5417 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5418 allow_fake_blobs=True)
5419 err = stderr.getvalue()
5422 "Image '.*' has faked external blobs and is non-functional: .*")
5424 def testExtblobListFaked(self):
5425 """Test an extblob with missing external blob that are faked"""
5426 with test_util.capture_sys_output() as (stdout, stderr):
5427 self._DoTestFile('216_blob_ext_list_missing.dts',
5428 allow_fake_blobs=True)
5429 err = stderr.getvalue()
5430 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
5432 def testListBintools(self):
5433 args = ['tool', '--list']
5434 with test_util.capture_sys_output() as (stdout, _):
5435 self._DoBinman(*args)
5436 out = stdout.getvalue().splitlines()
5437 self.assertTrue(len(out) >= 2)
5439 def testFetchBintools(self):
5440 def fail_download(url):
5441 """Take the tools.download() function by raising an exception"""
5442 raise urllib.error.URLError('my error')
5445 with self.assertRaises(ValueError) as e:
5446 self._DoBinman(*args)
5447 self.assertIn("Invalid arguments to 'tool' subcommand",
5450 args = ['tool', '--fetch']
5451 with self.assertRaises(ValueError) as e:
5452 self._DoBinman(*args)
5453 self.assertIn('Please specify bintools to fetch', str(e.exception))
5455 args = ['tool', '--fetch', '_testing']
5456 with unittest.mock.patch.object(tools, 'download',
5457 side_effect=fail_download):
5458 with test_util.capture_sys_output() as (stdout, _):
5459 self._DoBinman(*args)
5460 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5462 def testBintoolDocs(self):
5463 """Test for creation of bintool documentation"""
5464 with test_util.capture_sys_output() as (stdout, stderr):
5465 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5466 self.assertTrue(len(stdout.getvalue()) > 0)
5468 def testBintoolDocsMissing(self):
5469 """Test handling of missing bintool documentation"""
5470 with self.assertRaises(ValueError) as e:
5471 with test_util.capture_sys_output() as (stdout, stderr):
5472 control.write_bintool_docs(
5473 control.bintool.Bintool.get_tool_list(), 'mkimage')
5474 self.assertIn('Documentation is missing for modules: mkimage',
5477 def testListWithGenNode(self):
5478 """Check handling of an FDT map when the section cannot be found"""
5480 'of-list': 'test-fdt1 test-fdt2',
5482 data = self._DoReadFileDtb(
5483 '219_fit_gennode.dts',
5484 entry_args=entry_args,
5486 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5490 tmpdir, updated_fname = self._SetupImageInTmpdir()
5491 with test_util.capture_sys_output() as (stdout, stderr):
5492 self._RunBinman('ls', '-i', updated_fname)
5495 shutil.rmtree(tmpdir)
5497 def testFitSubentryUsesBintool(self):
5498 """Test that binman FIT subentries can use bintools"""
5499 command.test_result = self._HandleGbbCommand
5501 'keydir': 'devkeys',
5502 'bmpblk': 'bmpblk.bin',
5504 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5505 entry_args=entry_args)
5507 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5508 tools.get_bytes(0, 0x2180 - 16))
5509 self.assertIn(expected, data)
5511 def testFitSubentryMissingBintool(self):
5512 """Test that binman reports missing bintools for FIT subentries"""
5514 'keydir': 'devkeys',
5516 with test_util.capture_sys_output() as (_, stderr):
5517 self._DoTestFile('220_fit_subentry_bintool.dts',
5518 force_missing_bintools='futility', entry_args=entry_args)
5519 err = stderr.getvalue()
5520 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
5522 def testFitSubentryHashSubnode(self):
5523 """Test an image with a FIT inside"""
5525 data, _, _, out_dtb_name = self._DoReadFileDtb(
5526 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5528 mkimage_dtb = fdt.Fdt.FromData(data)
5530 binman_dtb = fdt.Fdt(out_dtb_name)
5533 # Check that binman didn't add hash values
5534 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5535 self.assertNotIn('value', fnode.props)
5537 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5538 self.assertNotIn('value', fnode.props)
5540 # Check that mkimage added hash values
5541 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5542 self.assertIn('value', fnode.props)
5544 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5545 self.assertIn('value', fnode.props)
5547 def testPackTeeOs(self):
5548 """Test that an image with an TEE binary can be created"""
5549 data = self._DoReadFile('222_tee_os.dts')
5550 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5552 def testPackTiDm(self):
5553 """Test that an image with a TI DM binary can be created"""
5554 data = self._DoReadFile('225_ti_dm.dts')
5555 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5557 def testFitFdtOper(self):
5558 """Check handling of a specified FIT operation"""
5560 'of-list': 'test-fdt1 test-fdt2',
5561 'default-dt': 'test-fdt2',
5563 self._DoReadFileDtb(
5564 '223_fit_fdt_oper.dts',
5565 entry_args=entry_args,
5566 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5568 def testFitFdtBadOper(self):
5569 """Check handling of an FDT map when the section cannot be found"""
5570 with self.assertRaises(ValueError) as exc:
5571 self._DoReadFileDtb('224_fit_bad_oper.dts')
5572 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
5575 def test_uses_expand_size(self):
5576 """Test that the 'expand-size' property cannot be used anymore"""
5577 with self.assertRaises(ValueError) as e:
5578 data = self._DoReadFile('225_expand_size_bad.dts')
5580 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5583 def testFitSplitElf(self):
5584 """Test an image with an FIT with an split-elf operation"""
5585 if not elf.ELF_TOOLS:
5586 self.skipTest('Python elftools not available')
5588 'of-list': 'test-fdt1 test-fdt2',
5589 'default-dt': 'test-fdt2',
5590 'atf-bl31-path': 'bl31.elf',
5591 'tee-os-path': 'tee.elf',
5593 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5594 data = self._DoReadFileDtb(
5595 '226_fit_split_elf.dts',
5596 entry_args=entry_args,
5597 extra_indirs=[test_subdir])[0]
5599 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5600 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5602 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5604 dtb = fdt.Fdt.FromData(fit_data)
5607 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5608 segments, entry = elf.read_loadable_segments(elf_data)
5610 # We assume there are two segments
5611 self.assertEqual(2, len(segments))
5613 atf1 = dtb.GetNode('/images/atf-1')
5614 _, start, data = segments[0]
5615 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5616 self.assertEqual(entry,
5617 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5618 self.assertEqual(start,
5619 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5620 self.assertEqual(data, atf1.props['data'].bytes)
5622 hash_node = atf1.FindNode('hash')
5623 self.assertIsNotNone(hash_node)
5624 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5626 atf2 = dtb.GetNode('/images/atf-2')
5627 self.assertEqual(base_keys, atf2.props.keys())
5628 _, start, data = segments[1]
5629 self.assertEqual(start,
5630 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5631 self.assertEqual(data, atf2.props['data'].bytes)
5633 hash_node = atf2.FindNode('hash')
5634 self.assertIsNotNone(hash_node)
5635 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5637 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5638 self.assertIsNotNone(hash_node)
5639 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5641 conf = dtb.GetNode('/configurations')
5642 self.assertEqual({'default'}, conf.props.keys())
5644 for subnode in conf.subnodes:
5645 self.assertEqual({'description', 'fdt', 'loadables'},
5646 subnode.props.keys())
5648 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5649 fdt_util.GetStringList(subnode, 'loadables'))
5651 def _check_bad_fit(self, dts):
5654 This runs with the given dts and returns the assertion raised
5657 dts (str): dts filename to use
5660 str: Assertion string raised
5663 'of-list': 'test-fdt1 test-fdt2',
5664 'default-dt': 'test-fdt2',
5665 'atf-bl31-path': 'bl31.elf',
5666 'tee-os-path': 'tee.elf',
5668 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5669 with self.assertRaises(ValueError) as exc:
5670 self._DoReadFileDtb(dts, entry_args=entry_args,
5671 extra_indirs=[test_subdir])[0]
5672 return str(exc.exception)
5674 def testFitSplitElfBadElf(self):
5675 """Test a FIT split-elf operation with an invalid ELF file"""
5676 if not elf.ELF_TOOLS:
5677 self.skipTest('Python elftools not available')
5678 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5680 'of-list': 'test-fdt1 test-fdt2',
5681 'default-dt': 'test-fdt2',
5682 'atf-bl31-path': 'bad.elf',
5683 'tee-os-path': 'tee.elf',
5685 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5686 with self.assertRaises(ValueError) as exc:
5687 self._DoReadFileDtb(
5688 '226_fit_split_elf.dts',
5689 entry_args=entry_args,
5690 extra_indirs=[test_subdir])[0]
5692 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5695 def checkFitSplitElf(self, **kwargs):
5696 """Test an split-elf FIT with a missing ELF file
5699 kwargs (dict of str): Arguments to pass to _DoTestFile()
5707 'of-list': 'test-fdt1 test-fdt2',
5708 'default-dt': 'test-fdt2',
5709 'atf-bl31-path': 'bl31.elf',
5710 'tee-os-path': 'missing.elf',
5712 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5713 with test_util.capture_sys_output() as (stdout, stderr):
5715 '226_fit_split_elf.dts', entry_args=entry_args,
5716 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5717 out = stdout.getvalue()
5718 err = stderr.getvalue()
5721 def testFitSplitElfBadDirective(self):
5722 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5723 if not elf.ELF_TOOLS:
5724 self.skipTest('Python elftools not available')
5725 err = self._check_bad_fit('227_fit_bad_dir.dts')
5727 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5730 def testFitSplitElfBadDirectiveConfig(self):
5731 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5732 if not elf.ELF_TOOLS:
5733 self.skipTest('Python elftools not available')
5734 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5736 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5740 def testFitSplitElfMissing(self):
5741 """Test an split-elf FIT with a missing ELF file"""
5742 if not elf.ELF_TOOLS:
5743 self.skipTest('Python elftools not available')
5744 out, err = self.checkFitSplitElf(allow_missing=True)
5747 "Image '.*' is missing external blobs and is non-functional: .*")
5748 self.assertNotRegex(out, '.*Faked blob.*')
5749 fname = tools.get_output_filename('binman-fake/missing.elf')
5750 self.assertFalse(os.path.exists(fname))
5752 def testFitSplitElfFaked(self):
5753 """Test an split-elf FIT with faked ELF file"""
5754 if not elf.ELF_TOOLS:
5755 self.skipTest('Python elftools not available')
5756 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
5759 "Image '.*' is missing external blobs and is non-functional: .*")
5762 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5763 fname = tools.get_output_filename('binman-fake/missing.elf')
5764 self.assertTrue(os.path.exists(fname))
5766 def testMkimageMissingBlob(self):
5767 """Test using mkimage to build an image"""
5768 with test_util.capture_sys_output() as (stdout, stderr):
5769 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5770 allow_fake_blobs=True)
5771 err = stderr.getvalue()
5774 "Image '.*' has faked external blobs and is non-functional: .*")
5776 def testPreLoad(self):
5777 """Test an image with a pre-load header"""
5779 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5781 data = self._DoReadFileDtb(
5782 '230_pre_load.dts', entry_args=entry_args,
5783 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
5784 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5785 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5786 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5788 def testPreLoadNoKey(self):
5789 """Test an image with a pre-load heade0r with missing key"""
5790 with self.assertRaises(FileNotFoundError) as exc:
5791 self._DoReadFile('230_pre_load.dts')
5792 self.assertIn("No such file or directory: 'dev.key'",
5795 def testPreLoadPkcs(self):
5796 """Test an image with a pre-load header with padding pkcs"""
5798 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5800 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5801 entry_args=entry_args)[0]
5802 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5803 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5804 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5806 def testPreLoadPss(self):
5807 """Test an image with a pre-load header with padding pss"""
5809 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5811 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5812 entry_args=entry_args)[0]
5813 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5814 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5815 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5817 def testPreLoadInvalidPadding(self):
5818 """Test an image with a pre-load header with an invalid padding"""
5820 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5822 with self.assertRaises(ValueError) as e:
5823 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5824 entry_args=entry_args)
5826 def testPreLoadInvalidSha(self):
5827 """Test an image with a pre-load header with an invalid hash"""
5829 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5831 with self.assertRaises(ValueError) as e:
5832 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5833 entry_args=entry_args)
5835 def testPreLoadInvalidAlgo(self):
5836 """Test an image with a pre-load header with an invalid algo"""
5837 with self.assertRaises(ValueError) as e:
5838 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
5840 def testPreLoadInvalidKey(self):
5841 """Test an image with a pre-load header with an invalid key"""
5843 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5845 with self.assertRaises(ValueError) as e:
5846 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5847 entry_args=entry_args)
5849 def _CheckSafeUniqueNames(self, *images):
5850 """Check all entries of given images for unsafe unique names"""
5851 for image in images:
5853 image._CollectEntries(entries, {}, image)
5854 for entry in entries.values():
5855 uniq = entry.GetUniqueName()
5857 # Used as part of a filename, so must not be absolute paths.
5858 self.assertFalse(os.path.isabs(uniq))
5860 def testSafeUniqueNames(self):
5861 """Test entry unique names are safe in single image configuration"""
5862 data = self._DoReadFileRealDtb('237_unique_names.dts')
5864 orig_image = control.images['image']
5865 image_fname = tools.get_output_filename('image.bin')
5866 image = Image.FromFile(image_fname)
5868 self._CheckSafeUniqueNames(orig_image, image)
5870 def testSafeUniqueNamesMulti(self):
5871 """Test entry unique names are safe with multiple images"""
5872 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
5874 orig_image = control.images['image']
5875 image_fname = tools.get_output_filename('image.bin')
5876 image = Image.FromFile(image_fname)
5878 self._CheckSafeUniqueNames(orig_image, image)
5880 def testReplaceCmdWithBintool(self):
5881 """Test replacing an entry that needs a bintool to pack"""
5882 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
5883 expected = U_BOOT_DATA + b'aa'
5884 self.assertEqual(expected, data[:len(expected)])
5887 tmpdir, updated_fname = self._SetupImageInTmpdir()
5888 fname = os.path.join(tmpdir, 'update-testing.bin')
5889 tools.write_file(fname, b'zz')
5890 self._DoBinman('replace', '-i', updated_fname,
5891 '_testing', '-f', fname)
5893 data = tools.read_file(updated_fname)
5894 expected = U_BOOT_DATA + b'zz'
5895 self.assertEqual(expected, data[:len(expected)])
5897 shutil.rmtree(tmpdir)
5899 def testReplaceCmdOtherWithBintool(self):
5900 """Test replacing an entry when another needs a bintool to pack"""
5901 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
5902 expected = U_BOOT_DATA + b'aa'
5903 self.assertEqual(expected, data[:len(expected)])
5906 tmpdir, updated_fname = self._SetupImageInTmpdir()
5907 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5908 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5909 self._DoBinman('replace', '-i', updated_fname,
5910 'u-boot', '-f', fname)
5912 data = tools.read_file(updated_fname)
5913 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5914 self.assertEqual(expected, data[:len(expected)])
5916 shutil.rmtree(tmpdir)
5918 def testReplaceResizeNoRepackSameSize(self):
5919 """Test replacing entries with same-size data without repacking"""
5920 expected = b'x' * len(U_BOOT_DATA)
5921 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5922 self.assertEqual(expected, data)
5924 path, fdtmap = state.GetFdtContents('fdtmap')
5925 self.assertIsNotNone(path)
5926 self.assertEqual(expected_fdtmap, fdtmap)
5928 def testReplaceResizeNoRepackSmallerSize(self):
5929 """Test replacing entries with smaller-size data without repacking"""
5931 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5932 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5933 self.assertEqual(expected, data)
5935 path, fdtmap = state.GetFdtContents('fdtmap')
5936 self.assertIsNotNone(path)
5937 self.assertEqual(expected_fdtmap, fdtmap)
5939 def testExtractFit(self):
5940 """Test extracting a FIT section"""
5941 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
5942 image_fname = tools.get_output_filename('image.bin')
5944 fit_data = control.ReadEntry(image_fname, 'fit')
5945 fit = fdt.Fdt.FromData(fit_data)
5948 # Check subentry data inside the extracted fit
5949 for node_path, expected in [
5950 ('/images/kernel', U_BOOT_DATA),
5951 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5952 ('/images/scr-1', COMPRESS_DATA),
5954 node = fit.GetNode(node_path)
5955 data = fit.GetProps(node)['data'].bytes
5956 self.assertEqual(expected, data)
5958 def testExtractFitSubentries(self):
5959 """Test extracting FIT section subentries"""
5960 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
5961 image_fname = tools.get_output_filename('image.bin')
5963 for entry_path, expected in [
5964 ('fit/kernel', U_BOOT_DATA),
5965 ('fit/kernel/u-boot', U_BOOT_DATA),
5966 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5967 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5968 ('fit/scr-1', COMPRESS_DATA),
5969 ('fit/scr-1/blob', COMPRESS_DATA),
5971 data = control.ReadEntry(image_fname, entry_path)
5972 self.assertEqual(expected, data)
5974 def testReplaceFitSubentryLeafSameSize(self):
5975 """Test replacing a FIT leaf subentry with same-size data"""
5976 new_data = b'x' * len(U_BOOT_DATA)
5977 data, expected_fdtmap, _ = self._RunReplaceCmd(
5978 'fit/kernel/u-boot', new_data,
5979 dts='240_fit_extract_replace.dts')
5980 self.assertEqual(new_data, data)
5982 path, fdtmap = state.GetFdtContents('fdtmap')
5983 self.assertIsNotNone(path)
5984 self.assertEqual(expected_fdtmap, fdtmap)
5986 def testReplaceFitSubentryLeafBiggerSize(self):
5987 """Test replacing a FIT leaf subentry with bigger-size data"""
5988 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5989 data, expected_fdtmap, _ = self._RunReplaceCmd(
5990 'fit/fdt-1/u-boot-nodtb', new_data,
5991 dts='240_fit_extract_replace.dts')
5992 self.assertEqual(new_data, data)
5994 # Will be repacked, so fdtmap must change
5995 path, fdtmap = state.GetFdtContents('fdtmap')
5996 self.assertIsNotNone(path)
5997 self.assertNotEqual(expected_fdtmap, fdtmap)
5999 def testReplaceFitSubentryLeafSmallerSize(self):
6000 """Test replacing a FIT leaf subentry with smaller-size data"""
6002 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6003 data, expected_fdtmap, _ = self._RunReplaceCmd(
6004 'fit/fdt-1/u-boot-nodtb', new_data,
6005 dts='240_fit_extract_replace.dts')
6006 self.assertEqual(expected, data)
6008 path, fdtmap = state.GetFdtContents('fdtmap')
6009 self.assertIsNotNone(path)
6010 self.assertEqual(expected_fdtmap, fdtmap)
6012 def testReplaceSectionSimple(self):
6013 """Test replacing a simple section with same-sized data"""
6014 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
6015 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6016 new_data, dts='241_replace_section_simple.dts')
6017 self.assertEqual(new_data, data)
6019 entries = image.GetEntries()
6020 self.assertIn('section', entries)
6021 entry = entries['section']
6022 self.assertEqual(len(new_data), entry.size)
6024 def testReplaceSectionLarger(self):
6025 """Test replacing a simple section with larger data"""
6026 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6027 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6028 new_data, dts='241_replace_section_simple.dts')
6029 self.assertEqual(new_data, data)
6031 entries = image.GetEntries()
6032 self.assertIn('section', entries)
6033 entry = entries['section']
6034 self.assertEqual(len(new_data), entry.size)
6035 fentry = entries['fdtmap']
6036 self.assertEqual(entry.offset + entry.size, fentry.offset)
6038 def testReplaceSectionSmaller(self):
6039 """Test replacing a simple section with smaller data"""
6040 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6041 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6042 new_data, dts='241_replace_section_simple.dts')
6043 self.assertEqual(new_data, data)
6045 # The new size is the same as the old, just with a pad byte at the end
6046 entries = image.GetEntries()
6047 self.assertIn('section', entries)
6048 entry = entries['section']
6049 self.assertEqual(len(new_data), entry.size)
6051 def testReplaceSectionSmallerAllow(self):
6052 """Test failing to replace a simple section with smaller data"""
6053 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6055 state.SetAllowEntryContraction(True)
6056 with self.assertRaises(ValueError) as exc:
6057 self._RunReplaceCmd('section', new_data,
6058 dts='241_replace_section_simple.dts')
6060 state.SetAllowEntryContraction(False)
6062 # Since we have no information about the position of things within the
6063 # section, we cannot adjust the position of /section-u-boot so it ends
6064 # up outside the section
6066 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6067 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
6070 def testMkimageImagename(self):
6071 """Test using mkimage with -n holding the data too"""
6073 data = self._DoReadFile('242_mkimage_name.dts')
6075 # Check that the data appears in the file somewhere
6076 self.assertIn(U_BOOT_SPL_DATA, data)
6078 # Get struct legacy_img_hdr -> ih_name
6079 name = data[0x20:0x40]
6081 # Build the filename that we expect to be placed in there, by virtue of
6083 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6085 # Check that the image name is set to the temporary filename used
6086 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6088 def testMkimageImage(self):
6089 """Test using mkimage with -n holding the data too"""
6091 data = self._DoReadFile('243_mkimage_image.dts')
6093 # Check that the data appears in the file somewhere
6094 self.assertIn(U_BOOT_SPL_DATA, data)
6096 # Get struct legacy_img_hdr -> ih_name
6097 name = data[0x20:0x40]
6099 # Build the filename that we expect to be placed in there, by virtue of
6101 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6103 # Check that the image name is set to the temporary filename used
6104 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6106 # Check the corect data is in the imagename file
6107 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6109 def testMkimageImageNoContent(self):
6110 """Test using mkimage with -n and no data"""
6112 with self.assertRaises(ValueError) as exc:
6113 self._DoReadFile('244_mkimage_image_no_content.dts')
6114 self.assertIn('Could not complete processing of contents',
6117 def testMkimageImageBad(self):
6118 """Test using mkimage with imagename node and data-to-imagename"""
6120 with self.assertRaises(ValueError) as exc:
6121 self._DoReadFile('245_mkimage_image_bad.dts')
6122 self.assertIn('Cannot use both imagename node and data-to-imagename',
6125 def testCollectionOther(self):
6126 """Test a collection where the data comes from another section"""
6127 data = self._DoReadFile('246_collection_other.dts')
6128 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6129 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6130 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6133 def testMkimageCollection(self):
6134 """Test using a collection referring to an entry in a mkimage entry"""
6136 data = self._DoReadFile('247_mkimage_coll.dts')
6137 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6138 self.assertEqual(expect, data[:len(expect)])
6140 def testCompressDtbPrependInvalid(self):
6141 """Test that invalid header is detected"""
6142 with self.assertRaises(ValueError) as e:
6143 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
6144 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6145 "'u-boot-dtb': 'invalid'", str(e.exception))
6147 def testCompressDtbPrependLength(self):
6148 """Test that compress with length header works as expected"""
6149 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
6150 image = control.images['image']
6151 entries = image.GetEntries()
6152 self.assertIn('u-boot-dtb', entries)
6153 u_boot_dtb = entries['u-boot-dtb']
6154 self.assertIn('fdtmap', entries)
6155 fdtmap = entries['fdtmap']
6157 image_fname = tools.get_output_filename('image.bin')
6158 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6159 dtb = fdt.Fdt.FromData(orig)
6161 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6163 'u-boot:size': len(U_BOOT_DATA),
6164 'u-boot-dtb:uncomp-size': len(orig),
6165 'u-boot-dtb:size': u_boot_dtb.size,
6166 'fdtmap:size': fdtmap.size,
6169 self.assertEqual(expected, props)
6171 # Check implementation
6172 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6173 rest = data[len(U_BOOT_DATA):]
6174 comp_data_len = struct.unpack('<I', rest[:4])[0]
6175 comp_data = rest[4:4 + comp_data_len]
6176 orig2 = self._decompress(comp_data)
6177 self.assertEqual(orig, orig2)
6179 def testInvalidCompress(self):
6180 """Test that invalid compress algorithm is detected"""
6181 with self.assertRaises(ValueError) as e:
6182 self._DoTestFile('250_compress_dtb_invalid.dts')
6183 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6185 def testCompUtilCompressions(self):
6186 """Test compression algorithms"""
6187 for bintool in self.comp_bintools.values():
6188 self._CheckBintool(bintool)
6189 data = bintool.compress(COMPRESS_DATA)
6190 self.assertNotEqual(COMPRESS_DATA, data)
6191 orig = bintool.decompress(data)
6192 self.assertEqual(COMPRESS_DATA, orig)
6194 def testCompUtilVersions(self):
6195 """Test tool version of compression algorithms"""
6196 for bintool in self.comp_bintools.values():
6197 self._CheckBintool(bintool)
6198 version = bintool.version()
6199 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6201 def testCompUtilPadding(self):
6202 """Test padding of compression algorithms"""
6203 # Skip zstd because it doesn't support padding
6204 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
6205 self._CheckBintool(bintool)
6206 data = bintool.compress(COMPRESS_DATA)
6207 self.assertNotEqual(COMPRESS_DATA, data)
6208 data += tools.get_bytes(0, 64)
6209 orig = bintool.decompress(data)
6210 self.assertEqual(COMPRESS_DATA, orig)
6212 def testCompressDtbZstd(self):
6213 """Test that zstd compress of device-tree files failed"""
6214 with self.assertRaises(ValueError) as e:
6215 self._DoTestFile('251_compress_dtb_zstd.dts')
6216 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6217 "requires a length header", str(e.exception))
6219 def testMkimageMultipleDataFiles(self):
6220 """Test passing multiple files to mkimage in a mkimage entry"""
6223 data = self._DoReadFile('252_mkimage_mult_data.dts')
6224 # Size of files are packed in their 4B big-endian format
6225 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6226 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6227 # Size info is always followed by a 4B zero value.
6228 expect += tools.get_bytes(0, 4)
6229 expect += U_BOOT_TPL_DATA
6230 # All but last files are 4B-aligned
6231 align_pad = len(U_BOOT_TPL_DATA) % 4
6233 expect += tools.get_bytes(0, align_pad)
6234 expect += U_BOOT_SPL_DATA
6235 self.assertEqual(expect, data[-len(expect):])
6237 def testMkimageMultipleExpanded(self):
6238 """Test passing multiple files to mkimage in a mkimage entry"""
6245 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6246 use_expanded=True, entry_args=entry_args)[0]
6248 tpl_expect = U_BOOT_TPL_DATA
6249 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6250 spl_expect += U_BOOT_SPL_DTB_DATA
6252 content = data[0x40:]
6253 lens = struct.unpack('>III', content[:12])
6255 # Size of files are packed in their 4B big-endian format
6256 # Size info is always followed by a 4B zero value.
6257 self.assertEqual(len(tpl_expect), lens[0])
6258 self.assertEqual(len(spl_expect), lens[1])
6259 self.assertEqual(0, lens[2])
6262 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6264 rest = rest[len(tpl_expect):]
6265 align_pad = len(tpl_expect) % 4
6266 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6267 rest = rest[align_pad:]
6268 self.assertEqual(spl_expect, rest)
6270 def testMkimageMultipleNoContent(self):
6271 """Test passing multiple data files to mkimage with one data file having no content"""
6273 with self.assertRaises(ValueError) as exc:
6274 self._DoReadFile('253_mkimage_mult_no_content.dts')
6275 self.assertIn('Could not complete processing of contents',
6278 def testMkimageFilename(self):
6279 """Test using mkimage to build a binary with a filename"""
6281 retcode = self._DoTestFile('254_mkimage_filename.dts')
6282 self.assertEqual(0, retcode)
6283 fname = tools.get_output_filename('mkimage-test.bin')
6284 self.assertTrue(os.path.exists(fname))
6287 """Test that an image with VPL and its device tree can be created"""
6288 # ELF file with a '__bss_size' symbol
6290 data = self._DoReadFile('255_u_boot_vpl.dts')
6291 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6293 def testVplNoDtb(self):
6294 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6296 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6297 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6298 data[:len(U_BOOT_VPL_NODTB_DATA)])
6300 def testExpandedVpl(self):
6301 """Test that an expanded entry type is selected for TPL when needed"""
6308 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6309 entry_args=entry_args)
6310 image = control.images['image']
6311 entries = image.GetEntries()
6312 self.assertEqual(1, len(entries))
6314 # We only have u-boot-vpl, which be expanded
6315 self.assertIn('u-boot-vpl', entries)
6316 entry = entries['u-boot-vpl']
6317 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6318 subent = entry.GetEntries()
6319 self.assertEqual(3, len(subent))
6320 self.assertIn('u-boot-vpl-nodtb', subent)
6321 self.assertIn('u-boot-vpl-bss-pad', subent)
6322 self.assertIn('u-boot-vpl-dtb', subent)
6324 def testVplBssPadMissing(self):
6325 """Test that a missing symbol is detected"""
6326 self._SetupVplElf('u_boot_ucode_ptr')
6327 with self.assertRaises(ValueError) as e:
6328 self._DoReadFile('258_vpl_bss_pad.dts')
6329 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6332 def testSymlink(self):
6333 """Test that image files can be symlinked"""
6334 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6335 self.assertEqual(0, retcode)
6336 image = control.images['test_image']
6337 fname = tools.get_output_filename('test_image.bin')
6338 sname = tools.get_output_filename('symlink_to_test.bin')
6339 self.assertTrue(os.path.islink(sname))
6340 self.assertEqual(os.readlink(sname), fname)
6342 def testSymlinkOverwrite(self):
6343 """Test that symlinked images can be overwritten"""
6344 testdir = TestFunctional._MakeInputDir('symlinktest')
6345 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6346 # build the same image again in the same directory so that existing symlink is present
6347 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6348 fname = tools.get_output_filename('test_image.bin')
6349 sname = tools.get_output_filename('symlink_to_test.bin')
6350 self.assertTrue(os.path.islink(sname))
6351 self.assertEqual(os.readlink(sname), fname)
6353 def testSymbolsElf(self):
6354 """Test binman can assign symbols embedded in an ELF file"""
6355 if not elf.ELF_TOOLS:
6356 self.skipTest('Python elftools not available')
6357 self._SetupTplElf('u_boot_binman_syms')
6358 self._SetupVplElf('u_boot_binman_syms')
6359 self._SetupSplElf('u_boot_binman_syms')
6360 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6361 image_fname = tools.get_output_filename('image.bin')
6363 image = control.images['image']
6364 entries = image.GetEntries()
6366 for entry in entries.values():
6367 # No symbols in u-boot and it has faked contents anyway
6368 if entry.name == 'u-boot':
6370 edata = data[entry.image_pos:entry.image_pos + entry.size]
6371 efname = tools.get_output_filename(f'edata-{entry.name}')
6372 tools.write_file(efname, edata)
6374 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6375 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6376 for name, sym in syms.items():
6378 val = elf.GetSymbolValue(sym, edata, msg)
6379 entry_m = re_name.match(name)
6381 ename, prop = entry_m.group(1), entry_m.group(3)
6382 entry, entry_name, prop_name = image.LookupEntry(entries,
6384 if prop_name == 'offset':
6385 expect_val = entry.offset
6386 elif prop_name == 'image_pos':
6387 expect_val = entry.image_pos
6388 elif prop_name == 'size':
6389 expect_val = entry.size
6390 self.assertEqual(expect_val, val)
6392 def testSymbolsElfBad(self):
6393 """Check error when trying to write symbols without the elftools lib"""
6394 if not elf.ELF_TOOLS:
6395 self.skipTest('Python elftools not available')
6396 self._SetupTplElf('u_boot_binman_syms')
6397 self._SetupVplElf('u_boot_binman_syms')
6398 self._SetupSplElf('u_boot_binman_syms')
6400 elf.ELF_TOOLS = False
6401 with self.assertRaises(ValueError) as exc:
6402 self._DoReadFileDtb('260_symbols_elf.dts')
6404 elf.ELF_TOOLS = True
6406 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6407 'Cannot write symbols to an ELF file without Python elftools',
6410 def testSectionFilename(self):
6411 """Check writing of section contents to a file"""
6412 data = self._DoReadFile('261_section_fname.dts')
6413 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6414 tools.get_bytes(ord('!'), 7) +
6415 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6416 self.assertEqual(expected, data)
6418 sect_fname = tools.get_output_filename('outfile.bin')
6419 self.assertTrue(os.path.exists(sect_fname))
6420 sect_data = tools.read_file(sect_fname)
6421 self.assertEqual(U_BOOT_DATA, sect_data)
6423 def testAbsent(self):
6424 """Check handling of absent entries"""
6425 data = self._DoReadFile('262_absent.dts')
6426 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6428 def testPackTeeOsOptional(self):
6429 """Test that an image with an optional TEE binary can be created"""
6431 'tee-os-path': 'tee.elf',
6433 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6434 entry_args=entry_args)[0]
6435 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6437 def checkFitTee(self, dts, tee_fname):
6438 """Check that a tee-os entry works and returns data
6441 dts (str): Device tree filename to use
6442 tee_fname (str): filename containing tee-os
6445 bytes: Image contents
6447 if not elf.ELF_TOOLS:
6448 self.skipTest('Python elftools not available')
6450 'of-list': 'test-fdt1 test-fdt2',
6451 'default-dt': 'test-fdt2',
6452 'tee-os-path': tee_fname,
6454 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6455 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6456 extra_indirs=[test_subdir])[0]
6459 def testFitTeeOsOptionalFit(self):
6460 """Test an image with a FIT with an optional OP-TEE binary"""
6461 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6463 # There should be only one node, holding the data set up in SetUpClass()
6465 dtb = fdt.Fdt.FromData(data)
6467 node = dtb.GetNode('/images/tee-1')
6468 self.assertEqual(TEE_ADDR,
6469 fdt_util.fdt32_to_cpu(node.props['load'].value))
6470 self.assertEqual(TEE_ADDR,
6471 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6472 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6474 with test_util.capture_sys_output() as (stdout, stderr):
6475 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6476 err = stderr.getvalue()
6479 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6481 def testFitTeeOsOptionalFitBad(self):
6482 """Test an image with a FIT with an optional OP-TEE binary"""
6483 with self.assertRaises(ValueError) as exc:
6484 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6486 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6489 def testFitTeeOsBad(self):
6490 """Test an OP-TEE binary with wrong formats"""
6491 self.make_tee_bin('tee.bad1', 123)
6492 with self.assertRaises(ValueError) as exc:
6493 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6495 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6498 self.make_tee_bin('tee.bad2', 0, b'extra data')
6499 with self.assertRaises(ValueError) as exc:
6500 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6502 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6505 def testExtblobOptional(self):
6506 """Test an image with an external blob that is optional"""
6507 with test_util.capture_sys_output() as (stdout, stderr):
6508 data = self._DoReadFile('266_blob_ext_opt.dts')
6509 self.assertEqual(REFCODE_DATA, data)
6510 err = stderr.getvalue()
6513 "Image '.*' is missing optional external blobs but is still functional: missing")
6515 def testSectionInner(self):
6516 """Test an inner section with a size"""
6517 data = self._DoReadFile('267_section_inner.dts')
6518 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6519 self.assertEqual(expected, data)
6522 """Test an image with a null entry"""
6523 data = self._DoReadFile('268_null.dts')
6524 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6526 def testOverlap(self):
6527 """Test an image with a overlapping entry"""
6528 data = self._DoReadFile('269_overlap.dts')
6529 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6531 image = control.images['image']
6532 entries = image.GetEntries()
6534 self.assertIn('inset', entries)
6535 inset = entries['inset']
6536 self.assertEqual(1, inset.offset);
6537 self.assertEqual(1, inset.image_pos);
6538 self.assertEqual(2, inset.size);
6540 def testOverlapNull(self):
6541 """Test an image with a null overlap"""
6542 data = self._DoReadFile('270_overlap_null.dts')
6543 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6546 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6547 self.assertEqual(4, fhdr.nareas)
6548 fiter = iter(fentries)
6550 fentry = next(fiter)
6551 self.assertEqual(b'SECTION', fentry.name)
6552 self.assertEqual(0, fentry.offset)
6553 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6554 self.assertEqual(0, fentry.flags)
6556 fentry = next(fiter)
6557 self.assertEqual(b'U_BOOT', fentry.name)
6558 self.assertEqual(0, fentry.offset)
6559 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6560 self.assertEqual(0, fentry.flags)
6562 # Make sure that the NULL entry appears in the FMAP
6563 fentry = next(fiter)
6564 self.assertEqual(b'NULL', fentry.name)
6565 self.assertEqual(1, fentry.offset)
6566 self.assertEqual(2, fentry.size)
6567 self.assertEqual(0, fentry.flags)
6569 fentry = next(fiter)
6570 self.assertEqual(b'FMAP', fentry.name)
6571 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6573 def testOverlapBad(self):
6574 """Test an image with a bad overlapping entry"""
6575 with self.assertRaises(ValueError) as exc:
6576 self._DoReadFile('271_overlap_bad.dts')
6578 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6581 def testOverlapNoOffset(self):
6582 """Test an image with a bad overlapping entry"""
6583 with self.assertRaises(ValueError) as exc:
6584 self._DoReadFile('272_overlap_no_size.dts')
6586 "Node '/binman/inset': 'fill' entry is missing properties: size",
6589 def testBlobSymbol(self):
6590 """Test a blob with symbols read from an ELF file"""
6591 elf_fname = self.ElfTestFile('blob_syms')
6592 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6593 TestFunctional._MakeInputFile('blob_syms.bin',
6594 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6596 data = self._DoReadFile('273_blob_symbol.dts')
6598 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6599 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6600 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6601 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6602 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6604 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6605 expected = sym_values
6606 self.assertEqual(expected, data[:len(expected)])
6608 def testOffsetFromElf(self):
6609 """Test a blob with symbols read from an ELF file"""
6610 elf_fname = self.ElfTestFile('blob_syms')
6611 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6612 TestFunctional._MakeInputFile('blob_syms.bin',
6613 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6615 data = self._DoReadFile('274_offset_from_elf.dts')
6617 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6618 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6620 image = control.images['image']
6621 entries = image.GetEntries()
6623 self.assertIn('inset', entries)
6624 inset = entries['inset']
6626 self.assertEqual(base + 4, inset.offset);
6627 self.assertEqual(base + 4, inset.image_pos);
6628 self.assertEqual(4, inset.size);
6630 self.assertIn('inset2', entries)
6631 inset = entries['inset2']
6632 self.assertEqual(base + 8, inset.offset);
6633 self.assertEqual(base + 8, inset.image_pos);
6634 self.assertEqual(4, inset.size);
6636 def testFitAlign(self):
6637 """Test an image with an FIT with aligned external data"""
6638 data = self._DoReadFile('275_fit_align.dts')
6639 self.assertEqual(4096, len(data))
6641 dtb = fdt.Fdt.FromData(data)
6644 props = self._GetPropTree(dtb, ['data-position'])
6646 'u-boot:data-position': 1024,
6647 'fdt-1:data-position': 2048,
6648 'fdt-2:data-position': 3072,
6650 self.assertEqual(expected, props)
6652 def testFitFirmwareLoadables(self):
6653 """Test an image with an FIT that use fit,firmware"""
6654 if not elf.ELF_TOOLS:
6655 self.skipTest('Python elftools not available')
6657 'of-list': 'test-fdt1',
6658 'default-dt': 'test-fdt1',
6659 'atf-bl31-path': 'bl31.elf',
6660 'tee-os-path': 'missing.bin',
6662 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6663 with test_util.capture_sys_output() as (stdout, stderr):
6664 data = self._DoReadFileDtb(
6665 '276_fit_firmware_loadables.dts',
6666 entry_args=entry_args,
6667 extra_indirs=[test_subdir])[0]
6669 dtb = fdt.Fdt.FromData(data)
6672 node = dtb.GetNode('/configurations/conf-uboot-1')
6673 self.assertEqual('u-boot', node.props['firmware'].value)
6674 self.assertEqual(['atf-1', 'atf-2'],
6675 fdt_util.GetStringList(node, 'loadables'))
6677 node = dtb.GetNode('/configurations/conf-atf-1')
6678 self.assertEqual('atf-1', node.props['firmware'].value)
6679 self.assertEqual(['u-boot', 'atf-2'],
6680 fdt_util.GetStringList(node, 'loadables'))
6682 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6683 self.assertEqual('u-boot', node.props['firmware'].value)
6684 self.assertEqual(['atf-1', 'atf-2'],
6685 fdt_util.GetStringList(node, 'loadables'))
6687 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6688 self.assertEqual('atf-1', node.props['firmware'].value)
6689 self.assertEqual(['u-boot', 'atf-2'],
6690 fdt_util.GetStringList(node, 'loadables'))
6692 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6693 self.assertEqual('atf-1', node.props['firmware'].value)
6694 self.assertEqual(['u-boot', 'atf-2'],
6695 fdt_util.GetStringList(node, 'loadables'))
6697 def testTooldir(self):
6698 """Test that we can specify the tooldir"""
6699 with test_util.capture_sys_output() as (stdout, stderr):
6700 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6702 self.assertEqual('fred', bintool.Bintool.tooldir)
6704 # Check that the toolpath is updated correctly
6705 self.assertEqual(['fred'], tools.tool_search_paths)
6707 # Try with a few toolpaths; the tooldir should be at the end
6708 with test_util.capture_sys_output() as (stdout, stderr):
6709 self.assertEqual(0, self._DoBinman(
6710 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6712 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6714 def testReplaceSectionEntry(self):
6715 """Test replacing an entry in a section"""
6716 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6717 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6718 expect_data, dts='241_replace_section_simple.dts')
6719 self.assertEqual(expect_data, entry_data)
6721 entries = image.GetEntries()
6722 self.assertIn('section', entries)
6723 section = entries['section']
6725 sect_entries = section.GetEntries()
6726 self.assertIn('blob', sect_entries)
6727 entry = sect_entries['blob']
6728 self.assertEqual(len(expect_data), entry.size)
6730 fname = tools.get_output_filename('image-updated.bin')
6731 data = tools.read_file(fname)
6733 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6734 self.assertEqual(expect_data, new_blob_data)
6736 self.assertEqual(U_BOOT_DATA,
6737 data[entry.image_pos + len(expect_data):]
6738 [:len(U_BOOT_DATA)])
6740 def testReplaceSectionDeep(self):
6741 """Test replacing an entry in two levels of sections"""
6742 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6743 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6744 'section/section/blob', expect_data,
6745 dts='278_replace_section_deep.dts')
6746 self.assertEqual(expect_data, entry_data)
6748 entries = image.GetEntries()
6749 self.assertIn('section', entries)
6750 section = entries['section']
6752 subentries = section.GetEntries()
6753 self.assertIn('section', subentries)
6754 section = subentries['section']
6756 sect_entries = section.GetEntries()
6757 self.assertIn('blob', sect_entries)
6758 entry = sect_entries['blob']
6759 self.assertEqual(len(expect_data), entry.size)
6761 fname = tools.get_output_filename('image-updated.bin')
6762 data = tools.read_file(fname)
6764 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6765 self.assertEqual(expect_data, new_blob_data)
6767 self.assertEqual(U_BOOT_DATA,
6768 data[entry.image_pos + len(expect_data):]
6769 [:len(U_BOOT_DATA)])
6771 def testReplaceFitSibling(self):
6772 """Test an image with a FIT inside where we replace its sibling"""
6774 fname = TestFunctional._MakeInputFile('once', b'available once')
6775 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6779 tmpdir, updated_fname = self._SetupImageInTmpdir()
6781 fname = os.path.join(tmpdir, 'update-blob')
6782 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6783 tools.write_file(fname, expected)
6785 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6786 data = tools.read_file(updated_fname)
6787 start = len(U_BOOT_DTB_DATA)
6788 self.assertEqual(expected, data[start:start + len(expected)])
6789 map_fname = os.path.join(tmpdir, 'image-updated.map')
6790 self.assertFalse(os.path.exists(map_fname))
6792 shutil.rmtree(tmpdir)
6794 def testX509Cert(self):
6795 """Test creating an X509 certificate"""
6796 keyfile = self.TestFile('key.key')
6800 data = self._DoReadFileDtb('279_x509_cert.dts',
6801 entry_args=entry_args)[0]
6803 self.assertEqual(U_BOOT_DATA, data[-4:])
6805 # TODO: verify the signature
6807 def testX509CertMissing(self):
6808 """Test that binman still produces an image if openssl is missing"""
6809 keyfile = self.TestFile('key.key')
6811 'keyfile': 'keyfile',
6813 with test_util.capture_sys_output() as (_, stderr):
6814 self._DoTestFile('279_x509_cert.dts',
6815 force_missing_bintools='openssl',
6816 entry_args=entry_args)
6817 err = stderr.getvalue()
6818 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6820 def testPackRockchipTpl(self):
6821 """Test that an image with a Rockchip TPL binary can be created"""
6822 data = self._DoReadFile('291_rockchip_tpl.dts')
6823 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6825 def testMkimageMissingBlobMultiple(self):
6826 """Test missing blob with mkimage entry and multiple-data-files"""
6827 with test_util.capture_sys_output() as (stdout, stderr):
6828 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
6829 err = stderr.getvalue()
6830 self.assertIn("is missing external blobs and is non-functional", err)
6832 with self.assertRaises(ValueError) as e:
6833 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
6834 self.assertIn("not found in input path", str(e.exception))
6836 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6837 """Prepare sign environment
6839 Create private and public keys, add pubkey into dtb.
6849 data = self._DoReadFileRealDtb(dts)
6850 updated_fname = tools.get_output_filename('image-updated.bin')
6851 tools.write_file(updated_fname, data)
6852 dtb = tools.get_output_filename('source.dtb')
6853 private_key = tools.get_output_filename('test_key.key')
6854 public_key = tools.get_output_filename('test_key.crt')
6855 fit = tools.get_output_filename('fit.fit')
6856 key_dir = tools.get_output_dir()
6858 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6859 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6860 private_key, '-out', public_key)
6861 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6862 '-n', 'test_key', '-r', 'conf', dtb)
6864 return fit, updated_fname, private_key, dtb
6866 def testSignSimple(self):
6867 """Test that a FIT container can be signed in image"""
6869 fit, fname, private_key, dtb = self._PrepareSignEnv()
6871 # do sign with private key
6872 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6874 is_signed = self._CheckSign(fit, dtb)
6876 self.assertEqual(is_signed, True)
6878 def testSignExactFIT(self):
6879 """Test that a FIT container can be signed and replaced in image"""
6881 fit, fname, private_key, dtb = self._PrepareSignEnv()
6883 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6886 for path in self.toolpath:
6887 args += ['--toolpath', path]
6889 # do sign with private key
6890 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6891 'sha256,rsa4096', '-f', fit, 'fit')
6892 is_signed = self._CheckSign(fit, dtb)
6894 self.assertEqual(is_signed, True)
6896 def testSignNonFit(self):
6897 """Test a non-FIT entry cannot be signed"""
6899 fit, fname, private_key, _ = self._PrepareSignEnv(
6900 '281_sign_non_fit.dts')
6902 # do sign with private key
6903 with self.assertRaises(ValueError) as e:
6904 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6905 'sha256,rsa4096', '-f', fit, 'u-boot')
6907 "Node '/u-boot': Updating signatures is not supported with this entry type",
6910 def testSignMissingMkimage(self):
6911 """Test that FIT signing handles a missing mkimage tool"""
6912 fit, fname, private_key, _ = self._PrepareSignEnv()
6914 # try to sign with a missing mkimage tool
6915 bintool.Bintool.set_missing_list(['mkimage'])
6916 with self.assertRaises(ValueError) as e:
6917 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6919 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6921 def testSymbolNoWrite(self):
6922 """Test disabling of symbol writing"""
6924 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6925 no_write_symbols=True)
6927 def testSymbolNoWriteExpanded(self):
6928 """Test disabling of symbol writing in expanded entries"""
6932 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6933 U_BOOT_SPL_DTB_DATA, 0x38,
6934 entry_args=entry_args, use_expanded=True,
6935 no_write_symbols=True)
6937 def testMkimageSpecial(self):
6938 """Test mkimage ignores special hash-1 node"""
6939 data = self._DoReadFile('283_mkimage_special.dts')
6941 # Just check that the data appears in the file somewhere
6942 self.assertIn(U_BOOT_DATA, data)
6944 def testFitFdtList(self):
6945 """Test an image with an FIT with the fit,fdt-list-val option"""
6947 'default-dt': 'test-fdt2',
6949 data = self._DoReadFileDtb(
6950 '284_fit_fdt_list.dts',
6951 entry_args=entry_args,
6952 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6953 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6954 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6956 def testSplEmptyBss(self):
6957 """Test an expanded SPL with a zero-size BSS"""
6958 # ELF file with a '__bss_size' symbol
6959 self._SetupSplElf(src_fname='bss_data_zero')
6965 data = self._DoReadFileDtb('285_spl_expand.dts',
6966 use_expanded=True, entry_args=entry_args)[0]
6968 def testTemplate(self):
6969 """Test using a template"""
6970 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6971 data = self._DoReadFile('286_template.dts')
6972 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6973 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6974 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6976 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6977 self.assertTrue(os.path.exists(dtb_fname1))
6978 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6980 node1 = dtb.GetNode('/binman/template')
6981 self.assertTrue(node1)
6982 vga = dtb.GetNode('/binman/first/intel-vga')
6983 self.assertTrue(vga)
6985 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6986 self.assertTrue(os.path.exists(dtb_fname2))
6987 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6989 node2 = dtb2.GetNode('/binman/template')
6990 self.assertFalse(node2)
6992 def testTemplateBlobMulti(self):
6993 """Test using a template with 'multiple-images' enabled"""
6994 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6995 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6996 retcode = self._DoTestFile('287_template_multi.dts')
6998 self.assertEqual(0, retcode)
6999 image = control.images['image']
7000 image_fname = tools.get_output_filename('my-image.bin')
7001 data = tools.read_file(image_fname)
7002 self.assertEqual(b'blob@@@@other', data)
7004 def testTemplateFit(self):
7005 """Test using a template in a FIT"""
7006 fit_data = self._DoReadFile('288_template_fit.dts')
7007 fname = os.path.join(self._indir, 'fit_data.fit')
7008 tools.write_file(fname, fit_data)
7009 out = tools.run('dumpimage', '-l', fname)
7011 def testTemplateSection(self):
7012 """Test using a template in a section (not at top level)"""
7013 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7014 data = self._DoReadFile('289_template_section.dts')
7015 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7016 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7017 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7019 def testMkimageSymbols(self):
7020 """Test using mkimage to build an image with symbols in it"""
7021 self._SetupSplElf('u_boot_binman_syms')
7022 data = self._DoReadFile('290_mkimage_sym.dts')
7024 image = control.images['image']
7025 entries = image.GetEntries()
7026 self.assertIn('u-boot', entries)
7027 u_boot = entries['u-boot']
7029 mkim = entries['mkimage']
7030 mkim_entries = mkim.GetEntries()
7031 self.assertIn('u-boot-spl', mkim_entries)
7032 spl = mkim_entries['u-boot-spl']
7033 self.assertIn('u-boot-spl2', mkim_entries)
7034 spl2 = mkim_entries['u-boot-spl2']
7036 # skip the mkimage header and the area sizes
7037 mk_data = data[mkim.offset + 0x40:]
7038 size, term = struct.unpack('>LL', mk_data[:8])
7040 # There should be only one image, so check that the zero terminator is
7042 self.assertEqual(0, term)
7044 content = mk_data[8:8 + size]
7046 # The image should contain the symbols from u_boot_binman_syms.c
7047 # Note that image_pos is adjusted by the base address of the image,
7048 # which is 0x10 in our test image
7049 spl_data = content[:0x18]
7050 content = content[0x1b:]
7052 # After the header is a table of offsets for each image. There should
7053 # only be one image, then a 0 terminator, so figure out the real start
7057 # Check symbols in both u-boot-spl and u-boot-spl2
7059 vals = struct.unpack('<LLQLL', spl_data)
7061 # The image should contain the symbols from u_boot_binman_syms.c
7062 # Note that image_pos is adjusted by the base address of the image,
7063 # which is 0x10 in our 'u_boot_binman_syms' test image
7064 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7065 self.assertEqual(base, vals[1])
7066 self.assertEqual(spl2.offset, vals[2])
7067 # figure out the internal positions of its components
7068 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7070 # Check that spl and spl2 are actually at the indicated positions
7072 elf.BINMAN_SYM_MAGIC_VALUE,
7073 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7075 elf.BINMAN_SYM_MAGIC_VALUE,
7076 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7078 self.assertEqual(len(U_BOOT_DATA), vals[4])
7081 spl_data = content[:0x18]
7083 def testTemplatePhandle(self):
7084 """Test using a template in a node containing a phandle"""
7086 'atf-bl31-path': 'bl31.elf',
7088 data = self._DoReadFileDtb('309_template_phandle.dts',
7089 entry_args=entry_args)
7090 fname = tools.get_output_filename('image.bin')
7091 out = tools.run('dumpimage', '-l', fname)
7093 # We should see the FIT description and one for each of the two images
7094 lines = out.splitlines()
7095 descs = [line.split()[-1] for line in lines if 'escription' in line]
7096 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7098 def testTemplatePhandleDup(self):
7099 """Test using a template in a node containing a phandle"""
7101 'atf-bl31-path': 'bl31.elf',
7103 with self.assertRaises(ValueError) as e:
7104 self._DoReadFileDtb('310_template_phandle_dup.dts',
7105 entry_args=entry_args)
7107 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7110 def testTIBoardConfig(self):
7111 """Test that a schema validated board config file can be generated"""
7112 data = self._DoReadFile('293_ti_board_cfg.dts')
7113 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7115 def testTIBoardConfigLint(self):
7116 """Test that an incorrectly linted config file would generate error"""
7117 with self.assertRaises(ValueError) as e:
7118 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7119 self.assertIn("Yamllint error", str(e.exception))
7121 def testTIBoardConfigCombined(self):
7122 """Test that a schema validated combined board config file can be generated"""
7123 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
7124 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7125 self.assertGreater(data, configlen_noheader)
7127 def testTIBoardConfigNoDataType(self):
7128 """Test that error is thrown when data type is not supported"""
7129 with self.assertRaises(ValueError) as e:
7130 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
7131 self.assertIn("Schema validation error", str(e.exception))
7133 def testPackTiSecure(self):
7134 """Test that an image with a TI secured binary can be created"""
7135 keyfile = self.TestFile('key.key')
7139 data = self._DoReadFileDtb('296_ti_secure.dts',
7140 entry_args=entry_args)[0]
7141 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7143 def testPackTiSecureFirewall(self):
7144 """Test that an image with a TI secured binary can be created"""
7145 keyfile = self.TestFile('key.key')
7149 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7150 entry_args=entry_args)[0]
7151 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7152 entry_args=entry_args)[0]
7153 self.assertGreater(len(data_firewall),len(data_no_firewall))
7155 def testPackTiSecureFirewallMissingProperty(self):
7156 """Test that an image with a TI secured binary can be created"""
7157 keyfile = self.TestFile('key.key')
7161 with self.assertRaises(ValueError) as e:
7162 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7163 entry_args=entry_args)[0]
7164 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7166 def testPackTiSecureMissingTool(self):
7167 """Test that an image with a TI secured binary (non-functional) can be created
7168 when openssl is missing"""
7169 keyfile = self.TestFile('key.key')
7173 with test_util.capture_sys_output() as (_, stderr):
7174 self._DoTestFile('296_ti_secure.dts',
7175 force_missing_bintools='openssl',
7176 entry_args=entry_args)
7177 err = stderr.getvalue()
7178 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7180 def testPackTiSecureROM(self):
7181 """Test that a ROM image with a TI secured binary can be created"""
7182 keyfile = self.TestFile('key.key')
7186 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
7187 entry_args=entry_args)[0]
7188 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
7189 entry_args=entry_args)[0]
7190 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
7191 entry_args=entry_args)[0]
7192 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7193 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7194 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7196 def testPackTiSecureROMCombined(self):
7197 """Test that a ROM image with a TI secured binary can be created"""
7198 keyfile = self.TestFile('key.key')
7202 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
7203 entry_args=entry_args)[0]
7204 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7206 def testEncryptedNoAlgo(self):
7207 """Test encrypted node with missing required properties"""
7208 with self.assertRaises(ValueError) as e:
7209 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7211 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7214 def testEncryptedInvalidIvfile(self):
7215 """Test encrypted node with invalid iv file"""
7216 with self.assertRaises(ValueError) as e:
7217 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7218 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7221 def testEncryptedMissingKey(self):
7222 """Test encrypted node with missing key properties"""
7223 with self.assertRaises(ValueError) as e:
7224 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7226 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7229 def testEncryptedKeySource(self):
7230 """Test encrypted node with key-source property"""
7231 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7233 dtb = fdt.Fdt.FromData(data)
7236 node = dtb.GetNode('/images/u-boot/cipher')
7237 self.assertEqual('algo-name', node.props['algo'].value)
7238 self.assertEqual('key-source-value', node.props['key-source'].value)
7239 self.assertEqual(ENCRYPTED_IV_DATA,
7240 tools.to_bytes(''.join(node.props['iv'].value)))
7241 self.assertNotIn('key', node.props)
7243 def testEncryptedKeyFile(self):
7244 """Test encrypted node with key-filename property"""
7245 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7247 dtb = fdt.Fdt.FromData(data)
7250 node = dtb.GetNode('/images/u-boot/cipher')
7251 self.assertEqual('algo-name', node.props['algo'].value)
7252 self.assertEqual(ENCRYPTED_IV_DATA,
7253 tools.to_bytes(''.join(node.props['iv'].value)))
7254 self.assertEqual(ENCRYPTED_KEY_DATA,
7255 tools.to_bytes(''.join(node.props['key'].value)))
7256 self.assertNotIn('key-source', node.props)
7259 def testSplPubkeyDtb(self):
7260 """Test u_boot_spl_pubkey_dtb etype"""
7261 data = tools.read_file(self.TestFile("key.pem"))
7262 self._MakeInputFile("key.crt", data)
7263 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7264 image = control.images['image']
7265 entries = image.GetEntries()
7266 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7267 dtb_data = dtb_entry.GetData()
7268 dtb = fdt.Fdt.FromData(dtb_data)
7271 signature_node = dtb.GetNode('/signature')
7272 self.assertIsNotNone(signature_node)
7273 key_node = signature_node.FindNode("key-key")
7274 self.assertIsNotNone(key_node)
7275 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7276 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7277 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
7279 def testXilinxBootgenSigning(self):
7280 """Test xilinx-bootgen etype"""
7281 bootgen = bintool.Bintool.create('bootgen')
7282 self._CheckBintool(bootgen)
7283 data = tools.read_file(self.TestFile("key.key"))
7284 self._MakeInputFile("psk.pem", data)
7285 self._MakeInputFile("ssk.pem", data)
7286 self._SetupPmuFwlElf()
7288 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7289 image_fname = tools.get_output_filename('image.bin')
7291 # Read partition header table and check if authentication is enabled
7292 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7293 "-read", image_fname, "pht").splitlines()
7294 attributes = {"authentication": None,
7298 for l in bootgen_out:
7299 for a in attributes.keys():
7301 m = re.match(fr".*{a} \[([^]]+)\]", l)
7302 attributes[a] = m.group(1)
7304 self.assertTrue(attributes['authentication'] == "rsa")
7305 self.assertTrue(attributes['core'] == "a53-0")
7306 self.assertTrue(attributes['encryption'] == "no")
7308 def testXilinxBootgenSigningEncryption(self):
7309 """Test xilinx-bootgen etype"""
7310 bootgen = bintool.Bintool.create('bootgen')
7311 self._CheckBintool(bootgen)
7312 data = tools.read_file(self.TestFile("key.key"))
7313 self._MakeInputFile("psk.pem", data)
7314 self._MakeInputFile("ssk.pem", data)
7315 self._SetupPmuFwlElf()
7317 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7318 image_fname = tools.get_output_filename('image.bin')
7320 # Read boot header in order to verify encryption source and
7321 # encryption parameter
7322 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7323 "-read", image_fname, "bh").splitlines()
7324 attributes = {"auth_only":
7325 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7326 "encryption_keystore":
7327 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7331 for l in bootgen_out:
7332 for a in attributes.keys():
7334 m = re.match(attributes[a]['re'], l)
7335 attributes[a] = m.group(1)
7337 # Check if fsbl-attribute is set correctly
7338 self.assertTrue(attributes['auth_only'] == "true")
7339 # Check if key is stored in efuse
7340 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7342 def testXilinxBootgenMissing(self):
7343 """Test that binman still produces an image if bootgen is missing"""
7344 data = tools.read_file(self.TestFile("key.key"))
7345 self._MakeInputFile("psk.pem", data)
7346 self._MakeInputFile("ssk.pem", data)
7347 self._SetupPmuFwlElf()
7349 with test_util.capture_sys_output() as (_, stderr):
7350 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7351 force_missing_bintools='bootgen')
7352 err = stderr.getvalue()
7353 self.assertRegex(err,
7354 "Image 'image'.*missing bintools.*: bootgen")
7356 def _GetCapsuleHeaders(self, data):
7357 """Get the capsule header contents
7360 data: Capsule file contents
7364 key: Capsule Header name (str)
7365 value: Header field value (str)
7367 capsule_file = os.path.join(self._indir, 'test.capsule')
7368 tools.write_file(capsule_file, data)
7370 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7371 lines = out.splitlines()
7373 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7376 mat = re_line.match(line)
7378 vals[mat.group(1)] = mat.group(2)
7382 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7384 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7385 fmp_size = "00000010"
7386 fmp_fw_version = "00000002"
7387 capsule_image_index = "00000001"
7388 oemflag = "00018000"
7389 auth_hdr_revision = "00000200"
7390 auth_hdr_cert_type = "00000EF1"
7392 payload_data_len = len(EFI_CAPSULE_DATA)
7394 hdr = self._GetCapsuleHeaders(data)
7396 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7398 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7399 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7400 self.assertEqual(capsule_image_index,
7401 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
7404 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7407 self.assertEqual(auth_hdr_revision,
7408 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7409 self.assertEqual(auth_hdr_cert_type,
7410 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7411 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7412 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7415 self.assertEqual(fmp_signature,
7416 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7417 self.assertEqual(fmp_size,
7418 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7419 self.assertEqual(fmp_fw_version,
7420 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7422 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
7424 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7426 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7428 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7430 hdr = self._GetCapsuleHeaders(data)
7432 self.assertEqual(capsule_hdr_guid.upper(),
7433 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7436 capsule_size = "0000002C"
7438 capsule_size = "0000001C"
7439 self.assertEqual(capsule_size,
7440 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7443 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7445 def testCapsuleGen(self):
7446 """Test generation of EFI capsule"""
7447 data = self._DoReadFile('311_capsule.dts')
7449 self._CheckCapsule(data)
7451 def testSignedCapsuleGen(self):
7452 """Test generation of EFI capsule"""
7453 data = tools.read_file(self.TestFile("key.key"))
7454 self._MakeInputFile("key.key", data)
7455 data = tools.read_file(self.TestFile("key.pem"))
7456 self._MakeInputFile("key.crt", data)
7458 data = self._DoReadFile('312_capsule_signed.dts')
7460 self._CheckCapsule(data, signed_capsule=True)
7462 def testCapsuleGenVersionSupport(self):
7463 """Test generation of EFI capsule with version support"""
7464 data = self._DoReadFile('313_capsule_version.dts')
7466 self._CheckCapsule(data, version_check=True)
7468 def testCapsuleGenSignedVer(self):
7469 """Test generation of signed EFI capsule with version information"""
7470 data = tools.read_file(self.TestFile("key.key"))
7471 self._MakeInputFile("key.key", data)
7472 data = tools.read_file(self.TestFile("key.pem"))
7473 self._MakeInputFile("key.crt", data)
7475 data = self._DoReadFile('314_capsule_signed_ver.dts')
7477 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7479 def testCapsuleGenCapOemFlags(self):
7480 """Test generation of EFI capsule with OEM Flags set"""
7481 data = self._DoReadFile('315_capsule_oemflags.dts')
7483 self._CheckCapsule(data, capoemflags=True)
7485 def testCapsuleGenKeyMissing(self):
7486 """Test that binman errors out on missing key"""
7487 with self.assertRaises(ValueError) as e:
7488 self._DoReadFile('316_capsule_missing_key.dts')
7490 self.assertIn("Both private key and public key certificate need to be provided",
7493 def testCapsuleGenIndexMissing(self):
7494 """Test that binman errors out on missing image index"""
7495 with self.assertRaises(ValueError) as e:
7496 self._DoReadFile('317_capsule_missing_index.dts')
7498 self.assertIn("entry is missing properties: image-index",
7501 def testCapsuleGenGuidMissing(self):
7502 """Test that binman errors out on missing image GUID"""
7503 with self.assertRaises(ValueError) as e:
7504 self._DoReadFile('318_capsule_missing_guid.dts')
7506 self.assertIn("entry is missing properties: image-guid",
7509 def testCapsuleGenAcceptCapsule(self):
7510 """Test generationg of accept EFI capsule"""
7511 data = self._DoReadFile('319_capsule_accept.dts')
7513 self._CheckEmptyCapsule(data, accept_capsule=True)
7515 def testCapsuleGenRevertCapsule(self):
7516 """Test generationg of revert EFI capsule"""
7517 data = self._DoReadFile('320_capsule_revert.dts')
7519 self._CheckEmptyCapsule(data)
7521 def testCapsuleGenAcceptGuidMissing(self):
7522 """Test that binman errors out on missing image GUID for accept capsule"""
7523 with self.assertRaises(ValueError) as e:
7524 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7526 self.assertIn("Image GUID needed for generating accept capsule",
7529 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7530 """Test that capsule-type is specified"""
7531 with self.assertRaises(ValueError) as e:
7532 self._DoReadFile('322_empty_capsule_type_missing.dts')
7534 self.assertIn("entry is missing properties: capsule-type",
7537 def testCapsuleGenAcceptOrRevertMissing(self):
7538 """Test that both accept and revert capsule are not specified"""
7539 with self.assertRaises(ValueError) as e:
7540 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7542 def test_assume_size(self):
7543 """Test handling of the assume-size property for external blob"""
7544 with self.assertRaises(ValueError) as e:
7545 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7546 allow_fake_blobs=True)
7547 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7550 def test_assume_size_ok(self):
7551 """Test handling of the assume-size where it fits OK"""
7552 with test_util.capture_sys_output() as (stdout, stderr):
7553 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7554 allow_fake_blobs=True)
7555 err = stderr.getvalue()
7558 "Image '.*' has faked external blobs and is non-functional: .*")
7560 def test_assume_size_no_fake(self):
7561 """Test handling of the assume-size where it fits OK"""
7562 with test_util.capture_sys_output() as (stdout, stderr):
7563 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7564 err = stderr.getvalue()
7567 "Image '.*' is missing external blobs and is non-functional: .*")
7569 def SetupAlternateDts(self):
7570 """Compile the .dts test files for alternative-fdt
7574 str: Test directory created
7575 list of str: '.bin' files which we expect Binman to create
7577 testdir = TestFunctional._MakeInputDir('dtb')
7579 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7580 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7581 base = os.path.splitext(os.path.basename(fname))[0]
7582 dtb_list.append(base + '.bin')
7583 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7585 return testdir, dtb_list
7587 def CheckAlternates(self, dts, phase, xpl_data):
7588 """Run the test for the alterative-fdt etype
7591 dts (str): Devicetree file to process
7592 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7593 xpl_data (bytes): Expected data for the phase's binary
7596 dict of .dtb files produced
7600 dtb_list = self.SetupAlternateDts()[1]
7603 f'{phase}-dtb': '1',
7604 f'{phase}-bss-pad': 'y',
7605 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7607 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7608 use_expanded=True, entry_args=entry_args)[0]
7609 self.assertEqual(xpl_data, data[:len(xpl_data)])
7610 rest = data[len(xpl_data):]
7612 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7614 # Check the dtb is using the test file
7615 dtb_data = rest[pad_len:]
7616 dtb = fdt.Fdt.FromData(dtb_data)
7618 fdt_size = dtb.GetFdtObj().totalsize()
7619 self.assertEqual('model-not-set',
7620 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7624 # Check the other output files
7626 for fname in dtb_list:
7627 pathname = tools.get_output_filename(fname)
7628 self.assertTrue(os.path.exists(pathname))
7630 data = tools.read_file(pathname)
7631 self.assertEqual(xpl_data, data[:len(xpl_data)])
7632 rest = data[len(xpl_data):]
7634 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7635 rest = rest[pad_len:]
7637 dtb = fdt.Fdt.FromData(rest)
7641 expected = 'one' if '1' in fname else 'two'
7642 self.assertEqual(f'u-boot,model-{expected}',
7643 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7645 # Make sure the FDT is the same size as the 'main' one
7646 rest = rest[fdt_size:]
7648 self.assertEqual(b'', rest)
7651 def testAlternatesFdt(self):
7652 """Test handling of alternates-fdt etype"""
7654 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7655 U_BOOT_TPL_NODTB_DATA)
7656 for dtb in dtbs.values():
7657 # Check for the node with the tag
7658 node = dtb.GetNode('/node')
7659 self.assertIsNotNone(node)
7660 self.assertEqual(5, len(node.props.keys()))
7662 # Make sure the other node is still there
7663 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7665 def testAlternatesFdtgrep(self):
7666 """Test handling of alternates-fdt etype using fdtgrep"""
7668 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7669 U_BOOT_TPL_NODTB_DATA)
7670 for dtb in dtbs.values():
7671 # Check for the node with the tag
7672 node = dtb.GetNode('/node')
7673 self.assertIsNotNone(node)
7674 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7677 # Make sure the other node is gone
7678 self.assertIsNone(dtb.GetNode('/node/other-node'))
7680 def testAlternatesFdtgrepVpl(self):
7681 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7683 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7684 U_BOOT_VPL_NODTB_DATA)
7686 def testAlternatesFdtgrepSpl(self):
7687 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7689 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7690 U_BOOT_SPL_NODTB_DATA)
7692 def testAlternatesFdtgrepInval(self):
7693 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7695 with self.assertRaises(ValueError) as e:
7696 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7697 U_BOOT_SPL_NODTB_DATA)
7698 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7701 def testFitFdtListDir(self):
7702 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
7703 old_dir = os.getcwd()
7705 os.chdir(self._indir)
7706 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7710 def testFitFdtListDirDefault(self):
7711 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7712 old_dir = os.getcwd()
7714 os.chdir(self._indir)
7715 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7716 default_dt='rockchip/test-fdt2')
7720 def testFitFdtCompat(self):
7721 """Test an image with an FIT with compatible in the config nodes"""
7723 'of-list': 'model1 model2',
7724 'default-dt': 'model2',
7726 testdir, dtb_list = self.SetupAlternateDts()
7727 data = self._DoReadFileDtb(
7728 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7729 entry_args=entry_args, extra_indirs=[testdir])[0]
7731 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7733 fit = fdt.Fdt.FromData(fit_data)
7736 cnode = fit.GetNode('/configurations')
7737 self.assertIn('default', cnode.props)
7738 self.assertEqual('config-2', cnode.props['default'].value)
7740 for seq in range(1, 2):
7741 name = f'config-{seq}'
7742 fnode = fit.GetNode('/configurations/%s' % name)
7743 self.assertIsNotNone(fnode)
7744 self.assertIn('compatible', fnode.props.keys())
7745 expected = 'one' if seq == 1 else 'two'
7746 self.assertEqual(f'u-boot,model-{expected}',
7747 fnode.props['compatible'].value)
7749 def testFitFdtPhase(self):
7750 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7753 f'{phase}-dtb': '1',
7754 f'{phase}-bss-pad': 'y',
7755 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7756 'of-list': 'model1 model2',
7757 'default-dt': 'model2',
7759 testdir, dtb_list = self.SetupAlternateDts()
7760 data = self._DoReadFileDtb(
7761 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7762 entry_args=entry_args, extra_indirs=[testdir])[0]
7763 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7764 fit = fdt.Fdt.FromData(fit_data)
7767 # Check that each FDT has only the expected properties for the phase
7768 for seq in range(1, 2):
7769 fnode = fit.GetNode(f'/images/fdt-{seq}')
7770 self.assertIsNotNone(fnode)
7771 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7774 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7776 node = dtb.GetNode('/node')
7777 self.assertIsNotNone(node)
7778 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7781 # Make sure the other node is gone
7782 self.assertIsNone(dtb.GetNode('/node/other-node'))
7784 def testMkeficapsuleMissing(self):
7785 """Test that binman complains if mkeficapsule is missing"""
7786 with self.assertRaises(ValueError) as e:
7787 self._DoTestFile('311_capsule.dts',
7788 force_missing_bintools='mkeficapsule')
7789 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7792 def testMkeficapsuleMissingOk(self):
7793 """Test that binman deals with mkeficapsule being missing"""
7794 with test_util.capture_sys_output() as (stdout, stderr):
7795 ret = self._DoTestFile('311_capsule.dts',
7796 force_missing_bintools='mkeficapsule',
7798 self.assertEqual(103, ret)
7799 err = stderr.getvalue()
7800 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7802 def testSymbolsBase(self):
7803 """Test handling of symbols-base"""
7804 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7807 def testSymbolsBaseExpanded(self):
7808 """Test handling of symbols-base with expanded entries"""
7812 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7813 U_BOOT_SPL_DTB_DATA, 0x38,
7814 entry_args=entry_args, use_expanded=True,
7817 def testSymbolsCompressed(self):
7818 """Test binman complains about symbols from a compressed section"""
7819 with test_util.capture_sys_output() as (stdout, stderr):
7820 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7821 out = stdout.getvalue()
7822 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7825 def testNxpImx8Image(self):
7826 """Test that binman can produce an iMX8 image"""
7827 self._DoTestFile('339_nxp_imx8.dts')
7829 def testFitSignSimple(self):
7830 """Test that image with FIT and signature nodes can be signed"""
7831 if not elf.ELF_TOOLS:
7832 self.skipTest('Python elftools not available')
7834 'of-list': 'test-fdt1',
7835 'default-dt': 'test-fdt1',
7836 'atf-bl31-path': 'bl31.elf',
7838 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7839 self._MakeInputFile("keys/rsa2048.key", data)
7841 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7842 keys_subdir = os.path.join(self._indir, "keys")
7843 data = self._DoReadFileDtb(
7844 '340_fit_signature.dts',
7845 entry_args=entry_args,
7846 extra_indirs=[test_subdir, keys_subdir])[0]
7848 dtb = fdt.Fdt.FromData(data)
7851 conf = dtb.GetNode('/configurations/conf-uboot-1')
7852 self.assertIsNotNone(conf)
7853 signature = conf.FindNode('signature')
7854 self.assertIsNotNone(signature)
7855 self.assertIsNotNone(signature.props.get('value'))
7857 images = dtb.GetNode('/images')
7858 self.assertIsNotNone(images)
7859 for subnode in images.subnodes:
7860 signature = subnode.FindNode('signature')
7861 self.assertIsNotNone(signature)
7862 self.assertIsNotNone(signature.props.get('value'))
7864 def testFitSignKeyNotFound(self):
7865 """Test that missing keys raise an error"""
7866 if not elf.ELF_TOOLS:
7867 self.skipTest('Python elftools not available')
7869 'of-list': 'test-fdt1',
7870 'default-dt': 'test-fdt1',
7871 'atf-bl31-path': 'bl31.elf',
7873 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7874 with self.assertRaises(ValueError) as e:
7875 self._DoReadFileDtb(
7876 '340_fit_signature.dts',
7877 entry_args=entry_args,
7878 extra_indirs=[test_subdir])[0]
7880 'Filename \'rsa2048.key\' not found in input path',
7883 def testFitSignMultipleKeyPaths(self):
7884 """Test that keys found in multiple paths raise an error"""
7885 if not elf.ELF_TOOLS:
7886 self.skipTest('Python elftools not available')
7888 'of-list': 'test-fdt1',
7889 'default-dt': 'test-fdt1',
7890 'atf-bl31-path': 'bl31.elf',
7892 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7893 self._MakeInputFile("keys1/rsa2048.key", data)
7894 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7895 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7897 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7898 keys_subdir1 = os.path.join(self._indir, "keys1")
7899 keys_subdir2 = os.path.join(self._indir, "keys2")
7900 with self.assertRaises(ValueError) as e:
7901 self._DoReadFileDtb(
7902 '341_fit_signature.dts',
7903 entry_args=entry_args,
7904 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7906 'Node \'/binman/fit\': multiple key paths found',
7909 def testFitSignNoSingatureNodes(self):
7910 """Test that fit,sign doens't raise error if no signature nodes found"""
7911 if not elf.ELF_TOOLS:
7912 self.skipTest('Python elftools not available')
7914 'of-list': 'test-fdt1',
7915 'default-dt': 'test-fdt1',
7916 'atf-bl31-path': 'bl31.elf',
7918 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7919 self._DoReadFileDtb(
7920 '342_fit_signature.dts',
7921 entry_args=entry_args,
7922 extra_indirs=[test_subdir])[0]
7925 def testSimpleFitEncryptedData(self):
7926 """Test an image with a FIT containing data to be encrypted"""
7927 data = tools.read_file(self.TestFile("aes256.bin"))
7928 self._MakeInputFile("keys/aes256.bin", data)
7930 keys_subdir = os.path.join(self._indir, "keys")
7931 data = self._DoReadFileDtb(
7932 '343_fit_encrypt_data.dts',
7933 extra_indirs=[keys_subdir])[0]
7935 fit = fdt.Fdt.FromData(data)
7938 # Extract the encrypted data and the Initialization Vector from the FIT
7939 node = fit.GetNode('/images/u-boot')
7940 subnode = fit.GetNode('/images/u-boot/cipher')
7941 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7943 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7945 # Retrieve the key name from the FIT removing any null byte
7946 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7947 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7949 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7950 enc_data = fit.GetProps(node)['data'].bytes
7951 outdir = tools.get_output_dir()
7952 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7953 tools.write_file(enc_data_file, enc_data)
7954 data_file = os.path.join(outdir, 'data.bin')
7956 # Decrypt the encrypted data from the FIT and compare the data
7957 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7958 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7959 with open(data_file, 'r') as file:
7960 dec_data = file.read()
7961 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7963 def testSimpleFitEncryptedDataMissingKey(self):
7964 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7965 with self.assertRaises(ValueError) as e:
7966 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7968 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7970 def testFitFdtName(self):
7971 """Test an image with an FIT with multiple FDT images using NAME"""
7972 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7974 if __name__ == "__main__":