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
12 from optparse import OptionParser
23 from binman import bintool
24 from binman import cbfs_util
25 from binman import cmdline
26 from binman import control
27 from binman import elf
28 from binman import elf_test
29 from binman import fip_util
30 from binman import fmap_util
31 from binman import state
33 from dtoc import fdt_util
34 from binman.etype import fdtmap
35 from binman.etype import image_header
36 from binman.image import Image
37 from u_boot_pylib import command
38 from u_boot_pylib import test_util
39 from u_boot_pylib import tools
40 from u_boot_pylib import tout
42 # Contents of test files, corresponding to different entry types
44 U_BOOT_IMG_DATA = b'img'
45 U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
47 U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
51 EFI_CAPSULE_DATA = b'efi'
52 U_BOOT_DTB_DATA = b'udtb'
53 U_BOOT_SPL_DTB_DATA = b'spldtb'
54 U_BOOT_TPL_DTB_DATA = b'tpldtb'
55 U_BOOT_VPL_DTB_DATA = b'vpldtb'
56 X86_START16_DATA = b'start16'
57 X86_START16_SPL_DATA = b'start16spl'
58 X86_START16_TPL_DATA = b'start16tpl'
59 X86_RESET16_DATA = b'reset16'
60 X86_RESET16_SPL_DATA = b'reset16spl'
61 X86_RESET16_TPL_DATA = b'reset16tpl'
62 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
63 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
64 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
65 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
66 U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
67 U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
68 U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
69 U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
77 CROS_EC_RW_DATA = b'ecrw'
81 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
82 b"sorry you're alive\n")
83 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
84 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
85 REFCODE_DATA = b'refcode'
89 ATF_BL31_DATA = b'bl31'
90 TEE_OS_DATA = b'this is some tee OS data'
91 ATF_BL2U_DATA = b'bl2u'
92 OPENSBI_DATA = b'opensbi'
94 ROCKCHIP_TPL_DATA = b'rockchip-tpl'
95 TEST_FDT1_DATA = b'fdt1'
96 TEST_FDT2_DATA = b'test-fdt2'
97 ENV_DATA = b'var1=1\nvar2="2"'
98 ENCRYPTED_IV_DATA = b'123456'
99 ENCRYPTED_KEY_DATA = b'abcde'
100 PRE_LOAD_MAGIC = b'UBSH'
101 PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
102 PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
103 TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
104 TI_UNSECURE_DATA = b'unsecuredata'
106 # Subdirectory of the input dir to use to put test FDTs
107 TEST_FDT_SUBDIR = 'fdts'
109 # The expected size for the device tree in some tests
110 EXTRACT_DTB_SIZE = 0x3c9
112 # Properties expected to be in the device tree when update_dtb is used
113 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
115 # Extra properties expected to be in the device tree when allow-repack is used
116 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
118 # Supported compression bintools
119 COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
123 # Firmware Management Protocol(FMP) GUID
124 FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
125 # Image GUID specified in the DTS
126 CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
128 WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
129 # Empty capsule GUIDs
130 EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
131 EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
133 class TestFunctional(unittest.TestCase):
134 """Functional tests for binman
136 Most of these use a sample .dts file to build an image and then check
137 that it looks correct. The sample files are in the test/ subdirectory
140 For each entry type a very small test file is created using fixed
141 string contents. This makes it easy to test that things look right, and
144 In some cases a 'real' file must be used - these are also supplied in
145 the test/ diurectory.
150 from binman import entry
152 # Handle the case where argv[0] is 'python'
153 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
154 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
156 # Create a temporary directory for input files
157 cls._indir = tempfile.mkdtemp(prefix='binmant.')
159 # Create some test files
160 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
161 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
162 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
163 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
164 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
165 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
166 TestFunctional._MakeInputFile('me.bin', ME_DATA)
167 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
170 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
172 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
173 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
174 X86_START16_SPL_DATA)
175 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
176 X86_START16_TPL_DATA)
178 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
180 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
181 X86_RESET16_SPL_DATA)
182 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
183 X86_RESET16_TPL_DATA)
185 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
186 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
187 U_BOOT_SPL_NODTB_DATA)
188 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
189 U_BOOT_TPL_NODTB_DATA)
190 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
191 U_BOOT_VPL_NODTB_DATA)
192 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
193 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
194 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
195 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
196 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
197 TestFunctional._MakeInputDir('devkeys')
198 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
199 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
200 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
201 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
202 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
204 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
205 elf_test.BuildElfTestFiles(cls._elf_testdir)
207 # ELF file with a '_dt_ucode_base_size' symbol
208 TestFunctional._MakeInputFile('u-boot',
209 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
211 # Intel flash descriptor file
212 cls._SetupDescriptor()
214 shutil.copytree(cls.TestFile('files'),
215 os.path.join(cls._indir, 'files'))
217 shutil.copytree(cls.TestFile('yaml'),
218 os.path.join(cls._indir, 'yaml'))
220 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
221 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
222 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
223 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
224 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
225 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
226 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
227 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
228 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
229 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
231 # Add a few .dtb files for testing
232 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
234 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
237 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
239 # ELF file with two sections in different parts of memory, used for both
241 TestFunctional._MakeInputFile('bl31.elf',
242 tools.read_file(cls.ElfTestFile('elf_sections')))
243 TestFunctional._MakeInputFile('tee.elf',
244 tools.read_file(cls.ElfTestFile('elf_sections')))
246 # Newer OP_TEE file in v1 binary format
247 cls.make_tee_bin('tee.bin')
249 # test files for encrypted tests
250 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
251 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
253 cls.comp_bintools = {}
254 for name in COMP_BINTOOLS:
255 cls.comp_bintools[name] = bintool.Bintool.create(name)
258 def tearDownClass(cls):
259 """Remove the temporary input directory and its contents"""
260 if cls.preserve_indir:
261 print('Preserving input dir: %s' % cls._indir)
264 shutil.rmtree(cls._indir)
268 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
269 toolpath=None, verbosity=None):
270 """Accept arguments controlling test execution
273 preserve_indir: Preserve the shared input directory used by all
275 preserve_outdir: Preserve the output directories used by tests. Each
276 test has its own, so this is normally only useful when running a
278 toolpath: ist of paths to use for tools
280 cls.preserve_indir = preserve_indir
281 cls.preserve_outdirs = preserve_outdirs
282 cls.toolpath = toolpath
283 cls.verbosity = verbosity
285 def _CheckBintool(self, bintool):
286 if not bintool.is_present():
287 self.skipTest('%s not available' % bintool.name)
290 bintool = self.comp_bintools['lz4']
291 self._CheckBintool(bintool)
293 def _CleanupOutputDir(self):
294 """Remove the temporary output directory"""
295 if self.preserve_outdirs:
296 print('Preserving output dir: %s' % tools.outdir)
298 tools._finalise_for_test()
301 # Enable this to turn on debugging output
302 # tout.init(tout.DEBUG)
303 command.test_result = None
306 """Remove the temporary output directory"""
307 self._CleanupOutputDir()
309 def _SetupImageInTmpdir(self):
310 """Set up the output image in a new temporary directory
312 This is used when an image has been generated in the output directory,
313 but we want to run binman again. This will create a new output
314 directory and fail to delete the original one.
316 This creates a new temporary directory, copies the image to it (with a
317 new name) and removes the old output directory.
321 Temporary directory to use
324 image_fname = tools.get_output_filename('image.bin')
325 tmpdir = tempfile.mkdtemp(prefix='binman.')
326 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
327 tools.write_file(updated_fname, tools.read_file(image_fname))
328 self._CleanupOutputDir()
329 return tmpdir, updated_fname
333 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
334 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
335 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
336 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
338 def _RunBinman(self, *args, **kwargs):
339 """Run binman using the command line
342 Arguments to pass, as a list of strings
343 kwargs: Arguments to pass to Command.RunPipe()
345 result = command.run_pipe([[self._binman_pathname] + list(args)],
346 capture=True, capture_stderr=True, raise_on_error=False)
347 if result.return_code and kwargs.get('raise_on_error', True):
348 raise Exception("Error running '%s': %s" % (' '.join(args),
349 result.stdout + result.stderr))
352 def _DoBinman(self, *argv):
353 """Run binman using directly (in the same process)
356 Arguments to pass, as a list of strings
358 Return value (0 for success)
361 args = cmdline.ParseArgs(argv)
362 args.pager = 'binman-invalid-pager'
363 args.build_dir = self._indir
365 # For testing, you can force an increase in verbosity here
366 # args.verbosity = tout.DEBUG
367 return control.Binman(args)
369 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
370 entry_args=None, images=None, use_real_dtb=False,
371 use_expanded=False, verbosity=None, allow_missing=False,
372 allow_fake_blobs=False, extra_indirs=None, threads=None,
373 test_section_timeout=False, update_fdt_in_elf=None,
374 force_missing_bintools='', ignore_missing=False, output_dir=None):
375 """Run binman with a given test file
378 fname: Device-tree source filename to use (e.g. 005_simple.dts)
379 debug: True to enable debugging output
380 map: True to output map files for the images
381 update_dtb: Update the offset and size of each entry in the device
382 tree before packing it into the image
383 entry_args: Dict of entry args to supply to binman
385 value: value of that arg
386 images: List of image names to build
387 use_real_dtb: True to use the test file as the contents of
388 the u-boot-dtb entry. Normally this is not needed and the
389 test contents (the U_BOOT_DTB_DATA string) can be used.
390 But in some test we need the real contents.
391 use_expanded: True to use expanded entries where available, e.g.
392 'u-boot-expanded' instead of 'u-boot'
393 verbosity: Verbosity level to use (0-3, None=don't set it)
394 allow_missing: Set the '--allow-missing' flag so that missing
395 external binaries just produce a warning instead of an error
396 allow_fake_blobs: Set the '--fake-ext-blobs' flag
397 extra_indirs: Extra input directories to add using -I
398 threads: Number of threads to use (None for default, 0 for
400 test_section_timeout: True to force the first time to timeout, as
401 used in testThreadTimeout()
402 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
403 force_missing_tools (str): comma-separated list of bintools to
405 output_dir: Specific output directory to use for image using -O
408 int return code, 0 on success
413 if verbosity is not None:
414 args.append('-v%d' % verbosity)
416 args.append('-v%d' % self.verbosity)
418 for path in self.toolpath:
419 args += ['--toolpath', path]
420 if threads is not None:
421 args.append('-T%d' % threads)
422 if test_section_timeout:
423 args.append('--test-section-timeout')
424 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
430 args.append('--fake-dtb')
432 args.append('--no-expanded')
434 for arg, value in entry_args.items():
435 args.append('-a%s=%s' % (arg, value))
441 args.append('--fake-ext-blobs')
442 if force_missing_bintools:
443 args += ['--force-missing-bintools', force_missing_bintools]
444 if update_fdt_in_elf:
445 args += ['--update-fdt-in-elf', update_fdt_in_elf]
448 args += ['-i', image]
450 for indir in extra_indirs:
451 args += ['-I', indir]
453 args += ['-O', output_dir]
454 return self._DoBinman(*args)
456 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
457 """Set up a new test device-tree file
459 The given file is compiled and set up as the device tree to be used
463 fname: Filename of .dts file to read
464 outfile: Output filename for compiled device-tree binary
467 Contents of device-tree binary
469 tmpdir = tempfile.mkdtemp(prefix='binmant.')
470 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
471 with open(dtb, 'rb') as fd:
473 TestFunctional._MakeInputFile(outfile, data)
474 shutil.rmtree(tmpdir)
477 def _GetDtbContentsForSpls(self, dtb_data, name):
478 """Create a version of the main DTB for SPL / TPL / VPL
480 For testing we don't actually have different versions of the DTB. With
481 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
482 we don't normally have any unwanted nodes.
484 We still want the DTBs for SPL and TPL to be different though, since
485 otherwise it is confusing to know which one we are looking at. So add
486 an 'spl' or 'tpl' property to the top-level node.
489 dtb_data: dtb data to modify (this should be a value devicetree)
490 name: Name of a new property to add
493 New dtb data with the property added
495 dtb = fdt.Fdt.FromData(dtb_data)
497 dtb.GetNode('/binman').AddZeroProp(name)
498 dtb.Sync(auto_resize=True)
500 return dtb.GetContents()
502 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
503 map=False, update_dtb=False, entry_args=None,
504 reset_dtbs=True, extra_indirs=None, threads=None):
505 """Run binman and return the resulting image
507 This runs binman with a given test file and then reads the resulting
508 output file. It is a shortcut function since most tests need to do
511 Raises an assertion failure if binman returns a non-zero exit code.
514 fname: Device-tree source filename to use (e.g. 005_simple.dts)
515 use_real_dtb: True to use the test file as the contents of
516 the u-boot-dtb entry. Normally this is not needed and the
517 test contents (the U_BOOT_DTB_DATA string) can be used.
518 But in some test we need the real contents.
519 use_expanded: True to use expanded entries where available, e.g.
520 'u-boot-expanded' instead of 'u-boot'
521 map: True to output map files for the images
522 update_dtb: Update the offset and size of each entry in the device
523 tree before packing it into the image
524 entry_args: Dict of entry args to supply to binman
526 value: value of that arg
527 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
528 function. If reset_dtbs is True, then the original test dtb
529 is written back before this function finishes
530 extra_indirs: Extra input directories to add using -I
531 threads: Number of threads to use (None for default, 0 for
536 Resulting image contents
538 Map data showing contents of image (or None if none)
539 Output device tree binary filename ('u-boot.dtb' path)
542 # Use the compiled test file as the u-boot-dtb input
544 dtb_data = self._SetupDtb(fname)
546 # For testing purposes, make a copy of the DT for SPL and TPL. Add
547 # a node indicating which it is, so aid verification.
548 for name in ['spl', 'tpl', 'vpl']:
549 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
550 outfile = os.path.join(self._indir, dtb_fname)
551 TestFunctional._MakeInputFile(dtb_fname,
552 self._GetDtbContentsForSpls(dtb_data, name))
555 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
556 entry_args=entry_args, use_real_dtb=use_real_dtb,
557 use_expanded=use_expanded, extra_indirs=extra_indirs,
559 self.assertEqual(0, retcode)
560 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
562 # Find the (only) image, read it and return its contents
563 image = control.images['image']
564 image_fname = tools.get_output_filename('image.bin')
565 self.assertTrue(os.path.exists(image_fname))
567 map_fname = tools.get_output_filename('image.map')
568 with open(map_fname) as fd:
572 with open(image_fname, 'rb') as fd:
573 return fd.read(), dtb_data, map_data, out_dtb_fname
575 # Put the test file back
576 if reset_dtbs and use_real_dtb:
579 def _DoReadFileRealDtb(self, fname):
580 """Run binman with a real .dtb file and return the resulting data
583 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
586 Resulting image contents
588 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
590 def _DoReadFile(self, fname, use_real_dtb=False):
591 """Helper function which discards the device-tree binary
594 fname: Device-tree source filename to use (e.g. 005_simple.dts)
595 use_real_dtb: True to use the test file as the contents of
596 the u-boot-dtb entry. Normally this is not needed and the
597 test contents (the U_BOOT_DTB_DATA string) can be used.
598 But in some test we need the real contents.
601 Resulting image contents
603 return self._DoReadFileDtb(fname, use_real_dtb)[0]
606 def _MakeInputFile(cls, fname, contents):
607 """Create a new test input file, creating directories as needed
610 fname: Filename to create
611 contents: File contents to write in to the file
613 Full pathname of file created
615 pathname = os.path.join(cls._indir, fname)
616 dirname = os.path.dirname(pathname)
617 if dirname and not os.path.exists(dirname):
619 with open(pathname, 'wb') as fd:
624 def _MakeInputDir(cls, dirname):
625 """Create a new test input directory, creating directories as needed
628 dirname: Directory name to create
631 Full pathname of directory created
633 pathname = os.path.join(cls._indir, dirname)
634 if not os.path.exists(pathname):
635 os.makedirs(pathname)
639 def _SetupSplElf(cls, src_fname='bss_data'):
640 """Set up an ELF file with a '_dt_ucode_base_size' symbol
643 Filename of ELF file to use as SPL
645 TestFunctional._MakeInputFile('spl/u-boot-spl',
646 tools.read_file(cls.ElfTestFile(src_fname)))
649 def _SetupTplElf(cls, src_fname='bss_data'):
650 """Set up an ELF file with a '_dt_ucode_base_size' symbol
653 Filename of ELF file to use as TPL
655 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
656 tools.read_file(cls.ElfTestFile(src_fname)))
659 def _SetupVplElf(cls, src_fname='bss_data'):
660 """Set up an ELF file with a '_dt_ucode_base_size' symbol
663 Filename of ELF file to use as VPL
665 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
666 tools.read_file(cls.ElfTestFile(src_fname)))
669 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
670 """Set up an ELF file with a '_dt_ucode_base_size' symbol
673 Filename of ELF file to use as VPL
675 TestFunctional._MakeInputFile('pmu-firmware.elf',
676 tools.read_file(cls.ElfTestFile(src_fname)))
679 def _SetupDescriptor(cls):
680 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
681 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
684 def TestFile(cls, fname):
685 return os.path.join(cls._binman_dir, 'test', fname)
688 def ElfTestFile(cls, fname):
689 return os.path.join(cls._elf_testdir, fname)
692 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
693 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
694 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
695 dummy, paged_sz) + U_BOOT_DATA
697 TestFunctional._MakeInputFile(fname, data)
699 def AssertInList(self, grep_list, target):
700 """Assert that at least one of a list of things is in a target
703 grep_list: List of strings to check
704 target: Target string
706 for grep in grep_list:
709 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
711 def CheckNoGaps(self, entries):
712 """Check that all entries fit together without gaps
715 entries: List of entries to check
718 for entry in entries.values():
719 self.assertEqual(offset, entry.offset)
722 def GetFdtLen(self, dtb):
723 """Get the totalsize field from a device-tree binary
726 dtb: Device-tree binary contents
729 Total size of device-tree binary, from the header
731 return struct.unpack('>L', dtb[4:8])[0]
733 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
734 def AddNode(node, path):
736 path += '/' + node.name
737 for prop in node.props.values():
738 if prop.name in prop_names:
739 prop_path = path + ':' + prop.name
740 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
742 for subnode in node.subnodes:
743 AddNode(subnode, path)
746 AddNode(dtb.GetRoot(), '')
749 def _CheckSign(self, fit, key):
751 tools.run('fit_check_sign', '-k', key, '-f', fit)
753 self.fail('Expected signed FIT container')
758 """Test a basic run with valid args"""
759 result = self._RunBinman('-h')
761 def testFullHelp(self):
762 """Test that the full help is displayed with -H"""
763 result = self._RunBinman('-H')
764 help_file = os.path.join(self._binman_dir, 'README.rst')
765 # Remove possible extraneous strings
766 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
767 gothelp = result.stdout.replace(extra, '')
768 self.assertEqual(len(gothelp), os.path.getsize(help_file))
769 self.assertEqual(0, len(result.stderr))
770 self.assertEqual(0, result.return_code)
772 def testFullHelpInternal(self):
773 """Test that the full help is displayed with -H"""
775 command.test_result = command.CommandResult()
776 result = self._DoBinman('-H')
777 help_file = os.path.join(self._binman_dir, 'README.rst')
779 command.test_result = None
782 """Test that the basic help is displayed with -h"""
783 result = self._RunBinman('-h')
784 self.assertTrue(len(result.stdout) > 200)
785 self.assertEqual(0, len(result.stderr))
786 self.assertEqual(0, result.return_code)
789 """Test that we can run it with a specific board"""
790 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
791 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
792 result = self._DoBinman('build', '-n', '-b', 'sandbox')
793 self.assertEqual(0, result)
795 def testNeedBoard(self):
796 """Test that we get an error when no board ius supplied"""
797 with self.assertRaises(ValueError) as e:
798 result = self._DoBinman('build')
799 self.assertIn("Must provide a board to process (use -b <board>)",
802 def testMissingDt(self):
803 """Test that an invalid device-tree file generates an error"""
804 with self.assertRaises(Exception) as e:
805 self._RunBinman('build', '-d', 'missing_file')
806 # We get one error from libfdt, and a different one from fdtget.
807 self.AssertInList(["Couldn't open blob from 'missing_file'",
808 'No such file or directory'], str(e.exception))
810 def testBrokenDt(self):
811 """Test that an invalid device-tree source file generates an error
813 Since this is a source file it should be compiled and the error
814 will come from the device-tree compiler (dtc).
816 with self.assertRaises(Exception) as e:
817 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
818 self.assertIn("FATAL ERROR: Unable to parse input tree",
821 def testMissingNode(self):
822 """Test that a device tree without a 'binman' node generates an error"""
823 with self.assertRaises(Exception) as e:
824 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
825 self.assertIn("does not have a 'binman' node", str(e.exception))
828 """Test that an empty binman node works OK (i.e. does nothing)"""
829 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
830 self.assertEqual(0, len(result.stderr))
831 self.assertEqual(0, result.return_code)
833 def testInvalidEntry(self):
834 """Test that an invalid entry is flagged"""
835 with self.assertRaises(Exception) as e:
836 result = self._RunBinman('build', '-d',
837 self.TestFile('004_invalid_entry.dts'))
838 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
839 "'/binman/not-a-valid-type'", str(e.exception))
841 def testSimple(self):
842 """Test a simple binman with a single file"""
843 data = self._DoReadFile('005_simple.dts')
844 self.assertEqual(U_BOOT_DATA, data)
846 def testSimpleDebug(self):
847 """Test a simple binman run with debugging enabled"""
848 self._DoTestFile('005_simple.dts', debug=True)
851 """Test that we can handle creating two images
853 This also tests image padding.
855 retcode = self._DoTestFile('006_dual_image.dts')
856 self.assertEqual(0, retcode)
858 image = control.images['image1']
859 self.assertEqual(len(U_BOOT_DATA), image.size)
860 fname = tools.get_output_filename('image1.bin')
861 self.assertTrue(os.path.exists(fname))
862 with open(fname, 'rb') as fd:
864 self.assertEqual(U_BOOT_DATA, data)
866 image = control.images['image2']
867 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
868 fname = tools.get_output_filename('image2.bin')
869 self.assertTrue(os.path.exists(fname))
870 with open(fname, 'rb') as fd:
872 self.assertEqual(U_BOOT_DATA, data[3:7])
873 self.assertEqual(tools.get_bytes(0, 3), data[:3])
874 self.assertEqual(tools.get_bytes(0, 5), data[7:])
876 def testBadAlign(self):
877 """Test that an invalid alignment value is detected"""
878 with self.assertRaises(ValueError) as e:
879 self._DoTestFile('007_bad_align.dts')
880 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
881 "of two", str(e.exception))
883 def testPackSimple(self):
884 """Test that packing works as expected"""
885 retcode = self._DoTestFile('008_pack.dts')
886 self.assertEqual(0, retcode)
887 self.assertIn('image', control.images)
888 image = control.images['image']
889 entries = image.GetEntries()
890 self.assertEqual(5, len(entries))
893 self.assertIn('u-boot', entries)
894 entry = entries['u-boot']
895 self.assertEqual(0, entry.offset)
896 self.assertEqual(len(U_BOOT_DATA), entry.size)
898 # Second u-boot, aligned to 16-byte boundary
899 self.assertIn('u-boot-align', entries)
900 entry = entries['u-boot-align']
901 self.assertEqual(16, entry.offset)
902 self.assertEqual(len(U_BOOT_DATA), entry.size)
904 # Third u-boot, size 23 bytes
905 self.assertIn('u-boot-size', entries)
906 entry = entries['u-boot-size']
907 self.assertEqual(20, entry.offset)
908 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
909 self.assertEqual(23, entry.size)
911 # Fourth u-boot, placed immediate after the above
912 self.assertIn('u-boot-next', entries)
913 entry = entries['u-boot-next']
914 self.assertEqual(43, entry.offset)
915 self.assertEqual(len(U_BOOT_DATA), entry.size)
917 # Fifth u-boot, placed at a fixed offset
918 self.assertIn('u-boot-fixed', entries)
919 entry = entries['u-boot-fixed']
920 self.assertEqual(61, entry.offset)
921 self.assertEqual(len(U_BOOT_DATA), entry.size)
923 self.assertEqual(65, image.size)
925 def testPackExtra(self):
926 """Test that extra packing feature works as expected"""
927 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
930 self.assertIn('image', control.images)
931 image = control.images['image']
932 entries = image.GetEntries()
933 self.assertEqual(6, len(entries))
935 # First u-boot with padding before and after (included in minimum size)
936 self.assertIn('u-boot', entries)
937 entry = entries['u-boot']
938 self.assertEqual(0, entry.offset)
939 self.assertEqual(3, entry.pad_before)
940 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
941 self.assertEqual(U_BOOT_DATA, entry.data)
942 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
943 tools.get_bytes(0, 5), data[:entry.size])
946 # Second u-boot has an aligned size, but it has no effect
947 self.assertIn('u-boot-align-size-nop', entries)
948 entry = entries['u-boot-align-size-nop']
949 self.assertEqual(pos, entry.offset)
950 self.assertEqual(len(U_BOOT_DATA), entry.size)
951 self.assertEqual(U_BOOT_DATA, entry.data)
952 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
955 # Third u-boot has an aligned size too
956 self.assertIn('u-boot-align-size', entries)
957 entry = entries['u-boot-align-size']
958 self.assertEqual(pos, entry.offset)
959 self.assertEqual(32, entry.size)
960 self.assertEqual(U_BOOT_DATA, entry.data)
961 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
962 data[pos:pos + entry.size])
965 # Fourth u-boot has an aligned end
966 self.assertIn('u-boot-align-end', entries)
967 entry = entries['u-boot-align-end']
968 self.assertEqual(48, entry.offset)
969 self.assertEqual(16, entry.size)
970 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
971 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
972 data[pos:pos + entry.size])
975 # Fifth u-boot immediately afterwards
976 self.assertIn('u-boot-align-both', entries)
977 entry = entries['u-boot-align-both']
978 self.assertEqual(64, entry.offset)
979 self.assertEqual(64, entry.size)
980 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
981 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
982 data[pos:pos + entry.size])
984 # Sixth u-boot with both minimum size and aligned size
985 self.assertIn('u-boot-min-size', entries)
986 entry = entries['u-boot-min-size']
987 self.assertEqual(128, entry.offset)
988 self.assertEqual(32, entry.size)
989 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
990 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
991 data[pos:pos + entry.size])
993 self.CheckNoGaps(entries)
994 self.assertEqual(160, image.size)
996 dtb = fdt.Fdt(out_dtb_fname)
998 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1004 'u-boot:image-pos': 0,
1006 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1008 'u-boot-align-size-nop:image-pos': 12,
1009 'u-boot-align-size-nop:offset': 12,
1010 'u-boot-align-size-nop:size': 4,
1012 'u-boot-align-size:image-pos': 16,
1013 'u-boot-align-size:offset': 16,
1014 'u-boot-align-size:size': 32,
1016 'u-boot-align-end:image-pos': 48,
1017 'u-boot-align-end:offset': 48,
1018 'u-boot-align-end:size': 16,
1020 'u-boot-align-both:image-pos': 64,
1021 'u-boot-align-both:offset': 64,
1022 'u-boot-align-both:size': 64,
1024 'u-boot-min-size:image-pos': 128,
1025 'u-boot-min-size:offset': 128,
1026 'u-boot-min-size:size': 32,
1028 self.assertEqual(expected, props)
1030 def testPackAlignPowerOf2(self):
1031 """Test that invalid entry alignment is detected"""
1032 with self.assertRaises(ValueError) as e:
1033 self._DoTestFile('010_pack_align_power2.dts')
1034 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1035 "of two", str(e.exception))
1037 def testPackAlignSizePowerOf2(self):
1038 """Test that invalid entry size alignment is detected"""
1039 with self.assertRaises(ValueError) as e:
1040 self._DoTestFile('011_pack_align_size_power2.dts')
1041 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1042 "power of two", str(e.exception))
1044 def testPackInvalidAlign(self):
1045 """Test detection of an offset that does not match its alignment"""
1046 with self.assertRaises(ValueError) as e:
1047 self._DoTestFile('012_pack_inv_align.dts')
1048 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
1049 "align 0x4 (4)", str(e.exception))
1051 def testPackInvalidSizeAlign(self):
1052 """Test that invalid entry size alignment is detected"""
1053 with self.assertRaises(ValueError) as e:
1054 self._DoTestFile('013_pack_inv_size_align.dts')
1055 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1056 "align-size 0x4 (4)", str(e.exception))
1058 def testPackOverlap(self):
1059 """Test that overlapping regions are detected"""
1060 with self.assertRaises(ValueError) as e:
1061 self._DoTestFile('014_pack_overlap.dts')
1062 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
1063 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1066 def testPackEntryOverflow(self):
1067 """Test that entries that overflow their size are detected"""
1068 with self.assertRaises(ValueError) as e:
1069 self._DoTestFile('015_pack_overflow.dts')
1070 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1071 "but entry size is 0x3 (3)", str(e.exception))
1073 def testPackImageOverflow(self):
1074 """Test that entries which overflow the image size are detected"""
1075 with self.assertRaises(ValueError) as e:
1076 self._DoTestFile('016_pack_image_overflow.dts')
1077 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
1078 "size 0x3 (3)", str(e.exception))
1080 def testPackImageSize(self):
1081 """Test that the image size can be set"""
1082 retcode = self._DoTestFile('017_pack_image_size.dts')
1083 self.assertEqual(0, retcode)
1084 self.assertIn('image', control.images)
1085 image = control.images['image']
1086 self.assertEqual(7, image.size)
1088 def testPackImageSizeAlign(self):
1089 """Test that image size alignemnt works as expected"""
1090 retcode = self._DoTestFile('018_pack_image_align.dts')
1091 self.assertEqual(0, retcode)
1092 self.assertIn('image', control.images)
1093 image = control.images['image']
1094 self.assertEqual(16, image.size)
1096 def testPackInvalidImageAlign(self):
1097 """Test that invalid image alignment is detected"""
1098 with self.assertRaises(ValueError) as e:
1099 self._DoTestFile('019_pack_inv_image_align.dts')
1100 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
1101 "align-size 0x8 (8)", str(e.exception))
1103 def testPackAlignPowerOf2Inv(self):
1104 """Test that invalid image alignment is detected"""
1105 with self.assertRaises(ValueError) as e:
1106 self._DoTestFile('020_pack_inv_image_align_power2.dts')
1107 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
1108 "two", str(e.exception))
1110 def testImagePadByte(self):
1111 """Test that the image pad byte can be specified"""
1113 data = self._DoReadFile('021_image_pad.dts')
1114 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
1117 def testImageName(self):
1118 """Test that image files can be named"""
1119 retcode = self._DoTestFile('022_image_name.dts')
1120 self.assertEqual(0, retcode)
1121 image = control.images['image1']
1122 fname = tools.get_output_filename('test-name')
1123 self.assertTrue(os.path.exists(fname))
1125 image = control.images['image2']
1126 fname = tools.get_output_filename('test-name.xx')
1127 self.assertTrue(os.path.exists(fname))
1129 def testBlobFilename(self):
1130 """Test that generic blobs can be provided by filename"""
1131 data = self._DoReadFile('023_blob.dts')
1132 self.assertEqual(BLOB_DATA, data)
1134 def testPackSorted(self):
1135 """Test that entries can be sorted"""
1137 data = self._DoReadFile('024_sorted.dts')
1138 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1139 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
1141 def testPackZeroOffset(self):
1142 """Test that an entry at offset 0 is not given a new offset"""
1144 with self.assertRaises(ValueError) as e:
1145 self._DoTestFile('025_pack_zero_size.dts')
1146 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1147 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1150 def testPackUbootDtb(self):
1151 """Test that a device tree can be added to U-Boot"""
1152 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1153 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1155 def testPackX86RomNoSize(self):
1156 """Test that the end-at-4gb property requires a size property"""
1158 with self.assertRaises(ValueError) as e:
1159 self._DoTestFile('027_pack_4gb_no_size.dts')
1160 self.assertIn("Image '/binman': Section size must be provided when "
1161 "using end-at-4gb", str(e.exception))
1163 def test4gbAndSkipAtStartTogether(self):
1164 """Test that the end-at-4gb and skip-at-size property can't be used
1167 with self.assertRaises(ValueError) as e:
1168 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1169 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1170 "'skip-at-start'", str(e.exception))
1172 def testPackX86RomOutside(self):
1173 """Test that the end-at-4gb property checks for offset boundaries"""
1175 with self.assertRaises(ValueError) as e:
1176 self._DoTestFile('028_pack_4gb_outside.dts')
1177 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1178 "is outside the section '/binman' starting at "
1179 '0xffffffe0 (4294967264) of size 0x20 (32)',
1182 def testPackX86Rom(self):
1183 """Test that a basic x86 ROM can be created"""
1185 data = self._DoReadFile('029_x86_rom.dts')
1186 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1187 tools.get_bytes(0, 2), data)
1189 def testPackX86RomMeNoDesc(self):
1190 """Test that an invalid Intel descriptor entry is detected"""
1192 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1193 with self.assertRaises(ValueError) as e:
1194 self._DoTestFile('163_x86_rom_me_empty.dts')
1195 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1198 self._SetupDescriptor()
1200 def testPackX86RomBadDesc(self):
1201 """Test that the Intel requires a descriptor entry"""
1202 with self.assertRaises(ValueError) as e:
1203 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1204 self.assertIn("Node '/binman/intel-me': No offset set with "
1205 "offset-unset: should another entry provide this correct "
1206 "offset?", str(e.exception))
1208 def testPackX86RomMe(self):
1209 """Test that an x86 ROM with an ME region can be created"""
1210 data = self._DoReadFile('031_x86_rom_me.dts')
1211 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
1212 if data[:0x1000] != expected_desc:
1213 self.fail('Expected descriptor binary at start of image')
1214 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1216 def testPackVga(self):
1217 """Test that an image with a VGA binary can be created"""
1218 data = self._DoReadFile('032_intel_vga.dts')
1219 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1221 def testPackStart16(self):
1222 """Test that an image with an x86 start16 region can be created"""
1223 data = self._DoReadFile('033_x86_start16.dts')
1224 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1226 def testPackPowerpcMpc85xxBootpgResetvec(self):
1227 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1229 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1230 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1232 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1233 """Handle running a test for insertion of microcode
1236 dts_fname: Name of test .dts file
1237 nodtb_data: Data that we expect in the first section
1238 ucode_second: True if the microsecond entry is second instead of
1243 Contents of first region (U-Boot or SPL)
1244 Offset and size components of microcode pointer, as inserted
1245 in the above (two 4-byte words)
1247 data = self._DoReadFile(dts_fname, True)
1249 # Now check the device tree has no microcode
1251 ucode_content = data[len(nodtb_data):]
1252 ucode_pos = len(nodtb_data)
1253 dtb_with_ucode = ucode_content[16:]
1254 fdt_len = self.GetFdtLen(dtb_with_ucode)
1256 dtb_with_ucode = data[len(nodtb_data):]
1257 fdt_len = self.GetFdtLen(dtb_with_ucode)
1258 ucode_content = dtb_with_ucode[fdt_len:]
1259 ucode_pos = len(nodtb_data) + fdt_len
1260 fname = tools.get_output_filename('test.dtb')
1261 with open(fname, 'wb') as fd:
1262 fd.write(dtb_with_ucode)
1263 dtb = fdt.FdtScan(fname)
1264 ucode = dtb.GetNode('/microcode')
1265 self.assertTrue(ucode)
1266 for node in ucode.subnodes:
1267 self.assertFalse(node.props.get('data'))
1269 # Check that the microcode appears immediately after the Fdt
1270 # This matches the concatenation of the data properties in
1271 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1272 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1274 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1276 # Check that the microcode pointer was inserted. It should match the
1277 # expected offset and size
1278 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1280 u_boot = data[:len(nodtb_data)]
1281 return u_boot, pos_and_size
1283 def testPackUbootMicrocode(self):
1284 """Test that x86 microcode can be handled correctly
1286 We expect to see the following in the image, in order:
1287 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1289 u-boot.dtb with the microcode removed
1292 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1294 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1295 b' somewhere in here', first)
1297 def _RunPackUbootSingleMicrocode(self):
1298 """Test that x86 microcode can be handled correctly
1300 We expect to see the following in the image, in order:
1301 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1303 u-boot.dtb with the microcode
1304 an empty microcode region
1306 # We need the libfdt library to run this test since only that allows
1307 # finding the offset of a property. This is required by
1308 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1309 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1311 second = data[len(U_BOOT_NODTB_DATA):]
1313 fdt_len = self.GetFdtLen(second)
1314 third = second[fdt_len:]
1315 second = second[:fdt_len]
1317 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1318 self.assertIn(ucode_data, second)
1319 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1321 # Check that the microcode pointer was inserted. It should match the
1322 # expected offset and size
1323 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1325 first = data[:len(U_BOOT_NODTB_DATA)]
1326 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1327 b' somewhere in here', first)
1329 def testPackUbootSingleMicrocode(self):
1330 """Test that x86 microcode can be handled correctly with fdt_normal.
1332 self._RunPackUbootSingleMicrocode()
1334 def testUBootImg(self):
1335 """Test that u-boot.img can be put in a file"""
1336 data = self._DoReadFile('036_u_boot_img.dts')
1337 self.assertEqual(U_BOOT_IMG_DATA, data)
1339 def testNoMicrocode(self):
1340 """Test that a missing microcode region is detected"""
1341 with self.assertRaises(ValueError) as e:
1342 self._DoReadFile('037_x86_no_ucode.dts', True)
1343 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1344 "node found in ", str(e.exception))
1346 def testMicrocodeWithoutNode(self):
1347 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1348 with self.assertRaises(ValueError) as e:
1349 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1350 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1351 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1353 def testMicrocodeWithoutNode2(self):
1354 """Test that a missing u-boot-ucode node is detected"""
1355 with self.assertRaises(ValueError) as e:
1356 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1357 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1358 "microcode region u-boot-ucode", str(e.exception))
1360 def testMicrocodeWithoutPtrInElf(self):
1361 """Test that a U-Boot binary without the microcode symbol is detected"""
1362 # ELF file without a '_dt_ucode_base_size' symbol
1364 TestFunctional._MakeInputFile('u-boot',
1365 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1367 with self.assertRaises(ValueError) as e:
1368 self._RunPackUbootSingleMicrocode()
1369 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1370 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1373 # Put the original file back
1374 TestFunctional._MakeInputFile('u-boot',
1375 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
1377 def testMicrocodeNotInImage(self):
1378 """Test that microcode must be placed within the image"""
1379 with self.assertRaises(ValueError) as e:
1380 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1381 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1382 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1383 "section ranging from 00000000 to 0000002e", str(e.exception))
1385 def testWithoutMicrocode(self):
1386 """Test that we can cope with an image without microcode (e.g. qemu)"""
1387 TestFunctional._MakeInputFile('u-boot',
1388 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1389 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1391 # Now check the device tree has no microcode
1392 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1393 second = data[len(U_BOOT_NODTB_DATA):]
1395 fdt_len = self.GetFdtLen(second)
1396 self.assertEqual(dtb, second[:fdt_len])
1398 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1399 third = data[used_len:]
1400 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
1402 def testUnknownPosSize(self):
1403 """Test that microcode must be placed within the image"""
1404 with self.assertRaises(ValueError) as e:
1405 self._DoReadFile('041_unknown_pos_size.dts', True)
1406 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1407 "entry 'invalid-entry'", str(e.exception))
1409 def testPackFsp(self):
1410 """Test that an image with a FSP binary can be created"""
1411 data = self._DoReadFile('042_intel_fsp.dts')
1412 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1414 def testPackCmc(self):
1415 """Test that an image with a CMC binary can be created"""
1416 data = self._DoReadFile('043_intel_cmc.dts')
1417 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1419 def testPackVbt(self):
1420 """Test that an image with a VBT binary can be created"""
1421 data = self._DoReadFile('046_intel_vbt.dts')
1422 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1424 def testSplBssPad(self):
1425 """Test that we can pad SPL's BSS with zeros"""
1426 # ELF file with a '__bss_size' symbol
1428 data = self._DoReadFile('047_spl_bss_pad.dts')
1429 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
1432 def testSplBssPadMissing(self):
1433 """Test that a missing symbol is detected"""
1434 self._SetupSplElf('u_boot_ucode_ptr')
1435 with self.assertRaises(ValueError) as e:
1436 self._DoReadFile('047_spl_bss_pad.dts')
1437 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1440 def testPackStart16Spl(self):
1441 """Test that an image with an x86 start16 SPL region can be created"""
1442 data = self._DoReadFile('048_x86_start16_spl.dts')
1443 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1445 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1446 """Helper function for microcode tests
1448 We expect to see the following in the image, in order:
1449 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1451 u-boot.dtb with the microcode removed
1455 dts: Device tree file to use for test
1456 ucode_second: True if the microsecond entry is second instead of
1459 self._SetupSplElf('u_boot_ucode_ptr')
1460 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1461 ucode_second=ucode_second)
1462 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1463 b'ter somewhere in here', first)
1465 def testPackUbootSplMicrocode(self):
1466 """Test that x86 microcode can be handled correctly in SPL"""
1468 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1470 def testPackUbootSplMicrocodeReorder(self):
1471 """Test that order doesn't matter for microcode entries
1473 This is the same as testPackUbootSplMicrocode but when we process the
1474 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1475 entry, so we reply on binman to try later.
1477 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1480 def testPackMrc(self):
1481 """Test that an image with an MRC binary can be created"""
1482 data = self._DoReadFile('050_intel_mrc.dts')
1483 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1485 def testSplDtb(self):
1486 """Test that an image with spl/u-boot-spl.dtb can be created"""
1488 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1489 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1491 def testSplNoDtb(self):
1492 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1494 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1495 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1497 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1498 use_expanded=False, no_write_symbols=False):
1499 """Check the image contains the expected symbol values
1502 dts: Device tree file to use for test
1503 base_data: Data before and after 'u-boot' section
1504 u_boot_offset: Offset of 'u-boot' section in image
1505 entry_args: Dict of entry args to supply to binman
1507 value: value of that arg
1508 use_expanded: True to use expanded entries where available, e.g.
1509 'u-boot-expanded' instead of 'u-boot'
1511 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1512 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1513 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1514 self.assertEqual(syms['_binman_sym_magic'].address, addr)
1515 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1518 self._SetupSplElf('u_boot_binman_syms')
1519 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1520 use_expanded=use_expanded)[0]
1521 # The image should contain the symbols from u_boot_binman_syms.c
1522 # Note that image_pos is adjusted by the base address of the image,
1523 # which is 0x10 in our test image
1524 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1525 0x00, u_boot_offset + len(U_BOOT_DATA),
1526 0x10 + u_boot_offset, 0x04)
1527 if no_write_symbols:
1528 expected = (base_data +
1529 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1530 U_BOOT_DATA + base_data)
1532 expected = (sym_values + base_data[24:] +
1533 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1535 self.assertEqual(expected, data)
1537 def testSymbols(self):
1538 """Test binman can assign symbols embedded in U-Boot"""
1539 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
1541 def testSymbolsNoDtb(self):
1542 """Test binman can assign symbols embedded in U-Boot SPL"""
1543 self.checkSymbols('196_symbols_nodtb.dts',
1544 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1547 def testPackUnitAddress(self):
1548 """Test that we support multiple binaries with the same name"""
1549 data = self._DoReadFile('054_unit_address.dts')
1550 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1552 def testSections(self):
1553 """Basic test of sections"""
1554 data = self._DoReadFile('055_sections.dts')
1555 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1556 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1557 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
1558 self.assertEqual(expected, data)
1561 """Tests outputting a map of the images"""
1562 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1563 self.assertEqual('''ImagePos Offset Size Name
1564 00000000 00000000 00000028 image
1565 00000000 00000000 00000010 section@0
1566 00000000 00000000 00000004 u-boot
1567 00000010 00000010 00000010 section@1
1568 00000010 00000000 00000004 u-boot
1569 00000020 00000020 00000004 section@2
1570 00000020 00000000 00000004 u-boot
1573 def testNamePrefix(self):
1574 """Tests that name prefixes are used"""
1575 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1576 self.assertEqual('''ImagePos Offset Size Name
1577 00000000 00000000 00000028 image
1578 00000000 00000000 00000010 section@0
1579 00000000 00000000 00000004 ro-u-boot
1580 00000010 00000010 00000010 section@1
1581 00000010 00000000 00000004 rw-u-boot
1584 def testUnknownContents(self):
1585 """Test that obtaining the contents works as expected"""
1586 with self.assertRaises(ValueError) as e:
1587 self._DoReadFile('057_unknown_contents.dts', True)
1588 self.assertIn("Image '/binman': Internal error: Could not complete "
1589 "processing of contents: remaining ["
1590 "<binman.etype._testing.Entry__testing ", str(e.exception))
1592 def testBadChangeSize(self):
1593 """Test that trying to change the size of an entry fails"""
1595 state.SetAllowEntryExpansion(False)
1596 with self.assertRaises(ValueError) as e:
1597 self._DoReadFile('059_change_size.dts', True)
1598 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1601 state.SetAllowEntryExpansion(True)
1603 def testUpdateFdt(self):
1604 """Test that we can update the device tree with offset/size info"""
1605 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1607 dtb = fdt.Fdt(out_dtb_fname)
1609 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1613 '_testing:offset': 32,
1615 '_testing:image-pos': 32,
1616 'section@0/u-boot:offset': 0,
1617 'section@0/u-boot:size': len(U_BOOT_DATA),
1618 'section@0/u-boot:image-pos': 0,
1619 'section@0:offset': 0,
1620 'section@0:size': 16,
1621 'section@0:image-pos': 0,
1623 'section@1/u-boot:offset': 0,
1624 'section@1/u-boot:size': len(U_BOOT_DATA),
1625 'section@1/u-boot:image-pos': 16,
1626 'section@1:offset': 16,
1627 'section@1:size': 16,
1628 'section@1:image-pos': 16,
1632 def testUpdateFdtBad(self):
1633 """Test that we detect when ProcessFdt never completes"""
1634 with self.assertRaises(ValueError) as e:
1635 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1636 self.assertIn('Could not complete processing of Fdt: remaining '
1637 '[<binman.etype._testing.Entry__testing',
1640 def testEntryArgs(self):
1641 """Test passing arguments to entries from the command line"""
1643 'test-str-arg': 'test1',
1644 'test-int-arg': '456',
1646 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1647 self.assertIn('image', control.images)
1648 entry = control.images['image'].GetEntries()['_testing']
1649 self.assertEqual('test0', entry.test_str_fdt)
1650 self.assertEqual('test1', entry.test_str_arg)
1651 self.assertEqual(123, entry.test_int_fdt)
1652 self.assertEqual(456, entry.test_int_arg)
1654 def testEntryArgsMissing(self):
1655 """Test missing arguments and properties"""
1657 'test-int-arg': '456',
1659 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1660 entry = control.images['image'].GetEntries()['_testing']
1661 self.assertEqual('test0', entry.test_str_fdt)
1662 self.assertEqual(None, entry.test_str_arg)
1663 self.assertEqual(None, entry.test_int_fdt)
1664 self.assertEqual(456, entry.test_int_arg)
1666 def testEntryArgsRequired(self):
1667 """Test missing arguments and properties"""
1669 'test-int-arg': '456',
1671 with self.assertRaises(ValueError) as e:
1672 self._DoReadFileDtb('064_entry_args_required.dts')
1673 self.assertIn("Node '/binman/_testing': "
1674 'Missing required properties/entry args: test-str-arg, '
1675 'test-int-fdt, test-int-arg',
1678 def testEntryArgsInvalidFormat(self):
1679 """Test that an invalid entry-argument format is detected"""
1680 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1682 with self.assertRaises(ValueError) as e:
1683 self._DoBinman(*args)
1684 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1686 def testEntryArgsInvalidInteger(self):
1687 """Test that an invalid entry-argument integer is detected"""
1689 'test-int-arg': 'abc',
1691 with self.assertRaises(ValueError) as e:
1692 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1693 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1694 "'test-int-arg' (value 'abc') to integer",
1697 def testEntryArgsInvalidDatatype(self):
1698 """Test that an invalid entry-argument datatype is detected
1700 This test could be written in entry_test.py except that it needs
1701 access to control.entry_args, which seems more than that module should
1705 'test-bad-datatype-arg': '12',
1707 with self.assertRaises(ValueError) as e:
1708 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1709 entry_args=entry_args)
1710 self.assertIn('GetArg() internal error: Unknown data type ',
1714 """Test for a text entry type"""
1716 'test-id': TEXT_DATA,
1717 'test-id2': TEXT_DATA2,
1718 'test-id3': TEXT_DATA3,
1720 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1721 entry_args=entry_args)
1722 expected = (tools.to_bytes(TEXT_DATA) +
1723 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1724 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
1725 b'some text' + b'more text')
1726 self.assertEqual(expected, data)
1728 def testEntryDocs(self):
1729 """Test for creation of entry documentation"""
1730 with test_util.capture_sys_output() as (stdout, stderr):
1731 control.WriteEntryDocs(control.GetEntryModules())
1732 self.assertTrue(len(stdout.getvalue()) > 0)
1734 def testEntryDocsMissing(self):
1735 """Test handling of missing entry documentation"""
1736 with self.assertRaises(ValueError) as e:
1737 with test_util.capture_sys_output() as (stdout, stderr):
1738 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1739 self.assertIn('Documentation is missing for modules: u_boot',
1743 """Basic test of generation of a flashrom fmap"""
1744 data = self._DoReadFile('067_fmap.dts')
1745 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1746 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1747 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
1748 self.assertEqual(expected, data[:32])
1749 self.assertEqual(b'__FMAP__', fhdr.signature)
1750 self.assertEqual(1, fhdr.ver_major)
1751 self.assertEqual(0, fhdr.ver_minor)
1752 self.assertEqual(0, fhdr.base)
1753 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1754 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1755 self.assertEqual(b'FMAP', fhdr.name)
1756 self.assertEqual(5, fhdr.nareas)
1757 fiter = iter(fentries)
1759 fentry = next(fiter)
1760 self.assertEqual(b'SECTION0', fentry.name)
1761 self.assertEqual(0, fentry.offset)
1762 self.assertEqual(16, fentry.size)
1763 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
1765 fentry = next(fiter)
1766 self.assertEqual(b'RO_U_BOOT', fentry.name)
1767 self.assertEqual(0, fentry.offset)
1768 self.assertEqual(4, fentry.size)
1769 self.assertEqual(0, fentry.flags)
1771 fentry = next(fiter)
1772 self.assertEqual(b'SECTION1', fentry.name)
1773 self.assertEqual(16, fentry.offset)
1774 self.assertEqual(16, fentry.size)
1775 self.assertEqual(0, fentry.flags)
1777 fentry = next(fiter)
1778 self.assertEqual(b'RW_U_BOOT', fentry.name)
1779 self.assertEqual(16, fentry.offset)
1780 self.assertEqual(4, fentry.size)
1781 self.assertEqual(0, fentry.flags)
1783 fentry = next(fiter)
1784 self.assertEqual(b'FMAP', fentry.name)
1785 self.assertEqual(32, fentry.offset)
1786 self.assertEqual(expect_size, fentry.size)
1787 self.assertEqual(0, fentry.flags)
1789 def testBlobNamedByArg(self):
1790 """Test we can add a blob with the filename coming from an entry arg"""
1792 'cros-ec-rw-path': 'ecrw.bin',
1794 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1797 """Test for an fill entry type"""
1798 data = self._DoReadFile('069_fill.dts')
1799 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
1800 self.assertEqual(expected, data)
1802 def testFillNoSize(self):
1803 """Test for an fill entry type with no size"""
1804 with self.assertRaises(ValueError) as e:
1805 self._DoReadFile('070_fill_no_size.dts')
1806 self.assertIn("'fill' entry is missing properties: size",
1809 def _HandleGbbCommand(self, pipe_list):
1810 """Fake calls to the futility utility"""
1811 if 'futility' in pipe_list[0][0]:
1812 fname = pipe_list[0][-1]
1813 # Append our GBB data to the file, which will happen every time the
1814 # futility command is called.
1815 with open(fname, 'ab') as fd:
1817 return command.CommandResult()
1820 """Test for the Chromium OS Google Binary Block"""
1821 command.test_result = self._HandleGbbCommand
1823 'keydir': 'devkeys',
1824 'bmpblk': 'bmpblk.bin',
1826 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1829 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1830 tools.get_bytes(0, 0x2180 - 16))
1831 self.assertEqual(expected, data)
1833 def testGbbTooSmall(self):
1834 """Test for the Chromium OS Google Binary Block being large enough"""
1835 with self.assertRaises(ValueError) as e:
1836 self._DoReadFileDtb('072_gbb_too_small.dts')
1837 self.assertIn("Node '/binman/gbb': GBB is too small",
1840 def testGbbNoSize(self):
1841 """Test for the Chromium OS Google Binary Block having a size"""
1842 with self.assertRaises(ValueError) as e:
1843 self._DoReadFileDtb('073_gbb_no_size.dts')
1844 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1847 def testGbbMissing(self):
1848 """Test that binman still produces an image if futility is missing"""
1850 'keydir': 'devkeys',
1852 with test_util.capture_sys_output() as (_, stderr):
1853 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1854 entry_args=entry_args)
1855 err = stderr.getvalue()
1856 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
1858 def _HandleVblockCommand(self, pipe_list):
1859 """Fake calls to the futility utility
1861 The expected pipe is:
1863 [('futility', 'vbutil_firmware', '--vblock',
1864 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1865 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1866 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1867 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1869 This writes to the output file (here, 'vblock.vblock'). If
1870 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1871 of the input data (here, 'input.vblock').
1873 if 'futility' in pipe_list[0][0]:
1874 fname = pipe_list[0][3]
1875 with open(fname, 'wb') as fd:
1877 infile = pipe_list[0][11]
1878 m = hashlib.sha256()
1879 data = tools.read_file(infile)
1881 fd.write(m.digest())
1883 fd.write(VBLOCK_DATA)
1885 return command.CommandResult()
1887 def testVblock(self):
1888 """Test for the Chromium OS Verified Boot Block"""
1889 self._hash_data = False
1890 command.test_result = self._HandleVblockCommand
1892 'keydir': 'devkeys',
1894 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1895 entry_args=entry_args)
1896 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1897 self.assertEqual(expected, data)
1899 def testVblockNoContent(self):
1900 """Test we detect a vblock which has no content to sign"""
1901 with self.assertRaises(ValueError) as e:
1902 self._DoReadFile('075_vblock_no_content.dts')
1903 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1904 'property', str(e.exception))
1906 def testVblockBadPhandle(self):
1907 """Test that we detect a vblock with an invalid phandle in contents"""
1908 with self.assertRaises(ValueError) as e:
1909 self._DoReadFile('076_vblock_bad_phandle.dts')
1910 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1911 '1000', str(e.exception))
1913 def testVblockBadEntry(self):
1914 """Test that we detect an entry that points to a non-entry"""
1915 with self.assertRaises(ValueError) as e:
1916 self._DoReadFile('077_vblock_bad_entry.dts')
1917 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1918 "'other'", str(e.exception))
1920 def testVblockContent(self):
1921 """Test that the vblock signs the right data"""
1922 self._hash_data = True
1923 command.test_result = self._HandleVblockCommand
1925 'keydir': 'devkeys',
1927 data = self._DoReadFileDtb(
1928 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1929 entry_args=entry_args)[0]
1930 hashlen = 32 # SHA256 hash is 32 bytes
1931 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1932 hashval = data[-hashlen:]
1933 dtb = data[len(U_BOOT_DATA):-hashlen]
1935 expected_data = U_BOOT_DATA + dtb
1937 # The hashval should be a hash of the dtb
1938 m = hashlib.sha256()
1939 m.update(expected_data)
1940 expected_hashval = m.digest()
1941 self.assertEqual(expected_hashval, hashval)
1943 def testVblockMissing(self):
1944 """Test that binman still produces an image if futility is missing"""
1946 'keydir': 'devkeys',
1948 with test_util.capture_sys_output() as (_, stderr):
1949 self._DoTestFile('074_vblock.dts',
1950 force_missing_bintools='futility',
1951 entry_args=entry_args)
1952 err = stderr.getvalue()
1953 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
1956 """Test that an image with TPL and its device tree can be created"""
1957 # ELF file with a '__bss_size' symbol
1959 data = self._DoReadFile('078_u_boot_tpl.dts')
1960 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1962 def testUsesPos(self):
1963 """Test that the 'pos' property cannot be used anymore"""
1964 with self.assertRaises(ValueError) as e:
1965 data = self._DoReadFile('079_uses_pos.dts')
1966 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1967 "'pos'", str(e.exception))
1969 def testFillZero(self):
1970 """Test for an fill entry type with a size of 0"""
1971 data = self._DoReadFile('080_fill_empty.dts')
1972 self.assertEqual(tools.get_bytes(0, 16), data)
1974 def testTextMissing(self):
1975 """Test for a text entry type where there is no text"""
1976 with self.assertRaises(ValueError) as e:
1977 self._DoReadFileDtb('066_text.dts',)
1978 self.assertIn("Node '/binman/text': No value provided for text label "
1979 "'test-id'", str(e.exception))
1981 def testPackStart16Tpl(self):
1982 """Test that an image with an x86 start16 TPL region can be created"""
1983 data = self._DoReadFile('081_x86_start16_tpl.dts')
1984 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1986 def testSelectImage(self):
1987 """Test that we can select which images to build"""
1988 expected = 'Skipping images: image1'
1990 # We should only get the expected message in verbose mode
1991 for verbosity in (0, 2):
1992 with test_util.capture_sys_output() as (stdout, stderr):
1993 retcode = self._DoTestFile('006_dual_image.dts',
1994 verbosity=verbosity,
1996 self.assertEqual(0, retcode)
1998 self.assertIn(expected, stdout.getvalue())
2000 self.assertNotIn(expected, stdout.getvalue())
2002 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2003 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
2004 self._CleanupOutputDir()
2006 def testUpdateFdtAll(self):
2007 """Test that all device trees are updated with offset/size info"""
2010 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
2016 'section:offset': 0,
2017 'section:image-pos': 0,
2018 'section:size': 565,
2019 'section/u-boot-dtb:offset': 0,
2020 'section/u-boot-dtb:image-pos': 0,
2021 'section/u-boot-dtb:size': 565,
2022 'u-boot-spl-dtb:offset': 565,
2023 'u-boot-spl-dtb:image-pos': 565,
2024 'u-boot-spl-dtb:size': 585,
2025 'u-boot-tpl-dtb:offset': 1150,
2026 'u-boot-tpl-dtb:image-pos': 1150,
2027 'u-boot-tpl-dtb:size': 585,
2028 'u-boot-vpl-dtb:image-pos': 1735,
2029 'u-boot-vpl-dtb:offset': 1735,
2030 'u-boot-vpl-dtb:size': 585,
2033 # We expect three device-tree files in the output, one after the other.
2034 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2035 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2036 # main U-Boot tree. All three should have the same postions and offset.
2039 for item in ['', 'spl', 'tpl', 'vpl']:
2040 dtb = fdt.Fdt.FromData(data[start:])
2042 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
2043 ['spl', 'tpl', 'vpl'])
2044 expected = dict(base_expected)
2047 self.assertEqual(expected, props)
2048 start += dtb._fdt_obj.totalsize()
2050 def testUpdateFdtOutput(self):
2051 """Test that output DTB files are updated"""
2053 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
2054 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2056 # Unfortunately, compiling a source file always results in a file
2057 # called source.dtb (see fdt_util.EnsureCompiled()). The test
2058 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
2059 # binman as a file called u-boot.dtb. To fix this, copy the file
2060 # over to the expected place.
2062 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
2063 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
2064 dtb = fdt.Fdt.FromData(data[start:])
2065 size = dtb._fdt_obj.totalsize()
2066 pathname = tools.get_output_filename(os.path.split(fname)[1])
2067 outdata = tools.read_file(pathname)
2068 name = os.path.split(fname)[0]
2071 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
2073 orig_indata = dtb_data
2074 self.assertNotEqual(outdata, orig_indata,
2075 "Expected output file '%s' be updated" % pathname)
2076 self.assertEqual(outdata, data[start:start + size],
2077 "Expected output file '%s' to match output image" %
2083 def _decompress(self, data):
2084 bintool = self.comp_bintools['lz4']
2085 return bintool.decompress(data)
2087 def testCompress(self):
2088 """Test compression of blobs"""
2090 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
2091 use_real_dtb=True, update_dtb=True)
2092 dtb = fdt.Fdt(out_dtb_fname)
2094 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2095 orig = self._decompress(data)
2096 self.assertEquals(COMPRESS_DATA, orig)
2098 # Do a sanity check on various fields
2099 image = control.images['image']
2100 entries = image.GetEntries()
2101 self.assertEqual(1, len(entries))
2103 entry = entries['blob']
2104 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2105 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2106 orig = self._decompress(entry.data)
2107 self.assertEqual(orig, entry.uncomp_data)
2109 self.assertEqual(image.data, entry.data)
2112 'blob:uncomp-size': len(COMPRESS_DATA),
2113 'blob:size': len(data),
2116 self.assertEqual(expected, props)
2118 def testFiles(self):
2119 """Test bringing in multiple files"""
2120 data = self._DoReadFile('084_files.dts')
2121 self.assertEqual(FILES_DATA, data)
2123 def testFilesCompress(self):
2124 """Test bringing in multiple files and compressing them"""
2126 data = self._DoReadFile('085_files_compress.dts')
2128 image = control.images['image']
2129 entries = image.GetEntries()
2130 files = entries['files']
2131 entries = files._entries
2134 for i in range(1, 3):
2136 start = entries[key].image_pos
2137 len = entries[key].size
2138 chunk = data[start:start + len]
2139 orig += self._decompress(chunk)
2141 self.assertEqual(FILES_DATA, orig)
2143 def testFilesMissing(self):
2144 """Test missing files"""
2145 with self.assertRaises(ValueError) as e:
2146 data = self._DoReadFile('086_files_none.dts')
2147 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2148 'no files', str(e.exception))
2150 def testFilesNoPattern(self):
2151 """Test missing files"""
2152 with self.assertRaises(ValueError) as e:
2153 data = self._DoReadFile('087_files_no_pattern.dts')
2154 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2157 def testExtendSize(self):
2158 """Test an extending entry"""
2159 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
2161 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2162 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2163 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2164 tools.get_bytes(ord('d'), 8))
2165 self.assertEqual(expect, data)
2166 self.assertEqual('''ImagePos Offset Size Name
2167 00000000 00000000 00000028 image
2168 00000000 00000000 00000008 fill
2169 00000008 00000008 00000004 u-boot
2170 0000000c 0000000c 00000004 section
2171 0000000c 00000000 00000003 intel-mrc
2172 00000010 00000010 00000004 u-boot2
2173 00000014 00000014 0000000c section2
2174 00000014 00000000 00000008 fill
2175 0000001c 00000008 00000004 u-boot
2176 00000020 00000020 00000008 fill2
2179 def testExtendSizeBad(self):
2180 """Test an extending entry which fails to provide contents"""
2181 with test_util.capture_sys_output() as (stdout, stderr):
2182 with self.assertRaises(ValueError) as e:
2183 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
2184 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2185 'expanding entry', str(e.exception))
2188 """Test hashing of the contents of an entry"""
2189 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2190 use_real_dtb=True, update_dtb=True)
2191 dtb = fdt.Fdt(out_dtb_fname)
2193 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2194 m = hashlib.sha256()
2195 m.update(U_BOOT_DATA)
2196 self.assertEqual(m.digest(), b''.join(hash_node.value))
2198 def testHashNoAlgo(self):
2199 with self.assertRaises(ValueError) as e:
2200 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2201 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2202 'hash node', str(e.exception))
2204 def testHashBadAlgo(self):
2205 with self.assertRaises(ValueError) as e:
2206 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2207 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
2210 def testHashSection(self):
2211 """Test hashing of the contents of an entry"""
2212 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2213 use_real_dtb=True, update_dtb=True)
2214 dtb = fdt.Fdt(out_dtb_fname)
2216 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2217 m = hashlib.sha256()
2218 m.update(U_BOOT_DATA)
2219 m.update(tools.get_bytes(ord('a'), 16))
2220 self.assertEqual(m.digest(), b''.join(hash_node.value))
2222 def testPackUBootTplMicrocode(self):
2223 """Test that x86 microcode can be handled correctly in TPL
2225 We expect to see the following in the image, in order:
2226 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2228 u-boot-tpl.dtb with the microcode removed
2231 self._SetupTplElf('u_boot_ucode_ptr')
2232 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2233 U_BOOT_TPL_NODTB_DATA)
2234 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2235 b'ter somewhere in here', first)
2237 def testFmapX86(self):
2238 """Basic test of generation of a flashrom fmap"""
2239 data = self._DoReadFile('094_fmap_x86.dts')
2240 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2241 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
2242 self.assertEqual(expected, data[:32])
2243 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2245 self.assertEqual(0x100, fhdr.image_size)
2247 self.assertEqual(0, fentries[0].offset)
2248 self.assertEqual(4, fentries[0].size)
2249 self.assertEqual(b'U_BOOT', fentries[0].name)
2251 self.assertEqual(4, fentries[1].offset)
2252 self.assertEqual(3, fentries[1].size)
2253 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2255 self.assertEqual(32, fentries[2].offset)
2256 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2257 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2258 self.assertEqual(b'FMAP', fentries[2].name)
2260 def testFmapX86Section(self):
2261 """Basic test of generation of a flashrom fmap"""
2262 data = self._DoReadFile('095_fmap_x86_section.dts')
2263 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
2264 self.assertEqual(expected, data[:32])
2265 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2267 self.assertEqual(0x180, fhdr.image_size)
2268 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2269 fiter = iter(fentries)
2271 fentry = next(fiter)
2272 self.assertEqual(b'U_BOOT', fentry.name)
2273 self.assertEqual(0, fentry.offset)
2274 self.assertEqual(4, fentry.size)
2276 fentry = next(fiter)
2277 self.assertEqual(b'SECTION', fentry.name)
2278 self.assertEqual(4, fentry.offset)
2279 self.assertEqual(0x20 + expect_size, fentry.size)
2281 fentry = next(fiter)
2282 self.assertEqual(b'INTEL_MRC', fentry.name)
2283 self.assertEqual(4, fentry.offset)
2284 self.assertEqual(3, fentry.size)
2286 fentry = next(fiter)
2287 self.assertEqual(b'FMAP', fentry.name)
2288 self.assertEqual(36, fentry.offset)
2289 self.assertEqual(expect_size, fentry.size)
2292 """Basic test of ELF entries"""
2295 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2296 TestFunctional._MakeInputFile('-boot', fd.read())
2297 data = self._DoReadFile('096_elf.dts')
2299 def testElfStrip(self):
2300 """Basic test of ELF entries"""
2302 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2303 TestFunctional._MakeInputFile('-boot', fd.read())
2304 data = self._DoReadFile('097_elf_strip.dts')
2306 def testPackOverlapMap(self):
2307 """Test that overlapping regions are detected"""
2308 with test_util.capture_sys_output() as (stdout, stderr):
2309 with self.assertRaises(ValueError) as e:
2310 self._DoTestFile('014_pack_overlap.dts', map=True)
2311 map_fname = tools.get_output_filename('image.map')
2312 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2315 # We should not get an inmage, but there should be a map file
2316 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
2317 self.assertTrue(os.path.exists(map_fname))
2318 map_data = tools.read_file(map_fname, binary=False)
2319 self.assertEqual('''ImagePos Offset Size Name
2320 <none> 00000000 00000008 image
2321 <none> 00000000 00000004 u-boot
2322 <none> 00000003 00000004 u-boot-align
2325 def testPackRefCode(self):
2326 """Test that an image with an Intel Reference code binary works"""
2327 data = self._DoReadFile('100_intel_refcode.dts')
2328 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2330 def testSectionOffset(self):
2331 """Tests use of a section with an offset"""
2332 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2334 self.assertEqual('''ImagePos Offset Size Name
2335 00000000 00000000 00000038 image
2336 00000004 00000004 00000010 section@0
2337 00000004 00000000 00000004 u-boot
2338 00000018 00000018 00000010 section@1
2339 00000018 00000000 00000004 u-boot
2340 0000002c 0000002c 00000004 section@2
2341 0000002c 00000000 00000004 u-boot
2343 self.assertEqual(data,
2344 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2345 tools.get_bytes(0x21, 12) +
2346 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2347 tools.get_bytes(0x61, 12) +
2348 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2349 tools.get_bytes(0x26, 8))
2351 def testCbfsRaw(self):
2352 """Test base handling of a Coreboot Filesystem (CBFS)
2354 The exact contents of the CBFS is verified by similar tests in
2355 cbfs_util_test.py. The tests here merely check that the files added to
2356 the CBFS can be found in the final image.
2358 data = self._DoReadFile('102_cbfs_raw.dts')
2361 cbfs = cbfs_util.CbfsReader(data)
2362 self.assertEqual(size, cbfs.rom_size)
2364 self.assertIn('u-boot-dtb', cbfs.files)
2365 cfile = cbfs.files['u-boot-dtb']
2366 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2368 def testCbfsArch(self):
2369 """Test on non-x86 architecture"""
2370 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2373 cbfs = cbfs_util.CbfsReader(data)
2374 self.assertEqual(size, cbfs.rom_size)
2376 self.assertIn('u-boot-dtb', cbfs.files)
2377 cfile = cbfs.files['u-boot-dtb']
2378 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2380 def testCbfsStage(self):
2381 """Tests handling of a Coreboot Filesystem (CBFS)"""
2382 if not elf.ELF_TOOLS:
2383 self.skipTest('Python elftools not available')
2384 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2385 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2388 data = self._DoReadFile('104_cbfs_stage.dts')
2389 cbfs = cbfs_util.CbfsReader(data)
2390 self.assertEqual(size, cbfs.rom_size)
2392 self.assertIn('u-boot', cbfs.files)
2393 cfile = cbfs.files['u-boot']
2394 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2396 def testCbfsRawCompress(self):
2397 """Test handling of compressing raw files"""
2399 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2402 cbfs = cbfs_util.CbfsReader(data)
2403 self.assertIn('u-boot', cbfs.files)
2404 cfile = cbfs.files['u-boot']
2405 self.assertEqual(COMPRESS_DATA, cfile.data)
2407 def testCbfsBadArch(self):
2408 """Test handling of a bad architecture"""
2409 with self.assertRaises(ValueError) as e:
2410 self._DoReadFile('106_cbfs_bad_arch.dts')
2411 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2413 def testCbfsNoSize(self):
2414 """Test handling of a missing size property"""
2415 with self.assertRaises(ValueError) as e:
2416 self._DoReadFile('107_cbfs_no_size.dts')
2417 self.assertIn('entry must have a size property', str(e.exception))
2419 def testCbfsNoContents(self):
2420 """Test handling of a CBFS entry which does not provide contentsy"""
2421 with self.assertRaises(ValueError) as e:
2422 self._DoReadFile('108_cbfs_no_contents.dts')
2423 self.assertIn('Could not complete processing of contents',
2426 def testCbfsBadCompress(self):
2427 """Test handling of a bad architecture"""
2428 with self.assertRaises(ValueError) as e:
2429 self._DoReadFile('109_cbfs_bad_compress.dts')
2430 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2433 def testCbfsNamedEntries(self):
2434 """Test handling of named entries"""
2435 data = self._DoReadFile('110_cbfs_name.dts')
2437 cbfs = cbfs_util.CbfsReader(data)
2438 self.assertIn('FRED', cbfs.files)
2439 cfile1 = cbfs.files['FRED']
2440 self.assertEqual(U_BOOT_DATA, cfile1.data)
2442 self.assertIn('hello', cbfs.files)
2443 cfile2 = cbfs.files['hello']
2444 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2446 def _SetupIfwi(self, fname):
2447 """Set up to run an IFWI test
2450 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2455 # Intel Integrated Firmware Image (IFWI) file
2456 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2458 TestFunctional._MakeInputFile(fname,data)
2460 def _CheckIfwi(self, data):
2461 """Check that an image with an IFWI contains the correct output
2464 data: Conents of output file
2466 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
2467 if data[:0x1000] != expected_desc:
2468 self.fail('Expected descriptor binary at start of image')
2470 # We expect to find the TPL wil in subpart IBBP entry IBBL
2471 image_fname = tools.get_output_filename('image.bin')
2472 tpl_fname = tools.get_output_filename('tpl.out')
2473 ifwitool = bintool.Bintool.create('ifwitool')
2474 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
2476 tpl_data = tools.read_file(tpl_fname)
2477 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2479 def testPackX86RomIfwi(self):
2480 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2481 self._SetupIfwi('fitimage.bin')
2482 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2483 self._CheckIfwi(data)
2485 def testPackX86RomIfwiNoDesc(self):
2486 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2487 self._SetupIfwi('ifwi.bin')
2488 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2489 self._CheckIfwi(data)
2491 def testPackX86RomIfwiNoData(self):
2492 """Test that an x86 ROM with IFWI handles missing data"""
2493 self._SetupIfwi('ifwi.bin')
2494 with self.assertRaises(ValueError) as e:
2495 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2496 self.assertIn('Could not complete processing of contents',
2499 def testIfwiMissing(self):
2500 """Test that binman still produces an image if ifwitool is missing"""
2501 self._SetupIfwi('fitimage.bin')
2502 with test_util.capture_sys_output() as (_, stderr):
2503 self._DoTestFile('111_x86_rom_ifwi.dts',
2504 force_missing_bintools='ifwitool')
2505 err = stderr.getvalue()
2506 self.assertRegex(err,
2507 "Image 'image'.*missing bintools.*: ifwitool")
2509 def testCbfsOffset(self):
2510 """Test a CBFS with files at particular offsets
2512 Like all CFBS tests, this is just checking the logic that calls
2513 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2515 data = self._DoReadFile('114_cbfs_offset.dts')
2518 cbfs = cbfs_util.CbfsReader(data)
2519 self.assertEqual(size, cbfs.rom_size)
2521 self.assertIn('u-boot', cbfs.files)
2522 cfile = cbfs.files['u-boot']
2523 self.assertEqual(U_BOOT_DATA, cfile.data)
2524 self.assertEqual(0x40, cfile.cbfs_offset)
2526 self.assertIn('u-boot-dtb', cbfs.files)
2527 cfile2 = cbfs.files['u-boot-dtb']
2528 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2529 self.assertEqual(0x140, cfile2.cbfs_offset)
2531 def testFdtmap(self):
2532 """Test an FDT map can be inserted in the image"""
2533 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2534 fdtmap_data = data[len(U_BOOT_DATA):]
2535 magic = fdtmap_data[:8]
2536 self.assertEqual(b'_FDTMAP_', magic)
2537 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
2539 fdt_data = fdtmap_data[16:]
2540 dtb = fdt.Fdt.FromData(fdt_data)
2542 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2547 'u-boot:size': len(U_BOOT_DATA),
2548 'u-boot:image-pos': 0,
2549 'fdtmap:image-pos': 4,
2551 'fdtmap:size': len(fdtmap_data),
2555 def testFdtmapNoMatch(self):
2556 """Check handling of an FDT map when the section cannot be found"""
2557 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2559 # Mangle the section name, which should cause a mismatch between the
2560 # correct FDT path and the one expected by the section
2561 image = control.images['image']
2562 image._node.path += '-suffix'
2563 entries = image.GetEntries()
2564 fdtmap = entries['fdtmap']
2565 with self.assertRaises(ValueError) as e:
2567 self.assertIn("Cannot locate node for path '/binman-suffix'",
2570 def testFdtmapHeader(self):
2571 """Test an FDT map and image header can be inserted in the image"""
2572 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2573 fdtmap_pos = len(U_BOOT_DATA)
2574 fdtmap_data = data[fdtmap_pos:]
2575 fdt_data = fdtmap_data[16:]
2576 dtb = fdt.Fdt.FromData(fdt_data)
2577 fdt_size = dtb.GetFdtObj().totalsize()
2578 hdr_data = data[-8:]
2579 self.assertEqual(b'BinM', hdr_data[:4])
2580 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2581 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2583 def testFdtmapHeaderStart(self):
2584 """Test an image header can be inserted at the image start"""
2585 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2586 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2588 self.assertEqual(b'BinM', hdr_data[:4])
2589 offset = struct.unpack('<I', hdr_data[4:])[0]
2590 self.assertEqual(fdtmap_pos, offset)
2592 def testFdtmapHeaderPos(self):
2593 """Test an image header can be inserted at a chosen position"""
2594 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2595 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2596 hdr_data = data[0x80:0x88]
2597 self.assertEqual(b'BinM', hdr_data[:4])
2598 offset = struct.unpack('<I', hdr_data[4:])[0]
2599 self.assertEqual(fdtmap_pos, offset)
2601 def testHeaderMissingFdtmap(self):
2602 """Test an image header requires an fdtmap"""
2603 with self.assertRaises(ValueError) as e:
2604 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2605 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2608 def testHeaderNoLocation(self):
2609 """Test an image header with a no specified location is detected"""
2610 with self.assertRaises(ValueError) as e:
2611 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2612 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2615 def testEntryExpand(self):
2616 """Test extending an entry after it is packed"""
2617 data = self._DoReadFile('121_entry_extend.dts')
2618 self.assertEqual(b'aaa', data[:3])
2619 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2620 self.assertEqual(b'aaa', data[-3:])
2622 def testEntryExtendBad(self):
2623 """Test extending an entry after it is packed, twice"""
2624 with self.assertRaises(ValueError) as e:
2625 self._DoReadFile('122_entry_extend_twice.dts')
2626 self.assertIn("Image '/binman': Entries changed size after packing",
2629 def testEntryExtendSection(self):
2630 """Test extending an entry within a section after it is packed"""
2631 data = self._DoReadFile('123_entry_extend_section.dts')
2632 self.assertEqual(b'aaa', data[:3])
2633 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2634 self.assertEqual(b'aaa', data[-3:])
2636 def testCompressDtb(self):
2637 """Test that compress of device-tree files is supported"""
2639 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2640 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2641 comp_data = data[len(U_BOOT_DATA):]
2642 orig = self._decompress(comp_data)
2643 dtb = fdt.Fdt.FromData(orig)
2645 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2647 'u-boot:size': len(U_BOOT_DATA),
2648 'u-boot-dtb:uncomp-size': len(orig),
2649 'u-boot-dtb:size': len(comp_data),
2652 self.assertEqual(expected, props)
2654 def testCbfsUpdateFdt(self):
2655 """Test that we can update the device tree with CBFS offset/size info"""
2657 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2659 dtb = fdt.Fdt(out_dtb_fname)
2661 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2662 del props['cbfs/u-boot:size']
2668 'cbfs:size': len(data),
2669 'cbfs:image-pos': 0,
2670 'cbfs/u-boot:offset': 0x38,
2671 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2672 'cbfs/u-boot:image-pos': 0x38,
2673 'cbfs/u-boot-dtb:offset': 0xb8,
2674 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2675 'cbfs/u-boot-dtb:image-pos': 0xb8,
2678 def testCbfsBadType(self):
2679 """Test an image header with a no specified location is detected"""
2680 with self.assertRaises(ValueError) as e:
2681 self._DoReadFile('126_cbfs_bad_type.dts')
2682 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2685 """Test listing the files in an image"""
2687 data = self._DoReadFile('127_list.dts')
2688 image = control.images['image']
2689 entries = image.BuildEntryList()
2690 self.assertEqual(7, len(entries))
2693 self.assertEqual(0, ent.indent)
2694 self.assertEqual('image', ent.name)
2695 self.assertEqual('section', ent.etype)
2696 self.assertEqual(len(data), ent.size)
2697 self.assertEqual(0, ent.image_pos)
2698 self.assertEqual(None, ent.uncomp_size)
2699 self.assertEqual(0, ent.offset)
2702 self.assertEqual(1, ent.indent)
2703 self.assertEqual('u-boot', ent.name)
2704 self.assertEqual('u-boot', ent.etype)
2705 self.assertEqual(len(U_BOOT_DATA), ent.size)
2706 self.assertEqual(0, ent.image_pos)
2707 self.assertEqual(None, ent.uncomp_size)
2708 self.assertEqual(0, ent.offset)
2711 self.assertEqual(1, ent.indent)
2712 self.assertEqual('section', ent.name)
2713 self.assertEqual('section', ent.etype)
2714 section_size = ent.size
2715 self.assertEqual(0x100, ent.image_pos)
2716 self.assertEqual(None, ent.uncomp_size)
2717 self.assertEqual(0x100, ent.offset)
2720 self.assertEqual(2, ent.indent)
2721 self.assertEqual('cbfs', ent.name)
2722 self.assertEqual('cbfs', ent.etype)
2723 self.assertEqual(0x400, ent.size)
2724 self.assertEqual(0x100, ent.image_pos)
2725 self.assertEqual(None, ent.uncomp_size)
2726 self.assertEqual(0, ent.offset)
2729 self.assertEqual(3, ent.indent)
2730 self.assertEqual('u-boot', ent.name)
2731 self.assertEqual('u-boot', ent.etype)
2732 self.assertEqual(len(U_BOOT_DATA), ent.size)
2733 self.assertEqual(0x138, ent.image_pos)
2734 self.assertEqual(None, ent.uncomp_size)
2735 self.assertEqual(0x38, ent.offset)
2738 self.assertEqual(3, ent.indent)
2739 self.assertEqual('u-boot-dtb', ent.name)
2740 self.assertEqual('text', ent.etype)
2741 self.assertGreater(len(COMPRESS_DATA), ent.size)
2742 self.assertEqual(0x178, ent.image_pos)
2743 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2744 self.assertEqual(0x78, ent.offset)
2747 self.assertEqual(2, ent.indent)
2748 self.assertEqual('u-boot-dtb', ent.name)
2749 self.assertEqual('u-boot-dtb', ent.etype)
2750 self.assertEqual(0x500, ent.image_pos)
2751 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2753 # Compressing this data expands it since headers are added
2754 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2755 self.assertEqual(0x400, ent.offset)
2757 self.assertEqual(len(data), 0x100 + section_size)
2758 self.assertEqual(section_size, 0x400 + dtb_size)
2760 def testFindFdtmap(self):
2761 """Test locating an FDT map in an image"""
2763 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2764 image = control.images['image']
2765 entries = image.GetEntries()
2766 entry = entries['fdtmap']
2767 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2769 def testFindFdtmapMissing(self):
2770 """Test failing to locate an FDP map"""
2771 data = self._DoReadFile('005_simple.dts')
2772 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2774 def testFindImageHeader(self):
2775 """Test locating a image header"""
2777 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2778 image = control.images['image']
2779 entries = image.GetEntries()
2780 entry = entries['fdtmap']
2781 # The header should point to the FDT map
2782 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2784 def testFindImageHeaderStart(self):
2785 """Test locating a image header located at the start of an image"""
2786 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2787 image = control.images['image']
2788 entries = image.GetEntries()
2789 entry = entries['fdtmap']
2790 # The header should point to the FDT map
2791 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2793 def testFindImageHeaderMissing(self):
2794 """Test failing to locate an image header"""
2795 data = self._DoReadFile('005_simple.dts')
2796 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2798 def testReadImage(self):
2799 """Test reading an image and accessing its FDT map"""
2801 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2802 image_fname = tools.get_output_filename('image.bin')
2803 orig_image = control.images['image']
2804 image = Image.FromFile(image_fname)
2805 self.assertEqual(orig_image.GetEntries().keys(),
2806 image.GetEntries().keys())
2808 orig_entry = orig_image.GetEntries()['fdtmap']
2809 entry = image.GetEntries()['fdtmap']
2810 self.assertEquals(orig_entry.offset, entry.offset)
2811 self.assertEquals(orig_entry.size, entry.size)
2812 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2814 def testReadImageNoHeader(self):
2815 """Test accessing an image's FDT map without an image header"""
2817 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2818 image_fname = tools.get_output_filename('image.bin')
2819 image = Image.FromFile(image_fname)
2820 self.assertTrue(isinstance(image, Image))
2821 self.assertEqual('image', image.image_name[-5:])
2823 def testReadImageFail(self):
2824 """Test failing to read an image image's FDT map"""
2825 self._DoReadFile('005_simple.dts')
2826 image_fname = tools.get_output_filename('image.bin')
2827 with self.assertRaises(ValueError) as e:
2828 image = Image.FromFile(image_fname)
2829 self.assertIn("Cannot find FDT map in image", str(e.exception))
2831 def testListCmd(self):
2832 """Test listing the files in an image using an Fdtmap"""
2834 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2836 # lz4 compression size differs depending on the version
2837 image = control.images['image']
2838 entries = image.GetEntries()
2839 section_size = entries['section'].size
2840 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2841 fdtmap_offset = entries['fdtmap'].offset
2844 tmpdir, updated_fname = self._SetupImageInTmpdir()
2845 with test_util.capture_sys_output() as (stdout, stderr):
2846 self._DoBinman('ls', '-i', updated_fname)
2848 shutil.rmtree(tmpdir)
2849 lines = stdout.getvalue().splitlines()
2851 'Name Image-pos Size Entry-type Offset Uncomp-size',
2852 '----------------------------------------------------------------------',
2853 'image 0 c00 section 0',
2854 ' u-boot 0 4 u-boot 0',
2855 ' section 100 %x section 100' % section_size,
2856 ' cbfs 100 400 cbfs 0',
2857 ' u-boot 138 4 u-boot 38',
2858 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2859 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2860 ' fdtmap %x 3bd fdtmap %x' %
2861 (fdtmap_offset, fdtmap_offset),
2862 ' image-header bf8 8 image-header bf8',
2864 self.assertEqual(expected, lines)
2866 def testListCmdFail(self):
2867 """Test failing to list an image"""
2868 self._DoReadFile('005_simple.dts')
2870 tmpdir, updated_fname = self._SetupImageInTmpdir()
2871 with self.assertRaises(ValueError) as e:
2872 self._DoBinman('ls', '-i', updated_fname)
2874 shutil.rmtree(tmpdir)
2875 self.assertIn("Cannot find FDT map in image", str(e.exception))
2877 def _RunListCmd(self, paths, expected):
2878 """List out entries and check the result
2881 paths: List of paths to pass to the list command
2882 expected: Expected list of filenames to be returned, in order
2885 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2886 image_fname = tools.get_output_filename('image.bin')
2887 image = Image.FromFile(image_fname)
2888 lines = image.GetListEntries(paths)[1]
2889 files = [line[0].strip() for line in lines[1:]]
2890 self.assertEqual(expected, files)
2892 def testListCmdSection(self):
2893 """Test listing the files in a section"""
2894 self._RunListCmd(['section'],
2895 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2897 def testListCmdFile(self):
2898 """Test listing a particular file"""
2899 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2901 def testListCmdWildcard(self):
2902 """Test listing a wildcarded file"""
2903 self._RunListCmd(['*boot*'],
2904 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2906 def testListCmdWildcardMulti(self):
2907 """Test listing a wildcarded file"""
2908 self._RunListCmd(['*cb*', '*head*'],
2909 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2911 def testListCmdEmpty(self):
2912 """Test listing a wildcarded file"""
2913 self._RunListCmd(['nothing'], [])
2915 def testListCmdPath(self):
2916 """Test listing the files in a sub-entry of a section"""
2917 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2919 def _RunExtractCmd(self, entry_name, decomp=True):
2920 """Extract an entry from an image
2923 entry_name: Entry name to extract
2924 decomp: True to decompress the data if compressed, False to leave
2925 it in its raw uncompressed format
2931 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2932 image_fname = tools.get_output_filename('image.bin')
2933 return control.ReadEntry(image_fname, entry_name, decomp)
2935 def testExtractSimple(self):
2936 """Test extracting a single file"""
2937 data = self._RunExtractCmd('u-boot')
2938 self.assertEqual(U_BOOT_DATA, data)
2940 def testExtractSection(self):
2941 """Test extracting the files in a section"""
2942 data = self._RunExtractCmd('section')
2943 cbfs_data = data[:0x400]
2944 cbfs = cbfs_util.CbfsReader(cbfs_data)
2945 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2946 dtb_data = data[0x400:]
2947 dtb = self._decompress(dtb_data)
2948 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2950 def testExtractCompressed(self):
2951 """Test extracting compressed data"""
2952 data = self._RunExtractCmd('section/u-boot-dtb')
2953 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2955 def testExtractRaw(self):
2956 """Test extracting compressed data without decompressing it"""
2957 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2958 dtb = self._decompress(data)
2959 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2961 def testExtractCbfs(self):
2962 """Test extracting CBFS data"""
2963 data = self._RunExtractCmd('section/cbfs/u-boot')
2964 self.assertEqual(U_BOOT_DATA, data)
2966 def testExtractCbfsCompressed(self):
2967 """Test extracting CBFS compressed data"""
2968 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2969 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2971 def testExtractCbfsRaw(self):
2972 """Test extracting CBFS compressed data without decompressing it"""
2973 bintool = self.comp_bintools['lzma_alone']
2974 self._CheckBintool(bintool)
2975 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2976 dtb = bintool.decompress(data)
2977 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2979 def testExtractBadEntry(self):
2980 """Test extracting a bad section path"""
2981 with self.assertRaises(ValueError) as e:
2982 self._RunExtractCmd('section/does-not-exist')
2983 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2986 def testExtractMissingFile(self):
2987 """Test extracting file that does not exist"""
2988 with self.assertRaises(IOError) as e:
2989 control.ReadEntry('missing-file', 'name')
2991 def testExtractBadFile(self):
2992 """Test extracting an invalid file"""
2993 fname = os.path.join(self._indir, 'badfile')
2994 tools.write_file(fname, b'')
2995 with self.assertRaises(ValueError) as e:
2996 control.ReadEntry(fname, 'name')
2998 def testExtractCmd(self):
2999 """Test extracting a file fron an image on the command line"""
3001 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3002 fname = os.path.join(self._indir, 'output.extact')
3004 tmpdir, updated_fname = self._SetupImageInTmpdir()
3005 with test_util.capture_sys_output() as (stdout, stderr):
3006 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3009 shutil.rmtree(tmpdir)
3010 data = tools.read_file(fname)
3011 self.assertEqual(U_BOOT_DATA, data)
3013 def testExtractOneEntry(self):
3014 """Test extracting a single entry fron an image """
3016 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3017 image_fname = tools.get_output_filename('image.bin')
3018 fname = os.path.join(self._indir, 'output.extact')
3019 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
3020 data = tools.read_file(fname)
3021 self.assertEqual(U_BOOT_DATA, data)
3023 def _CheckExtractOutput(self, decomp):
3024 """Helper to test file output with and without decompression
3027 decomp: True to decompress entry data, False to output it raw
3029 def _CheckPresent(entry_path, expect_data, expect_size=None):
3030 """Check and remove expected file
3032 This checks the data/size of a file and removes the file both from
3033 the outfiles set and from the output directory. Once all files are
3034 processed, both the set and directory should be empty.
3037 entry_path: Entry path
3038 expect_data: Data to expect in file, or None to skip check
3039 expect_size: Size of data to expect in file, or None to skip
3041 path = os.path.join(outdir, entry_path)
3042 data = tools.read_file(path)
3045 self.assertEqual(expect_data, data)
3047 self.assertEqual(expect_size, len(data))
3048 outfiles.remove(path)
3050 def _CheckDirPresent(name):
3051 """Remove expected directory
3053 This gives an error if the directory does not exist as expected
3056 name: Name of directory to remove
3058 path = os.path.join(outdir, name)
3061 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3062 image_fname = tools.get_output_filename('image.bin')
3063 outdir = os.path.join(self._indir, 'extract')
3064 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3066 # Create a set of all file that were output (should be 9)
3068 for root, dirs, files in os.walk(outdir):
3069 outfiles |= set([os.path.join(root, fname) for fname in files])
3070 self.assertEqual(9, len(outfiles))
3071 self.assertEqual(9, len(einfos))
3073 image = control.images['image']
3074 entries = image.GetEntries()
3076 # Check the 9 files in various ways
3077 section = entries['section']
3078 section_entries = section.GetEntries()
3079 cbfs_entries = section_entries['cbfs'].GetEntries()
3080 _CheckPresent('u-boot', U_BOOT_DATA)
3081 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3082 dtb_len = EXTRACT_DTB_SIZE
3084 dtb_len = cbfs_entries['u-boot-dtb'].size
3085 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3087 dtb_len = section_entries['u-boot-dtb'].size
3088 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3090 fdtmap = entries['fdtmap']
3091 _CheckPresent('fdtmap', fdtmap.data)
3092 hdr = entries['image-header']
3093 _CheckPresent('image-header', hdr.data)
3095 _CheckPresent('section/root', section.data)
3096 cbfs = section_entries['cbfs']
3097 _CheckPresent('section/cbfs/root', cbfs.data)
3098 data = tools.read_file(image_fname)
3099 _CheckPresent('root', data)
3101 # There should be no files left. Remove all the directories to check.
3102 # If there are any files/dirs remaining, one of these checks will fail.
3103 self.assertEqual(0, len(outfiles))
3104 _CheckDirPresent('section/cbfs')
3105 _CheckDirPresent('section')
3106 _CheckDirPresent('')
3107 self.assertFalse(os.path.exists(outdir))
3109 def testExtractAllEntries(self):
3110 """Test extracting all entries"""
3112 self._CheckExtractOutput(decomp=True)
3114 def testExtractAllEntriesRaw(self):
3115 """Test extracting all entries without decompressing them"""
3117 self._CheckExtractOutput(decomp=False)
3119 def testExtractSelectedEntries(self):
3120 """Test extracting some entries"""
3122 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3123 image_fname = tools.get_output_filename('image.bin')
3124 outdir = os.path.join(self._indir, 'extract')
3125 einfos = control.ExtractEntries(image_fname, None, outdir,
3128 # File output is tested by testExtractAllEntries(), so just check that
3129 # the expected entries are selected
3130 names = [einfo.name for einfo in einfos]
3131 self.assertEqual(names,
3132 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3134 def testExtractNoEntryPaths(self):
3135 """Test extracting some entries"""
3137 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3138 image_fname = tools.get_output_filename('image.bin')
3139 with self.assertRaises(ValueError) as e:
3140 control.ExtractEntries(image_fname, 'fname', None, [])
3141 self.assertIn('Must specify an entry path to write with -f',
3144 def testExtractTooManyEntryPaths(self):
3145 """Test extracting some entries"""
3147 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3148 image_fname = tools.get_output_filename('image.bin')
3149 with self.assertRaises(ValueError) as e:
3150 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
3151 self.assertIn('Must specify exactly one entry path to write with -f',
3154 def testPackAlignSection(self):
3155 """Test that sections can have alignment"""
3156 self._DoReadFile('131_pack_align_section.dts')
3158 self.assertIn('image', control.images)
3159 image = control.images['image']
3160 entries = image.GetEntries()
3161 self.assertEqual(3, len(entries))
3164 self.assertIn('u-boot', entries)
3165 entry = entries['u-boot']
3166 self.assertEqual(0, entry.offset)
3167 self.assertEqual(0, entry.image_pos)
3168 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3169 self.assertEqual(len(U_BOOT_DATA), entry.size)
3172 self.assertIn('section0', entries)
3173 section0 = entries['section0']
3174 self.assertEqual(0x10, section0.offset)
3175 self.assertEqual(0x10, section0.image_pos)
3176 self.assertEqual(len(U_BOOT_DATA), section0.size)
3179 section_entries = section0.GetEntries()
3180 self.assertIn('u-boot', section_entries)
3181 entry = section_entries['u-boot']
3182 self.assertEqual(0, entry.offset)
3183 self.assertEqual(0x10, entry.image_pos)
3184 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3185 self.assertEqual(len(U_BOOT_DATA), entry.size)
3188 self.assertIn('section1', entries)
3189 section1 = entries['section1']
3190 self.assertEqual(0x14, section1.offset)
3191 self.assertEqual(0x14, section1.image_pos)
3192 self.assertEqual(0x20, section1.size)
3195 section_entries = section1.GetEntries()
3196 self.assertIn('u-boot', section_entries)
3197 entry = section_entries['u-boot']
3198 self.assertEqual(0, entry.offset)
3199 self.assertEqual(0x14, entry.image_pos)
3200 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3201 self.assertEqual(len(U_BOOT_DATA), entry.size)
3204 self.assertIn('section2', section_entries)
3205 section2 = section_entries['section2']
3206 self.assertEqual(0x4, section2.offset)
3207 self.assertEqual(0x18, section2.image_pos)
3208 self.assertEqual(4, section2.size)
3211 section_entries = section2.GetEntries()
3212 self.assertIn('u-boot', section_entries)
3213 entry = section_entries['u-boot']
3214 self.assertEqual(0, entry.offset)
3215 self.assertEqual(0x18, entry.image_pos)
3216 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3217 self.assertEqual(len(U_BOOT_DATA), entry.size)
3219 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3220 dts='132_replace.dts'):
3221 """Replace an entry in an image
3223 This writes the entry data to update it, then opens the updated file and
3224 returns the value that it now finds there.
3227 entry_name: Entry name to replace
3228 data: Data to replace it with
3229 decomp: True to compress the data if needed, False if data is
3230 already compressed so should be used as is
3231 allow_resize: True to allow entries to change size, False to raise
3237 data from fdtmap (excluding header)
3238 Image object that was modified
3240 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3243 self.assertIn('image', control.images)
3244 image = control.images['image']
3245 entries = image.GetEntries()
3246 orig_dtb_data = entries['u-boot-dtb'].data
3247 orig_fdtmap_data = entries['fdtmap'].data
3249 image_fname = tools.get_output_filename('image.bin')
3250 updated_fname = tools.get_output_filename('image-updated.bin')
3251 tools.write_file(updated_fname, tools.read_file(image_fname))
3252 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3254 data = control.ReadEntry(updated_fname, entry_name, decomp)
3256 # The DT data should not change unless resized:
3257 if not allow_resize:
3258 new_dtb_data = entries['u-boot-dtb'].data
3259 self.assertEqual(new_dtb_data, orig_dtb_data)
3260 new_fdtmap_data = entries['fdtmap'].data
3261 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3263 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3265 def testReplaceSimple(self):
3266 """Test replacing a single file"""
3267 expected = b'x' * len(U_BOOT_DATA)
3268 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3270 self.assertEqual(expected, data)
3272 # Test that the state looks right. There should be an FDT for the fdtmap
3273 # that we jsut read back in, and it should match what we find in the
3274 # 'control' tables. Checking for an FDT that does not exist should
3276 path, fdtmap = state.GetFdtContents('fdtmap')
3277 self.assertIsNotNone(path)
3278 self.assertEqual(expected_fdtmap, fdtmap)
3280 dtb = state.GetFdtForEtype('fdtmap')
3281 self.assertEqual(dtb.GetContents(), fdtmap)
3283 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3284 self.assertIsNone(missing_path)
3285 self.assertIsNone(missing_fdtmap)
3287 missing_dtb = state.GetFdtForEtype('missing')
3288 self.assertIsNone(missing_dtb)
3290 self.assertEqual('/binman', state.fdt_path_prefix)
3292 def testReplaceResizeFail(self):
3293 """Test replacing a file by something larger"""
3294 expected = U_BOOT_DATA + b'x'
3295 with self.assertRaises(ValueError) as e:
3296 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3297 dts='139_replace_repack.dts')
3298 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3301 def testReplaceMulti(self):
3302 """Test replacing entry data where multiple images are generated"""
3303 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3305 expected = b'x' * len(U_BOOT_DATA)
3306 updated_fname = tools.get_output_filename('image-updated.bin')
3307 tools.write_file(updated_fname, data)
3308 entry_name = 'u-boot'
3309 control.WriteEntry(updated_fname, entry_name, expected,
3311 data = control.ReadEntry(updated_fname, entry_name)
3312 self.assertEqual(expected, data)
3314 # Check the state looks right.
3315 self.assertEqual('/binman/image', state.fdt_path_prefix)
3317 # Now check we can write the first image
3318 image_fname = tools.get_output_filename('first-image.bin')
3319 updated_fname = tools.get_output_filename('first-updated.bin')
3320 tools.write_file(updated_fname, tools.read_file(image_fname))
3321 entry_name = 'u-boot'
3322 control.WriteEntry(updated_fname, entry_name, expected,
3324 data = control.ReadEntry(updated_fname, entry_name)
3325 self.assertEqual(expected, data)
3327 # Check the state looks right.
3328 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3330 def testUpdateFdtAllRepack(self):
3331 """Test that all device trees are updated with offset/size info"""
3334 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3335 SECTION_SIZE = 0x300
3340 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3342 'section:offset': 0,
3343 'section:size': SECTION_SIZE,
3344 'section:image-pos': 0,
3345 'section/u-boot-dtb:offset': 4,
3346 'section/u-boot-dtb:size': 636,
3347 'section/u-boot-dtb:image-pos': 4,
3348 'u-boot-spl-dtb:offset': SECTION_SIZE,
3349 'u-boot-spl-dtb:size': DTB_SIZE,
3350 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3351 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3352 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3353 'u-boot-tpl-dtb:size': DTB_SIZE,
3354 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3355 'fdtmap:size': FDTMAP_SIZE,
3356 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3359 'section:orig-size': SECTION_SIZE,
3360 'section/u-boot-dtb:orig-offset': 4,
3363 # We expect three device-tree files in the output, with the first one
3364 # within a fixed-size section.
3365 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3366 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3367 # main U-Boot tree. All three should have the same positions and offset
3368 # except that the main tree should include the main_expected properties
3370 for item in ['', 'spl', 'tpl', None]:
3372 start += 16 # Move past fdtmap header
3373 dtb = fdt.Fdt.FromData(data[start:])
3375 props = self._GetPropTree(dtb,
3376 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3377 prefix='/' if item is None else '/binman/')
3378 expected = dict(base_expected)
3382 # Main DTB and fdtdec should include the 'orig-' properties
3383 expected.update(main_expected)
3384 # Helpful for debugging:
3385 #for prop in sorted(props):
3386 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3387 self.assertEqual(expected, props)
3389 start = SECTION_SIZE
3391 start += dtb._fdt_obj.totalsize()
3393 def testFdtmapHeaderMiddle(self):
3394 """Test an FDT map in the middle of an image when it should be at end"""
3395 with self.assertRaises(ValueError) as e:
3396 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3397 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3400 def testFdtmapHeaderStartBad(self):
3401 """Test an FDT map in middle of an image when it should be at start"""
3402 with self.assertRaises(ValueError) as e:
3403 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3404 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3407 def testFdtmapHeaderEndBad(self):
3408 """Test an FDT map at the start of an image when it should be at end"""
3409 with self.assertRaises(ValueError) as e:
3410 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3411 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3414 def testFdtmapHeaderNoSize(self):
3415 """Test an image header at the end of an image with undefined size"""
3416 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3418 def testReplaceResize(self):
3419 """Test replacing a single file in an entry with a larger file"""
3420 expected = U_BOOT_DATA + b'x'
3421 data, _, image = self._RunReplaceCmd('u-boot', expected,
3422 dts='139_replace_repack.dts')
3423 self.assertEqual(expected, data)
3425 entries = image.GetEntries()
3426 dtb_data = entries['u-boot-dtb'].data
3427 dtb = fdt.Fdt.FromData(dtb_data)
3430 # The u-boot section should now be larger in the dtb
3431 node = dtb.GetNode('/binman/u-boot')
3432 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3434 # Same for the fdtmap
3435 fdata = entries['fdtmap'].data
3436 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3438 fnode = fdtb.GetNode('/u-boot')
3439 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3441 def testReplaceResizeNoRepack(self):
3442 """Test replacing an entry with a larger file when not allowed"""
3443 expected = U_BOOT_DATA + b'x'
3444 with self.assertRaises(ValueError) as e:
3445 self._RunReplaceCmd('u-boot', expected)
3446 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3449 def testEntryShrink(self):
3450 """Test contracting an entry after it is packed"""
3452 state.SetAllowEntryContraction(True)
3453 data = self._DoReadFileDtb('140_entry_shrink.dts',
3456 state.SetAllowEntryContraction(False)
3457 self.assertEqual(b'a', data[:1])
3458 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3459 self.assertEqual(b'a', data[-1:])
3461 def testEntryShrinkFail(self):
3462 """Test not being allowed to contract an entry after it is packed"""
3463 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3465 # In this case there is a spare byte at the end of the data. The size of
3466 # the contents is only 1 byte but we still have the size before it
3468 self.assertEqual(b'a\0', data[:2])
3469 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3470 self.assertEqual(b'a\0', data[-2:])
3472 def testDescriptorOffset(self):
3473 """Test that the Intel descriptor is always placed at at the start"""
3474 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3475 image = control.images['image']
3476 entries = image.GetEntries()
3477 desc = entries['intel-descriptor']
3478 self.assertEqual(0xff800000, desc.offset);
3479 self.assertEqual(0xff800000, desc.image_pos);
3481 def testReplaceCbfs(self):
3482 """Test replacing a single file in CBFS without changing the size"""
3484 expected = b'x' * len(U_BOOT_DATA)
3485 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3486 updated_fname = tools.get_output_filename('image-updated.bin')
3487 tools.write_file(updated_fname, data)
3488 entry_name = 'section/cbfs/u-boot'
3489 control.WriteEntry(updated_fname, entry_name, expected,
3491 data = control.ReadEntry(updated_fname, entry_name)
3492 self.assertEqual(expected, data)
3494 def testReplaceResizeCbfs(self):
3495 """Test replacing a single file in CBFS with one of a different size"""
3497 expected = U_BOOT_DATA + b'x'
3498 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3499 updated_fname = tools.get_output_filename('image-updated.bin')
3500 tools.write_file(updated_fname, data)
3501 entry_name = 'section/cbfs/u-boot'
3502 control.WriteEntry(updated_fname, entry_name, expected,
3504 data = control.ReadEntry(updated_fname, entry_name)
3505 self.assertEqual(expected, data)
3507 def _SetupForReplace(self):
3508 """Set up some files to use to replace entries
3510 This generates an image, copies it to a new file, extracts all the files
3511 in it and updates some of them
3517 Expected values for updated entries, each a string
3519 data = self._DoReadFileRealDtb('143_replace_all.dts')
3521 updated_fname = tools.get_output_filename('image-updated.bin')
3522 tools.write_file(updated_fname, data)
3524 outdir = os.path.join(self._indir, 'extract')
3525 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3527 expected1 = b'x' + U_BOOT_DATA + b'y'
3528 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3529 tools.write_file(u_boot_fname1, expected1)
3531 expected2 = b'a' + U_BOOT_DATA + b'b'
3532 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3533 tools.write_file(u_boot_fname2, expected2)
3535 expected_text = b'not the same text'
3536 text_fname = os.path.join(outdir, 'text')
3537 tools.write_file(text_fname, expected_text)
3539 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3540 dtb = fdt.FdtScan(dtb_fname)
3541 node = dtb.GetNode('/binman/text')
3542 node.AddString('my-property', 'the value')
3543 dtb.Sync(auto_resize=True)
3546 return updated_fname, outdir, expected1, expected2, expected_text
3548 def _CheckReplaceMultiple(self, entry_paths):
3549 """Handle replacing the contents of multiple entries
3552 entry_paths: List of entry paths to replace
3556 Dict of entries in the image:
3559 Expected values for updated entries, each a string
3561 updated_fname, outdir, expected1, expected2, expected_text = (
3562 self._SetupForReplace())
3563 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3565 image = Image.FromFile(updated_fname)
3567 return image.GetEntries(), expected1, expected2, expected_text
3569 def testReplaceAll(self):
3570 """Test replacing the contents of all entries"""
3571 entries, expected1, expected2, expected_text = (
3572 self._CheckReplaceMultiple([]))
3573 data = entries['u-boot'].data
3574 self.assertEqual(expected1, data)
3576 data = entries['u-boot2'].data
3577 self.assertEqual(expected2, data)
3579 data = entries['text'].data
3580 self.assertEqual(expected_text, data)
3582 # Check that the device tree is updated
3583 data = entries['u-boot-dtb'].data
3584 dtb = fdt.Fdt.FromData(data)
3586 node = dtb.GetNode('/binman/text')
3587 self.assertEqual('the value', node.props['my-property'].value)
3589 def testReplaceSome(self):
3590 """Test replacing the contents of a few entries"""
3591 entries, expected1, expected2, expected_text = (
3592 self._CheckReplaceMultiple(['u-boot2', 'text']))
3594 # This one should not change
3595 data = entries['u-boot'].data
3596 self.assertEqual(U_BOOT_DATA, data)
3598 data = entries['u-boot2'].data
3599 self.assertEqual(expected2, data)
3601 data = entries['text'].data
3602 self.assertEqual(expected_text, data)
3604 def testReplaceCmd(self):
3605 """Test replacing a file fron an image on the command line"""
3606 self._DoReadFileRealDtb('143_replace_all.dts')
3609 tmpdir, updated_fname = self._SetupImageInTmpdir()
3611 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3612 expected = b'x' * len(U_BOOT_DATA)
3613 tools.write_file(fname, expected)
3615 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3616 data = tools.read_file(updated_fname)
3617 self.assertEqual(expected, data[:len(expected)])
3618 map_fname = os.path.join(tmpdir, 'image-updated.map')
3619 self.assertFalse(os.path.exists(map_fname))
3621 shutil.rmtree(tmpdir)
3623 def testReplaceCmdSome(self):
3624 """Test replacing some files fron an image on the command line"""
3625 updated_fname, outdir, expected1, expected2, expected_text = (
3626 self._SetupForReplace())
3628 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3631 tools.prepare_output_dir(None)
3632 image = Image.FromFile(updated_fname)
3634 entries = image.GetEntries()
3636 # This one should not change
3637 data = entries['u-boot'].data
3638 self.assertEqual(U_BOOT_DATA, data)
3640 data = entries['u-boot2'].data
3641 self.assertEqual(expected2, data)
3643 data = entries['text'].data
3644 self.assertEqual(expected_text, data)
3646 def testReplaceMissing(self):
3647 """Test replacing entries where the file is missing"""
3648 updated_fname, outdir, expected1, expected2, expected_text = (
3649 self._SetupForReplace())
3651 # Remove one of the files, to generate a warning
3652 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3653 os.remove(u_boot_fname1)
3655 with test_util.capture_sys_output() as (stdout, stderr):
3656 control.ReplaceEntries(updated_fname, None, outdir, [])
3657 self.assertIn("Skipping entry '/u-boot' from missing file",
3660 def testReplaceCmdMap(self):
3661 """Test replacing a file fron an image on the command line"""
3662 self._DoReadFileRealDtb('143_replace_all.dts')
3665 tmpdir, updated_fname = self._SetupImageInTmpdir()
3667 fname = os.path.join(self._indir, 'update-u-boot.bin')
3668 expected = b'x' * len(U_BOOT_DATA)
3669 tools.write_file(fname, expected)
3671 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3673 map_fname = os.path.join(tmpdir, 'image-updated.map')
3674 self.assertTrue(os.path.exists(map_fname))
3676 shutil.rmtree(tmpdir)
3678 def testReplaceNoEntryPaths(self):
3679 """Test replacing an entry without an entry path"""
3680 self._DoReadFileRealDtb('143_replace_all.dts')
3681 image_fname = tools.get_output_filename('image.bin')
3682 with self.assertRaises(ValueError) as e:
3683 control.ReplaceEntries(image_fname, 'fname', None, [])
3684 self.assertIn('Must specify an entry path to read with -f',
3687 def testReplaceTooManyEntryPaths(self):
3688 """Test extracting some entries"""
3689 self._DoReadFileRealDtb('143_replace_all.dts')
3690 image_fname = tools.get_output_filename('image.bin')
3691 with self.assertRaises(ValueError) as e:
3692 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3693 self.assertIn('Must specify exactly one entry path to write with -f',
3696 def testPackReset16(self):
3697 """Test that an image with an x86 reset16 region can be created"""
3698 data = self._DoReadFile('144_x86_reset16.dts')
3699 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3701 def testPackReset16Spl(self):
3702 """Test that an image with an x86 reset16-spl region can be created"""
3703 data = self._DoReadFile('145_x86_reset16_spl.dts')
3704 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3706 def testPackReset16Tpl(self):
3707 """Test that an image with an x86 reset16-tpl region can be created"""
3708 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3709 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3711 def testPackIntelFit(self):
3712 """Test that an image with an Intel FIT and pointer can be created"""
3713 data = self._DoReadFile('147_intel_fit.dts')
3714 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3716 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3717 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3719 image = control.images['image']
3720 entries = image.GetEntries()
3721 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3722 self.assertEqual(expected_ptr, ptr)
3724 def testPackIntelFitMissing(self):
3725 """Test detection of a FIT pointer with not FIT region"""
3726 with self.assertRaises(ValueError) as e:
3727 self._DoReadFile('148_intel_fit_missing.dts')
3728 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3731 def _CheckSymbolsTplSection(self, dts, expected_vals):
3732 data = self._DoReadFile(dts)
3733 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
3734 upto1 = 4 + len(U_BOOT_SPL_DATA)
3735 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
3736 self.assertEqual(expected1, data[:upto1])
3738 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3739 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
3740 self.assertEqual(expected2, data[upto1:upto2])
3742 upto3 = 0x3c + len(U_BOOT_DATA)
3743 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
3744 self.assertEqual(expected3, data[upto2:upto3])
3746 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
3747 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3749 def testSymbolsTplSection(self):
3750 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3751 self._SetupSplElf('u_boot_binman_syms')
3752 self._SetupTplElf('u_boot_binman_syms')
3753 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3754 [0x04, 0x20, 0x10 + 0x3c, 0x04])
3756 def testSymbolsTplSectionX86(self):
3757 """Test binman can assign symbols in a section with end-at-4gb"""
3758 self._SetupSplElf('u_boot_binman_syms_x86')
3759 self._SetupTplElf('u_boot_binman_syms_x86')
3760 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3761 [0xffffff04, 0xffffff20, 0xffffff3c,
3764 def testPackX86RomIfwiSectiom(self):
3765 """Test that a section can be placed in an IFWI region"""
3766 self._SetupIfwi('fitimage.bin')
3767 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3768 self._CheckIfwi(data)
3770 def testPackFspM(self):
3771 """Test that an image with a FSP memory-init binary can be created"""
3772 data = self._DoReadFile('152_intel_fsp_m.dts')
3773 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3775 def testPackFspS(self):
3776 """Test that an image with a FSP silicon-init binary can be created"""
3777 data = self._DoReadFile('153_intel_fsp_s.dts')
3778 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3780 def testPackFspT(self):
3781 """Test that an image with a FSP temp-ram-init binary can be created"""
3782 data = self._DoReadFile('154_intel_fsp_t.dts')
3783 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3785 def testMkimage(self):
3786 """Test using mkimage to build an image"""
3788 data = self._DoReadFile('156_mkimage.dts')
3790 # Just check that the data appears in the file somewhere
3791 self.assertIn(U_BOOT_SPL_DATA, data)
3793 def testMkimageMissing(self):
3794 """Test that binman still produces an image if mkimage is missing"""
3796 with test_util.capture_sys_output() as (_, stderr):
3797 self._DoTestFile('156_mkimage.dts',
3798 force_missing_bintools='mkimage')
3799 err = stderr.getvalue()
3800 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
3802 def testExtblob(self):
3803 """Test an image with an external blob"""
3804 data = self._DoReadFile('157_blob_ext.dts')
3805 self.assertEqual(REFCODE_DATA, data)
3807 def testExtblobMissing(self):
3808 """Test an image with a missing external blob"""
3809 with self.assertRaises(ValueError) as e:
3810 self._DoReadFile('158_blob_ext_missing.dts')
3811 self.assertIn("Filename 'missing-file' not found in input path",
3814 def testExtblobMissingOk(self):
3815 """Test an image with an missing external blob that is allowed"""
3816 with test_util.capture_sys_output() as (stdout, stderr):
3817 ret = self._DoTestFile('158_blob_ext_missing.dts',
3819 self.assertEqual(103, ret)
3820 err = stderr.getvalue()
3821 self.assertIn('(missing-file)', err)
3822 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
3823 self.assertIn('Some images are invalid', err)
3825 def testExtblobMissingOkFlag(self):
3826 """Test an image with an missing external blob allowed with -W"""
3827 with test_util.capture_sys_output() as (stdout, stderr):
3828 ret = self._DoTestFile('158_blob_ext_missing.dts',
3829 allow_missing=True, ignore_missing=True)
3830 self.assertEqual(0, ret)
3831 err = stderr.getvalue()
3832 self.assertIn('(missing-file)', err)
3833 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
3834 self.assertIn('Some images are invalid', err)
3836 def testExtblobMissingOkSect(self):
3837 """Test an image with an missing external blob that is allowed"""
3838 with test_util.capture_sys_output() as (stdout, stderr):
3839 self._DoTestFile('159_blob_ext_missing_sect.dts',
3841 err = stderr.getvalue()
3842 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
3844 def testPackX86RomMeMissingDesc(self):
3845 """Test that an missing Intel descriptor entry is allowed"""
3846 with test_util.capture_sys_output() as (stdout, stderr):
3847 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3848 err = stderr.getvalue()
3849 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
3851 def testPackX86RomMissingIfwi(self):
3852 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3853 self._SetupIfwi('fitimage.bin')
3854 pathname = os.path.join(self._indir, 'fitimage.bin')
3856 with test_util.capture_sys_output() as (stdout, stderr):
3857 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3858 err = stderr.getvalue()
3859 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
3861 def testPackOverlapZero(self):
3862 """Test that zero-size overlapping regions are ignored"""
3863 self._DoTestFile('160_pack_overlap_zero.dts')
3865 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
3866 # The data should be inside the FIT
3867 dtb = fdt.Fdt.FromData(fit_data)
3869 fnode = dtb.GetNode('/images/kernel')
3870 self.assertIn('data', fnode.props)
3872 fname = os.path.join(self._indir, 'fit_data.fit')
3873 tools.write_file(fname, fit_data)
3874 out = tools.run('dumpimage', '-l', fname)
3876 # Check a few features to make sure the plumbing works. We don't need
3877 # to test the operation of mkimage or dumpimage here. First convert the
3878 # output into a dict where the keys are the fields printed by dumpimage
3879 # and the values are a list of values for each field
3880 lines = out.splitlines()
3882 # Converts "Compression: gzip compressed" into two groups:
3883 # 'Compression' and 'gzip compressed'
3884 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3885 vals = collections.defaultdict(list)
3887 mat = re_line.match(line)
3888 vals[mat.group(1)].append(mat.group(2))
3890 self.assertEquals('FIT description: test-desc', lines[0])
3891 self.assertIn('Created:', lines[1])
3892 self.assertIn('Image 0 (kernel)', vals)
3893 self.assertIn('Hash value', vals)
3894 data_sizes = vals.get('Data Size')
3895 self.assertIsNotNone(data_sizes)
3896 self.assertEqual(2, len(data_sizes))
3897 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3898 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3899 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3901 # Check if entry listing correctly omits /images/
3902 image = control.images['image']
3903 fit_entry = image.GetEntries()['fit']
3904 subentries = list(fit_entry.GetEntries().keys())
3905 expected = ['kernel', 'fdt-1']
3906 self.assertEqual(expected, subentries)
3908 def testSimpleFit(self):
3909 """Test an image with a FIT inside"""
3911 data = self._DoReadFile('161_fit.dts')
3912 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3913 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3914 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3916 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3918 def testSimpleFitExpandsSubentries(self):
3919 """Test that FIT images expand their subentries"""
3920 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3921 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3922 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3923 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3925 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
3927 def testSimpleFitImagePos(self):
3928 """Test that we have correct image-pos for FIT subentries"""
3929 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3931 dtb = fdt.Fdt(out_dtb_fname)
3933 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3941 'u-boot:image-pos': 0,
3949 'fit/images/kernel:image-pos': 304,
3950 'fit/images/kernel:offset': 300,
3951 'fit/images/kernel:size': 4,
3953 'fit/images/kernel/u-boot:image-pos': 304,
3954 'fit/images/kernel/u-boot:offset': 0,
3955 'fit/images/kernel/u-boot:size': 4,
3957 'fit/images/fdt-1:image-pos': 552,
3958 'fit/images/fdt-1:offset': 548,
3959 'fit/images/fdt-1:size': 6,
3961 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
3962 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3963 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3965 'u-boot-nodtb:image-pos': 1844,
3966 'u-boot-nodtb:offset': 1844,
3967 'u-boot-nodtb:size': 46,
3970 # Actually check the data is where we think it is
3971 for node, expected in [
3972 ("u-boot", U_BOOT_DATA),
3973 ("fit/images/kernel", U_BOOT_DATA),
3974 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3975 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3976 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3977 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3979 image_pos = props[f"{node}:image-pos"]
3980 size = props[f"{node}:size"]
3981 self.assertEqual(len(expected), size)
3982 self.assertEqual(expected, data[image_pos:image_pos+size])
3984 def testFitExternal(self):
3985 """Test an image with an FIT with external images"""
3986 data = self._DoReadFile('162_fit_external.dts')
3987 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3989 # Size of the external-data region as set up by mkimage
3990 external_data_size = len(U_BOOT_DATA) + 2
3991 expected_size = (len(U_BOOT_DATA) + 0x400 +
3992 tools.align(external_data_size, 4) +
3993 len(U_BOOT_NODTB_DATA))
3995 # The data should be outside the FIT
3996 dtb = fdt.Fdt.FromData(fit_data)
3998 fnode = dtb.GetNode('/images/kernel')
3999 self.assertNotIn('data', fnode.props)
4000 self.assertEqual(len(U_BOOT_DATA),
4001 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4005 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4007 self.assertEquals(expected_size, len(data))
4008 actual_pos = len(U_BOOT_DATA) + fit_pos
4009 self.assertEqual(U_BOOT_DATA + b'aa',
4010 data[actual_pos:actual_pos + external_data_size])
4012 def testFitExternalImagePos(self):
4013 """Test that we have correct image-pos for external FIT subentries"""
4014 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4016 dtb = fdt.Fdt(out_dtb_fname)
4018 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4025 'u-boot:image-pos': 0,
4033 'fit/images/kernel:size': 4,
4034 'fit/images/kernel:offset': 1024,
4035 'fit/images/kernel:image-pos': 1028,
4037 'fit/images/kernel/u-boot:size': 4,
4038 'fit/images/kernel/u-boot:offset': 0,
4039 'fit/images/kernel/u-boot:image-pos': 1028,
4041 'fit/images/fdt-1:size': 2,
4042 'fit/images/fdt-1:offset': 1028,
4043 'fit/images/fdt-1:image-pos': 1032,
4045 'fit/images/fdt-1/_testing:size': 2,
4046 'fit/images/fdt-1/_testing:offset': 0,
4047 'fit/images/fdt-1/_testing:image-pos': 1032,
4049 'u-boot-nodtb:image-pos': 1036,
4050 'u-boot-nodtb:offset': 1036,
4051 'u-boot-nodtb:size': 46,
4054 # Actually check the data is where we think it is
4055 for node, expected in [
4056 ("u-boot", U_BOOT_DATA),
4057 ("fit/images/kernel", U_BOOT_DATA),
4058 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4059 ("fit/images/fdt-1", b'aa'),
4060 ("fit/images/fdt-1/_testing", b'aa'),
4061 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4063 image_pos = props[f"{node}:image-pos"]
4064 size = props[f"{node}:size"]
4065 self.assertEqual(len(expected), size)
4066 self.assertEqual(expected, data[image_pos:image_pos+size])
4068 def testFitMissing(self):
4069 """Test that binman complains if mkimage is missing"""
4070 with self.assertRaises(ValueError) as e:
4071 self._DoTestFile('162_fit_external.dts',
4072 force_missing_bintools='mkimage')
4073 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4076 def testFitMissingOK(self):
4077 """Test that binman still produces a FIT image if mkimage is missing"""
4078 with test_util.capture_sys_output() as (_, stderr):
4079 self._DoTestFile('162_fit_external.dts', allow_missing=True,
4080 force_missing_bintools='mkimage')
4081 err = stderr.getvalue()
4082 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
4084 def testSectionIgnoreHashSignature(self):
4085 """Test that sections ignore hash, signature nodes for its data"""
4086 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4087 expected = (U_BOOT_DATA + U_BOOT_DATA)
4088 self.assertEqual(expected, data)
4090 def testPadInSections(self):
4091 """Test pad-before, pad-after for entries in sections"""
4092 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4093 '166_pad_in_sections.dts', update_dtb=True)
4094 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4095 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
4097 self.assertEqual(expected, data)
4099 dtb = fdt.Fdt(out_dtb_fname)
4101 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4105 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4107 'section:image-pos': 0,
4108 'section:offset': 0,
4109 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4111 'section/before:image-pos': 0,
4112 'section/before:offset': 0,
4113 'section/before:size': len(U_BOOT_DATA),
4115 'section/u-boot:image-pos': 4,
4116 'section/u-boot:offset': 4,
4117 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4119 'section/after:image-pos': 26,
4120 'section/after:offset': 26,
4121 'section/after:size': len(U_BOOT_DATA),
4123 self.assertEqual(expected, props)
4125 def testFitImageSubentryAlignment(self):
4126 """Test relative alignability of FIT image subentries"""
4129 'test-id': TEXT_DATA,
4131 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4132 entry_args=entry_args)
4133 dtb = fdt.Fdt.FromData(data)
4136 node = dtb.GetNode('/images/kernel')
4137 data = dtb.GetProps(node)["data"].bytes
4138 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
4139 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4140 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
4141 self.assertEqual(expected, data)
4143 node = dtb.GetNode('/images/fdt-1')
4144 data = dtb.GetProps(node)["data"].bytes
4145 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4146 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
4148 self.assertEqual(expected, data)
4150 def testFitExtblobMissingOk(self):
4151 """Test a FIT with a missing external blob that is allowed"""
4152 with test_util.capture_sys_output() as (stdout, stderr):
4153 self._DoTestFile('168_fit_missing_blob.dts',
4155 err = stderr.getvalue()
4156 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
4158 def testBlobNamedByArgMissing(self):
4159 """Test handling of a missing entry arg"""
4160 with self.assertRaises(ValueError) as e:
4161 self._DoReadFile('068_blob_named_by_arg.dts')
4162 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4165 def testPackBl31(self):
4166 """Test that an image with an ATF BL31 binary can be created"""
4167 data = self._DoReadFile('169_atf_bl31.dts')
4168 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4170 def testPackScp(self):
4171 """Test that an image with an SCP binary can be created"""
4172 data = self._DoReadFile('172_scp.dts')
4173 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4175 def testFitFdt(self):
4176 """Test an image with an FIT with multiple FDT images"""
4177 def _CheckFdt(seq, expected_data):
4178 """Check the FDT nodes
4181 seq: Sequence number to check (0 or 1)
4182 expected_data: Expected contents of 'data' property
4184 name = 'fdt-%d' % seq
4185 fnode = dtb.GetNode('/images/%s' % name)
4186 self.assertIsNotNone(fnode)
4187 self.assertEqual({'description','type', 'compression', 'data'},
4188 set(fnode.props.keys()))
4189 self.assertEqual(expected_data, fnode.props['data'].bytes)
4190 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4191 fnode.props['description'].value)
4192 self.assertEqual(fnode.subnodes[0].name, 'hash')
4194 def _CheckConfig(seq, expected_data):
4195 """Check the configuration nodes
4198 seq: Sequence number to check (0 or 1)
4199 expected_data: Expected contents of 'data' property
4201 cnode = dtb.GetNode('/configurations')
4202 self.assertIn('default', cnode.props)
4203 self.assertEqual('config-2', cnode.props['default'].value)
4205 name = 'config-%d' % seq
4206 fnode = dtb.GetNode('/configurations/%s' % name)
4207 self.assertIsNotNone(fnode)
4208 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4209 set(fnode.props.keys()))
4210 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4211 fnode.props['description'].value)
4212 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4215 'of-list': 'test-fdt1 test-fdt2',
4216 'default-dt': 'test-fdt2',
4218 data = self._DoReadFileDtb(
4220 entry_args=entry_args,
4221 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4222 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4223 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4225 dtb = fdt.Fdt.FromData(fit_data)
4227 fnode = dtb.GetNode('/images/kernel')
4228 self.assertIn('data', fnode.props)
4230 # Check all the properties in fdt-1 and fdt-2
4231 _CheckFdt(1, TEST_FDT1_DATA)
4232 _CheckFdt(2, TEST_FDT2_DATA)
4234 # Check configurations
4235 _CheckConfig(1, TEST_FDT1_DATA)
4236 _CheckConfig(2, TEST_FDT2_DATA)
4238 def testFitFdtMissingList(self):
4239 """Test handling of a missing 'of-list' entry arg"""
4240 with self.assertRaises(ValueError) as e:
4241 self._DoReadFile('170_fit_fdt.dts')
4242 self.assertIn("Generator node requires 'of-list' entry argument",
4245 def testFitFdtEmptyList(self):
4246 """Test handling of an empty 'of-list' entry arg"""
4250 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4252 def testFitFdtMissingProp(self):
4253 """Test handling of a missing 'fit,fdt-list' property"""
4254 with self.assertRaises(ValueError) as e:
4255 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4256 self.assertIn("Generator node requires 'fit,fdt-list' property",
4259 def testFitFdtMissing(self):
4260 """Test handling of a missing 'default-dt' entry arg"""
4262 'of-list': 'test-fdt1 test-fdt2',
4264 with self.assertRaises(ValueError) as e:
4265 self._DoReadFileDtb(
4267 entry_args=entry_args,
4268 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4269 self.assertIn("Generated 'default' node requires default-dt entry argument",
4272 def testFitFdtNotInList(self):
4273 """Test handling of a default-dt that is not in the of-list"""
4275 'of-list': 'test-fdt1 test-fdt2',
4276 'default-dt': 'test-fdt3',
4278 with self.assertRaises(ValueError) as e:
4279 self._DoReadFileDtb(
4281 entry_args=entry_args,
4282 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4283 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4286 def testFitExtblobMissingHelp(self):
4287 """Test display of help messages when an external blob is missing"""
4288 control.missing_blob_help = control._ReadMissingBlobHelp()
4289 control.missing_blob_help['wibble'] = 'Wibble test'
4290 control.missing_blob_help['another'] = 'Another test'
4291 with test_util.capture_sys_output() as (stdout, stderr):
4292 self._DoTestFile('168_fit_missing_blob.dts',
4294 err = stderr.getvalue()
4296 # We can get the tag from the name, the type or the missing-msg
4297 # property. Check all three.
4298 self.assertIn('You may need to build ARM Trusted', err)
4299 self.assertIn('Wibble test', err)
4300 self.assertIn('Another test', err)
4302 def testMissingBlob(self):
4303 """Test handling of a blob containing a missing file"""
4304 with self.assertRaises(ValueError) as e:
4305 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4306 self.assertIn("Filename 'missing' not found in input path",
4309 def testEnvironment(self):
4310 """Test adding a U-Boot environment"""
4311 data = self._DoReadFile('174_env.dts')
4312 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4313 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4314 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4315 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4318 def testEnvironmentNoSize(self):
4319 """Test that a missing 'size' property is detected"""
4320 with self.assertRaises(ValueError) as e:
4321 self._DoTestFile('175_env_no_size.dts')
4322 self.assertIn("'u-boot-env' entry must have a size property",
4325 def testEnvironmentTooSmall(self):
4326 """Test handling of an environment that does not fit"""
4327 with self.assertRaises(ValueError) as e:
4328 self._DoTestFile('176_env_too_small.dts')
4330 # checksum, start byte, environment with \0 terminator, final \0
4331 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4333 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4336 def testSkipAtStart(self):
4337 """Test handling of skip-at-start section"""
4338 data = self._DoReadFile('177_skip_at_start.dts')
4339 self.assertEqual(U_BOOT_DATA, data)
4341 image = control.images['image']
4342 entries = image.GetEntries()
4343 section = entries['section']
4344 self.assertEqual(0, section.offset)
4345 self.assertEqual(len(U_BOOT_DATA), section.size)
4346 self.assertEqual(U_BOOT_DATA, section.GetData())
4348 entry = section.GetEntries()['u-boot']
4349 self.assertEqual(16, entry.offset)
4350 self.assertEqual(len(U_BOOT_DATA), entry.size)
4351 self.assertEqual(U_BOOT_DATA, entry.data)
4353 def testSkipAtStartPad(self):
4354 """Test handling of skip-at-start section with padded entry"""
4355 data = self._DoReadFile('178_skip_at_start_pad.dts')
4356 before = tools.get_bytes(0, 8)
4357 after = tools.get_bytes(0, 4)
4358 all = before + U_BOOT_DATA + after
4359 self.assertEqual(all, data)
4361 image = control.images['image']
4362 entries = image.GetEntries()
4363 section = entries['section']
4364 self.assertEqual(0, section.offset)
4365 self.assertEqual(len(all), section.size)
4366 self.assertEqual(all, section.GetData())
4368 entry = section.GetEntries()['u-boot']
4369 self.assertEqual(16, entry.offset)
4370 self.assertEqual(len(all), entry.size)
4371 self.assertEqual(U_BOOT_DATA, entry.data)
4373 def testSkipAtStartSectionPad(self):
4374 """Test handling of skip-at-start section with padding"""
4375 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4376 before = tools.get_bytes(0, 8)
4377 after = tools.get_bytes(0, 4)
4378 all = before + U_BOOT_DATA + after
4379 self.assertEqual(all, data)
4381 image = control.images['image']
4382 entries = image.GetEntries()
4383 section = entries['section']
4384 self.assertEqual(0, section.offset)
4385 self.assertEqual(len(all), section.size)
4386 self.assertEqual(U_BOOT_DATA, section.data)
4387 self.assertEqual(all, section.GetPaddedData())
4389 entry = section.GetEntries()['u-boot']
4390 self.assertEqual(16, entry.offset)
4391 self.assertEqual(len(U_BOOT_DATA), entry.size)
4392 self.assertEqual(U_BOOT_DATA, entry.data)
4394 def testSectionPad(self):
4395 """Testing padding with sections"""
4396 data = self._DoReadFile('180_section_pad.dts')
4397 expected = (tools.get_bytes(ord('&'), 3) +
4398 tools.get_bytes(ord('!'), 5) +
4400 tools.get_bytes(ord('!'), 1) +
4401 tools.get_bytes(ord('&'), 2))
4402 self.assertEqual(expected, data)
4404 def testSectionAlign(self):
4405 """Testing alignment with sections"""
4406 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4407 expected = (b'\0' + # fill section
4408 tools.get_bytes(ord('&'), 1) + # padding to section align
4409 b'\0' + # fill section
4410 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
4412 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4413 tools.get_bytes(ord('!'), 4)) # padding to section size
4414 self.assertEqual(expected, data)
4416 def testCompressImage(self):
4417 """Test compression of the entire image"""
4419 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4420 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4421 dtb = fdt.Fdt(out_dtb_fname)
4423 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4425 orig = self._decompress(data)
4426 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4428 # Do a sanity check on various fields
4429 image = control.images['image']
4430 entries = image.GetEntries()
4431 self.assertEqual(2, len(entries))
4433 entry = entries['blob']
4434 self.assertEqual(COMPRESS_DATA, entry.data)
4435 self.assertEqual(len(COMPRESS_DATA), entry.size)
4437 entry = entries['u-boot']
4438 self.assertEqual(U_BOOT_DATA, entry.data)
4439 self.assertEqual(len(U_BOOT_DATA), entry.size)
4441 self.assertEqual(len(data), image.size)
4442 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4443 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4444 orig = self._decompress(image.data)
4445 self.assertEqual(orig, image.uncomp_data)
4449 'blob:size': len(COMPRESS_DATA),
4450 'u-boot:offset': len(COMPRESS_DATA),
4451 'u-boot:size': len(U_BOOT_DATA),
4452 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4457 self.assertEqual(expected, props)
4459 def testCompressImageLess(self):
4460 """Test compression where compression reduces the image size"""
4462 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4463 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4464 dtb = fdt.Fdt(out_dtb_fname)
4466 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4468 orig = self._decompress(data)
4470 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4472 # Do a sanity check on various fields
4473 image = control.images['image']
4474 entries = image.GetEntries()
4475 self.assertEqual(2, len(entries))
4477 entry = entries['blob']
4478 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4479 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4481 entry = entries['u-boot']
4482 self.assertEqual(U_BOOT_DATA, entry.data)
4483 self.assertEqual(len(U_BOOT_DATA), entry.size)
4485 self.assertEqual(len(data), image.size)
4486 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4487 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4489 orig = self._decompress(image.data)
4490 self.assertEqual(orig, image.uncomp_data)
4494 'blob:size': len(COMPRESS_DATA_BIG),
4495 'u-boot:offset': len(COMPRESS_DATA_BIG),
4496 'u-boot:size': len(U_BOOT_DATA),
4497 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4502 self.assertEqual(expected, props)
4504 def testCompressSectionSize(self):
4505 """Test compression of a section with a fixed size"""
4507 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4508 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4509 dtb = fdt.Fdt(out_dtb_fname)
4511 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4513 orig = self._decompress(data)
4514 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4516 'section/blob:offset': 0,
4517 'section/blob:size': len(COMPRESS_DATA),
4518 'section/u-boot:offset': len(COMPRESS_DATA),
4519 'section/u-boot:size': len(U_BOOT_DATA),
4520 'section:offset': 0,
4521 'section:image-pos': 0,
4522 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4523 'section:size': 0x30,
4528 self.assertEqual(expected, props)
4530 def testCompressSection(self):
4531 """Test compression of a section with no fixed size"""
4533 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4534 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4535 dtb = fdt.Fdt(out_dtb_fname)
4537 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4539 orig = self._decompress(data)
4540 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4542 'section/blob:offset': 0,
4543 'section/blob:size': len(COMPRESS_DATA),
4544 'section/u-boot:offset': len(COMPRESS_DATA),
4545 'section/u-boot:size': len(U_BOOT_DATA),
4546 'section:offset': 0,
4547 'section:image-pos': 0,
4548 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4549 'section:size': len(data),
4554 self.assertEqual(expected, props)
4556 def testLz4Missing(self):
4557 """Test that binman still produces an image if lz4 is missing"""
4558 with test_util.capture_sys_output() as (_, stderr):
4559 self._DoTestFile('185_compress_section.dts',
4560 force_missing_bintools='lz4')
4561 err = stderr.getvalue()
4562 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
4564 def testCompressExtra(self):
4565 """Test compression of a section with no fixed size"""
4567 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4568 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4569 dtb = fdt.Fdt(out_dtb_fname)
4571 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4574 base = data[len(U_BOOT_DATA):]
4575 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4576 rest = base[len(U_BOOT_DATA):]
4578 # Check compressed data
4579 bintool = self.comp_bintools['lz4']
4580 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
4581 data1 = rest[:len(expect1)]
4582 section1 = self._decompress(data1)
4583 self.assertEquals(expect1, data1)
4584 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4585 rest1 = rest[len(expect1):]
4587 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
4588 data2 = rest1[:len(expect2)]
4589 section2 = self._decompress(data2)
4590 self.assertEquals(expect2, data2)
4591 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4592 rest2 = rest1[len(expect2):]
4594 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4595 len(expect2) + len(U_BOOT_DATA))
4596 #self.assertEquals(expect_size, len(data))
4598 #self.assertEquals(U_BOOT_DATA, rest2)
4603 'u-boot:image-pos': 0,
4604 'u-boot:size': len(U_BOOT_DATA),
4606 'base:offset': len(U_BOOT_DATA),
4607 'base:image-pos': len(U_BOOT_DATA),
4608 'base:size': len(data) - len(U_BOOT_DATA),
4609 'base/u-boot:offset': 0,
4610 'base/u-boot:image-pos': len(U_BOOT_DATA),
4611 'base/u-boot:size': len(U_BOOT_DATA),
4612 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4614 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4616 'base/u-boot2:size': len(U_BOOT_DATA),
4618 'base/section:offset': len(U_BOOT_DATA),
4619 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4620 'base/section:size': len(expect1),
4621 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4622 'base/section/blob:offset': 0,
4623 'base/section/blob:size': len(COMPRESS_DATA),
4624 'base/section/u-boot:offset': len(COMPRESS_DATA),
4625 'base/section/u-boot:size': len(U_BOOT_DATA),
4627 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4628 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4629 'base/section2:size': len(expect2),
4630 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4631 'base/section2/blob:offset': 0,
4632 'base/section2/blob:size': len(COMPRESS_DATA),
4633 'base/section2/blob2:offset': len(COMPRESS_DATA),
4634 'base/section2/blob2:size': len(COMPRESS_DATA),
4640 self.assertEqual(expected, props)
4642 def testSymbolsSubsection(self):
4643 """Test binman can assign symbols from a subsection"""
4644 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
4646 def testReadImageEntryArg(self):
4647 """Test reading an image that would need an entry arg to generate"""
4649 'cros-ec-rw-path': 'ecrw.bin',
4651 data = self.data = self._DoReadFileDtb(
4652 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4653 entry_args=entry_args)
4655 image_fname = tools.get_output_filename('image.bin')
4656 orig_image = control.images['image']
4658 # This should not generate an error about the missing 'cros-ec-rw-path'
4659 # since we are reading the image from a file. Compare with
4660 # testEntryArgsRequired()
4661 image = Image.FromFile(image_fname)
4662 self.assertEqual(orig_image.GetEntries().keys(),
4663 image.GetEntries().keys())
4665 def testFilesAlign(self):
4666 """Test alignment with files"""
4667 data = self._DoReadFile('190_files_align.dts')
4669 # The first string is 15 bytes so will align to 16
4670 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4671 self.assertEqual(expect, data)
4673 def testReadImageSkip(self):
4674 """Test reading an image and accessing its FDT map"""
4675 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4676 image_fname = tools.get_output_filename('image.bin')
4677 orig_image = control.images['image']
4678 image = Image.FromFile(image_fname)
4679 self.assertEqual(orig_image.GetEntries().keys(),
4680 image.GetEntries().keys())
4682 orig_entry = orig_image.GetEntries()['fdtmap']
4683 entry = image.GetEntries()['fdtmap']
4684 self.assertEqual(orig_entry.offset, entry.offset)
4685 self.assertEqual(orig_entry.size, entry.size)
4686 self.assertEqual(16, entry.image_pos)
4688 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4690 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4692 def testTplNoDtb(self):
4693 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4695 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4696 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4697 data[:len(U_BOOT_TPL_NODTB_DATA)])
4699 def testTplBssPad(self):
4700 """Test that we can pad TPL's BSS with zeros"""
4701 # ELF file with a '__bss_size' symbol
4703 data = self._DoReadFile('193_tpl_bss_pad.dts')
4704 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
4707 def testTplBssPadMissing(self):
4708 """Test that a missing symbol is detected"""
4709 self._SetupTplElf('u_boot_ucode_ptr')
4710 with self.assertRaises(ValueError) as e:
4711 self._DoReadFile('193_tpl_bss_pad.dts')
4712 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4715 def checkDtbSizes(self, data, pad_len, start):
4716 """Check the size arguments in a dtb embedded in an image
4719 data: The image data
4720 pad_len: Length of the pad section in the image, in bytes
4721 start: Start offset of the devicetree to examine, within the image
4724 Size of the devicetree in bytes
4726 dtb_data = data[start:]
4727 dtb = fdt.Fdt.FromData(dtb_data)
4728 fdt_size = dtb.GetFdtObj().totalsize()
4730 props = self._GetPropTree(dtb, 'size')
4733 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4734 'u-boot-spl/u-boot-spl-dtb:size': 801,
4735 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4736 'u-boot-spl:size': 860,
4737 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4738 'u-boot/u-boot-dtb:size': 781,
4739 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4744 def testExpanded(self):
4745 """Test that an expanded entry type is selected when needed"""
4749 # SPL has a devicetree, TPL does not
4755 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4756 entry_args=entry_args)
4757 image = control.images['image']
4758 entries = image.GetEntries()
4759 self.assertEqual(3, len(entries))
4761 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4762 self.assertIn('u-boot', entries)
4763 entry = entries['u-boot']
4764 self.assertEqual('u-boot-expanded', entry.etype)
4765 subent = entry.GetEntries()
4766 self.assertEqual(2, len(subent))
4767 self.assertIn('u-boot-nodtb', subent)
4768 self.assertIn('u-boot-dtb', subent)
4770 # Second, u-boot-spl, which should be expanded into three parts
4771 self.assertIn('u-boot-spl', entries)
4772 entry = entries['u-boot-spl']
4773 self.assertEqual('u-boot-spl-expanded', entry.etype)
4774 subent = entry.GetEntries()
4775 self.assertEqual(3, len(subent))
4776 self.assertIn('u-boot-spl-nodtb', subent)
4777 self.assertIn('u-boot-spl-bss-pad', subent)
4778 self.assertIn('u-boot-spl-dtb', subent)
4780 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4782 self.assertIn('u-boot-tpl', entries)
4783 entry = entries['u-boot-tpl']
4784 self.assertEqual('u-boot-tpl', entry.etype)
4785 self.assertEqual(None, entry.GetEntries())
4787 def testExpandedTpl(self):
4788 """Test that an expanded entry type is selected for TPL when needed"""
4795 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4796 entry_args=entry_args)
4797 image = control.images['image']
4798 entries = image.GetEntries()
4799 self.assertEqual(1, len(entries))
4801 # We only have u-boot-tpl, which be expanded
4802 self.assertIn('u-boot-tpl', entries)
4803 entry = entries['u-boot-tpl']
4804 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4805 subent = entry.GetEntries()
4806 self.assertEqual(3, len(subent))
4807 self.assertIn('u-boot-tpl-nodtb', subent)
4808 self.assertIn('u-boot-tpl-bss-pad', subent)
4809 self.assertIn('u-boot-tpl-dtb', subent)
4811 def testExpandedNoPad(self):
4812 """Test an expanded entry without BSS pad enabled"""
4816 # SPL has a devicetree, TPL does not
4818 'spl-dtb': 'something',
4822 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4823 entry_args=entry_args)
4824 image = control.images['image']
4825 entries = image.GetEntries()
4827 # Just check u-boot-spl, which should be expanded into two parts
4828 self.assertIn('u-boot-spl', entries)
4829 entry = entries['u-boot-spl']
4830 self.assertEqual('u-boot-spl-expanded', entry.etype)
4831 subent = entry.GetEntries()
4832 self.assertEqual(2, len(subent))
4833 self.assertIn('u-boot-spl-nodtb', subent)
4834 self.assertIn('u-boot-spl-dtb', subent)
4836 def testExpandedTplNoPad(self):
4837 """Test that an expanded entry type with padding disabled in TPL"""
4844 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4845 entry_args=entry_args)
4846 image = control.images['image']
4847 entries = image.GetEntries()
4848 self.assertEqual(1, len(entries))
4850 # We only have u-boot-tpl, which be expanded
4851 self.assertIn('u-boot-tpl', entries)
4852 entry = entries['u-boot-tpl']
4853 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4854 subent = entry.GetEntries()
4855 self.assertEqual(2, len(subent))
4856 self.assertIn('u-boot-tpl-nodtb', subent)
4857 self.assertIn('u-boot-tpl-dtb', subent)
4859 def testFdtInclude(self):
4860 """Test that an Fdt is update within all binaries"""
4864 # SPL has a devicetree, TPL does not
4871 # Build the image. It includes two separate devicetree binaries, each
4872 # with their own contents, but all contain the binman definition.
4873 data = self._DoReadFileDtb(
4874 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4875 update_dtb=True, entry_args=entry_args)[0]
4878 # Check the U-Boot dtb
4879 start = len(U_BOOT_NODTB_DATA)
4880 fdt_size = self.checkDtbSizes(data, pad_len, start)
4883 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4884 fdt_size = self.checkDtbSizes(data, pad_len, start)
4886 # TPL has no devicetree
4887 start += fdt_size + len(U_BOOT_TPL_DATA)
4888 self.assertEqual(len(data), start)
4890 def testSymbolsExpanded(self):
4891 """Test binman can assign symbols in expanded entries"""
4895 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4896 U_BOOT_SPL_DTB_DATA, 0x38,
4897 entry_args=entry_args, use_expanded=True)
4899 def testCollection(self):
4900 """Test a collection"""
4901 data = self._DoReadFile('198_collection.dts')
4902 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4903 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4904 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
4907 def testCollectionSection(self):
4908 """Test a collection where a section must be built first"""
4909 # Sections never have their contents when GetData() is called, but when
4910 # BuildSectionData() is called with required=True, a section will force
4911 # building the contents, producing an error is anything is still
4913 data = self._DoReadFile('199_collection_section.dts')
4914 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4915 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4916 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
4919 def testAlignDefault(self):
4920 """Test that default alignment works on sections"""
4921 data = self._DoReadFile('200_align_default.dts')
4922 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
4924 # Special alignment for section
4925 expected += tools.get_bytes(0, 32 - len(expected))
4926 # No alignment within the nested section
4927 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4928 # Now the final piece, which should be default-aligned
4929 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4930 self.assertEqual(expected, data)
4932 def testPackOpenSBI(self):
4933 """Test that an image with an OpenSBI binary can be created"""
4934 data = self._DoReadFile('201_opensbi.dts')
4935 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4937 def testSectionsSingleThread(self):
4938 """Test sections without multithreading"""
4939 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4940 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4941 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4942 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
4943 self.assertEqual(expected, data)
4945 def testThreadTimeout(self):
4946 """Test handling a thread that takes too long"""
4947 with self.assertRaises(ValueError) as e:
4948 self._DoTestFile('202_section_timeout.dts',
4949 test_section_timeout=True)
4950 self.assertIn("Timed out obtaining contents", str(e.exception))
4952 def testTiming(self):
4953 """Test output of timing information"""
4954 data = self._DoReadFile('055_sections.dts')
4955 with test_util.capture_sys_output() as (stdout, stderr):
4957 self.assertIn('read:', stdout.getvalue())
4958 self.assertIn('compress:', stdout.getvalue())
4960 def testUpdateFdtInElf(self):
4961 """Test that we can update the devicetree in an ELF file"""
4962 if not elf.ELF_TOOLS:
4963 self.skipTest('Python elftools not available')
4964 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4965 outfile = os.path.join(self._indir, 'u-boot.out')
4966 begin_sym = 'dtb_embed_begin'
4967 end_sym = 'dtb_embed_end'
4968 retcode = self._DoTestFile(
4969 '060_fdt_update.dts', update_dtb=True,
4970 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4971 self.assertEqual(0, retcode)
4973 # Check that the output file does in fact contact a dtb with the binman
4974 # definition in the correct place
4975 syms = elf.GetSymbolFileOffset(infile,
4976 ['dtb_embed_begin', 'dtb_embed_end'])
4977 data = tools.read_file(outfile)
4978 dtb_data = data[syms['dtb_embed_begin'].offset:
4979 syms['dtb_embed_end'].offset]
4981 dtb = fdt.Fdt.FromData(dtb_data)
4983 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4987 '_testing:offset': 32,
4989 '_testing:image-pos': 32,
4990 'section@0/u-boot:offset': 0,
4991 'section@0/u-boot:size': len(U_BOOT_DATA),
4992 'section@0/u-boot:image-pos': 0,
4993 'section@0:offset': 0,
4994 'section@0:size': 16,
4995 'section@0:image-pos': 0,
4997 'section@1/u-boot:offset': 0,
4998 'section@1/u-boot:size': len(U_BOOT_DATA),
4999 'section@1/u-boot:image-pos': 16,
5000 'section@1:offset': 16,
5001 'section@1:size': 16,
5002 'section@1:image-pos': 16,
5006 def testUpdateFdtInElfInvalid(self):
5007 """Test that invalid args are detected with --update-fdt-in-elf"""
5008 with self.assertRaises(ValueError) as e:
5009 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5010 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5013 def testUpdateFdtInElfNoSyms(self):
5014 """Test that missing symbols are detected with --update-fdt-in-elf"""
5015 if not elf.ELF_TOOLS:
5016 self.skipTest('Python elftools not available')
5017 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5019 begin_sym = 'wrong_begin'
5020 end_sym = 'wrong_end'
5021 with self.assertRaises(ValueError) as e:
5023 '060_fdt_update.dts',
5024 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5025 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5028 def testUpdateFdtInElfTooSmall(self):
5029 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
5030 if not elf.ELF_TOOLS:
5031 self.skipTest('Python elftools not available')
5032 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5033 outfile = os.path.join(self._indir, 'u-boot.out')
5034 begin_sym = 'dtb_embed_begin'
5035 end_sym = 'dtb_embed_end'
5036 with self.assertRaises(ValueError) as e:
5038 '060_fdt_update.dts', update_dtb=True,
5039 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5042 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5044 def testVersion(self):
5045 """Test we can get the binman version"""
5046 version = '(unreleased)'
5047 self.assertEqual(version, state.GetVersion(self._indir))
5049 with self.assertRaises(SystemExit):
5050 with test_util.capture_sys_output() as (_, stderr):
5051 self._DoBinman('-V')
5052 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5054 # Try running the tool too, just to be safe
5055 result = self._RunBinman('-V')
5056 self.assertEqual('Binman %s\n' % version, result.stderr)
5058 # Set up a version file to make sure that works
5059 version = 'v2025.01-rc2'
5060 tools.write_file(os.path.join(self._indir, 'version'), version,
5062 self.assertEqual(version, state.GetVersion(self._indir))
5064 def testAltFormat(self):
5065 """Test that alternative formats can be used to extract"""
5066 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5069 tmpdir, updated_fname = self._SetupImageInTmpdir()
5070 with test_util.capture_sys_output() as (stdout, _):
5071 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5073 '''Flag (-F) Entry type Description
5074 fdt fdtmap Extract the devicetree blob from the fdtmap
5078 dtb = os.path.join(tmpdir, 'fdt.dtb')
5079 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5082 # Check that we can read it and it can be scanning, meaning it does
5083 # not have a 16-byte fdtmap header
5084 data = tools.read_file(dtb)
5085 dtb = fdt.Fdt.FromData(data)
5088 # Now check u-boot which has no alt_format
5089 fname = os.path.join(tmpdir, 'fdt.dtb')
5090 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5091 '-f', fname, 'u-boot')
5092 data = tools.read_file(fname)
5093 self.assertEqual(U_BOOT_DATA, data)
5096 shutil.rmtree(tmpdir)
5098 def testExtblobList(self):
5099 """Test an image with an external blob list"""
5100 data = self._DoReadFile('215_blob_ext_list.dts')
5101 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5103 def testExtblobListMissing(self):
5104 """Test an image with a missing external blob"""
5105 with self.assertRaises(ValueError) as e:
5106 self._DoReadFile('216_blob_ext_list_missing.dts')
5107 self.assertIn("Filename 'missing-file' not found in input path",
5110 def testExtblobListMissingOk(self):
5111 """Test an image with an missing external blob that is allowed"""
5112 with test_util.capture_sys_output() as (stdout, stderr):
5113 self._DoTestFile('216_blob_ext_list_missing.dts',
5115 err = stderr.getvalue()
5116 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
5119 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5120 data = self._DoReadFile('203_fip.dts')
5121 hdr, fents = fip_util.decode_fip(data)
5122 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5123 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5124 self.assertEqual(0x123, hdr.flags)
5126 self.assertEqual(2, len(fents))
5130 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5131 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5132 self.assertEqual('soc-fw', fent.fip_type)
5133 self.assertEqual(0x88, fent.offset)
5134 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5135 self.assertEqual(0x123456789abcdef, fent.flags)
5136 self.assertEqual(ATF_BL31_DATA, fent.data)
5137 self.assertEqual(True, fent.valid)
5141 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5142 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5143 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5144 self.assertEqual(0x8c, fent.offset)
5145 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5146 self.assertEqual(0, fent.flags)
5147 self.assertEqual(ATF_BL2U_DATA, fent.data)
5148 self.assertEqual(True, fent.valid)
5150 def testFipOther(self):
5151 """Basic FIP with something that isn't a external blob"""
5152 data = self._DoReadFile('204_fip_other.dts')
5153 hdr, fents = fip_util.decode_fip(data)
5155 self.assertEqual(2, len(fents))
5157 self.assertEqual('rot-cert', fent.fip_type)
5158 self.assertEqual(b'aa', fent.data)
5160 def testFipNoType(self):
5161 """FIP with an entry of an unknown type"""
5162 with self.assertRaises(ValueError) as e:
5163 self._DoReadFile('205_fip_no_type.dts')
5164 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5167 def testFipUuid(self):
5168 """Basic FIP with a manual uuid"""
5169 data = self._DoReadFile('206_fip_uuid.dts')
5170 hdr, fents = fip_util.decode_fip(data)
5172 self.assertEqual(2, len(fents))
5174 self.assertEqual(None, fent.fip_type)
5176 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5177 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5179 self.assertEqual(U_BOOT_DATA, fent.data)
5181 def testFipLs(self):
5182 """Test listing a FIP"""
5183 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5184 hdr, fents = fip_util.decode_fip(data)
5187 tmpdir, updated_fname = self._SetupImageInTmpdir()
5188 with test_util.capture_sys_output() as (stdout, stderr):
5189 self._DoBinman('ls', '-i', updated_fname)
5191 shutil.rmtree(tmpdir)
5192 lines = stdout.getvalue().splitlines()
5194 'Name Image-pos Size Entry-type Offset Uncomp-size',
5195 '--------------------------------------------------------------',
5196 'image 0 2d3 section 0',
5197 ' atf-fip 0 90 atf-fip 0',
5198 ' soc-fw 88 4 blob-ext 88',
5199 ' u-boot 8c 4 u-boot 8c',
5200 ' fdtmap 90 243 fdtmap 90',
5202 self.assertEqual(expected, lines)
5204 image = control.images['image']
5205 entries = image.GetEntries()
5206 fdtmap = entries['fdtmap']
5208 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5209 magic = fdtmap_data[:8]
5210 self.assertEqual(b'_FDTMAP_', magic)
5211 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
5213 fdt_data = fdtmap_data[16:]
5214 dtb = fdt.Fdt.FromData(fdt_data)
5216 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5218 'atf-fip/soc-fw:image-pos': 136,
5219 'atf-fip/soc-fw:offset': 136,
5220 'atf-fip/soc-fw:size': 4,
5221 'atf-fip/u-boot:image-pos': 140,
5222 'atf-fip/u-boot:offset': 140,
5223 'atf-fip/u-boot:size': 4,
5224 'atf-fip:image-pos': 0,
5225 'atf-fip:offset': 0,
5226 'atf-fip:size': 144,
5229 'fdtmap:image-pos': fdtmap.image_pos,
5230 'fdtmap:offset': fdtmap.offset,
5231 'fdtmap:size': len(fdtmap_data),
5235 def testFipExtractOneEntry(self):
5236 """Test extracting a single entry fron an FIP"""
5237 self._DoReadFileRealDtb('207_fip_ls.dts')
5238 image_fname = tools.get_output_filename('image.bin')
5239 fname = os.path.join(self._indir, 'output.extact')
5240 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
5241 data = tools.read_file(fname)
5242 self.assertEqual(U_BOOT_DATA, data)
5244 def testFipReplace(self):
5245 """Test replacing a single file in a FIP"""
5246 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
5247 data = self._DoReadFileRealDtb('208_fip_replace.dts')
5248 updated_fname = tools.get_output_filename('image-updated.bin')
5249 tools.write_file(updated_fname, data)
5250 entry_name = 'atf-fip/u-boot'
5251 control.WriteEntry(updated_fname, entry_name, expected,
5253 actual = control.ReadEntry(updated_fname, entry_name)
5254 self.assertEqual(expected, actual)
5256 new_data = tools.read_file(updated_fname)
5257 hdr, fents = fip_util.decode_fip(new_data)
5259 self.assertEqual(2, len(fents))
5261 # Check that the FIP entry is updated
5263 self.assertEqual(0x8c, fent.offset)
5264 self.assertEqual(len(expected), fent.size)
5265 self.assertEqual(0, fent.flags)
5266 self.assertEqual(expected, fent.data)
5267 self.assertEqual(True, fent.valid)
5269 def testFipMissing(self):
5270 with test_util.capture_sys_output() as (stdout, stderr):
5271 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5272 err = stderr.getvalue()
5273 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
5275 def testFipSize(self):
5276 """Test a FIP with a size property"""
5277 data = self._DoReadFile('210_fip_size.dts')
5278 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5279 hdr, fents = fip_util.decode_fip(data)
5280 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5281 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5283 self.assertEqual(1, len(fents))
5286 self.assertEqual('soc-fw', fent.fip_type)
5287 self.assertEqual(0x60, fent.offset)
5288 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5289 self.assertEqual(ATF_BL31_DATA, fent.data)
5290 self.assertEqual(True, fent.valid)
5292 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
5293 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
5295 def testFipBadAlign(self):
5296 """Test that an invalid alignment value in a FIP is detected"""
5297 with self.assertRaises(ValueError) as e:
5298 self._DoTestFile('211_fip_bad_align.dts')
5300 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5303 def testFipCollection(self):
5304 """Test using a FIP in a collection"""
5305 data = self._DoReadFile('212_fip_collection.dts')
5306 entry1 = control.images['image'].GetEntries()['collection']
5307 data1 = data[:entry1.size]
5308 hdr1, fents2 = fip_util.decode_fip(data1)
5310 entry2 = control.images['image'].GetEntries()['atf-fip']
5311 data2 = data[entry2.offset:entry2.offset + entry2.size]
5312 hdr1, fents2 = fip_util.decode_fip(data2)
5314 # The 'collection' entry should have U-Boot included at the end
5315 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5316 self.assertEqual(data1, data2 + U_BOOT_DATA)
5317 self.assertEqual(U_BOOT_DATA, data1[-4:])
5319 # There should be a U-Boot after the final FIP
5320 self.assertEqual(U_BOOT_DATA, data[-4:])
5322 def testFakeBlob(self):
5323 """Test handling of faking an external blob"""
5324 with test_util.capture_sys_output() as (stdout, stderr):
5325 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5326 allow_fake_blobs=True)
5327 err = stderr.getvalue()
5330 "Image '.*' has faked external blobs and is non-functional: .*")
5332 def testExtblobListFaked(self):
5333 """Test an extblob with missing external blob that are faked"""
5334 with test_util.capture_sys_output() as (stdout, stderr):
5335 self._DoTestFile('216_blob_ext_list_missing.dts',
5336 allow_fake_blobs=True)
5337 err = stderr.getvalue()
5338 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
5340 def testListBintools(self):
5341 args = ['tool', '--list']
5342 with test_util.capture_sys_output() as (stdout, _):
5343 self._DoBinman(*args)
5344 out = stdout.getvalue().splitlines()
5345 self.assertTrue(len(out) >= 2)
5347 def testFetchBintools(self):
5348 def fail_download(url):
5349 """Take the tools.download() function by raising an exception"""
5350 raise urllib.error.URLError('my error')
5353 with self.assertRaises(ValueError) as e:
5354 self._DoBinman(*args)
5355 self.assertIn("Invalid arguments to 'tool' subcommand",
5358 args = ['tool', '--fetch']
5359 with self.assertRaises(ValueError) as e:
5360 self._DoBinman(*args)
5361 self.assertIn('Please specify bintools to fetch', str(e.exception))
5363 args = ['tool', '--fetch', '_testing']
5364 with unittest.mock.patch.object(tools, 'download',
5365 side_effect=fail_download):
5366 with test_util.capture_sys_output() as (stdout, _):
5367 self._DoBinman(*args)
5368 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5370 def testBintoolDocs(self):
5371 """Test for creation of bintool documentation"""
5372 with test_util.capture_sys_output() as (stdout, stderr):
5373 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5374 self.assertTrue(len(stdout.getvalue()) > 0)
5376 def testBintoolDocsMissing(self):
5377 """Test handling of missing bintool documentation"""
5378 with self.assertRaises(ValueError) as e:
5379 with test_util.capture_sys_output() as (stdout, stderr):
5380 control.write_bintool_docs(
5381 control.bintool.Bintool.get_tool_list(), 'mkimage')
5382 self.assertIn('Documentation is missing for modules: mkimage',
5385 def testListWithGenNode(self):
5386 """Check handling of an FDT map when the section cannot be found"""
5388 'of-list': 'test-fdt1 test-fdt2',
5390 data = self._DoReadFileDtb(
5391 '219_fit_gennode.dts',
5392 entry_args=entry_args,
5394 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5397 tmpdir, updated_fname = self._SetupImageInTmpdir()
5398 with test_util.capture_sys_output() as (stdout, stderr):
5399 self._RunBinman('ls', '-i', updated_fname)
5401 shutil.rmtree(tmpdir)
5403 def testFitSubentryUsesBintool(self):
5404 """Test that binman FIT subentries can use bintools"""
5405 command.test_result = self._HandleGbbCommand
5407 'keydir': 'devkeys',
5408 'bmpblk': 'bmpblk.bin',
5410 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5411 entry_args=entry_args)
5413 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5414 tools.get_bytes(0, 0x2180 - 16))
5415 self.assertIn(expected, data)
5417 def testFitSubentryMissingBintool(self):
5418 """Test that binman reports missing bintools for FIT subentries"""
5420 'keydir': 'devkeys',
5422 with test_util.capture_sys_output() as (_, stderr):
5423 self._DoTestFile('220_fit_subentry_bintool.dts',
5424 force_missing_bintools='futility', entry_args=entry_args)
5425 err = stderr.getvalue()
5426 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
5428 def testFitSubentryHashSubnode(self):
5429 """Test an image with a FIT inside"""
5431 data, _, _, out_dtb_name = self._DoReadFileDtb(
5432 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5434 mkimage_dtb = fdt.Fdt.FromData(data)
5436 binman_dtb = fdt.Fdt(out_dtb_name)
5439 # Check that binman didn't add hash values
5440 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5441 self.assertNotIn('value', fnode.props)
5443 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5444 self.assertNotIn('value', fnode.props)
5446 # Check that mkimage added hash values
5447 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5448 self.assertIn('value', fnode.props)
5450 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5451 self.assertIn('value', fnode.props)
5453 def testPackTeeOs(self):
5454 """Test that an image with an TEE binary can be created"""
5455 data = self._DoReadFile('222_tee_os.dts')
5456 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5458 def testFitFdtOper(self):
5459 """Check handling of a specified FIT operation"""
5461 'of-list': 'test-fdt1 test-fdt2',
5462 'default-dt': 'test-fdt2',
5464 self._DoReadFileDtb(
5465 '223_fit_fdt_oper.dts',
5466 entry_args=entry_args,
5467 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5469 def testFitFdtBadOper(self):
5470 """Check handling of an FDT map when the section cannot be found"""
5471 with self.assertRaises(ValueError) as exc:
5472 self._DoReadFileDtb('224_fit_bad_oper.dts')
5473 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
5476 def test_uses_expand_size(self):
5477 """Test that the 'expand-size' property cannot be used anymore"""
5478 with self.assertRaises(ValueError) as e:
5479 data = self._DoReadFile('225_expand_size_bad.dts')
5481 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5484 def testFitSplitElf(self):
5485 """Test an image with an FIT with an split-elf operation"""
5486 if not elf.ELF_TOOLS:
5487 self.skipTest('Python elftools not available')
5489 'of-list': 'test-fdt1 test-fdt2',
5490 'default-dt': 'test-fdt2',
5491 'atf-bl31-path': 'bl31.elf',
5492 'tee-os-path': 'tee.elf',
5494 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5495 data = self._DoReadFileDtb(
5496 '226_fit_split_elf.dts',
5497 entry_args=entry_args,
5498 extra_indirs=[test_subdir])[0]
5500 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5501 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5503 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5505 dtb = fdt.Fdt.FromData(fit_data)
5508 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5509 segments, entry = elf.read_loadable_segments(elf_data)
5511 # We assume there are two segments
5512 self.assertEquals(2, len(segments))
5514 atf1 = dtb.GetNode('/images/atf-1')
5515 _, start, data = segments[0]
5516 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5517 self.assertEqual(entry,
5518 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5519 self.assertEqual(start,
5520 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5521 self.assertEqual(data, atf1.props['data'].bytes)
5523 hash_node = atf1.FindNode('hash')
5524 self.assertIsNotNone(hash_node)
5525 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5527 atf2 = dtb.GetNode('/images/atf-2')
5528 self.assertEqual(base_keys, atf2.props.keys())
5529 _, start, data = segments[1]
5530 self.assertEqual(start,
5531 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5532 self.assertEqual(data, atf2.props['data'].bytes)
5534 hash_node = atf2.FindNode('hash')
5535 self.assertIsNotNone(hash_node)
5536 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5538 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5539 self.assertIsNotNone(hash_node)
5540 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5542 conf = dtb.GetNode('/configurations')
5543 self.assertEqual({'default'}, conf.props.keys())
5545 for subnode in conf.subnodes:
5546 self.assertEqual({'description', 'fdt', 'loadables'},
5547 subnode.props.keys())
5549 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5550 fdt_util.GetStringList(subnode, 'loadables'))
5552 def _check_bad_fit(self, dts):
5555 This runs with the given dts and returns the assertion raised
5558 dts (str): dts filename to use
5561 str: Assertion string raised
5564 'of-list': 'test-fdt1 test-fdt2',
5565 'default-dt': 'test-fdt2',
5566 'atf-bl31-path': 'bl31.elf',
5567 'tee-os-path': 'tee.elf',
5569 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5570 with self.assertRaises(ValueError) as exc:
5571 self._DoReadFileDtb(dts, entry_args=entry_args,
5572 extra_indirs=[test_subdir])[0]
5573 return str(exc.exception)
5575 def testFitSplitElfBadElf(self):
5576 """Test a FIT split-elf operation with an invalid ELF file"""
5577 if not elf.ELF_TOOLS:
5578 self.skipTest('Python elftools not available')
5579 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5581 'of-list': 'test-fdt1 test-fdt2',
5582 'default-dt': 'test-fdt2',
5583 'atf-bl31-path': 'bad.elf',
5584 'tee-os-path': 'tee.elf',
5586 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5587 with self.assertRaises(ValueError) as exc:
5588 self._DoReadFileDtb(
5589 '226_fit_split_elf.dts',
5590 entry_args=entry_args,
5591 extra_indirs=[test_subdir])[0]
5593 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5596 def checkFitSplitElf(self, **kwargs):
5597 """Test an split-elf FIT with a missing ELF file
5600 kwargs (dict of str): Arguments to pass to _DoTestFile()
5608 'of-list': 'test-fdt1 test-fdt2',
5609 'default-dt': 'test-fdt2',
5610 'atf-bl31-path': 'bl31.elf',
5611 'tee-os-path': 'missing.elf',
5613 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5614 with test_util.capture_sys_output() as (stdout, stderr):
5616 '226_fit_split_elf.dts', entry_args=entry_args,
5617 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5618 out = stdout.getvalue()
5619 err = stderr.getvalue()
5622 def testFitSplitElfBadDirective(self):
5623 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5624 if not elf.ELF_TOOLS:
5625 self.skipTest('Python elftools not available')
5626 err = self._check_bad_fit('227_fit_bad_dir.dts')
5628 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5631 def testFitSplitElfBadDirectiveConfig(self):
5632 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5633 if not elf.ELF_TOOLS:
5634 self.skipTest('Python elftools not available')
5635 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5637 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5641 def testFitSplitElfMissing(self):
5642 """Test an split-elf FIT with a missing ELF file"""
5643 if not elf.ELF_TOOLS:
5644 self.skipTest('Python elftools not available')
5645 out, err = self.checkFitSplitElf(allow_missing=True)
5648 "Image '.*' is missing external blobs and is non-functional: .*")
5649 self.assertNotRegex(out, '.*Faked blob.*')
5650 fname = tools.get_output_filename('binman-fake/missing.elf')
5651 self.assertFalse(os.path.exists(fname))
5653 def testFitSplitElfFaked(self):
5654 """Test an split-elf FIT with faked ELF file"""
5655 if not elf.ELF_TOOLS:
5656 self.skipTest('Python elftools not available')
5657 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
5660 "Image '.*' is missing external blobs and is non-functional: .*")
5663 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5664 fname = tools.get_output_filename('binman-fake/missing.elf')
5665 self.assertTrue(os.path.exists(fname))
5667 def testMkimageMissingBlob(self):
5668 """Test using mkimage to build an image"""
5669 with test_util.capture_sys_output() as (stdout, stderr):
5670 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5671 allow_fake_blobs=True)
5672 err = stderr.getvalue()
5675 "Image '.*' has faked external blobs and is non-functional: .*")
5677 def testPreLoad(self):
5678 """Test an image with a pre-load header"""
5680 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5682 data = self._DoReadFileDtb(
5683 '230_pre_load.dts', entry_args=entry_args,
5684 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
5685 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5686 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5687 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5689 def testPreLoadNoKey(self):
5690 """Test an image with a pre-load heade0r with missing key"""
5691 with self.assertRaises(FileNotFoundError) as exc:
5692 self._DoReadFile('230_pre_load.dts')
5693 self.assertIn("No such file or directory: 'dev.key'",
5696 def testPreLoadPkcs(self):
5697 """Test an image with a pre-load header with padding pkcs"""
5699 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5701 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5702 entry_args=entry_args)[0]
5703 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5704 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5705 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5707 def testPreLoadPss(self):
5708 """Test an image with a pre-load header with padding pss"""
5710 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5712 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5713 entry_args=entry_args)[0]
5714 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5715 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5716 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5718 def testPreLoadInvalidPadding(self):
5719 """Test an image with a pre-load header with an invalid padding"""
5721 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5723 with self.assertRaises(ValueError) as e:
5724 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5725 entry_args=entry_args)
5727 def testPreLoadInvalidSha(self):
5728 """Test an image with a pre-load header with an invalid hash"""
5730 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5732 with self.assertRaises(ValueError) as e:
5733 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5734 entry_args=entry_args)
5736 def testPreLoadInvalidAlgo(self):
5737 """Test an image with a pre-load header with an invalid algo"""
5738 with self.assertRaises(ValueError) as e:
5739 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
5741 def testPreLoadInvalidKey(self):
5742 """Test an image with a pre-load header with an invalid key"""
5744 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5746 with self.assertRaises(ValueError) as e:
5747 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5748 entry_args=entry_args)
5750 def _CheckSafeUniqueNames(self, *images):
5751 """Check all entries of given images for unsafe unique names"""
5752 for image in images:
5754 image._CollectEntries(entries, {}, image)
5755 for entry in entries.values():
5756 uniq = entry.GetUniqueName()
5758 # Used as part of a filename, so must not be absolute paths.
5759 self.assertFalse(os.path.isabs(uniq))
5761 def testSafeUniqueNames(self):
5762 """Test entry unique names are safe in single image configuration"""
5763 data = self._DoReadFileRealDtb('237_unique_names.dts')
5765 orig_image = control.images['image']
5766 image_fname = tools.get_output_filename('image.bin')
5767 image = Image.FromFile(image_fname)
5769 self._CheckSafeUniqueNames(orig_image, image)
5771 def testSafeUniqueNamesMulti(self):
5772 """Test entry unique names are safe with multiple images"""
5773 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
5775 orig_image = control.images['image']
5776 image_fname = tools.get_output_filename('image.bin')
5777 image = Image.FromFile(image_fname)
5779 self._CheckSafeUniqueNames(orig_image, image)
5781 def testReplaceCmdWithBintool(self):
5782 """Test replacing an entry that needs a bintool to pack"""
5783 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
5784 expected = U_BOOT_DATA + b'aa'
5785 self.assertEqual(expected, data[:len(expected)])
5788 tmpdir, updated_fname = self._SetupImageInTmpdir()
5789 fname = os.path.join(tmpdir, 'update-testing.bin')
5790 tools.write_file(fname, b'zz')
5791 self._DoBinman('replace', '-i', updated_fname,
5792 '_testing', '-f', fname)
5794 data = tools.read_file(updated_fname)
5795 expected = U_BOOT_DATA + b'zz'
5796 self.assertEqual(expected, data[:len(expected)])
5798 shutil.rmtree(tmpdir)
5800 def testReplaceCmdOtherWithBintool(self):
5801 """Test replacing an entry when another needs a bintool to pack"""
5802 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
5803 expected = U_BOOT_DATA + b'aa'
5804 self.assertEqual(expected, data[:len(expected)])
5807 tmpdir, updated_fname = self._SetupImageInTmpdir()
5808 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5809 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5810 self._DoBinman('replace', '-i', updated_fname,
5811 'u-boot', '-f', fname)
5813 data = tools.read_file(updated_fname)
5814 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5815 self.assertEqual(expected, data[:len(expected)])
5817 shutil.rmtree(tmpdir)
5819 def testReplaceResizeNoRepackSameSize(self):
5820 """Test replacing entries with same-size data without repacking"""
5821 expected = b'x' * len(U_BOOT_DATA)
5822 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5823 self.assertEqual(expected, data)
5825 path, fdtmap = state.GetFdtContents('fdtmap')
5826 self.assertIsNotNone(path)
5827 self.assertEqual(expected_fdtmap, fdtmap)
5829 def testReplaceResizeNoRepackSmallerSize(self):
5830 """Test replacing entries with smaller-size data without repacking"""
5832 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5833 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5834 self.assertEqual(expected, data)
5836 path, fdtmap = state.GetFdtContents('fdtmap')
5837 self.assertIsNotNone(path)
5838 self.assertEqual(expected_fdtmap, fdtmap)
5840 def testExtractFit(self):
5841 """Test extracting a FIT section"""
5842 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
5843 image_fname = tools.get_output_filename('image.bin')
5845 fit_data = control.ReadEntry(image_fname, 'fit')
5846 fit = fdt.Fdt.FromData(fit_data)
5849 # Check subentry data inside the extracted fit
5850 for node_path, expected in [
5851 ('/images/kernel', U_BOOT_DATA),
5852 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5853 ('/images/scr-1', COMPRESS_DATA),
5855 node = fit.GetNode(node_path)
5856 data = fit.GetProps(node)['data'].bytes
5857 self.assertEqual(expected, data)
5859 def testExtractFitSubentries(self):
5860 """Test extracting FIT section subentries"""
5861 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
5862 image_fname = tools.get_output_filename('image.bin')
5864 for entry_path, expected in [
5865 ('fit/kernel', U_BOOT_DATA),
5866 ('fit/kernel/u-boot', U_BOOT_DATA),
5867 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5868 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5869 ('fit/scr-1', COMPRESS_DATA),
5870 ('fit/scr-1/blob', COMPRESS_DATA),
5872 data = control.ReadEntry(image_fname, entry_path)
5873 self.assertEqual(expected, data)
5875 def testReplaceFitSubentryLeafSameSize(self):
5876 """Test replacing a FIT leaf subentry with same-size data"""
5877 new_data = b'x' * len(U_BOOT_DATA)
5878 data, expected_fdtmap, _ = self._RunReplaceCmd(
5879 'fit/kernel/u-boot', new_data,
5880 dts='240_fit_extract_replace.dts')
5881 self.assertEqual(new_data, data)
5883 path, fdtmap = state.GetFdtContents('fdtmap')
5884 self.assertIsNotNone(path)
5885 self.assertEqual(expected_fdtmap, fdtmap)
5887 def testReplaceFitSubentryLeafBiggerSize(self):
5888 """Test replacing a FIT leaf subentry with bigger-size data"""
5889 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5890 data, expected_fdtmap, _ = self._RunReplaceCmd(
5891 'fit/fdt-1/u-boot-nodtb', new_data,
5892 dts='240_fit_extract_replace.dts')
5893 self.assertEqual(new_data, data)
5895 # Will be repacked, so fdtmap must change
5896 path, fdtmap = state.GetFdtContents('fdtmap')
5897 self.assertIsNotNone(path)
5898 self.assertNotEqual(expected_fdtmap, fdtmap)
5900 def testReplaceFitSubentryLeafSmallerSize(self):
5901 """Test replacing a FIT leaf subentry with smaller-size data"""
5903 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5904 data, expected_fdtmap, _ = self._RunReplaceCmd(
5905 'fit/fdt-1/u-boot-nodtb', new_data,
5906 dts='240_fit_extract_replace.dts')
5907 self.assertEqual(expected, data)
5909 path, fdtmap = state.GetFdtContents('fdtmap')
5910 self.assertIsNotNone(path)
5911 self.assertEqual(expected_fdtmap, fdtmap)
5913 def testReplaceSectionSimple(self):
5914 """Test replacing a simple section with same-sized data"""
5915 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
5916 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5917 new_data, dts='241_replace_section_simple.dts')
5918 self.assertEqual(new_data, data)
5920 entries = image.GetEntries()
5921 self.assertIn('section', entries)
5922 entry = entries['section']
5923 self.assertEqual(len(new_data), entry.size)
5925 def testReplaceSectionLarger(self):
5926 """Test replacing a simple section with larger data"""
5927 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5928 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5929 new_data, dts='241_replace_section_simple.dts')
5930 self.assertEqual(new_data, data)
5932 entries = image.GetEntries()
5933 self.assertIn('section', entries)
5934 entry = entries['section']
5935 self.assertEqual(len(new_data), entry.size)
5936 fentry = entries['fdtmap']
5937 self.assertEqual(entry.offset + entry.size, fentry.offset)
5939 def testReplaceSectionSmaller(self):
5940 """Test replacing a simple section with smaller data"""
5941 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5942 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5943 new_data, dts='241_replace_section_simple.dts')
5944 self.assertEqual(new_data, data)
5946 # The new size is the same as the old, just with a pad byte at the end
5947 entries = image.GetEntries()
5948 self.assertIn('section', entries)
5949 entry = entries['section']
5950 self.assertEqual(len(new_data), entry.size)
5952 def testReplaceSectionSmallerAllow(self):
5953 """Test failing to replace a simple section with smaller data"""
5954 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5956 state.SetAllowEntryContraction(True)
5957 with self.assertRaises(ValueError) as exc:
5958 self._RunReplaceCmd('section', new_data,
5959 dts='241_replace_section_simple.dts')
5961 state.SetAllowEntryContraction(False)
5963 # Since we have no information about the position of things within the
5964 # section, we cannot adjust the position of /section-u-boot so it ends
5965 # up outside the section
5967 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5968 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
5971 def testMkimageImagename(self):
5972 """Test using mkimage with -n holding the data too"""
5974 data = self._DoReadFile('242_mkimage_name.dts')
5976 # Check that the data appears in the file somewhere
5977 self.assertIn(U_BOOT_SPL_DATA, data)
5979 # Get struct legacy_img_hdr -> ih_name
5980 name = data[0x20:0x40]
5982 # Build the filename that we expect to be placed in there, by virtue of
5984 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5986 # Check that the image name is set to the temporary filename used
5987 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5989 def testMkimageImage(self):
5990 """Test using mkimage with -n holding the data too"""
5992 data = self._DoReadFile('243_mkimage_image.dts')
5994 # Check that the data appears in the file somewhere
5995 self.assertIn(U_BOOT_SPL_DATA, data)
5997 # Get struct legacy_img_hdr -> ih_name
5998 name = data[0x20:0x40]
6000 # Build the filename that we expect to be placed in there, by virtue of
6002 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6004 # Check that the image name is set to the temporary filename used
6005 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6007 # Check the corect data is in the imagename file
6008 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6010 def testMkimageImageNoContent(self):
6011 """Test using mkimage with -n and no data"""
6013 with self.assertRaises(ValueError) as exc:
6014 self._DoReadFile('244_mkimage_image_no_content.dts')
6015 self.assertIn('Could not complete processing of contents',
6018 def testMkimageImageBad(self):
6019 """Test using mkimage with imagename node and data-to-imagename"""
6021 with self.assertRaises(ValueError) as exc:
6022 self._DoReadFile('245_mkimage_image_bad.dts')
6023 self.assertIn('Cannot use both imagename node and data-to-imagename',
6026 def testCollectionOther(self):
6027 """Test a collection where the data comes from another section"""
6028 data = self._DoReadFile('246_collection_other.dts')
6029 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6030 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6031 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6034 def testMkimageCollection(self):
6035 """Test using a collection referring to an entry in a mkimage entry"""
6037 data = self._DoReadFile('247_mkimage_coll.dts')
6038 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6039 self.assertEqual(expect, data[:len(expect)])
6041 def testCompressDtbPrependInvalid(self):
6042 """Test that invalid header is detected"""
6043 with self.assertRaises(ValueError) as e:
6044 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
6045 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6046 "'u-boot-dtb': 'invalid'", str(e.exception))
6048 def testCompressDtbPrependLength(self):
6049 """Test that compress with length header works as expected"""
6050 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
6051 image = control.images['image']
6052 entries = image.GetEntries()
6053 self.assertIn('u-boot-dtb', entries)
6054 u_boot_dtb = entries['u-boot-dtb']
6055 self.assertIn('fdtmap', entries)
6056 fdtmap = entries['fdtmap']
6058 image_fname = tools.get_output_filename('image.bin')
6059 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6060 dtb = fdt.Fdt.FromData(orig)
6062 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6064 'u-boot:size': len(U_BOOT_DATA),
6065 'u-boot-dtb:uncomp-size': len(orig),
6066 'u-boot-dtb:size': u_boot_dtb.size,
6067 'fdtmap:size': fdtmap.size,
6070 self.assertEqual(expected, props)
6072 # Check implementation
6073 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6074 rest = data[len(U_BOOT_DATA):]
6075 comp_data_len = struct.unpack('<I', rest[:4])[0]
6076 comp_data = rest[4:4 + comp_data_len]
6077 orig2 = self._decompress(comp_data)
6078 self.assertEqual(orig, orig2)
6080 def testInvalidCompress(self):
6081 """Test that invalid compress algorithm is detected"""
6082 with self.assertRaises(ValueError) as e:
6083 self._DoTestFile('250_compress_dtb_invalid.dts')
6084 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6086 def testCompUtilCompressions(self):
6087 """Test compression algorithms"""
6088 for bintool in self.comp_bintools.values():
6089 self._CheckBintool(bintool)
6090 data = bintool.compress(COMPRESS_DATA)
6091 self.assertNotEqual(COMPRESS_DATA, data)
6092 orig = bintool.decompress(data)
6093 self.assertEquals(COMPRESS_DATA, orig)
6095 def testCompUtilVersions(self):
6096 """Test tool version of compression algorithms"""
6097 for bintool in self.comp_bintools.values():
6098 self._CheckBintool(bintool)
6099 version = bintool.version()
6100 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6102 def testCompUtilPadding(self):
6103 """Test padding of compression algorithms"""
6104 # Skip zstd because it doesn't support padding
6105 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
6106 self._CheckBintool(bintool)
6107 data = bintool.compress(COMPRESS_DATA)
6108 self.assertNotEqual(COMPRESS_DATA, data)
6109 data += tools.get_bytes(0, 64)
6110 orig = bintool.decompress(data)
6111 self.assertEquals(COMPRESS_DATA, orig)
6113 def testCompressDtbZstd(self):
6114 """Test that zstd compress of device-tree files failed"""
6115 with self.assertRaises(ValueError) as e:
6116 self._DoTestFile('251_compress_dtb_zstd.dts')
6117 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6118 "requires a length header", str(e.exception))
6120 def testMkimageMultipleDataFiles(self):
6121 """Test passing multiple files to mkimage in a mkimage entry"""
6124 data = self._DoReadFile('252_mkimage_mult_data.dts')
6125 # Size of files are packed in their 4B big-endian format
6126 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6127 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6128 # Size info is always followed by a 4B zero value.
6129 expect += tools.get_bytes(0, 4)
6130 expect += U_BOOT_TPL_DATA
6131 # All but last files are 4B-aligned
6132 align_pad = len(U_BOOT_TPL_DATA) % 4
6134 expect += tools.get_bytes(0, align_pad)
6135 expect += U_BOOT_SPL_DATA
6136 self.assertEqual(expect, data[-len(expect):])
6138 def testMkimageMultipleExpanded(self):
6139 """Test passing multiple files to mkimage in a mkimage entry"""
6146 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6147 use_expanded=True, entry_args=entry_args)[0]
6149 tpl_expect = U_BOOT_TPL_DATA
6150 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6151 spl_expect += U_BOOT_SPL_DTB_DATA
6153 content = data[0x40:]
6154 lens = struct.unpack('>III', content[:12])
6156 # Size of files are packed in their 4B big-endian format
6157 # Size info is always followed by a 4B zero value.
6158 self.assertEqual(len(tpl_expect), lens[0])
6159 self.assertEqual(len(spl_expect), lens[1])
6160 self.assertEqual(0, lens[2])
6163 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6165 rest = rest[len(tpl_expect):]
6166 align_pad = len(tpl_expect) % 4
6167 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6168 rest = rest[align_pad:]
6169 self.assertEqual(spl_expect, rest)
6171 def testMkimageMultipleNoContent(self):
6172 """Test passing multiple data files to mkimage with one data file having no content"""
6174 with self.assertRaises(ValueError) as exc:
6175 self._DoReadFile('253_mkimage_mult_no_content.dts')
6176 self.assertIn('Could not complete processing of contents',
6179 def testMkimageFilename(self):
6180 """Test using mkimage to build a binary with a filename"""
6182 retcode = self._DoTestFile('254_mkimage_filename.dts')
6183 self.assertEqual(0, retcode)
6184 fname = tools.get_output_filename('mkimage-test.bin')
6185 self.assertTrue(os.path.exists(fname))
6188 """Test that an image with VPL and its device tree can be created"""
6189 # ELF file with a '__bss_size' symbol
6191 data = self._DoReadFile('255_u_boot_vpl.dts')
6192 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6194 def testVplNoDtb(self):
6195 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6197 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6198 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6199 data[:len(U_BOOT_VPL_NODTB_DATA)])
6201 def testExpandedVpl(self):
6202 """Test that an expanded entry type is selected for TPL when needed"""
6209 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6210 entry_args=entry_args)
6211 image = control.images['image']
6212 entries = image.GetEntries()
6213 self.assertEqual(1, len(entries))
6215 # We only have u-boot-vpl, which be expanded
6216 self.assertIn('u-boot-vpl', entries)
6217 entry = entries['u-boot-vpl']
6218 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6219 subent = entry.GetEntries()
6220 self.assertEqual(3, len(subent))
6221 self.assertIn('u-boot-vpl-nodtb', subent)
6222 self.assertIn('u-boot-vpl-bss-pad', subent)
6223 self.assertIn('u-boot-vpl-dtb', subent)
6225 def testVplBssPadMissing(self):
6226 """Test that a missing symbol is detected"""
6227 self._SetupVplElf('u_boot_ucode_ptr')
6228 with self.assertRaises(ValueError) as e:
6229 self._DoReadFile('258_vpl_bss_pad.dts')
6230 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6233 def testSymlink(self):
6234 """Test that image files can be symlinked"""
6235 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6236 self.assertEqual(0, retcode)
6237 image = control.images['test_image']
6238 fname = tools.get_output_filename('test_image.bin')
6239 sname = tools.get_output_filename('symlink_to_test.bin')
6240 self.assertTrue(os.path.islink(sname))
6241 self.assertEqual(os.readlink(sname), fname)
6243 def testSymlinkOverwrite(self):
6244 """Test that symlinked images can be overwritten"""
6245 testdir = TestFunctional._MakeInputDir('symlinktest')
6246 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6247 # build the same image again in the same directory so that existing symlink is present
6248 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6249 fname = tools.get_output_filename('test_image.bin')
6250 sname = tools.get_output_filename('symlink_to_test.bin')
6251 self.assertTrue(os.path.islink(sname))
6252 self.assertEqual(os.readlink(sname), fname)
6254 def testSymbolsElf(self):
6255 """Test binman can assign symbols embedded in an ELF file"""
6256 if not elf.ELF_TOOLS:
6257 self.skipTest('Python elftools not available')
6258 self._SetupTplElf('u_boot_binman_syms')
6259 self._SetupVplElf('u_boot_binman_syms')
6260 self._SetupSplElf('u_boot_binman_syms')
6261 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6262 image_fname = tools.get_output_filename('image.bin')
6264 image = control.images['image']
6265 entries = image.GetEntries()
6267 for entry in entries.values():
6268 # No symbols in u-boot and it has faked contents anyway
6269 if entry.name == 'u-boot':
6271 edata = data[entry.image_pos:entry.image_pos + entry.size]
6272 efname = tools.get_output_filename(f'edata-{entry.name}')
6273 tools.write_file(efname, edata)
6275 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6276 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6277 for name, sym in syms.items():
6279 val = elf.GetSymbolValue(sym, edata, msg)
6280 entry_m = re_name.match(name)
6282 ename, prop = entry_m.group(1), entry_m.group(3)
6283 entry, entry_name, prop_name = image.LookupEntry(entries,
6285 if prop_name == 'offset':
6286 expect_val = entry.offset
6287 elif prop_name == 'image_pos':
6288 expect_val = entry.image_pos
6289 elif prop_name == 'size':
6290 expect_val = entry.size
6291 self.assertEqual(expect_val, val)
6293 def testSymbolsElfBad(self):
6294 """Check error when trying to write symbols without the elftools lib"""
6295 if not elf.ELF_TOOLS:
6296 self.skipTest('Python elftools not available')
6297 self._SetupTplElf('u_boot_binman_syms')
6298 self._SetupVplElf('u_boot_binman_syms')
6299 self._SetupSplElf('u_boot_binman_syms')
6301 elf.ELF_TOOLS = False
6302 with self.assertRaises(ValueError) as exc:
6303 self._DoReadFileDtb('260_symbols_elf.dts')
6305 elf.ELF_TOOLS = True
6307 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6308 'Cannot write symbols to an ELF file without Python elftools',
6311 def testSectionFilename(self):
6312 """Check writing of section contents to a file"""
6313 data = self._DoReadFile('261_section_fname.dts')
6314 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6315 tools.get_bytes(ord('!'), 7) +
6316 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6317 self.assertEqual(expected, data)
6319 sect_fname = tools.get_output_filename('outfile.bin')
6320 self.assertTrue(os.path.exists(sect_fname))
6321 sect_data = tools.read_file(sect_fname)
6322 self.assertEqual(U_BOOT_DATA, sect_data)
6324 def testAbsent(self):
6325 """Check handling of absent entries"""
6326 data = self._DoReadFile('262_absent.dts')
6327 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6329 def testPackTeeOsOptional(self):
6330 """Test that an image with an optional TEE binary can be created"""
6332 'tee-os-path': 'tee.elf',
6334 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6335 entry_args=entry_args)[0]
6336 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6338 def checkFitTee(self, dts, tee_fname):
6339 """Check that a tee-os entry works and returns data
6342 dts (str): Device tree filename to use
6343 tee_fname (str): filename containing tee-os
6346 bytes: Image contents
6348 if not elf.ELF_TOOLS:
6349 self.skipTest('Python elftools not available')
6351 'of-list': 'test-fdt1 test-fdt2',
6352 'default-dt': 'test-fdt2',
6353 'tee-os-path': tee_fname,
6355 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6356 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6357 extra_indirs=[test_subdir])[0]
6360 def testFitTeeOsOptionalFit(self):
6361 """Test an image with a FIT with an optional OP-TEE binary"""
6362 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6364 # There should be only one node, holding the data set up in SetUpClass()
6366 dtb = fdt.Fdt.FromData(data)
6368 node = dtb.GetNode('/images/tee-1')
6369 self.assertEqual(TEE_ADDR,
6370 fdt_util.fdt32_to_cpu(node.props['load'].value))
6371 self.assertEqual(TEE_ADDR,
6372 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6373 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6375 with test_util.capture_sys_output() as (stdout, stderr):
6376 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6377 err = stderr.getvalue()
6380 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6382 def testFitTeeOsOptionalFitBad(self):
6383 """Test an image with a FIT with an optional OP-TEE binary"""
6384 with self.assertRaises(ValueError) as exc:
6385 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6387 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6390 def testFitTeeOsBad(self):
6391 """Test an OP-TEE binary with wrong formats"""
6392 self.make_tee_bin('tee.bad1', 123)
6393 with self.assertRaises(ValueError) as exc:
6394 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6396 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6399 self.make_tee_bin('tee.bad2', 0, b'extra data')
6400 with self.assertRaises(ValueError) as exc:
6401 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6403 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6406 def testExtblobOptional(self):
6407 """Test an image with an external blob that is optional"""
6408 with test_util.capture_sys_output() as (stdout, stderr):
6409 data = self._DoReadFile('266_blob_ext_opt.dts')
6410 self.assertEqual(REFCODE_DATA, data)
6411 err = stderr.getvalue()
6414 "Image '.*' is missing optional external blobs but is still functional: missing")
6416 def testSectionInner(self):
6417 """Test an inner section with a size"""
6418 data = self._DoReadFile('267_section_inner.dts')
6419 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6420 self.assertEqual(expected, data)
6423 """Test an image with a null entry"""
6424 data = self._DoReadFile('268_null.dts')
6425 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6427 def testOverlap(self):
6428 """Test an image with a overlapping entry"""
6429 data = self._DoReadFile('269_overlap.dts')
6430 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6432 image = control.images['image']
6433 entries = image.GetEntries()
6435 self.assertIn('inset', entries)
6436 inset = entries['inset']
6437 self.assertEqual(1, inset.offset);
6438 self.assertEqual(1, inset.image_pos);
6439 self.assertEqual(2, inset.size);
6441 def testOverlapNull(self):
6442 """Test an image with a null overlap"""
6443 data = self._DoReadFile('270_overlap_null.dts')
6444 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6447 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6448 self.assertEqual(4, fhdr.nareas)
6449 fiter = iter(fentries)
6451 fentry = next(fiter)
6452 self.assertEqual(b'SECTION', fentry.name)
6453 self.assertEqual(0, fentry.offset)
6454 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6455 self.assertEqual(0, fentry.flags)
6457 fentry = next(fiter)
6458 self.assertEqual(b'U_BOOT', fentry.name)
6459 self.assertEqual(0, fentry.offset)
6460 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6461 self.assertEqual(0, fentry.flags)
6463 # Make sure that the NULL entry appears in the FMAP
6464 fentry = next(fiter)
6465 self.assertEqual(b'NULL', fentry.name)
6466 self.assertEqual(1, fentry.offset)
6467 self.assertEqual(2, fentry.size)
6468 self.assertEqual(0, fentry.flags)
6470 fentry = next(fiter)
6471 self.assertEqual(b'FMAP', fentry.name)
6472 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6474 def testOverlapBad(self):
6475 """Test an image with a bad overlapping entry"""
6476 with self.assertRaises(ValueError) as exc:
6477 self._DoReadFile('271_overlap_bad.dts')
6479 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6482 def testOverlapNoOffset(self):
6483 """Test an image with a bad overlapping entry"""
6484 with self.assertRaises(ValueError) as exc:
6485 self._DoReadFile('272_overlap_no_size.dts')
6487 "Node '/binman/inset': 'fill' entry is missing properties: size",
6490 def testBlobSymbol(self):
6491 """Test a blob with symbols read from an ELF file"""
6492 elf_fname = self.ElfTestFile('blob_syms')
6493 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6494 TestFunctional._MakeInputFile('blob_syms.bin',
6495 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6497 data = self._DoReadFile('273_blob_symbol.dts')
6499 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6500 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6501 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6502 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6503 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6505 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6506 expected = sym_values
6507 self.assertEqual(expected, data[:len(expected)])
6509 def testOffsetFromElf(self):
6510 """Test a blob with symbols read from an ELF file"""
6511 elf_fname = self.ElfTestFile('blob_syms')
6512 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6513 TestFunctional._MakeInputFile('blob_syms.bin',
6514 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6516 data = self._DoReadFile('274_offset_from_elf.dts')
6518 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6519 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6521 image = control.images['image']
6522 entries = image.GetEntries()
6524 self.assertIn('inset', entries)
6525 inset = entries['inset']
6527 self.assertEqual(base + 4, inset.offset);
6528 self.assertEqual(base + 4, inset.image_pos);
6529 self.assertEqual(4, inset.size);
6531 self.assertIn('inset2', entries)
6532 inset = entries['inset2']
6533 self.assertEqual(base + 8, inset.offset);
6534 self.assertEqual(base + 8, inset.image_pos);
6535 self.assertEqual(4, inset.size);
6537 def testFitAlign(self):
6538 """Test an image with an FIT with aligned external data"""
6539 data = self._DoReadFile('275_fit_align.dts')
6540 self.assertEqual(4096, len(data))
6542 dtb = fdt.Fdt.FromData(data)
6545 props = self._GetPropTree(dtb, ['data-position'])
6547 'u-boot:data-position': 1024,
6548 'fdt-1:data-position': 2048,
6549 'fdt-2:data-position': 3072,
6551 self.assertEqual(expected, props)
6553 def testFitFirmwareLoadables(self):
6554 """Test an image with an FIT that use fit,firmware"""
6555 if not elf.ELF_TOOLS:
6556 self.skipTest('Python elftools not available')
6558 'of-list': 'test-fdt1',
6559 'default-dt': 'test-fdt1',
6560 'atf-bl31-path': 'bl31.elf',
6561 'tee-os-path': 'missing.bin',
6563 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6564 with test_util.capture_sys_output() as (stdout, stderr):
6565 data = self._DoReadFileDtb(
6566 '276_fit_firmware_loadables.dts',
6567 entry_args=entry_args,
6568 extra_indirs=[test_subdir])[0]
6570 dtb = fdt.Fdt.FromData(data)
6573 node = dtb.GetNode('/configurations/conf-uboot-1')
6574 self.assertEqual('u-boot', node.props['firmware'].value)
6575 self.assertEqual(['atf-1', 'atf-2'],
6576 fdt_util.GetStringList(node, 'loadables'))
6578 node = dtb.GetNode('/configurations/conf-atf-1')
6579 self.assertEqual('atf-1', node.props['firmware'].value)
6580 self.assertEqual(['u-boot', 'atf-2'],
6581 fdt_util.GetStringList(node, 'loadables'))
6583 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6584 self.assertEqual('u-boot', node.props['firmware'].value)
6585 self.assertEqual(['atf-1', 'atf-2'],
6586 fdt_util.GetStringList(node, 'loadables'))
6588 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6589 self.assertEqual('atf-1', node.props['firmware'].value)
6590 self.assertEqual(['u-boot', 'atf-2'],
6591 fdt_util.GetStringList(node, 'loadables'))
6593 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6594 self.assertEqual('atf-1', node.props['firmware'].value)
6595 self.assertEqual(['u-boot', 'atf-2'],
6596 fdt_util.GetStringList(node, 'loadables'))
6598 def testTooldir(self):
6599 """Test that we can specify the tooldir"""
6600 with test_util.capture_sys_output() as (stdout, stderr):
6601 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6603 self.assertEqual('fred', bintool.Bintool.tooldir)
6605 # Check that the toolpath is updated correctly
6606 self.assertEqual(['fred'], tools.tool_search_paths)
6608 # Try with a few toolpaths; the tooldir should be at the end
6609 with test_util.capture_sys_output() as (stdout, stderr):
6610 self.assertEqual(0, self._DoBinman(
6611 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6613 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6615 def testReplaceSectionEntry(self):
6616 """Test replacing an entry in a section"""
6617 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6618 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6619 expect_data, dts='241_replace_section_simple.dts')
6620 self.assertEqual(expect_data, entry_data)
6622 entries = image.GetEntries()
6623 self.assertIn('section', entries)
6624 section = entries['section']
6626 sect_entries = section.GetEntries()
6627 self.assertIn('blob', sect_entries)
6628 entry = sect_entries['blob']
6629 self.assertEqual(len(expect_data), entry.size)
6631 fname = tools.get_output_filename('image-updated.bin')
6632 data = tools.read_file(fname)
6634 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6635 self.assertEqual(expect_data, new_blob_data)
6637 self.assertEqual(U_BOOT_DATA,
6638 data[entry.image_pos + len(expect_data):]
6639 [:len(U_BOOT_DATA)])
6641 def testReplaceSectionDeep(self):
6642 """Test replacing an entry in two levels of sections"""
6643 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6644 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6645 'section/section/blob', expect_data,
6646 dts='278_replace_section_deep.dts')
6647 self.assertEqual(expect_data, entry_data)
6649 entries = image.GetEntries()
6650 self.assertIn('section', entries)
6651 section = entries['section']
6653 subentries = section.GetEntries()
6654 self.assertIn('section', subentries)
6655 section = subentries['section']
6657 sect_entries = section.GetEntries()
6658 self.assertIn('blob', sect_entries)
6659 entry = sect_entries['blob']
6660 self.assertEqual(len(expect_data), entry.size)
6662 fname = tools.get_output_filename('image-updated.bin')
6663 data = tools.read_file(fname)
6665 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6666 self.assertEqual(expect_data, new_blob_data)
6668 self.assertEqual(U_BOOT_DATA,
6669 data[entry.image_pos + len(expect_data):]
6670 [:len(U_BOOT_DATA)])
6672 def testReplaceFitSibling(self):
6673 """Test an image with a FIT inside where we replace its sibling"""
6675 fname = TestFunctional._MakeInputFile('once', b'available once')
6676 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6680 tmpdir, updated_fname = self._SetupImageInTmpdir()
6682 fname = os.path.join(tmpdir, 'update-blob')
6683 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6684 tools.write_file(fname, expected)
6686 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6687 data = tools.read_file(updated_fname)
6688 start = len(U_BOOT_DTB_DATA)
6689 self.assertEqual(expected, data[start:start + len(expected)])
6690 map_fname = os.path.join(tmpdir, 'image-updated.map')
6691 self.assertFalse(os.path.exists(map_fname))
6693 shutil.rmtree(tmpdir)
6695 def testX509Cert(self):
6696 """Test creating an X509 certificate"""
6697 keyfile = self.TestFile('key.key')
6701 data = self._DoReadFileDtb('279_x509_cert.dts',
6702 entry_args=entry_args)[0]
6704 self.assertEqual(U_BOOT_DATA, data[-4:])
6706 # TODO: verify the signature
6708 def testX509CertMissing(self):
6709 """Test that binman still produces an image if openssl is missing"""
6710 keyfile = self.TestFile('key.key')
6712 'keyfile': 'keyfile',
6714 with test_util.capture_sys_output() as (_, stderr):
6715 self._DoTestFile('279_x509_cert.dts',
6716 force_missing_bintools='openssl',
6717 entry_args=entry_args)
6718 err = stderr.getvalue()
6719 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6721 def testPackRockchipTpl(self):
6722 """Test that an image with a Rockchip TPL binary can be created"""
6723 data = self._DoReadFile('291_rockchip_tpl.dts')
6724 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6726 def testMkimageMissingBlobMultiple(self):
6727 """Test missing blob with mkimage entry and multiple-data-files"""
6728 with test_util.capture_sys_output() as (stdout, stderr):
6729 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
6730 err = stderr.getvalue()
6731 self.assertIn("is missing external blobs and is non-functional", err)
6733 with self.assertRaises(ValueError) as e:
6734 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
6735 self.assertIn("not found in input path", str(e.exception))
6737 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6738 """Prepare sign environment
6740 Create private and public keys, add pubkey into dtb.
6750 data = self._DoReadFileRealDtb(dts)
6751 updated_fname = tools.get_output_filename('image-updated.bin')
6752 tools.write_file(updated_fname, data)
6753 dtb = tools.get_output_filename('source.dtb')
6754 private_key = tools.get_output_filename('test_key.key')
6755 public_key = tools.get_output_filename('test_key.crt')
6756 fit = tools.get_output_filename('fit.fit')
6757 key_dir = tools.get_output_dir()
6759 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6760 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6761 private_key, '-out', public_key)
6762 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6763 '-n', 'test_key', '-r', 'conf', dtb)
6765 return fit, updated_fname, private_key, dtb
6767 def testSignSimple(self):
6768 """Test that a FIT container can be signed in image"""
6770 fit, fname, private_key, dtb = self._PrepareSignEnv()
6772 # do sign with private key
6773 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6775 is_signed = self._CheckSign(fit, dtb)
6777 self.assertEqual(is_signed, True)
6779 def testSignExactFIT(self):
6780 """Test that a FIT container can be signed and replaced in image"""
6782 fit, fname, private_key, dtb = self._PrepareSignEnv()
6784 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6787 for path in self.toolpath:
6788 args += ['--toolpath', path]
6790 # do sign with private key
6791 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6792 'sha256,rsa4096', '-f', fit, 'fit')
6793 is_signed = self._CheckSign(fit, dtb)
6795 self.assertEqual(is_signed, True)
6797 def testSignNonFit(self):
6798 """Test a non-FIT entry cannot be signed"""
6800 fit, fname, private_key, _ = self._PrepareSignEnv(
6801 '281_sign_non_fit.dts')
6803 # do sign with private key
6804 with self.assertRaises(ValueError) as e:
6805 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6806 'sha256,rsa4096', '-f', fit, 'u-boot')
6808 "Node '/u-boot': Updating signatures is not supported with this entry type",
6811 def testSignMissingMkimage(self):
6812 """Test that FIT signing handles a missing mkimage tool"""
6813 fit, fname, private_key, _ = self._PrepareSignEnv()
6815 # try to sign with a missing mkimage tool
6816 bintool.Bintool.set_missing_list(['mkimage'])
6817 with self.assertRaises(ValueError) as e:
6818 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6820 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6822 def testSymbolNoWrite(self):
6823 """Test disabling of symbol writing"""
6825 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6826 no_write_symbols=True)
6828 def testSymbolNoWriteExpanded(self):
6829 """Test disabling of symbol writing in expanded entries"""
6833 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6834 U_BOOT_SPL_DTB_DATA, 0x38,
6835 entry_args=entry_args, use_expanded=True,
6836 no_write_symbols=True)
6838 def testMkimageSpecial(self):
6839 """Test mkimage ignores special hash-1 node"""
6840 data = self._DoReadFile('283_mkimage_special.dts')
6842 # Just check that the data appears in the file somewhere
6843 self.assertIn(U_BOOT_DATA, data)
6845 def testFitFdtList(self):
6846 """Test an image with an FIT with the fit,fdt-list-val option"""
6848 'default-dt': 'test-fdt2',
6850 data = self._DoReadFileDtb(
6851 '284_fit_fdt_list.dts',
6852 entry_args=entry_args,
6853 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6854 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6855 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6857 def testSplEmptyBss(self):
6858 """Test an expanded SPL with a zero-size BSS"""
6859 # ELF file with a '__bss_size' symbol
6860 self._SetupSplElf(src_fname='bss_data_zero')
6866 data = self._DoReadFileDtb('285_spl_expand.dts',
6867 use_expanded=True, entry_args=entry_args)[0]
6869 def testTemplate(self):
6870 """Test using a template"""
6871 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6872 data = self._DoReadFile('286_template.dts')
6873 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6874 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6875 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6877 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6878 self.assertTrue(os.path.exists(dtb_fname1))
6879 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6881 node1 = dtb.GetNode('/binman/template')
6882 self.assertTrue(node1)
6883 vga = dtb.GetNode('/binman/first/intel-vga')
6884 self.assertTrue(vga)
6886 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6887 self.assertTrue(os.path.exists(dtb_fname2))
6888 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6890 node2 = dtb2.GetNode('/binman/template')
6891 self.assertFalse(node2)
6893 def testTemplateBlobMulti(self):
6894 """Test using a template with 'multiple-images' enabled"""
6895 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6896 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6897 retcode = self._DoTestFile('287_template_multi.dts')
6899 self.assertEqual(0, retcode)
6900 image = control.images['image']
6901 image_fname = tools.get_output_filename('my-image.bin')
6902 data = tools.read_file(image_fname)
6903 self.assertEqual(b'blob@@@@other', data)
6905 def testTemplateFit(self):
6906 """Test using a template in a FIT"""
6907 fit_data = self._DoReadFile('288_template_fit.dts')
6908 fname = os.path.join(self._indir, 'fit_data.fit')
6909 tools.write_file(fname, fit_data)
6910 out = tools.run('dumpimage', '-l', fname)
6912 def testTemplateSection(self):
6913 """Test using a template in a section (not at top level)"""
6914 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6915 data = self._DoReadFile('289_template_section.dts')
6916 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6917 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6918 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6920 def testMkimageSymbols(self):
6921 """Test using mkimage to build an image with symbols in it"""
6922 self._SetupSplElf('u_boot_binman_syms')
6923 data = self._DoReadFile('290_mkimage_sym.dts')
6925 image = control.images['image']
6926 entries = image.GetEntries()
6927 self.assertIn('u-boot', entries)
6928 u_boot = entries['u-boot']
6930 mkim = entries['mkimage']
6931 mkim_entries = mkim.GetEntries()
6932 self.assertIn('u-boot-spl', mkim_entries)
6933 spl = mkim_entries['u-boot-spl']
6934 self.assertIn('u-boot-spl2', mkim_entries)
6935 spl2 = mkim_entries['u-boot-spl2']
6937 # skip the mkimage header and the area sizes
6938 mk_data = data[mkim.offset + 0x40:]
6939 size, term = struct.unpack('>LL', mk_data[:8])
6941 # There should be only one image, so check that the zero terminator is
6943 self.assertEqual(0, term)
6945 content = mk_data[8:8 + size]
6947 # The image should contain the symbols from u_boot_binman_syms.c
6948 # Note that image_pos is adjusted by the base address of the image,
6949 # which is 0x10 in our test image
6950 spl_data = content[:0x18]
6951 content = content[0x1b:]
6953 # After the header is a table of offsets for each image. There should
6954 # only be one image, then a 0 terminator, so figure out the real start
6958 # Check symbols in both u-boot-spl and u-boot-spl2
6960 vals = struct.unpack('<LLQLL', spl_data)
6962 # The image should contain the symbols from u_boot_binman_syms.c
6963 # Note that image_pos is adjusted by the base address of the image,
6964 # which is 0x10 in our 'u_boot_binman_syms' test image
6965 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6966 self.assertEqual(base, vals[1])
6967 self.assertEqual(spl2.offset, vals[2])
6968 # figure out the internal positions of its components
6969 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6971 # Check that spl and spl2 are actually at the indicated positions
6973 elf.BINMAN_SYM_MAGIC_VALUE,
6974 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6976 elf.BINMAN_SYM_MAGIC_VALUE,
6977 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6979 self.assertEqual(len(U_BOOT_DATA), vals[4])
6982 spl_data = content[:0x18]
6984 def testTemplatePhandle(self):
6985 """Test using a template in a node containing a phandle"""
6987 'atf-bl31-path': 'bl31.elf',
6989 data = self._DoReadFileDtb('309_template_phandle.dts',
6990 entry_args=entry_args)
6991 fname = tools.get_output_filename('image.bin')
6992 out = tools.run('dumpimage', '-l', fname)
6994 # We should see the FIT description and one for each of the two images
6995 lines = out.splitlines()
6996 descs = [line.split()[-1] for line in lines if 'escription' in line]
6997 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
6999 def testTemplatePhandleDup(self):
7000 """Test using a template in a node containing a phandle"""
7002 'atf-bl31-path': 'bl31.elf',
7004 with self.assertRaises(ValueError) as e:
7005 self._DoReadFileDtb('310_template_phandle_dup.dts',
7006 entry_args=entry_args)
7008 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7011 def testTIBoardConfig(self):
7012 """Test that a schema validated board config file can be generated"""
7013 data = self._DoReadFile('293_ti_board_cfg.dts')
7014 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7016 def testTIBoardConfigCombined(self):
7017 """Test that a schema validated combined board config file can be generated"""
7018 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
7019 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7020 self.assertGreater(data, configlen_noheader)
7022 def testTIBoardConfigNoDataType(self):
7023 """Test that error is thrown when data type is not supported"""
7024 with self.assertRaises(ValueError) as e:
7025 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
7026 self.assertIn("Schema validation error", str(e.exception))
7028 def testPackTiSecure(self):
7029 """Test that an image with a TI secured binary can be created"""
7030 keyfile = self.TestFile('key.key')
7034 data = self._DoReadFileDtb('296_ti_secure.dts',
7035 entry_args=entry_args)[0]
7036 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7038 def testPackTiSecureMissingTool(self):
7039 """Test that an image with a TI secured binary (non-functional) can be created
7040 when openssl is missing"""
7041 keyfile = self.TestFile('key.key')
7045 with test_util.capture_sys_output() as (_, stderr):
7046 self._DoTestFile('296_ti_secure.dts',
7047 force_missing_bintools='openssl',
7048 entry_args=entry_args)
7049 err = stderr.getvalue()
7050 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7052 def testPackTiSecureROM(self):
7053 """Test that a ROM image with a TI secured binary can be created"""
7054 keyfile = self.TestFile('key.key')
7058 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
7059 entry_args=entry_args)[0]
7060 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
7061 entry_args=entry_args)[0]
7062 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
7063 entry_args=entry_args)[0]
7064 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7065 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7066 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7068 def testPackTiSecureROMCombined(self):
7069 """Test that a ROM image with a TI secured binary can be created"""
7070 keyfile = self.TestFile('key.key')
7074 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
7075 entry_args=entry_args)[0]
7076 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7078 def testEncryptedNoAlgo(self):
7079 """Test encrypted node with missing required properties"""
7080 with self.assertRaises(ValueError) as e:
7081 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7083 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7086 def testEncryptedInvalidIvfile(self):
7087 """Test encrypted node with invalid iv file"""
7088 with self.assertRaises(ValueError) as e:
7089 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7090 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7093 def testEncryptedMissingKey(self):
7094 """Test encrypted node with missing key properties"""
7095 with self.assertRaises(ValueError) as e:
7096 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7098 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7101 def testEncryptedKeySource(self):
7102 """Test encrypted node with key-source property"""
7103 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7105 dtb = fdt.Fdt.FromData(data)
7108 node = dtb.GetNode('/images/u-boot/cipher')
7109 self.assertEqual('algo-name', node.props['algo'].value)
7110 self.assertEqual('key-source-value', node.props['key-source'].value)
7111 self.assertEqual(ENCRYPTED_IV_DATA,
7112 tools.to_bytes(''.join(node.props['iv'].value)))
7113 self.assertNotIn('key', node.props)
7115 def testEncryptedKeyFile(self):
7116 """Test encrypted node with key-filename property"""
7117 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7119 dtb = fdt.Fdt.FromData(data)
7122 node = dtb.GetNode('/images/u-boot/cipher')
7123 self.assertEqual('algo-name', node.props['algo'].value)
7124 self.assertEqual(ENCRYPTED_IV_DATA,
7125 tools.to_bytes(''.join(node.props['iv'].value)))
7126 self.assertEqual(ENCRYPTED_KEY_DATA,
7127 tools.to_bytes(''.join(node.props['key'].value)))
7128 self.assertNotIn('key-source', node.props)
7131 def testSplPubkeyDtb(self):
7132 """Test u_boot_spl_pubkey_dtb etype"""
7133 data = tools.read_file(self.TestFile("key.pem"))
7134 self._MakeInputFile("key.crt", data)
7135 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7136 image = control.images['image']
7137 entries = image.GetEntries()
7138 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7139 dtb_data = dtb_entry.GetData()
7140 dtb = fdt.Fdt.FromData(dtb_data)
7143 signature_node = dtb.GetNode('/signature')
7144 self.assertIsNotNone(signature_node)
7145 key_node = signature_node.FindNode("key-key")
7146 self.assertIsNotNone(key_node)
7147 self.assertEqual(fdt_util.GetString(key_node, "required"),
7149 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7151 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7154 def testXilinxBootgenSigning(self):
7155 """Test xilinx-bootgen etype"""
7156 bootgen = bintool.Bintool.create('bootgen')
7157 self._CheckBintool(bootgen)
7158 data = tools.read_file(self.TestFile("key.key"))
7159 self._MakeInputFile("psk.pem", data)
7160 self._MakeInputFile("ssk.pem", data)
7161 self._SetupPmuFwlElf()
7163 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7164 image_fname = tools.get_output_filename('image.bin')
7166 # Read partition header table and check if authentication is enabled
7167 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7168 "-read", image_fname, "pht").splitlines()
7169 attributes = {"authentication": None,
7173 for l in bootgen_out:
7174 for a in attributes.keys():
7176 m = re.match(fr".*{a} \[([^]]+)\]", l)
7177 attributes[a] = m.group(1)
7179 self.assertTrue(attributes['authentication'] == "rsa")
7180 self.assertTrue(attributes['core'] == "a53-0")
7181 self.assertTrue(attributes['encryption'] == "no")
7183 def testXilinxBootgenSigningEncryption(self):
7184 """Test xilinx-bootgen etype"""
7185 bootgen = bintool.Bintool.create('bootgen')
7186 self._CheckBintool(bootgen)
7187 data = tools.read_file(self.TestFile("key.key"))
7188 self._MakeInputFile("psk.pem", data)
7189 self._MakeInputFile("ssk.pem", data)
7190 self._SetupPmuFwlElf()
7192 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7193 image_fname = tools.get_output_filename('image.bin')
7195 # Read boot header in order to verify encryption source and
7196 # encryption parameter
7197 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7198 "-read", image_fname, "bh").splitlines()
7199 attributes = {"auth_only":
7200 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7201 "encryption_keystore":
7202 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7206 for l in bootgen_out:
7207 for a in attributes.keys():
7209 m = re.match(attributes[a]['re'], l)
7210 attributes[a] = m.group(1)
7212 # Check if fsbl-attribute is set correctly
7213 self.assertTrue(attributes['auth_only'] == "true")
7214 # Check if key is stored in efuse
7215 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7217 def testXilinxBootgenMissing(self):
7218 """Test that binman still produces an image if bootgen is missing"""
7219 data = tools.read_file(self.TestFile("key.key"))
7220 self._MakeInputFile("psk.pem", data)
7221 self._MakeInputFile("ssk.pem", data)
7222 self._SetupPmuFwlElf()
7224 with test_util.capture_sys_output() as (_, stderr):
7225 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7226 force_missing_bintools='bootgen')
7227 err = stderr.getvalue()
7228 self.assertRegex(err,
7229 "Image 'image'.*missing bintools.*: bootgen")
7231 def _GetCapsuleHeaders(self, data):
7232 """Get the capsule header contents
7235 data: Capsule file contents
7239 key: Capsule Header name (str)
7240 value: Header field value (str)
7242 capsule_file = os.path.join(self._indir, 'test.capsule')
7243 tools.write_file(capsule_file, data)
7245 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7246 lines = out.splitlines()
7248 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7251 mat = re_line.match(line)
7253 vals[mat.group(1)] = mat.group(2)
7257 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7259 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7260 fmp_size = "00000010"
7261 fmp_fw_version = "00000002"
7262 capsule_image_index = "00000001"
7263 oemflag = "00018000"
7264 auth_hdr_revision = "00000200"
7265 auth_hdr_cert_type = "00000EF1"
7267 payload_data_len = len(EFI_CAPSULE_DATA)
7269 hdr = self._GetCapsuleHeaders(data)
7271 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7273 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7274 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7275 self.assertEqual(capsule_image_index,
7276 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
7279 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7282 self.assertEqual(auth_hdr_revision,
7283 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7284 self.assertEqual(auth_hdr_cert_type,
7285 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7286 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7287 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7290 self.assertEqual(fmp_signature,
7291 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7292 self.assertEqual(fmp_size,
7293 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7294 self.assertEqual(fmp_fw_version,
7295 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7297 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
7299 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7301 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7303 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7305 hdr = self._GetCapsuleHeaders(data)
7307 self.assertEqual(capsule_hdr_guid.upper(),
7308 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7311 capsule_size = "0000002C"
7313 capsule_size = "0000001C"
7314 self.assertEqual(capsule_size,
7315 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7318 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7320 def testCapsuleGen(self):
7321 """Test generation of EFI capsule"""
7322 data = self._DoReadFile('311_capsule.dts')
7324 self._CheckCapsule(data)
7326 def testSignedCapsuleGen(self):
7327 """Test generation of EFI capsule"""
7328 data = tools.read_file(self.TestFile("key.key"))
7329 self._MakeInputFile("key.key", data)
7330 data = tools.read_file(self.TestFile("key.pem"))
7331 self._MakeInputFile("key.crt", data)
7333 data = self._DoReadFile('312_capsule_signed.dts')
7335 self._CheckCapsule(data, signed_capsule=True)
7337 def testCapsuleGenVersionSupport(self):
7338 """Test generation of EFI capsule with version support"""
7339 data = self._DoReadFile('313_capsule_version.dts')
7341 self._CheckCapsule(data, version_check=True)
7343 def testCapsuleGenSignedVer(self):
7344 """Test generation of signed EFI capsule with version information"""
7345 data = tools.read_file(self.TestFile("key.key"))
7346 self._MakeInputFile("key.key", data)
7347 data = tools.read_file(self.TestFile("key.pem"))
7348 self._MakeInputFile("key.crt", data)
7350 data = self._DoReadFile('314_capsule_signed_ver.dts')
7352 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7354 def testCapsuleGenCapOemFlags(self):
7355 """Test generation of EFI capsule with OEM Flags set"""
7356 data = self._DoReadFile('315_capsule_oemflags.dts')
7358 self._CheckCapsule(data, capoemflags=True)
7360 def testCapsuleGenKeyMissing(self):
7361 """Test that binman errors out on missing key"""
7362 with self.assertRaises(ValueError) as e:
7363 self._DoReadFile('316_capsule_missing_key.dts')
7365 self.assertIn("Both private key and public key certificate need to be provided",
7368 def testCapsuleGenIndexMissing(self):
7369 """Test that binman errors out on missing image index"""
7370 with self.assertRaises(ValueError) as e:
7371 self._DoReadFile('317_capsule_missing_index.dts')
7373 self.assertIn("entry is missing properties: image-index",
7376 def testCapsuleGenGuidMissing(self):
7377 """Test that binman errors out on missing image GUID"""
7378 with self.assertRaises(ValueError) as e:
7379 self._DoReadFile('318_capsule_missing_guid.dts')
7381 self.assertIn("entry is missing properties: image-guid",
7384 def testCapsuleGenAcceptCapsule(self):
7385 """Test generationg of accept EFI capsule"""
7386 data = self._DoReadFile('319_capsule_accept.dts')
7388 self._CheckEmptyCapsule(data, accept_capsule=True)
7390 def testCapsuleGenRevertCapsule(self):
7391 """Test generationg of revert EFI capsule"""
7392 data = self._DoReadFile('320_capsule_revert.dts')
7394 self._CheckEmptyCapsule(data)
7396 def testCapsuleGenAcceptGuidMissing(self):
7397 """Test that binman errors out on missing image GUID for accept capsule"""
7398 with self.assertRaises(ValueError) as e:
7399 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7401 self.assertIn("Image GUID needed for generating accept capsule",
7404 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7405 """Test that capsule-type is specified"""
7406 with self.assertRaises(ValueError) as e:
7407 self._DoReadFile('322_empty_capsule_type_missing.dts')
7409 self.assertIn("entry is missing properties: capsule-type",
7412 def testCapsuleGenAcceptOrRevertMissing(self):
7413 """Test that both accept and revert capsule are not specified"""
7414 with self.assertRaises(ValueError) as e:
7415 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7417 if __name__ == "__main__":