1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # To run a single test, change to this directory, and:
7 # python -m unittest func_test.TestFunctional.testHelp
12 from optparse import OptionParser
23 from binman import bintool
24 from binman import cbfs_util
25 from binman import cmdline
26 from binman import comp_util
27 from binman import control
28 from binman import elf
29 from binman import elf_test
30 from binman import fip_util
31 from binman import fmap_util
32 from binman import state
34 from dtoc import fdt_util
35 from binman.etype import fdtmap
36 from binman.etype import image_header
37 from binman.image import Image
38 from patman import command
39 from patman import test_util
40 from patman import tools
41 from patman import tout
43 # Contents of test files, corresponding to different entry types
45 U_BOOT_IMG_DATA = b'img'
46 U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
47 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
51 U_BOOT_DTB_DATA = b'udtb'
52 U_BOOT_SPL_DTB_DATA = b'spldtb'
53 U_BOOT_TPL_DTB_DATA = b'tpldtb'
54 X86_START16_DATA = b'start16'
55 X86_START16_SPL_DATA = b'start16spl'
56 X86_START16_TPL_DATA = b'start16tpl'
57 X86_RESET16_DATA = b'reset16'
58 X86_RESET16_SPL_DATA = b'reset16spl'
59 X86_RESET16_TPL_DATA = b'reset16tpl'
60 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
61 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
62 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
63 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
71 CROS_EC_RW_DATA = b'ecrw'
75 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
76 b"sorry you're alive\n")
77 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
78 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
79 REFCODE_DATA = b'refcode'
83 ATF_BL31_DATA = b'bl31'
84 ATF_BL2U_DATA = b'bl2u'
85 OPENSBI_DATA = b'opensbi'
87 TEST_FDT1_DATA = b'fdt1'
88 TEST_FDT2_DATA = b'test-fdt2'
89 ENV_DATA = b'var1=1\nvar2="2"'
91 # Subdirectory of the input dir to use to put test FDTs
92 TEST_FDT_SUBDIR = 'fdts'
94 # The expected size for the device tree in some tests
95 EXTRACT_DTB_SIZE = 0x3c9
97 # Properties expected to be in the device tree when update_dtb is used
98 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
100 # Extra properties expected to be in the device tree when allow-repack is used
101 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
104 class TestFunctional(unittest.TestCase):
105 """Functional tests for binman
107 Most of these use a sample .dts file to build an image and then check
108 that it looks correct. The sample files are in the test/ subdirectory
111 For each entry type a very small test file is created using fixed
112 string contents. This makes it easy to test that things look right, and
115 In some cases a 'real' file must be used - these are also supplied in
116 the test/ diurectory.
121 from binman import entry
123 # Handle the case where argv[0] is 'python'
124 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
125 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
127 # Create a temporary directory for input files
128 cls._indir = tempfile.mkdtemp(prefix='binmant.')
130 # Create some test files
131 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
132 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
133 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
134 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
135 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
136 TestFunctional._MakeInputFile('me.bin', ME_DATA)
137 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
140 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
142 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
143 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
144 X86_START16_SPL_DATA)
145 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
146 X86_START16_TPL_DATA)
148 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
150 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
151 X86_RESET16_SPL_DATA)
152 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
153 X86_RESET16_TPL_DATA)
155 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
156 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
157 U_BOOT_SPL_NODTB_DATA)
158 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
159 U_BOOT_TPL_NODTB_DATA)
160 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
161 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
162 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
163 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
164 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
165 TestFunctional._MakeInputDir('devkeys')
166 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
167 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
168 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
169 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
170 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
172 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
173 elf_test.BuildElfTestFiles(cls._elf_testdir)
175 # ELF file with a '_dt_ucode_base_size' symbol
176 TestFunctional._MakeInputFile('u-boot',
177 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
179 # Intel flash descriptor file
180 cls._SetupDescriptor()
182 shutil.copytree(cls.TestFile('files'),
183 os.path.join(cls._indir, 'files'))
185 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
186 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
187 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
188 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
189 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
190 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
192 # Add a few .dtb files for testing
193 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
195 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
198 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
200 cls.have_lz4 = comp_util.HAVE_LZ4
203 def tearDownClass(cls):
204 """Remove the temporary input directory and its contents"""
205 if cls.preserve_indir:
206 print('Preserving input dir: %s' % cls._indir)
209 shutil.rmtree(cls._indir)
213 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
214 toolpath=None, verbosity=None):
215 """Accept arguments controlling test execution
218 preserve_indir: Preserve the shared input directory used by all
220 preserve_outdir: Preserve the output directories used by tests. Each
221 test has its own, so this is normally only useful when running a
223 toolpath: ist of paths to use for tools
225 cls.preserve_indir = preserve_indir
226 cls.preserve_outdirs = preserve_outdirs
227 cls.toolpath = toolpath
228 cls.verbosity = verbosity
231 if not self.have_lz4:
232 self.skipTest('lz4 --no-frame-crc not available')
234 def _CleanupOutputDir(self):
235 """Remove the temporary output directory"""
236 if self.preserve_outdirs:
237 print('Preserving output dir: %s' % tools.outdir)
239 tools._finalise_for_test()
242 # Enable this to turn on debugging output
243 # tout.Init(tout.DEBUG)
244 command.test_result = None
247 """Remove the temporary output directory"""
248 self._CleanupOutputDir()
250 def _SetupImageInTmpdir(self):
251 """Set up the output image in a new temporary directory
253 This is used when an image has been generated in the output directory,
254 but we want to run binman again. This will create a new output
255 directory and fail to delete the original one.
257 This creates a new temporary directory, copies the image to it (with a
258 new name) and removes the old output directory.
262 Temporary directory to use
265 image_fname = tools.get_output_filename('image.bin')
266 tmpdir = tempfile.mkdtemp(prefix='binman.')
267 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
268 tools.write_file(updated_fname, tools.read_file(image_fname))
269 self._CleanupOutputDir()
270 return tmpdir, updated_fname
274 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
275 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
276 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
278 def _RunBinman(self, *args, **kwargs):
279 """Run binman using the command line
282 Arguments to pass, as a list of strings
283 kwargs: Arguments to pass to Command.RunPipe()
285 result = command.RunPipe([[self._binman_pathname] + list(args)],
286 capture=True, capture_stderr=True, raise_on_error=False)
287 if result.return_code and kwargs.get('raise_on_error', True):
288 raise Exception("Error running '%s': %s" % (' '.join(args),
289 result.stdout + result.stderr))
292 def _DoBinman(self, *argv):
293 """Run binman using directly (in the same process)
296 Arguments to pass, as a list of strings
298 Return value (0 for success)
301 args = cmdline.ParseArgs(argv)
302 args.pager = 'binman-invalid-pager'
303 args.build_dir = self._indir
305 # For testing, you can force an increase in verbosity here
306 # args.verbosity = tout.DEBUG
307 return control.Binman(args)
309 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
310 entry_args=None, images=None, use_real_dtb=False,
311 use_expanded=False, verbosity=None, allow_missing=False,
312 allow_fake_blobs=False, extra_indirs=None, threads=None,
313 test_section_timeout=False, update_fdt_in_elf=None,
314 force_missing_bintools=''):
315 """Run binman with a given test file
318 fname: Device-tree source filename to use (e.g. 005_simple.dts)
319 debug: True to enable debugging output
320 map: True to output map files for the images
321 update_dtb: Update the offset and size of each entry in the device
322 tree before packing it into the image
323 entry_args: Dict of entry args to supply to binman
325 value: value of that arg
326 images: List of image names to build
327 use_real_dtb: True to use the test file as the contents of
328 the u-boot-dtb entry. Normally this is not needed and the
329 test contents (the U_BOOT_DTB_DATA string) can be used.
330 But in some test we need the real contents.
331 use_expanded: True to use expanded entries where available, e.g.
332 'u-boot-expanded' instead of 'u-boot'
333 verbosity: Verbosity level to use (0-3, None=don't set it)
334 allow_missing: Set the '--allow-missing' flag so that missing
335 external binaries just produce a warning instead of an error
336 allow_fake_blobs: Set the '--fake-ext-blobs' flag
337 extra_indirs: Extra input directories to add using -I
338 threads: Number of threads to use (None for default, 0 for
340 test_section_timeout: True to force the first time to timeout, as
341 used in testThreadTimeout()
342 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
343 force_missing_tools (str): comma-separated list of bintools to
347 int return code, 0 on success
352 if verbosity is not None:
353 args.append('-v%d' % verbosity)
355 args.append('-v%d' % self.verbosity)
357 for path in self.toolpath:
358 args += ['--toolpath', path]
359 if threads is not None:
360 args.append('-T%d' % threads)
361 if test_section_timeout:
362 args.append('--test-section-timeout')
363 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
369 args.append('--fake-dtb')
371 args.append('--no-expanded')
373 for arg, value in entry_args.items():
374 args.append('-a%s=%s' % (arg, value))
378 args.append('--fake-ext-blobs')
379 if force_missing_bintools:
380 args += ['--force-missing-bintools', force_missing_bintools]
381 if update_fdt_in_elf:
382 args += ['--update-fdt-in-elf', update_fdt_in_elf]
385 args += ['-i', image]
387 for indir in extra_indirs:
388 args += ['-I', indir]
389 return self._DoBinman(*args)
391 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
392 """Set up a new test device-tree file
394 The given file is compiled and set up as the device tree to be used
398 fname: Filename of .dts file to read
399 outfile: Output filename for compiled device-tree binary
402 Contents of device-tree binary
404 tmpdir = tempfile.mkdtemp(prefix='binmant.')
405 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
406 with open(dtb, 'rb') as fd:
408 TestFunctional._MakeInputFile(outfile, data)
409 shutil.rmtree(tmpdir)
412 def _GetDtbContentsForSplTpl(self, dtb_data, name):
413 """Create a version of the main DTB for SPL or SPL
415 For testing we don't actually have different versions of the DTB. With
416 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
417 we don't normally have any unwanted nodes.
419 We still want the DTBs for SPL and TPL to be different though, since
420 otherwise it is confusing to know which one we are looking at. So add
421 an 'spl' or 'tpl' property to the top-level node.
424 dtb_data: dtb data to modify (this should be a value devicetree)
425 name: Name of a new property to add
428 New dtb data with the property added
430 dtb = fdt.Fdt.FromData(dtb_data)
432 dtb.GetNode('/binman').AddZeroProp(name)
433 dtb.Sync(auto_resize=True)
435 return dtb.GetContents()
437 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
438 map=False, update_dtb=False, entry_args=None,
439 reset_dtbs=True, extra_indirs=None, threads=None):
440 """Run binman and return the resulting image
442 This runs binman with a given test file and then reads the resulting
443 output file. It is a shortcut function since most tests need to do
446 Raises an assertion failure if binman returns a non-zero exit code.
449 fname: Device-tree source filename to use (e.g. 005_simple.dts)
450 use_real_dtb: True to use the test file as the contents of
451 the u-boot-dtb entry. Normally this is not needed and the
452 test contents (the U_BOOT_DTB_DATA string) can be used.
453 But in some test we need the real contents.
454 use_expanded: True to use expanded entries where available, e.g.
455 'u-boot-expanded' instead of 'u-boot'
456 map: True to output map files for the images
457 update_dtb: Update the offset and size of each entry in the device
458 tree before packing it into the image
459 entry_args: Dict of entry args to supply to binman
461 value: value of that arg
462 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
463 function. If reset_dtbs is True, then the original test dtb
464 is written back before this function finishes
465 extra_indirs: Extra input directories to add using -I
466 threads: Number of threads to use (None for default, 0 for
471 Resulting image contents
473 Map data showing contents of image (or None if none)
474 Output device tree binary filename ('u-boot.dtb' path)
477 # Use the compiled test file as the u-boot-dtb input
479 dtb_data = self._SetupDtb(fname)
481 # For testing purposes, make a copy of the DT for SPL and TPL. Add
482 # a node indicating which it is, so aid verification.
483 for name in ['spl', 'tpl']:
484 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
485 outfile = os.path.join(self._indir, dtb_fname)
486 TestFunctional._MakeInputFile(dtb_fname,
487 self._GetDtbContentsForSplTpl(dtb_data, name))
490 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
491 entry_args=entry_args, use_real_dtb=use_real_dtb,
492 use_expanded=use_expanded, extra_indirs=extra_indirs,
494 self.assertEqual(0, retcode)
495 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
497 # Find the (only) image, read it and return its contents
498 image = control.images['image']
499 image_fname = tools.get_output_filename('image.bin')
500 self.assertTrue(os.path.exists(image_fname))
502 map_fname = tools.get_output_filename('image.map')
503 with open(map_fname) as fd:
507 with open(image_fname, 'rb') as fd:
508 return fd.read(), dtb_data, map_data, out_dtb_fname
510 # Put the test file back
511 if reset_dtbs and use_real_dtb:
514 def _DoReadFileRealDtb(self, fname):
515 """Run binman with a real .dtb file and return the resulting data
518 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
521 Resulting image contents
523 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
525 def _DoReadFile(self, fname, use_real_dtb=False):
526 """Helper function which discards the device-tree binary
529 fname: Device-tree source filename to use (e.g. 005_simple.dts)
530 use_real_dtb: True to use the test file as the contents of
531 the u-boot-dtb entry. Normally this is not needed and the
532 test contents (the U_BOOT_DTB_DATA string) can be used.
533 But in some test we need the real contents.
536 Resulting image contents
538 return self._DoReadFileDtb(fname, use_real_dtb)[0]
541 def _MakeInputFile(cls, fname, contents):
542 """Create a new test input file, creating directories as needed
545 fname: Filename to create
546 contents: File contents to write in to the file
548 Full pathname of file created
550 pathname = os.path.join(cls._indir, fname)
551 dirname = os.path.dirname(pathname)
552 if dirname and not os.path.exists(dirname):
554 with open(pathname, 'wb') as fd:
559 def _MakeInputDir(cls, dirname):
560 """Create a new test input directory, creating directories as needed
563 dirname: Directory name to create
566 Full pathname of directory created
568 pathname = os.path.join(cls._indir, dirname)
569 if not os.path.exists(pathname):
570 os.makedirs(pathname)
574 def _SetupSplElf(cls, src_fname='bss_data'):
575 """Set up an ELF file with a '_dt_ucode_base_size' symbol
578 Filename of ELF file to use as SPL
580 TestFunctional._MakeInputFile('spl/u-boot-spl',
581 tools.read_file(cls.ElfTestFile(src_fname)))
584 def _SetupTplElf(cls, src_fname='bss_data'):
585 """Set up an ELF file with a '_dt_ucode_base_size' symbol
588 Filename of ELF file to use as TPL
590 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
591 tools.read_file(cls.ElfTestFile(src_fname)))
594 def _SetupDescriptor(cls):
595 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
596 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
599 def TestFile(cls, fname):
600 return os.path.join(cls._binman_dir, 'test', fname)
603 def ElfTestFile(cls, fname):
604 return os.path.join(cls._elf_testdir, fname)
606 def AssertInList(self, grep_list, target):
607 """Assert that at least one of a list of things is in a target
610 grep_list: List of strings to check
611 target: Target string
613 for grep in grep_list:
616 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
618 def CheckNoGaps(self, entries):
619 """Check that all entries fit together without gaps
622 entries: List of entries to check
625 for entry in entries.values():
626 self.assertEqual(offset, entry.offset)
629 def GetFdtLen(self, dtb):
630 """Get the totalsize field from a device-tree binary
633 dtb: Device-tree binary contents
636 Total size of device-tree binary, from the header
638 return struct.unpack('>L', dtb[4:8])[0]
640 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
641 def AddNode(node, path):
643 path += '/' + node.name
644 for prop in node.props.values():
645 if prop.name in prop_names:
646 prop_path = path + ':' + prop.name
647 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
649 for subnode in node.subnodes:
650 AddNode(subnode, path)
653 AddNode(dtb.GetRoot(), '')
657 """Test a basic run with valid args"""
658 result = self._RunBinman('-h')
660 def testFullHelp(self):
661 """Test that the full help is displayed with -H"""
662 result = self._RunBinman('-H')
663 help_file = os.path.join(self._binman_dir, 'README.rst')
664 # Remove possible extraneous strings
665 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
666 gothelp = result.stdout.replace(extra, '')
667 self.assertEqual(len(gothelp), os.path.getsize(help_file))
668 self.assertEqual(0, len(result.stderr))
669 self.assertEqual(0, result.return_code)
671 def testFullHelpInternal(self):
672 """Test that the full help is displayed with -H"""
674 command.test_result = command.CommandResult()
675 result = self._DoBinman('-H')
676 help_file = os.path.join(self._binman_dir, 'README.rst')
678 command.test_result = None
681 """Test that the basic help is displayed with -h"""
682 result = self._RunBinman('-h')
683 self.assertTrue(len(result.stdout) > 200)
684 self.assertEqual(0, len(result.stderr))
685 self.assertEqual(0, result.return_code)
688 """Test that we can run it with a specific board"""
689 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
690 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
691 result = self._DoBinman('build', '-n', '-b', 'sandbox')
692 self.assertEqual(0, result)
694 def testNeedBoard(self):
695 """Test that we get an error when no board ius supplied"""
696 with self.assertRaises(ValueError) as e:
697 result = self._DoBinman('build')
698 self.assertIn("Must provide a board to process (use -b <board>)",
701 def testMissingDt(self):
702 """Test that an invalid device-tree file generates an error"""
703 with self.assertRaises(Exception) as e:
704 self._RunBinman('build', '-d', 'missing_file')
705 # We get one error from libfdt, and a different one from fdtget.
706 self.AssertInList(["Couldn't open blob from 'missing_file'",
707 'No such file or directory'], str(e.exception))
709 def testBrokenDt(self):
710 """Test that an invalid device-tree source file generates an error
712 Since this is a source file it should be compiled and the error
713 will come from the device-tree compiler (dtc).
715 with self.assertRaises(Exception) as e:
716 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
717 self.assertIn("FATAL ERROR: Unable to parse input tree",
720 def testMissingNode(self):
721 """Test that a device tree without a 'binman' node generates an error"""
722 with self.assertRaises(Exception) as e:
723 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
724 self.assertIn("does not have a 'binman' node", str(e.exception))
727 """Test that an empty binman node works OK (i.e. does nothing)"""
728 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
729 self.assertEqual(0, len(result.stderr))
730 self.assertEqual(0, result.return_code)
732 def testInvalidEntry(self):
733 """Test that an invalid entry is flagged"""
734 with self.assertRaises(Exception) as e:
735 result = self._RunBinman('build', '-d',
736 self.TestFile('004_invalid_entry.dts'))
737 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
738 "'/binman/not-a-valid-type'", str(e.exception))
740 def testSimple(self):
741 """Test a simple binman with a single file"""
742 data = self._DoReadFile('005_simple.dts')
743 self.assertEqual(U_BOOT_DATA, data)
745 def testSimpleDebug(self):
746 """Test a simple binman run with debugging enabled"""
747 self._DoTestFile('005_simple.dts', debug=True)
750 """Test that we can handle creating two images
752 This also tests image padding.
754 retcode = self._DoTestFile('006_dual_image.dts')
755 self.assertEqual(0, retcode)
757 image = control.images['image1']
758 self.assertEqual(len(U_BOOT_DATA), image.size)
759 fname = tools.get_output_filename('image1.bin')
760 self.assertTrue(os.path.exists(fname))
761 with open(fname, 'rb') as fd:
763 self.assertEqual(U_BOOT_DATA, data)
765 image = control.images['image2']
766 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
767 fname = tools.get_output_filename('image2.bin')
768 self.assertTrue(os.path.exists(fname))
769 with open(fname, 'rb') as fd:
771 self.assertEqual(U_BOOT_DATA, data[3:7])
772 self.assertEqual(tools.get_bytes(0, 3), data[:3])
773 self.assertEqual(tools.get_bytes(0, 5), data[7:])
775 def testBadAlign(self):
776 """Test that an invalid alignment value is detected"""
777 with self.assertRaises(ValueError) as e:
778 self._DoTestFile('007_bad_align.dts')
779 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
780 "of two", str(e.exception))
782 def testPackSimple(self):
783 """Test that packing works as expected"""
784 retcode = self._DoTestFile('008_pack.dts')
785 self.assertEqual(0, retcode)
786 self.assertIn('image', control.images)
787 image = control.images['image']
788 entries = image.GetEntries()
789 self.assertEqual(5, len(entries))
792 self.assertIn('u-boot', entries)
793 entry = entries['u-boot']
794 self.assertEqual(0, entry.offset)
795 self.assertEqual(len(U_BOOT_DATA), entry.size)
797 # Second u-boot, aligned to 16-byte boundary
798 self.assertIn('u-boot-align', entries)
799 entry = entries['u-boot-align']
800 self.assertEqual(16, entry.offset)
801 self.assertEqual(len(U_BOOT_DATA), entry.size)
803 # Third u-boot, size 23 bytes
804 self.assertIn('u-boot-size', entries)
805 entry = entries['u-boot-size']
806 self.assertEqual(20, entry.offset)
807 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
808 self.assertEqual(23, entry.size)
810 # Fourth u-boot, placed immediate after the above
811 self.assertIn('u-boot-next', entries)
812 entry = entries['u-boot-next']
813 self.assertEqual(43, entry.offset)
814 self.assertEqual(len(U_BOOT_DATA), entry.size)
816 # Fifth u-boot, placed at a fixed offset
817 self.assertIn('u-boot-fixed', entries)
818 entry = entries['u-boot-fixed']
819 self.assertEqual(61, entry.offset)
820 self.assertEqual(len(U_BOOT_DATA), entry.size)
822 self.assertEqual(65, image.size)
824 def testPackExtra(self):
825 """Test that extra packing feature works as expected"""
826 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
829 self.assertIn('image', control.images)
830 image = control.images['image']
831 entries = image.GetEntries()
832 self.assertEqual(5, len(entries))
834 # First u-boot with padding before and after
835 self.assertIn('u-boot', entries)
836 entry = entries['u-boot']
837 self.assertEqual(0, entry.offset)
838 self.assertEqual(3, entry.pad_before)
839 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
840 self.assertEqual(U_BOOT_DATA, entry.data)
841 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
842 tools.get_bytes(0, 5), data[:entry.size])
845 # Second u-boot has an aligned size, but it has no effect
846 self.assertIn('u-boot-align-size-nop', entries)
847 entry = entries['u-boot-align-size-nop']
848 self.assertEqual(pos, entry.offset)
849 self.assertEqual(len(U_BOOT_DATA), entry.size)
850 self.assertEqual(U_BOOT_DATA, entry.data)
851 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
854 # Third u-boot has an aligned size too
855 self.assertIn('u-boot-align-size', entries)
856 entry = entries['u-boot-align-size']
857 self.assertEqual(pos, entry.offset)
858 self.assertEqual(32, entry.size)
859 self.assertEqual(U_BOOT_DATA, entry.data)
860 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
861 data[pos:pos + entry.size])
864 # Fourth u-boot has an aligned end
865 self.assertIn('u-boot-align-end', entries)
866 entry = entries['u-boot-align-end']
867 self.assertEqual(48, entry.offset)
868 self.assertEqual(16, entry.size)
869 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
870 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
871 data[pos:pos + entry.size])
874 # Fifth u-boot immediately afterwards
875 self.assertIn('u-boot-align-both', entries)
876 entry = entries['u-boot-align-both']
877 self.assertEqual(64, entry.offset)
878 self.assertEqual(64, entry.size)
879 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
880 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
881 data[pos:pos + entry.size])
883 self.CheckNoGaps(entries)
884 self.assertEqual(128, image.size)
886 dtb = fdt.Fdt(out_dtb_fname)
888 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
894 'u-boot:image-pos': 0,
896 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
898 'u-boot-align-size-nop:image-pos': 12,
899 'u-boot-align-size-nop:offset': 12,
900 'u-boot-align-size-nop:size': 4,
902 'u-boot-align-size:image-pos': 16,
903 'u-boot-align-size:offset': 16,
904 'u-boot-align-size:size': 32,
906 'u-boot-align-end:image-pos': 48,
907 'u-boot-align-end:offset': 48,
908 'u-boot-align-end:size': 16,
910 'u-boot-align-both:image-pos': 64,
911 'u-boot-align-both:offset': 64,
912 'u-boot-align-both:size': 64,
914 self.assertEqual(expected, props)
916 def testPackAlignPowerOf2(self):
917 """Test that invalid entry alignment is detected"""
918 with self.assertRaises(ValueError) as e:
919 self._DoTestFile('010_pack_align_power2.dts')
920 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
921 "of two", str(e.exception))
923 def testPackAlignSizePowerOf2(self):
924 """Test that invalid entry size alignment is detected"""
925 with self.assertRaises(ValueError) as e:
926 self._DoTestFile('011_pack_align_size_power2.dts')
927 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
928 "power of two", str(e.exception))
930 def testPackInvalidAlign(self):
931 """Test detection of an offset that does not match its alignment"""
932 with self.assertRaises(ValueError) as e:
933 self._DoTestFile('012_pack_inv_align.dts')
934 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
935 "align 0x4 (4)", str(e.exception))
937 def testPackInvalidSizeAlign(self):
938 """Test that invalid entry size alignment is detected"""
939 with self.assertRaises(ValueError) as e:
940 self._DoTestFile('013_pack_inv_size_align.dts')
941 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
942 "align-size 0x4 (4)", str(e.exception))
944 def testPackOverlap(self):
945 """Test that overlapping regions are detected"""
946 with self.assertRaises(ValueError) as e:
947 self._DoTestFile('014_pack_overlap.dts')
948 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
949 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
952 def testPackEntryOverflow(self):
953 """Test that entries that overflow their size are detected"""
954 with self.assertRaises(ValueError) as e:
955 self._DoTestFile('015_pack_overflow.dts')
956 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
957 "but entry size is 0x3 (3)", str(e.exception))
959 def testPackImageOverflow(self):
960 """Test that entries which overflow the image size are detected"""
961 with self.assertRaises(ValueError) as e:
962 self._DoTestFile('016_pack_image_overflow.dts')
963 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
964 "size 0x3 (3)", str(e.exception))
966 def testPackImageSize(self):
967 """Test that the image size can be set"""
968 retcode = self._DoTestFile('017_pack_image_size.dts')
969 self.assertEqual(0, retcode)
970 self.assertIn('image', control.images)
971 image = control.images['image']
972 self.assertEqual(7, image.size)
974 def testPackImageSizeAlign(self):
975 """Test that image size alignemnt works as expected"""
976 retcode = self._DoTestFile('018_pack_image_align.dts')
977 self.assertEqual(0, retcode)
978 self.assertIn('image', control.images)
979 image = control.images['image']
980 self.assertEqual(16, image.size)
982 def testPackInvalidImageAlign(self):
983 """Test that invalid image alignment is detected"""
984 with self.assertRaises(ValueError) as e:
985 self._DoTestFile('019_pack_inv_image_align.dts')
986 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
987 "align-size 0x8 (8)", str(e.exception))
989 def testPackAlignPowerOf2(self):
990 """Test that invalid image alignment is detected"""
991 with self.assertRaises(ValueError) as e:
992 self._DoTestFile('020_pack_inv_image_align_power2.dts')
993 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
994 "two", str(e.exception))
996 def testImagePadByte(self):
997 """Test that the image pad byte can be specified"""
999 data = self._DoReadFile('021_image_pad.dts')
1000 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
1003 def testImageName(self):
1004 """Test that image files can be named"""
1005 retcode = self._DoTestFile('022_image_name.dts')
1006 self.assertEqual(0, retcode)
1007 image = control.images['image1']
1008 fname = tools.get_output_filename('test-name')
1009 self.assertTrue(os.path.exists(fname))
1011 image = control.images['image2']
1012 fname = tools.get_output_filename('test-name.xx')
1013 self.assertTrue(os.path.exists(fname))
1015 def testBlobFilename(self):
1016 """Test that generic blobs can be provided by filename"""
1017 data = self._DoReadFile('023_blob.dts')
1018 self.assertEqual(BLOB_DATA, data)
1020 def testPackSorted(self):
1021 """Test that entries can be sorted"""
1023 data = self._DoReadFile('024_sorted.dts')
1024 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1025 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
1027 def testPackZeroOffset(self):
1028 """Test that an entry at offset 0 is not given a new offset"""
1029 with self.assertRaises(ValueError) as e:
1030 self._DoTestFile('025_pack_zero_size.dts')
1031 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1032 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1035 def testPackUbootDtb(self):
1036 """Test that a device tree can be added to U-Boot"""
1037 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1038 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1040 def testPackX86RomNoSize(self):
1041 """Test that the end-at-4gb property requires a size property"""
1042 with self.assertRaises(ValueError) as e:
1043 self._DoTestFile('027_pack_4gb_no_size.dts')
1044 self.assertIn("Image '/binman': Section size must be provided when "
1045 "using end-at-4gb", str(e.exception))
1047 def test4gbAndSkipAtStartTogether(self):
1048 """Test that the end-at-4gb and skip-at-size property can't be used
1050 with self.assertRaises(ValueError) as e:
1051 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1052 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1053 "'skip-at-start'", str(e.exception))
1055 def testPackX86RomOutside(self):
1056 """Test that the end-at-4gb property checks for offset boundaries"""
1057 with self.assertRaises(ValueError) as e:
1058 self._DoTestFile('028_pack_4gb_outside.dts')
1059 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1060 "is outside the section '/binman' starting at "
1061 '0xffffffe0 (4294967264) of size 0x20 (32)',
1064 def testPackX86Rom(self):
1065 """Test that a basic x86 ROM can be created"""
1067 data = self._DoReadFile('029_x86_rom.dts')
1068 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1069 tools.get_bytes(0, 2), data)
1071 def testPackX86RomMeNoDesc(self):
1072 """Test that an invalid Intel descriptor entry is detected"""
1074 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1075 with self.assertRaises(ValueError) as e:
1076 self._DoTestFile('163_x86_rom_me_empty.dts')
1077 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1080 self._SetupDescriptor()
1082 def testPackX86RomBadDesc(self):
1083 """Test that the Intel requires a descriptor entry"""
1084 with self.assertRaises(ValueError) as e:
1085 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1086 self.assertIn("Node '/binman/intel-me': No offset set with "
1087 "offset-unset: should another entry provide this correct "
1088 "offset?", str(e.exception))
1090 def testPackX86RomMe(self):
1091 """Test that an x86 ROM with an ME region can be created"""
1092 data = self._DoReadFile('031_x86_rom_me.dts')
1093 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
1094 if data[:0x1000] != expected_desc:
1095 self.fail('Expected descriptor binary at start of image')
1096 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1098 def testPackVga(self):
1099 """Test that an image with a VGA binary can be created"""
1100 data = self._DoReadFile('032_intel_vga.dts')
1101 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1103 def testPackStart16(self):
1104 """Test that an image with an x86 start16 region can be created"""
1105 data = self._DoReadFile('033_x86_start16.dts')
1106 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1108 def testPackPowerpcMpc85xxBootpgResetvec(self):
1109 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1111 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1112 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1114 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1115 """Handle running a test for insertion of microcode
1118 dts_fname: Name of test .dts file
1119 nodtb_data: Data that we expect in the first section
1120 ucode_second: True if the microsecond entry is second instead of
1125 Contents of first region (U-Boot or SPL)
1126 Offset and size components of microcode pointer, as inserted
1127 in the above (two 4-byte words)
1129 data = self._DoReadFile(dts_fname, True)
1131 # Now check the device tree has no microcode
1133 ucode_content = data[len(nodtb_data):]
1134 ucode_pos = len(nodtb_data)
1135 dtb_with_ucode = ucode_content[16:]
1136 fdt_len = self.GetFdtLen(dtb_with_ucode)
1138 dtb_with_ucode = data[len(nodtb_data):]
1139 fdt_len = self.GetFdtLen(dtb_with_ucode)
1140 ucode_content = dtb_with_ucode[fdt_len:]
1141 ucode_pos = len(nodtb_data) + fdt_len
1142 fname = tools.get_output_filename('test.dtb')
1143 with open(fname, 'wb') as fd:
1144 fd.write(dtb_with_ucode)
1145 dtb = fdt.FdtScan(fname)
1146 ucode = dtb.GetNode('/microcode')
1147 self.assertTrue(ucode)
1148 for node in ucode.subnodes:
1149 self.assertFalse(node.props.get('data'))
1151 # Check that the microcode appears immediately after the Fdt
1152 # This matches the concatenation of the data properties in
1153 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1154 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1156 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1158 # Check that the microcode pointer was inserted. It should match the
1159 # expected offset and size
1160 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1162 u_boot = data[:len(nodtb_data)]
1163 return u_boot, pos_and_size
1165 def testPackUbootMicrocode(self):
1166 """Test that x86 microcode can be handled correctly
1168 We expect to see the following in the image, in order:
1169 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1171 u-boot.dtb with the microcode removed
1174 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1176 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1177 b' somewhere in here', first)
1179 def _RunPackUbootSingleMicrocode(self):
1180 """Test that x86 microcode can be handled correctly
1182 We expect to see the following in the image, in order:
1183 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1185 u-boot.dtb with the microcode
1186 an empty microcode region
1188 # We need the libfdt library to run this test since only that allows
1189 # finding the offset of a property. This is required by
1190 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1191 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1193 second = data[len(U_BOOT_NODTB_DATA):]
1195 fdt_len = self.GetFdtLen(second)
1196 third = second[fdt_len:]
1197 second = second[:fdt_len]
1199 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1200 self.assertIn(ucode_data, second)
1201 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1203 # Check that the microcode pointer was inserted. It should match the
1204 # expected offset and size
1205 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1207 first = data[:len(U_BOOT_NODTB_DATA)]
1208 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1209 b' somewhere in here', first)
1211 def testPackUbootSingleMicrocode(self):
1212 """Test that x86 microcode can be handled correctly with fdt_normal.
1214 self._RunPackUbootSingleMicrocode()
1216 def testUBootImg(self):
1217 """Test that u-boot.img can be put in a file"""
1218 data = self._DoReadFile('036_u_boot_img.dts')
1219 self.assertEqual(U_BOOT_IMG_DATA, data)
1221 def testNoMicrocode(self):
1222 """Test that a missing microcode region is detected"""
1223 with self.assertRaises(ValueError) as e:
1224 self._DoReadFile('037_x86_no_ucode.dts', True)
1225 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1226 "node found in ", str(e.exception))
1228 def testMicrocodeWithoutNode(self):
1229 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1230 with self.assertRaises(ValueError) as e:
1231 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1232 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1233 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1235 def testMicrocodeWithoutNode2(self):
1236 """Test that a missing u-boot-ucode node is detected"""
1237 with self.assertRaises(ValueError) as e:
1238 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1239 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1240 "microcode region u-boot-ucode", str(e.exception))
1242 def testMicrocodeWithoutPtrInElf(self):
1243 """Test that a U-Boot binary without the microcode symbol is detected"""
1244 # ELF file without a '_dt_ucode_base_size' symbol
1246 TestFunctional._MakeInputFile('u-boot',
1247 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1249 with self.assertRaises(ValueError) as e:
1250 self._RunPackUbootSingleMicrocode()
1251 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1252 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1255 # Put the original file back
1256 TestFunctional._MakeInputFile('u-boot',
1257 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
1259 def testMicrocodeNotInImage(self):
1260 """Test that microcode must be placed within the image"""
1261 with self.assertRaises(ValueError) as e:
1262 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1263 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1264 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1265 "section ranging from 00000000 to 0000002e", str(e.exception))
1267 def testWithoutMicrocode(self):
1268 """Test that we can cope with an image without microcode (e.g. qemu)"""
1269 TestFunctional._MakeInputFile('u-boot',
1270 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
1271 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1273 # Now check the device tree has no microcode
1274 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1275 second = data[len(U_BOOT_NODTB_DATA):]
1277 fdt_len = self.GetFdtLen(second)
1278 self.assertEqual(dtb, second[:fdt_len])
1280 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1281 third = data[used_len:]
1282 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
1284 def testUnknownPosSize(self):
1285 """Test that microcode must be placed within the image"""
1286 with self.assertRaises(ValueError) as e:
1287 self._DoReadFile('041_unknown_pos_size.dts', True)
1288 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1289 "entry 'invalid-entry'", str(e.exception))
1291 def testPackFsp(self):
1292 """Test that an image with a FSP binary can be created"""
1293 data = self._DoReadFile('042_intel_fsp.dts')
1294 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1296 def testPackCmc(self):
1297 """Test that an image with a CMC binary can be created"""
1298 data = self._DoReadFile('043_intel_cmc.dts')
1299 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1301 def testPackVbt(self):
1302 """Test that an image with a VBT binary can be created"""
1303 data = self._DoReadFile('046_intel_vbt.dts')
1304 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1306 def testSplBssPad(self):
1307 """Test that we can pad SPL's BSS with zeros"""
1308 # ELF file with a '__bss_size' symbol
1310 data = self._DoReadFile('047_spl_bss_pad.dts')
1311 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
1314 def testSplBssPadMissing(self):
1315 """Test that a missing symbol is detected"""
1316 self._SetupSplElf('u_boot_ucode_ptr')
1317 with self.assertRaises(ValueError) as e:
1318 self._DoReadFile('047_spl_bss_pad.dts')
1319 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1322 def testPackStart16Spl(self):
1323 """Test that an image with an x86 start16 SPL region can be created"""
1324 data = self._DoReadFile('048_x86_start16_spl.dts')
1325 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1327 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1328 """Helper function for microcode tests
1330 We expect to see the following in the image, in order:
1331 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1333 u-boot.dtb with the microcode removed
1337 dts: Device tree file to use for test
1338 ucode_second: True if the microsecond entry is second instead of
1341 self._SetupSplElf('u_boot_ucode_ptr')
1342 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1343 ucode_second=ucode_second)
1344 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1345 b'ter somewhere in here', first)
1347 def testPackUbootSplMicrocode(self):
1348 """Test that x86 microcode can be handled correctly in SPL"""
1349 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1351 def testPackUbootSplMicrocodeReorder(self):
1352 """Test that order doesn't matter for microcode entries
1354 This is the same as testPackUbootSplMicrocode but when we process the
1355 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1356 entry, so we reply on binman to try later.
1358 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1361 def testPackMrc(self):
1362 """Test that an image with an MRC binary can be created"""
1363 data = self._DoReadFile('050_intel_mrc.dts')
1364 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1366 def testSplDtb(self):
1367 """Test that an image with spl/u-boot-spl.dtb can be created"""
1368 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1369 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1371 def testSplNoDtb(self):
1372 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1374 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1375 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1377 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1378 use_expanded=False):
1379 """Check the image contains the expected symbol values
1382 dts: Device tree file to use for test
1383 base_data: Data before and after 'u-boot' section
1384 u_boot_offset: Offset of 'u-boot' section in image
1385 entry_args: Dict of entry args to supply to binman
1387 value: value of that arg
1388 use_expanded: True to use expanded entries where available, e.g.
1389 'u-boot-expanded' instead of 'u-boot'
1391 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1392 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1393 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1394 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1397 self._SetupSplElf('u_boot_binman_syms')
1398 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1399 use_expanded=use_expanded)[0]
1400 # The image should contain the symbols from u_boot_binman_syms.c
1401 # Note that image_pos is adjusted by the base address of the image,
1402 # which is 0x10 in our test image
1403 sym_values = struct.pack('<LQLL', 0x00,
1404 u_boot_offset + len(U_BOOT_DATA),
1405 0x10 + u_boot_offset, 0x04)
1406 expected = (sym_values + base_data[20:] +
1407 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1409 self.assertEqual(expected, data)
1411 def testSymbols(self):
1412 """Test binman can assign symbols embedded in U-Boot"""
1413 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1415 def testSymbolsNoDtb(self):
1416 """Test binman can assign symbols embedded in U-Boot SPL"""
1417 self.checkSymbols('196_symbols_nodtb.dts',
1418 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1421 def testPackUnitAddress(self):
1422 """Test that we support multiple binaries with the same name"""
1423 data = self._DoReadFile('054_unit_address.dts')
1424 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1426 def testSections(self):
1427 """Basic test of sections"""
1428 data = self._DoReadFile('055_sections.dts')
1429 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1430 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1431 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
1432 self.assertEqual(expected, data)
1435 """Tests outputting a map of the images"""
1436 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1437 self.assertEqual('''ImagePos Offset Size Name
1438 00000000 00000000 00000028 main-section
1439 00000000 00000000 00000010 section@0
1440 00000000 00000000 00000004 u-boot
1441 00000010 00000010 00000010 section@1
1442 00000010 00000000 00000004 u-boot
1443 00000020 00000020 00000004 section@2
1444 00000020 00000000 00000004 u-boot
1447 def testNamePrefix(self):
1448 """Tests that name prefixes are used"""
1449 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1450 self.assertEqual('''ImagePos Offset Size Name
1451 00000000 00000000 00000028 main-section
1452 00000000 00000000 00000010 section@0
1453 00000000 00000000 00000004 ro-u-boot
1454 00000010 00000010 00000010 section@1
1455 00000010 00000000 00000004 rw-u-boot
1458 def testUnknownContents(self):
1459 """Test that obtaining the contents works as expected"""
1460 with self.assertRaises(ValueError) as e:
1461 self._DoReadFile('057_unknown_contents.dts', True)
1462 self.assertIn("Image '/binman': Internal error: Could not complete "
1463 "processing of contents: remaining ["
1464 "<binman.etype._testing.Entry__testing ", str(e.exception))
1466 def testBadChangeSize(self):
1467 """Test that trying to change the size of an entry fails"""
1469 state.SetAllowEntryExpansion(False)
1470 with self.assertRaises(ValueError) as e:
1471 self._DoReadFile('059_change_size.dts', True)
1472 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1475 state.SetAllowEntryExpansion(True)
1477 def testUpdateFdt(self):
1478 """Test that we can update the device tree with offset/size info"""
1479 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1481 dtb = fdt.Fdt(out_dtb_fname)
1483 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1487 '_testing:offset': 32,
1489 '_testing:image-pos': 32,
1490 'section@0/u-boot:offset': 0,
1491 'section@0/u-boot:size': len(U_BOOT_DATA),
1492 'section@0/u-boot:image-pos': 0,
1493 'section@0:offset': 0,
1494 'section@0:size': 16,
1495 'section@0:image-pos': 0,
1497 'section@1/u-boot:offset': 0,
1498 'section@1/u-boot:size': len(U_BOOT_DATA),
1499 'section@1/u-boot:image-pos': 16,
1500 'section@1:offset': 16,
1501 'section@1:size': 16,
1502 'section@1:image-pos': 16,
1506 def testUpdateFdtBad(self):
1507 """Test that we detect when ProcessFdt never completes"""
1508 with self.assertRaises(ValueError) as e:
1509 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1510 self.assertIn('Could not complete processing of Fdt: remaining '
1511 '[<binman.etype._testing.Entry__testing',
1514 def testEntryArgs(self):
1515 """Test passing arguments to entries from the command line"""
1517 'test-str-arg': 'test1',
1518 'test-int-arg': '456',
1520 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1521 self.assertIn('image', control.images)
1522 entry = control.images['image'].GetEntries()['_testing']
1523 self.assertEqual('test0', entry.test_str_fdt)
1524 self.assertEqual('test1', entry.test_str_arg)
1525 self.assertEqual(123, entry.test_int_fdt)
1526 self.assertEqual(456, entry.test_int_arg)
1528 def testEntryArgsMissing(self):
1529 """Test missing arguments and properties"""
1531 'test-int-arg': '456',
1533 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1534 entry = control.images['image'].GetEntries()['_testing']
1535 self.assertEqual('test0', entry.test_str_fdt)
1536 self.assertEqual(None, entry.test_str_arg)
1537 self.assertEqual(None, entry.test_int_fdt)
1538 self.assertEqual(456, entry.test_int_arg)
1540 def testEntryArgsRequired(self):
1541 """Test missing arguments and properties"""
1543 'test-int-arg': '456',
1545 with self.assertRaises(ValueError) as e:
1546 self._DoReadFileDtb('064_entry_args_required.dts')
1547 self.assertIn("Node '/binman/_testing': "
1548 'Missing required properties/entry args: test-str-arg, '
1549 'test-int-fdt, test-int-arg',
1552 def testEntryArgsInvalidFormat(self):
1553 """Test that an invalid entry-argument format is detected"""
1554 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1556 with self.assertRaises(ValueError) as e:
1557 self._DoBinman(*args)
1558 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1560 def testEntryArgsInvalidInteger(self):
1561 """Test that an invalid entry-argument integer is detected"""
1563 'test-int-arg': 'abc',
1565 with self.assertRaises(ValueError) as e:
1566 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1567 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1568 "'test-int-arg' (value 'abc') to integer",
1571 def testEntryArgsInvalidDatatype(self):
1572 """Test that an invalid entry-argument datatype is detected
1574 This test could be written in entry_test.py except that it needs
1575 access to control.entry_args, which seems more than that module should
1579 'test-bad-datatype-arg': '12',
1581 with self.assertRaises(ValueError) as e:
1582 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1583 entry_args=entry_args)
1584 self.assertIn('GetArg() internal error: Unknown data type ',
1588 """Test for a text entry type"""
1590 'test-id': TEXT_DATA,
1591 'test-id2': TEXT_DATA2,
1592 'test-id3': TEXT_DATA3,
1594 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1595 entry_args=entry_args)
1596 expected = (tools.to_bytes(TEXT_DATA) +
1597 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1598 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
1599 b'some text' + b'more text')
1600 self.assertEqual(expected, data)
1602 def testEntryDocs(self):
1603 """Test for creation of entry documentation"""
1604 with test_util.capture_sys_output() as (stdout, stderr):
1605 control.WriteEntryDocs(control.GetEntryModules())
1606 self.assertTrue(len(stdout.getvalue()) > 0)
1608 def testEntryDocsMissing(self):
1609 """Test handling of missing entry documentation"""
1610 with self.assertRaises(ValueError) as e:
1611 with test_util.capture_sys_output() as (stdout, stderr):
1612 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1613 self.assertIn('Documentation is missing for modules: u_boot',
1617 """Basic test of generation of a flashrom fmap"""
1618 data = self._DoReadFile('067_fmap.dts')
1619 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1620 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1621 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
1622 self.assertEqual(expected, data[:32])
1623 self.assertEqual(b'__FMAP__', fhdr.signature)
1624 self.assertEqual(1, fhdr.ver_major)
1625 self.assertEqual(0, fhdr.ver_minor)
1626 self.assertEqual(0, fhdr.base)
1627 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1628 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1629 self.assertEqual(b'FMAP', fhdr.name)
1630 self.assertEqual(5, fhdr.nareas)
1631 fiter = iter(fentries)
1633 fentry = next(fiter)
1634 self.assertEqual(b'SECTION0', fentry.name)
1635 self.assertEqual(0, fentry.offset)
1636 self.assertEqual(16, fentry.size)
1637 self.assertEqual(0, fentry.flags)
1639 fentry = next(fiter)
1640 self.assertEqual(b'RO_U_BOOT', fentry.name)
1641 self.assertEqual(0, fentry.offset)
1642 self.assertEqual(4, fentry.size)
1643 self.assertEqual(0, fentry.flags)
1645 fentry = next(fiter)
1646 self.assertEqual(b'SECTION1', fentry.name)
1647 self.assertEqual(16, fentry.offset)
1648 self.assertEqual(16, fentry.size)
1649 self.assertEqual(0, fentry.flags)
1651 fentry = next(fiter)
1652 self.assertEqual(b'RW_U_BOOT', fentry.name)
1653 self.assertEqual(16, fentry.offset)
1654 self.assertEqual(4, fentry.size)
1655 self.assertEqual(0, fentry.flags)
1657 fentry = next(fiter)
1658 self.assertEqual(b'FMAP', fentry.name)
1659 self.assertEqual(32, fentry.offset)
1660 self.assertEqual(expect_size, fentry.size)
1661 self.assertEqual(0, fentry.flags)
1663 def testBlobNamedByArg(self):
1664 """Test we can add a blob with the filename coming from an entry arg"""
1666 'cros-ec-rw-path': 'ecrw.bin',
1668 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1671 """Test for an fill entry type"""
1672 data = self._DoReadFile('069_fill.dts')
1673 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
1674 self.assertEqual(expected, data)
1676 def testFillNoSize(self):
1677 """Test for an fill entry type with no size"""
1678 with self.assertRaises(ValueError) as e:
1679 self._DoReadFile('070_fill_no_size.dts')
1680 self.assertIn("'fill' entry must have a size property",
1683 def _HandleGbbCommand(self, pipe_list):
1684 """Fake calls to the futility utility"""
1685 if pipe_list[0][0] == 'futility':
1686 fname = pipe_list[0][-1]
1687 # Append our GBB data to the file, which will happen every time the
1688 # futility command is called.
1689 with open(fname, 'ab') as fd:
1691 return command.CommandResult()
1694 """Test for the Chromium OS Google Binary Block"""
1695 command.test_result = self._HandleGbbCommand
1697 'keydir': 'devkeys',
1698 'bmpblk': 'bmpblk.bin',
1700 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1703 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1704 tools.get_bytes(0, 0x2180 - 16))
1705 self.assertEqual(expected, data)
1707 def testGbbTooSmall(self):
1708 """Test for the Chromium OS Google Binary Block being large enough"""
1709 with self.assertRaises(ValueError) as e:
1710 self._DoReadFileDtb('072_gbb_too_small.dts')
1711 self.assertIn("Node '/binman/gbb': GBB is too small",
1714 def testGbbNoSize(self):
1715 """Test for the Chromium OS Google Binary Block having a size"""
1716 with self.assertRaises(ValueError) as e:
1717 self._DoReadFileDtb('073_gbb_no_size.dts')
1718 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1721 def testGbbMissing(self):
1722 """Test that binman still produces an image if futility is missing"""
1724 'keydir': 'devkeys',
1726 with test_util.capture_sys_output() as (_, stderr):
1727 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1728 entry_args=entry_args)
1729 err = stderr.getvalue()
1730 self.assertRegex(err,
1731 "Image 'main-section'.*missing bintools.*: futility")
1733 def _HandleVblockCommand(self, pipe_list):
1734 """Fake calls to the futility utility
1736 The expected pipe is:
1738 [('futility', 'vbutil_firmware', '--vblock',
1739 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1740 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1741 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1742 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1744 This writes to the output file (here, 'vblock.vblock'). If
1745 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1746 of the input data (here, 'input.vblock').
1748 if pipe_list[0][0] == 'futility':
1749 fname = pipe_list[0][3]
1750 with open(fname, 'wb') as fd:
1752 infile = pipe_list[0][11]
1753 m = hashlib.sha256()
1754 data = tools.read_file(infile)
1756 fd.write(m.digest())
1758 fd.write(VBLOCK_DATA)
1760 return command.CommandResult()
1762 def testVblock(self):
1763 """Test for the Chromium OS Verified Boot Block"""
1764 self._hash_data = False
1765 command.test_result = self._HandleVblockCommand
1767 'keydir': 'devkeys',
1769 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1770 entry_args=entry_args)
1771 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1772 self.assertEqual(expected, data)
1774 def testVblockNoContent(self):
1775 """Test we detect a vblock which has no content to sign"""
1776 with self.assertRaises(ValueError) as e:
1777 self._DoReadFile('075_vblock_no_content.dts')
1778 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1779 'property', str(e.exception))
1781 def testVblockBadPhandle(self):
1782 """Test that we detect a vblock with an invalid phandle in contents"""
1783 with self.assertRaises(ValueError) as e:
1784 self._DoReadFile('076_vblock_bad_phandle.dts')
1785 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1786 '1000', str(e.exception))
1788 def testVblockBadEntry(self):
1789 """Test that we detect an entry that points to a non-entry"""
1790 with self.assertRaises(ValueError) as e:
1791 self._DoReadFile('077_vblock_bad_entry.dts')
1792 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1793 "'other'", str(e.exception))
1795 def testVblockContent(self):
1796 """Test that the vblock signs the right data"""
1797 self._hash_data = True
1798 command.test_result = self._HandleVblockCommand
1800 'keydir': 'devkeys',
1802 data = self._DoReadFileDtb(
1803 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1804 entry_args=entry_args)[0]
1805 hashlen = 32 # SHA256 hash is 32 bytes
1806 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1807 hashval = data[-hashlen:]
1808 dtb = data[len(U_BOOT_DATA):-hashlen]
1810 expected_data = U_BOOT_DATA + dtb
1812 # The hashval should be a hash of the dtb
1813 m = hashlib.sha256()
1814 m.update(expected_data)
1815 expected_hashval = m.digest()
1816 self.assertEqual(expected_hashval, hashval)
1818 def testVblockMissing(self):
1819 """Test that binman still produces an image if futility is missing"""
1821 'keydir': 'devkeys',
1823 with test_util.capture_sys_output() as (_, stderr):
1824 self._DoTestFile('074_vblock.dts',
1825 force_missing_bintools='futility',
1826 entry_args=entry_args)
1827 err = stderr.getvalue()
1828 self.assertRegex(err,
1829 "Image 'main-section'.*missing bintools.*: futility")
1832 """Test that an image with TPL and its device tree can be created"""
1833 # ELF file with a '__bss_size' symbol
1835 data = self._DoReadFile('078_u_boot_tpl.dts')
1836 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1838 def testUsesPos(self):
1839 """Test that the 'pos' property cannot be used anymore"""
1840 with self.assertRaises(ValueError) as e:
1841 data = self._DoReadFile('079_uses_pos.dts')
1842 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1843 "'pos'", str(e.exception))
1845 def testFillZero(self):
1846 """Test for an fill entry type with a size of 0"""
1847 data = self._DoReadFile('080_fill_empty.dts')
1848 self.assertEqual(tools.get_bytes(0, 16), data)
1850 def testTextMissing(self):
1851 """Test for a text entry type where there is no text"""
1852 with self.assertRaises(ValueError) as e:
1853 self._DoReadFileDtb('066_text.dts',)
1854 self.assertIn("Node '/binman/text': No value provided for text label "
1855 "'test-id'", str(e.exception))
1857 def testPackStart16Tpl(self):
1858 """Test that an image with an x86 start16 TPL region can be created"""
1859 data = self._DoReadFile('081_x86_start16_tpl.dts')
1860 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1862 def testSelectImage(self):
1863 """Test that we can select which images to build"""
1864 expected = 'Skipping images: image1'
1866 # We should only get the expected message in verbose mode
1867 for verbosity in (0, 2):
1868 with test_util.capture_sys_output() as (stdout, stderr):
1869 retcode = self._DoTestFile('006_dual_image.dts',
1870 verbosity=verbosity,
1872 self.assertEqual(0, retcode)
1874 self.assertIn(expected, stdout.getvalue())
1876 self.assertNotIn(expected, stdout.getvalue())
1878 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1879 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
1880 self._CleanupOutputDir()
1882 def testUpdateFdtAll(self):
1883 """Test that all device trees are updated with offset/size info"""
1884 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1887 'section:image-pos': 0,
1888 'u-boot-tpl-dtb:size': 513,
1889 'u-boot-spl-dtb:size': 513,
1890 'u-boot-spl-dtb:offset': 493,
1892 'section/u-boot-dtb:image-pos': 0,
1893 'u-boot-spl-dtb:image-pos': 493,
1894 'section/u-boot-dtb:size': 493,
1895 'u-boot-tpl-dtb:image-pos': 1006,
1896 'section/u-boot-dtb:offset': 0,
1897 'section:size': 493,
1899 'section:offset': 0,
1900 'u-boot-tpl-dtb:offset': 1006,
1904 # We expect three device-tree files in the output, one after the other.
1905 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1906 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1907 # main U-Boot tree. All three should have the same postions and offset.
1909 for item in ['', 'spl', 'tpl']:
1910 dtb = fdt.Fdt.FromData(data[start:])
1912 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1914 expected = dict(base_expected)
1917 self.assertEqual(expected, props)
1918 start += dtb._fdt_obj.totalsize()
1920 def testUpdateFdtOutput(self):
1921 """Test that output DTB files are updated"""
1923 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1924 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1926 # Unfortunately, compiling a source file always results in a file
1927 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1928 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1929 # binman as a file called u-boot.dtb. To fix this, copy the file
1930 # over to the expected place.
1932 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1933 'tpl/u-boot-tpl.dtb.out']:
1934 dtb = fdt.Fdt.FromData(data[start:])
1935 size = dtb._fdt_obj.totalsize()
1936 pathname = tools.get_output_filename(os.path.split(fname)[1])
1937 outdata = tools.read_file(pathname)
1938 name = os.path.split(fname)[0]
1941 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1943 orig_indata = dtb_data
1944 self.assertNotEqual(outdata, orig_indata,
1945 "Expected output file '%s' be updated" % pathname)
1946 self.assertEqual(outdata, data[start:start + size],
1947 "Expected output file '%s' to match output image" %
1953 def _decompress(self, data):
1954 return comp_util.decompress(data, 'lz4')
1956 def testCompress(self):
1957 """Test compression of blobs"""
1959 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1960 use_real_dtb=True, update_dtb=True)
1961 dtb = fdt.Fdt(out_dtb_fname)
1963 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1964 orig = self._decompress(data)
1965 self.assertEquals(COMPRESS_DATA, orig)
1967 # Do a sanity check on various fields
1968 image = control.images['image']
1969 entries = image.GetEntries()
1970 self.assertEqual(1, len(entries))
1972 entry = entries['blob']
1973 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1974 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1975 orig = self._decompress(entry.data)
1976 self.assertEqual(orig, entry.uncomp_data)
1978 self.assertEqual(image.data, entry.data)
1981 'blob:uncomp-size': len(COMPRESS_DATA),
1982 'blob:size': len(data),
1985 self.assertEqual(expected, props)
1987 def testFiles(self):
1988 """Test bringing in multiple files"""
1989 data = self._DoReadFile('084_files.dts')
1990 self.assertEqual(FILES_DATA, data)
1992 def testFilesCompress(self):
1993 """Test bringing in multiple files and compressing them"""
1995 data = self._DoReadFile('085_files_compress.dts')
1997 image = control.images['image']
1998 entries = image.GetEntries()
1999 files = entries['files']
2000 entries = files._entries
2003 for i in range(1, 3):
2005 start = entries[key].image_pos
2006 len = entries[key].size
2007 chunk = data[start:start + len]
2008 orig += self._decompress(chunk)
2010 self.assertEqual(FILES_DATA, orig)
2012 def testFilesMissing(self):
2013 """Test missing files"""
2014 with self.assertRaises(ValueError) as e:
2015 data = self._DoReadFile('086_files_none.dts')
2016 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2017 'no files', str(e.exception))
2019 def testFilesNoPattern(self):
2020 """Test missing files"""
2021 with self.assertRaises(ValueError) as e:
2022 data = self._DoReadFile('087_files_no_pattern.dts')
2023 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2026 def testExpandSize(self):
2027 """Test an expanding entry"""
2028 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
2030 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2031 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2032 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2033 tools.get_bytes(ord('d'), 8))
2034 self.assertEqual(expect, data)
2035 self.assertEqual('''ImagePos Offset Size Name
2036 00000000 00000000 00000028 main-section
2037 00000000 00000000 00000008 fill
2038 00000008 00000008 00000004 u-boot
2039 0000000c 0000000c 00000004 section
2040 0000000c 00000000 00000003 intel-mrc
2041 00000010 00000010 00000004 u-boot2
2042 00000014 00000014 0000000c section2
2043 00000014 00000000 00000008 fill
2044 0000001c 00000008 00000004 u-boot
2045 00000020 00000020 00000008 fill2
2048 def testExpandSizeBad(self):
2049 """Test an expanding entry which fails to provide contents"""
2050 with test_util.capture_sys_output() as (stdout, stderr):
2051 with self.assertRaises(ValueError) as e:
2052 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
2053 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2054 'expanding entry', str(e.exception))
2057 """Test hashing of the contents of an entry"""
2058 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2059 use_real_dtb=True, update_dtb=True)
2060 dtb = fdt.Fdt(out_dtb_fname)
2062 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2063 m = hashlib.sha256()
2064 m.update(U_BOOT_DATA)
2065 self.assertEqual(m.digest(), b''.join(hash_node.value))
2067 def testHashNoAlgo(self):
2068 with self.assertRaises(ValueError) as e:
2069 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2070 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2071 'hash node', str(e.exception))
2073 def testHashBadAlgo(self):
2074 with self.assertRaises(ValueError) as e:
2075 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2076 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2079 def testHashSection(self):
2080 """Test hashing of the contents of an entry"""
2081 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2082 use_real_dtb=True, update_dtb=True)
2083 dtb = fdt.Fdt(out_dtb_fname)
2085 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2086 m = hashlib.sha256()
2087 m.update(U_BOOT_DATA)
2088 m.update(tools.get_bytes(ord('a'), 16))
2089 self.assertEqual(m.digest(), b''.join(hash_node.value))
2091 def testPackUBootTplMicrocode(self):
2092 """Test that x86 microcode can be handled correctly in TPL
2094 We expect to see the following in the image, in order:
2095 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2097 u-boot-tpl.dtb with the microcode removed
2100 self._SetupTplElf('u_boot_ucode_ptr')
2101 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2102 U_BOOT_TPL_NODTB_DATA)
2103 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2104 b'ter somewhere in here', first)
2106 def testFmapX86(self):
2107 """Basic test of generation of a flashrom fmap"""
2108 data = self._DoReadFile('094_fmap_x86.dts')
2109 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2110 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
2111 self.assertEqual(expected, data[:32])
2112 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2114 self.assertEqual(0x100, fhdr.image_size)
2116 self.assertEqual(0, fentries[0].offset)
2117 self.assertEqual(4, fentries[0].size)
2118 self.assertEqual(b'U_BOOT', fentries[0].name)
2120 self.assertEqual(4, fentries[1].offset)
2121 self.assertEqual(3, fentries[1].size)
2122 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2124 self.assertEqual(32, fentries[2].offset)
2125 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2126 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2127 self.assertEqual(b'FMAP', fentries[2].name)
2129 def testFmapX86Section(self):
2130 """Basic test of generation of a flashrom fmap"""
2131 data = self._DoReadFile('095_fmap_x86_section.dts')
2132 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
2133 self.assertEqual(expected, data[:32])
2134 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2136 self.assertEqual(0x180, fhdr.image_size)
2137 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2138 fiter = iter(fentries)
2140 fentry = next(fiter)
2141 self.assertEqual(b'U_BOOT', fentry.name)
2142 self.assertEqual(0, fentry.offset)
2143 self.assertEqual(4, fentry.size)
2145 fentry = next(fiter)
2146 self.assertEqual(b'SECTION', fentry.name)
2147 self.assertEqual(4, fentry.offset)
2148 self.assertEqual(0x20 + expect_size, fentry.size)
2150 fentry = next(fiter)
2151 self.assertEqual(b'INTEL_MRC', fentry.name)
2152 self.assertEqual(4, fentry.offset)
2153 self.assertEqual(3, fentry.size)
2155 fentry = next(fiter)
2156 self.assertEqual(b'FMAP', fentry.name)
2157 self.assertEqual(36, fentry.offset)
2158 self.assertEqual(expect_size, fentry.size)
2161 """Basic test of ELF entries"""
2164 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2165 TestFunctional._MakeInputFile('-boot', fd.read())
2166 data = self._DoReadFile('096_elf.dts')
2168 def testElfStrip(self):
2169 """Basic test of ELF entries"""
2171 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2172 TestFunctional._MakeInputFile('-boot', fd.read())
2173 data = self._DoReadFile('097_elf_strip.dts')
2175 def testPackOverlapMap(self):
2176 """Test that overlapping regions are detected"""
2177 with test_util.capture_sys_output() as (stdout, stderr):
2178 with self.assertRaises(ValueError) as e:
2179 self._DoTestFile('014_pack_overlap.dts', map=True)
2180 map_fname = tools.get_output_filename('image.map')
2181 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2184 # We should not get an inmage, but there should be a map file
2185 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
2186 self.assertTrue(os.path.exists(map_fname))
2187 map_data = tools.read_file(map_fname, binary=False)
2188 self.assertEqual('''ImagePos Offset Size Name
2189 <none> 00000000 00000008 main-section
2190 <none> 00000000 00000004 u-boot
2191 <none> 00000003 00000004 u-boot-align
2194 def testPackRefCode(self):
2195 """Test that an image with an Intel Reference code binary works"""
2196 data = self._DoReadFile('100_intel_refcode.dts')
2197 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2199 def testSectionOffset(self):
2200 """Tests use of a section with an offset"""
2201 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2203 self.assertEqual('''ImagePos Offset Size Name
2204 00000000 00000000 00000038 main-section
2205 00000004 00000004 00000010 section@0
2206 00000004 00000000 00000004 u-boot
2207 00000018 00000018 00000010 section@1
2208 00000018 00000000 00000004 u-boot
2209 0000002c 0000002c 00000004 section@2
2210 0000002c 00000000 00000004 u-boot
2212 self.assertEqual(data,
2213 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2214 tools.get_bytes(0x21, 12) +
2215 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2216 tools.get_bytes(0x61, 12) +
2217 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2218 tools.get_bytes(0x26, 8))
2220 def testCbfsRaw(self):
2221 """Test base handling of a Coreboot Filesystem (CBFS)
2223 The exact contents of the CBFS is verified by similar tests in
2224 cbfs_util_test.py. The tests here merely check that the files added to
2225 the CBFS can be found in the final image.
2227 data = self._DoReadFile('102_cbfs_raw.dts')
2230 cbfs = cbfs_util.CbfsReader(data)
2231 self.assertEqual(size, cbfs.rom_size)
2233 self.assertIn('u-boot-dtb', cbfs.files)
2234 cfile = cbfs.files['u-boot-dtb']
2235 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2237 def testCbfsArch(self):
2238 """Test on non-x86 architecture"""
2239 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2242 cbfs = cbfs_util.CbfsReader(data)
2243 self.assertEqual(size, cbfs.rom_size)
2245 self.assertIn('u-boot-dtb', cbfs.files)
2246 cfile = cbfs.files['u-boot-dtb']
2247 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2249 def testCbfsStage(self):
2250 """Tests handling of a Coreboot Filesystem (CBFS)"""
2251 if not elf.ELF_TOOLS:
2252 self.skipTest('Python elftools not available')
2253 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2254 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2257 data = self._DoReadFile('104_cbfs_stage.dts')
2258 cbfs = cbfs_util.CbfsReader(data)
2259 self.assertEqual(size, cbfs.rom_size)
2261 self.assertIn('u-boot', cbfs.files)
2262 cfile = cbfs.files['u-boot']
2263 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2265 def testCbfsRawCompress(self):
2266 """Test handling of compressing raw files"""
2268 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2271 cbfs = cbfs_util.CbfsReader(data)
2272 self.assertIn('u-boot', cbfs.files)
2273 cfile = cbfs.files['u-boot']
2274 self.assertEqual(COMPRESS_DATA, cfile.data)
2276 def testCbfsBadArch(self):
2277 """Test handling of a bad architecture"""
2278 with self.assertRaises(ValueError) as e:
2279 self._DoReadFile('106_cbfs_bad_arch.dts')
2280 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2282 def testCbfsNoSize(self):
2283 """Test handling of a missing size property"""
2284 with self.assertRaises(ValueError) as e:
2285 self._DoReadFile('107_cbfs_no_size.dts')
2286 self.assertIn('entry must have a size property', str(e.exception))
2288 def testCbfsNoContents(self):
2289 """Test handling of a CBFS entry which does not provide contentsy"""
2290 with self.assertRaises(ValueError) as e:
2291 self._DoReadFile('108_cbfs_no_contents.dts')
2292 self.assertIn('Could not complete processing of contents',
2295 def testCbfsBadCompress(self):
2296 """Test handling of a bad architecture"""
2297 with self.assertRaises(ValueError) as e:
2298 self._DoReadFile('109_cbfs_bad_compress.dts')
2299 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2302 def testCbfsNamedEntries(self):
2303 """Test handling of named entries"""
2304 data = self._DoReadFile('110_cbfs_name.dts')
2306 cbfs = cbfs_util.CbfsReader(data)
2307 self.assertIn('FRED', cbfs.files)
2308 cfile1 = cbfs.files['FRED']
2309 self.assertEqual(U_BOOT_DATA, cfile1.data)
2311 self.assertIn('hello', cbfs.files)
2312 cfile2 = cbfs.files['hello']
2313 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2315 def _SetupIfwi(self, fname):
2316 """Set up to run an IFWI test
2319 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2324 # Intel Integrated Firmware Image (IFWI) file
2325 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2327 TestFunctional._MakeInputFile(fname,data)
2329 def _CheckIfwi(self, data):
2330 """Check that an image with an IFWI contains the correct output
2333 data: Conents of output file
2335 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
2336 if data[:0x1000] != expected_desc:
2337 self.fail('Expected descriptor binary at start of image')
2339 # We expect to find the TPL wil in subpart IBBP entry IBBL
2340 image_fname = tools.get_output_filename('image.bin')
2341 tpl_fname = tools.get_output_filename('tpl.out')
2342 ifwitool = bintool.Bintool.create('ifwitool')
2343 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
2345 tpl_data = tools.read_file(tpl_fname)
2346 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2348 def testPackX86RomIfwi(self):
2349 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2350 self._SetupIfwi('fitimage.bin')
2351 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2352 self._CheckIfwi(data)
2354 def testPackX86RomIfwiNoDesc(self):
2355 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2356 self._SetupIfwi('ifwi.bin')
2357 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2358 self._CheckIfwi(data)
2360 def testPackX86RomIfwiNoData(self):
2361 """Test that an x86 ROM with IFWI handles missing data"""
2362 self._SetupIfwi('ifwi.bin')
2363 with self.assertRaises(ValueError) as e:
2364 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2365 self.assertIn('Could not complete processing of contents',
2368 def testIfwiMissing(self):
2369 """Test that binman still produces an image if ifwitool is missing"""
2370 self._SetupIfwi('fitimage.bin')
2371 with test_util.capture_sys_output() as (_, stderr):
2372 self._DoTestFile('111_x86_rom_ifwi.dts',
2373 force_missing_bintools='ifwitool')
2374 err = stderr.getvalue()
2375 self.assertRegex(err,
2376 "Image 'main-section'.*missing bintools.*: ifwitool")
2378 def testCbfsOffset(self):
2379 """Test a CBFS with files at particular offsets
2381 Like all CFBS tests, this is just checking the logic that calls
2382 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2384 data = self._DoReadFile('114_cbfs_offset.dts')
2387 cbfs = cbfs_util.CbfsReader(data)
2388 self.assertEqual(size, cbfs.rom_size)
2390 self.assertIn('u-boot', cbfs.files)
2391 cfile = cbfs.files['u-boot']
2392 self.assertEqual(U_BOOT_DATA, cfile.data)
2393 self.assertEqual(0x40, cfile.cbfs_offset)
2395 self.assertIn('u-boot-dtb', cbfs.files)
2396 cfile2 = cbfs.files['u-boot-dtb']
2397 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2398 self.assertEqual(0x140, cfile2.cbfs_offset)
2400 def testFdtmap(self):
2401 """Test an FDT map can be inserted in the image"""
2402 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2403 fdtmap_data = data[len(U_BOOT_DATA):]
2404 magic = fdtmap_data[:8]
2405 self.assertEqual(b'_FDTMAP_', magic)
2406 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
2408 fdt_data = fdtmap_data[16:]
2409 dtb = fdt.Fdt.FromData(fdt_data)
2411 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2416 'u-boot:size': len(U_BOOT_DATA),
2417 'u-boot:image-pos': 0,
2418 'fdtmap:image-pos': 4,
2420 'fdtmap:size': len(fdtmap_data),
2424 def testFdtmapNoMatch(self):
2425 """Check handling of an FDT map when the section cannot be found"""
2426 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2428 # Mangle the section name, which should cause a mismatch between the
2429 # correct FDT path and the one expected by the section
2430 image = control.images['image']
2431 image._node.path += '-suffix'
2432 entries = image.GetEntries()
2433 fdtmap = entries['fdtmap']
2434 with self.assertRaises(ValueError) as e:
2436 self.assertIn("Cannot locate node for path '/binman-suffix'",
2439 def testFdtmapHeader(self):
2440 """Test an FDT map and image header can be inserted in the image"""
2441 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2442 fdtmap_pos = len(U_BOOT_DATA)
2443 fdtmap_data = data[fdtmap_pos:]
2444 fdt_data = fdtmap_data[16:]
2445 dtb = fdt.Fdt.FromData(fdt_data)
2446 fdt_size = dtb.GetFdtObj().totalsize()
2447 hdr_data = data[-8:]
2448 self.assertEqual(b'BinM', hdr_data[:4])
2449 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2450 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2452 def testFdtmapHeaderStart(self):
2453 """Test an image header can be inserted at the image start"""
2454 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2455 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2457 self.assertEqual(b'BinM', hdr_data[:4])
2458 offset = struct.unpack('<I', hdr_data[4:])[0]
2459 self.assertEqual(fdtmap_pos, offset)
2461 def testFdtmapHeaderPos(self):
2462 """Test an image header can be inserted at a chosen position"""
2463 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2464 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2465 hdr_data = data[0x80:0x88]
2466 self.assertEqual(b'BinM', hdr_data[:4])
2467 offset = struct.unpack('<I', hdr_data[4:])[0]
2468 self.assertEqual(fdtmap_pos, offset)
2470 def testHeaderMissingFdtmap(self):
2471 """Test an image header requires an fdtmap"""
2472 with self.assertRaises(ValueError) as e:
2473 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2474 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2477 def testHeaderNoLocation(self):
2478 """Test an image header with a no specified location is detected"""
2479 with self.assertRaises(ValueError) as e:
2480 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2481 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2484 def testEntryExpand(self):
2485 """Test expanding an entry after it is packed"""
2486 data = self._DoReadFile('121_entry_expand.dts')
2487 self.assertEqual(b'aaa', data[:3])
2488 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2489 self.assertEqual(b'aaa', data[-3:])
2491 def testEntryExpandBad(self):
2492 """Test expanding an entry after it is packed, twice"""
2493 with self.assertRaises(ValueError) as e:
2494 self._DoReadFile('122_entry_expand_twice.dts')
2495 self.assertIn("Image '/binman': Entries changed size after packing",
2498 def testEntryExpandSection(self):
2499 """Test expanding an entry within a section after it is packed"""
2500 data = self._DoReadFile('123_entry_expand_section.dts')
2501 self.assertEqual(b'aaa', data[:3])
2502 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2503 self.assertEqual(b'aaa', data[-3:])
2505 def testCompressDtb(self):
2506 """Test that compress of device-tree files is supported"""
2508 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2509 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2510 comp_data = data[len(U_BOOT_DATA):]
2511 orig = self._decompress(comp_data)
2512 dtb = fdt.Fdt.FromData(orig)
2514 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2516 'u-boot:size': len(U_BOOT_DATA),
2517 'u-boot-dtb:uncomp-size': len(orig),
2518 'u-boot-dtb:size': len(comp_data),
2521 self.assertEqual(expected, props)
2523 def testCbfsUpdateFdt(self):
2524 """Test that we can update the device tree with CBFS offset/size info"""
2526 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2528 dtb = fdt.Fdt(out_dtb_fname)
2530 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2531 del props['cbfs/u-boot:size']
2537 'cbfs:size': len(data),
2538 'cbfs:image-pos': 0,
2539 'cbfs/u-boot:offset': 0x38,
2540 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2541 'cbfs/u-boot:image-pos': 0x38,
2542 'cbfs/u-boot-dtb:offset': 0xb8,
2543 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2544 'cbfs/u-boot-dtb:image-pos': 0xb8,
2547 def testCbfsBadType(self):
2548 """Test an image header with a no specified location is detected"""
2549 with self.assertRaises(ValueError) as e:
2550 self._DoReadFile('126_cbfs_bad_type.dts')
2551 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2554 """Test listing the files in an image"""
2556 data = self._DoReadFile('127_list.dts')
2557 image = control.images['image']
2558 entries = image.BuildEntryList()
2559 self.assertEqual(7, len(entries))
2562 self.assertEqual(0, ent.indent)
2563 self.assertEqual('main-section', ent.name)
2564 self.assertEqual('section', ent.etype)
2565 self.assertEqual(len(data), ent.size)
2566 self.assertEqual(0, ent.image_pos)
2567 self.assertEqual(None, ent.uncomp_size)
2568 self.assertEqual(0, ent.offset)
2571 self.assertEqual(1, ent.indent)
2572 self.assertEqual('u-boot', ent.name)
2573 self.assertEqual('u-boot', ent.etype)
2574 self.assertEqual(len(U_BOOT_DATA), ent.size)
2575 self.assertEqual(0, ent.image_pos)
2576 self.assertEqual(None, ent.uncomp_size)
2577 self.assertEqual(0, ent.offset)
2580 self.assertEqual(1, ent.indent)
2581 self.assertEqual('section', ent.name)
2582 self.assertEqual('section', ent.etype)
2583 section_size = ent.size
2584 self.assertEqual(0x100, ent.image_pos)
2585 self.assertEqual(None, ent.uncomp_size)
2586 self.assertEqual(0x100, ent.offset)
2589 self.assertEqual(2, ent.indent)
2590 self.assertEqual('cbfs', ent.name)
2591 self.assertEqual('cbfs', ent.etype)
2592 self.assertEqual(0x400, ent.size)
2593 self.assertEqual(0x100, ent.image_pos)
2594 self.assertEqual(None, ent.uncomp_size)
2595 self.assertEqual(0, ent.offset)
2598 self.assertEqual(3, ent.indent)
2599 self.assertEqual('u-boot', ent.name)
2600 self.assertEqual('u-boot', ent.etype)
2601 self.assertEqual(len(U_BOOT_DATA), ent.size)
2602 self.assertEqual(0x138, ent.image_pos)
2603 self.assertEqual(None, ent.uncomp_size)
2604 self.assertEqual(0x38, ent.offset)
2607 self.assertEqual(3, ent.indent)
2608 self.assertEqual('u-boot-dtb', ent.name)
2609 self.assertEqual('text', ent.etype)
2610 self.assertGreater(len(COMPRESS_DATA), ent.size)
2611 self.assertEqual(0x178, ent.image_pos)
2612 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2613 self.assertEqual(0x78, ent.offset)
2616 self.assertEqual(2, ent.indent)
2617 self.assertEqual('u-boot-dtb', ent.name)
2618 self.assertEqual('u-boot-dtb', ent.etype)
2619 self.assertEqual(0x500, ent.image_pos)
2620 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2622 # Compressing this data expands it since headers are added
2623 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2624 self.assertEqual(0x400, ent.offset)
2626 self.assertEqual(len(data), 0x100 + section_size)
2627 self.assertEqual(section_size, 0x400 + dtb_size)
2629 def testFindFdtmap(self):
2630 """Test locating an FDT map in an image"""
2632 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2633 image = control.images['image']
2634 entries = image.GetEntries()
2635 entry = entries['fdtmap']
2636 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2638 def testFindFdtmapMissing(self):
2639 """Test failing to locate an FDP map"""
2640 data = self._DoReadFile('005_simple.dts')
2641 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2643 def testFindImageHeader(self):
2644 """Test locating a image header"""
2646 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2647 image = control.images['image']
2648 entries = image.GetEntries()
2649 entry = entries['fdtmap']
2650 # The header should point to the FDT map
2651 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2653 def testFindImageHeaderStart(self):
2654 """Test locating a image header located at the start of an image"""
2655 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2656 image = control.images['image']
2657 entries = image.GetEntries()
2658 entry = entries['fdtmap']
2659 # The header should point to the FDT map
2660 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2662 def testFindImageHeaderMissing(self):
2663 """Test failing to locate an image header"""
2664 data = self._DoReadFile('005_simple.dts')
2665 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2667 def testReadImage(self):
2668 """Test reading an image and accessing its FDT map"""
2670 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2671 image_fname = tools.get_output_filename('image.bin')
2672 orig_image = control.images['image']
2673 image = Image.FromFile(image_fname)
2674 self.assertEqual(orig_image.GetEntries().keys(),
2675 image.GetEntries().keys())
2677 orig_entry = orig_image.GetEntries()['fdtmap']
2678 entry = image.GetEntries()['fdtmap']
2679 self.assertEquals(orig_entry.offset, entry.offset)
2680 self.assertEquals(orig_entry.size, entry.size)
2681 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2683 def testReadImageNoHeader(self):
2684 """Test accessing an image's FDT map without an image header"""
2686 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2687 image_fname = tools.get_output_filename('image.bin')
2688 image = Image.FromFile(image_fname)
2689 self.assertTrue(isinstance(image, Image))
2690 self.assertEqual('image', image.image_name[-5:])
2692 def testReadImageFail(self):
2693 """Test failing to read an image image's FDT map"""
2694 self._DoReadFile('005_simple.dts')
2695 image_fname = tools.get_output_filename('image.bin')
2696 with self.assertRaises(ValueError) as e:
2697 image = Image.FromFile(image_fname)
2698 self.assertIn("Cannot find FDT map in image", str(e.exception))
2700 def testListCmd(self):
2701 """Test listing the files in an image using an Fdtmap"""
2703 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2705 # lz4 compression size differs depending on the version
2706 image = control.images['image']
2707 entries = image.GetEntries()
2708 section_size = entries['section'].size
2709 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2710 fdtmap_offset = entries['fdtmap'].offset
2713 tmpdir, updated_fname = self._SetupImageInTmpdir()
2714 with test_util.capture_sys_output() as (stdout, stderr):
2715 self._DoBinman('ls', '-i', updated_fname)
2717 shutil.rmtree(tmpdir)
2718 lines = stdout.getvalue().splitlines()
2720 'Name Image-pos Size Entry-type Offset Uncomp-size',
2721 '----------------------------------------------------------------------',
2722 'main-section 0 c00 section 0',
2723 ' u-boot 0 4 u-boot 0',
2724 ' section 100 %x section 100' % section_size,
2725 ' cbfs 100 400 cbfs 0',
2726 ' u-boot 138 4 u-boot 38',
2727 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2728 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2729 ' fdtmap %x 3bd fdtmap %x' %
2730 (fdtmap_offset, fdtmap_offset),
2731 ' image-header bf8 8 image-header bf8',
2733 self.assertEqual(expected, lines)
2735 def testListCmdFail(self):
2736 """Test failing to list an image"""
2737 self._DoReadFile('005_simple.dts')
2739 tmpdir, updated_fname = self._SetupImageInTmpdir()
2740 with self.assertRaises(ValueError) as e:
2741 self._DoBinman('ls', '-i', updated_fname)
2743 shutil.rmtree(tmpdir)
2744 self.assertIn("Cannot find FDT map in image", str(e.exception))
2746 def _RunListCmd(self, paths, expected):
2747 """List out entries and check the result
2750 paths: List of paths to pass to the list command
2751 expected: Expected list of filenames to be returned, in order
2754 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2755 image_fname = tools.get_output_filename('image.bin')
2756 image = Image.FromFile(image_fname)
2757 lines = image.GetListEntries(paths)[1]
2758 files = [line[0].strip() for line in lines[1:]]
2759 self.assertEqual(expected, files)
2761 def testListCmdSection(self):
2762 """Test listing the files in a section"""
2763 self._RunListCmd(['section'],
2764 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2766 def testListCmdFile(self):
2767 """Test listing a particular file"""
2768 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2770 def testListCmdWildcard(self):
2771 """Test listing a wildcarded file"""
2772 self._RunListCmd(['*boot*'],
2773 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2775 def testListCmdWildcardMulti(self):
2776 """Test listing a wildcarded file"""
2777 self._RunListCmd(['*cb*', '*head*'],
2778 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2780 def testListCmdEmpty(self):
2781 """Test listing a wildcarded file"""
2782 self._RunListCmd(['nothing'], [])
2784 def testListCmdPath(self):
2785 """Test listing the files in a sub-entry of a section"""
2786 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2788 def _RunExtractCmd(self, entry_name, decomp=True):
2789 """Extract an entry from an image
2792 entry_name: Entry name to extract
2793 decomp: True to decompress the data if compressed, False to leave
2794 it in its raw uncompressed format
2800 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2801 image_fname = tools.get_output_filename('image.bin')
2802 return control.ReadEntry(image_fname, entry_name, decomp)
2804 def testExtractSimple(self):
2805 """Test extracting a single file"""
2806 data = self._RunExtractCmd('u-boot')
2807 self.assertEqual(U_BOOT_DATA, data)
2809 def testExtractSection(self):
2810 """Test extracting the files in a section"""
2811 data = self._RunExtractCmd('section')
2812 cbfs_data = data[:0x400]
2813 cbfs = cbfs_util.CbfsReader(cbfs_data)
2814 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2815 dtb_data = data[0x400:]
2816 dtb = self._decompress(dtb_data)
2817 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2819 def testExtractCompressed(self):
2820 """Test extracting compressed data"""
2821 data = self._RunExtractCmd('section/u-boot-dtb')
2822 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2824 def testExtractRaw(self):
2825 """Test extracting compressed data without decompressing it"""
2826 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2827 dtb = self._decompress(data)
2828 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2830 def testExtractCbfs(self):
2831 """Test extracting CBFS data"""
2832 data = self._RunExtractCmd('section/cbfs/u-boot')
2833 self.assertEqual(U_BOOT_DATA, data)
2835 def testExtractCbfsCompressed(self):
2836 """Test extracting CBFS compressed data"""
2837 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2838 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2840 def testExtractCbfsRaw(self):
2841 """Test extracting CBFS compressed data without decompressing it"""
2842 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2843 dtb = comp_util.decompress(data, 'lzma', with_header=False)
2844 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2846 def testExtractBadEntry(self):
2847 """Test extracting a bad section path"""
2848 with self.assertRaises(ValueError) as e:
2849 self._RunExtractCmd('section/does-not-exist')
2850 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2853 def testExtractMissingFile(self):
2854 """Test extracting file that does not exist"""
2855 with self.assertRaises(IOError) as e:
2856 control.ReadEntry('missing-file', 'name')
2858 def testExtractBadFile(self):
2859 """Test extracting an invalid file"""
2860 fname = os.path.join(self._indir, 'badfile')
2861 tools.write_file(fname, b'')
2862 with self.assertRaises(ValueError) as e:
2863 control.ReadEntry(fname, 'name')
2865 def testExtractCmd(self):
2866 """Test extracting a file fron an image on the command line"""
2868 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2869 fname = os.path.join(self._indir, 'output.extact')
2871 tmpdir, updated_fname = self._SetupImageInTmpdir()
2872 with test_util.capture_sys_output() as (stdout, stderr):
2873 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2876 shutil.rmtree(tmpdir)
2877 data = tools.read_file(fname)
2878 self.assertEqual(U_BOOT_DATA, data)
2880 def testExtractOneEntry(self):
2881 """Test extracting a single entry fron an image """
2883 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2884 image_fname = tools.get_output_filename('image.bin')
2885 fname = os.path.join(self._indir, 'output.extact')
2886 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2887 data = tools.read_file(fname)
2888 self.assertEqual(U_BOOT_DATA, data)
2890 def _CheckExtractOutput(self, decomp):
2891 """Helper to test file output with and without decompression
2894 decomp: True to decompress entry data, False to output it raw
2896 def _CheckPresent(entry_path, expect_data, expect_size=None):
2897 """Check and remove expected file
2899 This checks the data/size of a file and removes the file both from
2900 the outfiles set and from the output directory. Once all files are
2901 processed, both the set and directory should be empty.
2904 entry_path: Entry path
2905 expect_data: Data to expect in file, or None to skip check
2906 expect_size: Size of data to expect in file, or None to skip
2908 path = os.path.join(outdir, entry_path)
2909 data = tools.read_file(path)
2912 self.assertEqual(expect_data, data)
2914 self.assertEqual(expect_size, len(data))
2915 outfiles.remove(path)
2917 def _CheckDirPresent(name):
2918 """Remove expected directory
2920 This gives an error if the directory does not exist as expected
2923 name: Name of directory to remove
2925 path = os.path.join(outdir, name)
2928 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2929 image_fname = tools.get_output_filename('image.bin')
2930 outdir = os.path.join(self._indir, 'extract')
2931 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2933 # Create a set of all file that were output (should be 9)
2935 for root, dirs, files in os.walk(outdir):
2936 outfiles |= set([os.path.join(root, fname) for fname in files])
2937 self.assertEqual(9, len(outfiles))
2938 self.assertEqual(9, len(einfos))
2940 image = control.images['image']
2941 entries = image.GetEntries()
2943 # Check the 9 files in various ways
2944 section = entries['section']
2945 section_entries = section.GetEntries()
2946 cbfs_entries = section_entries['cbfs'].GetEntries()
2947 _CheckPresent('u-boot', U_BOOT_DATA)
2948 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2949 dtb_len = EXTRACT_DTB_SIZE
2951 dtb_len = cbfs_entries['u-boot-dtb'].size
2952 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2954 dtb_len = section_entries['u-boot-dtb'].size
2955 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2957 fdtmap = entries['fdtmap']
2958 _CheckPresent('fdtmap', fdtmap.data)
2959 hdr = entries['image-header']
2960 _CheckPresent('image-header', hdr.data)
2962 _CheckPresent('section/root', section.data)
2963 cbfs = section_entries['cbfs']
2964 _CheckPresent('section/cbfs/root', cbfs.data)
2965 data = tools.read_file(image_fname)
2966 _CheckPresent('root', data)
2968 # There should be no files left. Remove all the directories to check.
2969 # If there are any files/dirs remaining, one of these checks will fail.
2970 self.assertEqual(0, len(outfiles))
2971 _CheckDirPresent('section/cbfs')
2972 _CheckDirPresent('section')
2973 _CheckDirPresent('')
2974 self.assertFalse(os.path.exists(outdir))
2976 def testExtractAllEntries(self):
2977 """Test extracting all entries"""
2979 self._CheckExtractOutput(decomp=True)
2981 def testExtractAllEntriesRaw(self):
2982 """Test extracting all entries without decompressing them"""
2984 self._CheckExtractOutput(decomp=False)
2986 def testExtractSelectedEntries(self):
2987 """Test extracting some entries"""
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2990 image_fname = tools.get_output_filename('image.bin')
2991 outdir = os.path.join(self._indir, 'extract')
2992 einfos = control.ExtractEntries(image_fname, None, outdir,
2995 # File output is tested by testExtractAllEntries(), so just check that
2996 # the expected entries are selected
2997 names = [einfo.name for einfo in einfos]
2998 self.assertEqual(names,
2999 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3001 def testExtractNoEntryPaths(self):
3002 """Test extracting some entries"""
3004 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3005 image_fname = tools.get_output_filename('image.bin')
3006 with self.assertRaises(ValueError) as e:
3007 control.ExtractEntries(image_fname, 'fname', None, [])
3008 self.assertIn('Must specify an entry path to write with -f',
3011 def testExtractTooManyEntryPaths(self):
3012 """Test extracting some entries"""
3014 self._DoReadFileRealDtb('130_list_fdtmap.dts')
3015 image_fname = tools.get_output_filename('image.bin')
3016 with self.assertRaises(ValueError) as e:
3017 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
3018 self.assertIn('Must specify exactly one entry path to write with -f',
3021 def testPackAlignSection(self):
3022 """Test that sections can have alignment"""
3023 self._DoReadFile('131_pack_align_section.dts')
3025 self.assertIn('image', control.images)
3026 image = control.images['image']
3027 entries = image.GetEntries()
3028 self.assertEqual(3, len(entries))
3031 self.assertIn('u-boot', entries)
3032 entry = entries['u-boot']
3033 self.assertEqual(0, entry.offset)
3034 self.assertEqual(0, entry.image_pos)
3035 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3036 self.assertEqual(len(U_BOOT_DATA), entry.size)
3039 self.assertIn('section0', entries)
3040 section0 = entries['section0']
3041 self.assertEqual(0x10, section0.offset)
3042 self.assertEqual(0x10, section0.image_pos)
3043 self.assertEqual(len(U_BOOT_DATA), section0.size)
3046 section_entries = section0.GetEntries()
3047 self.assertIn('u-boot', section_entries)
3048 entry = section_entries['u-boot']
3049 self.assertEqual(0, entry.offset)
3050 self.assertEqual(0x10, entry.image_pos)
3051 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3052 self.assertEqual(len(U_BOOT_DATA), entry.size)
3055 self.assertIn('section1', entries)
3056 section1 = entries['section1']
3057 self.assertEqual(0x14, section1.offset)
3058 self.assertEqual(0x14, section1.image_pos)
3059 self.assertEqual(0x20, section1.size)
3062 section_entries = section1.GetEntries()
3063 self.assertIn('u-boot', section_entries)
3064 entry = section_entries['u-boot']
3065 self.assertEqual(0, entry.offset)
3066 self.assertEqual(0x14, entry.image_pos)
3067 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3068 self.assertEqual(len(U_BOOT_DATA), entry.size)
3071 self.assertIn('section2', section_entries)
3072 section2 = section_entries['section2']
3073 self.assertEqual(0x4, section2.offset)
3074 self.assertEqual(0x18, section2.image_pos)
3075 self.assertEqual(4, section2.size)
3078 section_entries = section2.GetEntries()
3079 self.assertIn('u-boot', section_entries)
3080 entry = section_entries['u-boot']
3081 self.assertEqual(0, entry.offset)
3082 self.assertEqual(0x18, entry.image_pos)
3083 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3084 self.assertEqual(len(U_BOOT_DATA), entry.size)
3086 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3087 dts='132_replace.dts'):
3088 """Replace an entry in an image
3090 This writes the entry data to update it, then opens the updated file and
3091 returns the value that it now finds there.
3094 entry_name: Entry name to replace
3095 data: Data to replace it with
3096 decomp: True to compress the data if needed, False if data is
3097 already compressed so should be used as is
3098 allow_resize: True to allow entries to change size, False to raise
3104 data from fdtmap (excluding header)
3105 Image object that was modified
3107 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3110 self.assertIn('image', control.images)
3111 image = control.images['image']
3112 entries = image.GetEntries()
3113 orig_dtb_data = entries['u-boot-dtb'].data
3114 orig_fdtmap_data = entries['fdtmap'].data
3116 image_fname = tools.get_output_filename('image.bin')
3117 updated_fname = tools.get_output_filename('image-updated.bin')
3118 tools.write_file(updated_fname, tools.read_file(image_fname))
3119 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3121 data = control.ReadEntry(updated_fname, entry_name, decomp)
3123 # The DT data should not change unless resized:
3124 if not allow_resize:
3125 new_dtb_data = entries['u-boot-dtb'].data
3126 self.assertEqual(new_dtb_data, orig_dtb_data)
3127 new_fdtmap_data = entries['fdtmap'].data
3128 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3130 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3132 def testReplaceSimple(self):
3133 """Test replacing a single file"""
3134 expected = b'x' * len(U_BOOT_DATA)
3135 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3137 self.assertEqual(expected, data)
3139 # Test that the state looks right. There should be an FDT for the fdtmap
3140 # that we jsut read back in, and it should match what we find in the
3141 # 'control' tables. Checking for an FDT that does not exist should
3143 path, fdtmap = state.GetFdtContents('fdtmap')
3144 self.assertIsNotNone(path)
3145 self.assertEqual(expected_fdtmap, fdtmap)
3147 dtb = state.GetFdtForEtype('fdtmap')
3148 self.assertEqual(dtb.GetContents(), fdtmap)
3150 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3151 self.assertIsNone(missing_path)
3152 self.assertIsNone(missing_fdtmap)
3154 missing_dtb = state.GetFdtForEtype('missing')
3155 self.assertIsNone(missing_dtb)
3157 self.assertEqual('/binman', state.fdt_path_prefix)
3159 def testReplaceResizeFail(self):
3160 """Test replacing a file by something larger"""
3161 expected = U_BOOT_DATA + b'x'
3162 with self.assertRaises(ValueError) as e:
3163 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3164 dts='139_replace_repack.dts')
3165 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3168 def testReplaceMulti(self):
3169 """Test replacing entry data where multiple images are generated"""
3170 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3172 expected = b'x' * len(U_BOOT_DATA)
3173 updated_fname = tools.get_output_filename('image-updated.bin')
3174 tools.write_file(updated_fname, data)
3175 entry_name = 'u-boot'
3176 control.WriteEntry(updated_fname, entry_name, expected,
3178 data = control.ReadEntry(updated_fname, entry_name)
3179 self.assertEqual(expected, data)
3181 # Check the state looks right.
3182 self.assertEqual('/binman/image', state.fdt_path_prefix)
3184 # Now check we can write the first image
3185 image_fname = tools.get_output_filename('first-image.bin')
3186 updated_fname = tools.get_output_filename('first-updated.bin')
3187 tools.write_file(updated_fname, tools.read_file(image_fname))
3188 entry_name = 'u-boot'
3189 control.WriteEntry(updated_fname, entry_name, expected,
3191 data = control.ReadEntry(updated_fname, entry_name)
3192 self.assertEqual(expected, data)
3194 # Check the state looks right.
3195 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3197 def testUpdateFdtAllRepack(self):
3198 """Test that all device trees are updated with offset/size info"""
3199 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3200 SECTION_SIZE = 0x300
3205 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3207 'section:offset': 0,
3208 'section:size': SECTION_SIZE,
3209 'section:image-pos': 0,
3210 'section/u-boot-dtb:offset': 4,
3211 'section/u-boot-dtb:size': 636,
3212 'section/u-boot-dtb:image-pos': 4,
3213 'u-boot-spl-dtb:offset': SECTION_SIZE,
3214 'u-boot-spl-dtb:size': DTB_SIZE,
3215 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3216 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3217 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3218 'u-boot-tpl-dtb:size': DTB_SIZE,
3219 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3220 'fdtmap:size': FDTMAP_SIZE,
3221 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3224 'section:orig-size': SECTION_SIZE,
3225 'section/u-boot-dtb:orig-offset': 4,
3228 # We expect three device-tree files in the output, with the first one
3229 # within a fixed-size section.
3230 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3231 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3232 # main U-Boot tree. All three should have the same positions and offset
3233 # except that the main tree should include the main_expected properties
3235 for item in ['', 'spl', 'tpl', None]:
3237 start += 16 # Move past fdtmap header
3238 dtb = fdt.Fdt.FromData(data[start:])
3240 props = self._GetPropTree(dtb,
3241 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3242 prefix='/' if item is None else '/binman/')
3243 expected = dict(base_expected)
3247 # Main DTB and fdtdec should include the 'orig-' properties
3248 expected.update(main_expected)
3249 # Helpful for debugging:
3250 #for prop in sorted(props):
3251 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3252 self.assertEqual(expected, props)
3254 start = SECTION_SIZE
3256 start += dtb._fdt_obj.totalsize()
3258 def testFdtmapHeaderMiddle(self):
3259 """Test an FDT map in the middle of an image when it should be at end"""
3260 with self.assertRaises(ValueError) as e:
3261 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3262 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3265 def testFdtmapHeaderStartBad(self):
3266 """Test an FDT map in middle of an image when it should be at start"""
3267 with self.assertRaises(ValueError) as e:
3268 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3269 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3272 def testFdtmapHeaderEndBad(self):
3273 """Test an FDT map at the start of an image when it should be at end"""
3274 with self.assertRaises(ValueError) as e:
3275 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3276 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3279 def testFdtmapHeaderNoSize(self):
3280 """Test an image header at the end of an image with undefined size"""
3281 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3283 def testReplaceResize(self):
3284 """Test replacing a single file in an entry with a larger file"""
3285 expected = U_BOOT_DATA + b'x'
3286 data, _, image = self._RunReplaceCmd('u-boot', expected,
3287 dts='139_replace_repack.dts')
3288 self.assertEqual(expected, data)
3290 entries = image.GetEntries()
3291 dtb_data = entries['u-boot-dtb'].data
3292 dtb = fdt.Fdt.FromData(dtb_data)
3295 # The u-boot section should now be larger in the dtb
3296 node = dtb.GetNode('/binman/u-boot')
3297 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3299 # Same for the fdtmap
3300 fdata = entries['fdtmap'].data
3301 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3303 fnode = fdtb.GetNode('/u-boot')
3304 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3306 def testReplaceResizeNoRepack(self):
3307 """Test replacing an entry with a larger file when not allowed"""
3308 expected = U_BOOT_DATA + b'x'
3309 with self.assertRaises(ValueError) as e:
3310 self._RunReplaceCmd('u-boot', expected)
3311 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3314 def testEntryShrink(self):
3315 """Test contracting an entry after it is packed"""
3317 state.SetAllowEntryContraction(True)
3318 data = self._DoReadFileDtb('140_entry_shrink.dts',
3321 state.SetAllowEntryContraction(False)
3322 self.assertEqual(b'a', data[:1])
3323 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3324 self.assertEqual(b'a', data[-1:])
3326 def testEntryShrinkFail(self):
3327 """Test not being allowed to contract an entry after it is packed"""
3328 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3330 # In this case there is a spare byte at the end of the data. The size of
3331 # the contents is only 1 byte but we still have the size before it
3333 self.assertEqual(b'a\0', data[:2])
3334 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3335 self.assertEqual(b'a\0', data[-2:])
3337 def testDescriptorOffset(self):
3338 """Test that the Intel descriptor is always placed at at the start"""
3339 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3340 image = control.images['image']
3341 entries = image.GetEntries()
3342 desc = entries['intel-descriptor']
3343 self.assertEqual(0xff800000, desc.offset);
3344 self.assertEqual(0xff800000, desc.image_pos);
3346 def testReplaceCbfs(self):
3347 """Test replacing a single file in CBFS without changing the size"""
3349 expected = b'x' * len(U_BOOT_DATA)
3350 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3351 updated_fname = tools.get_output_filename('image-updated.bin')
3352 tools.write_file(updated_fname, data)
3353 entry_name = 'section/cbfs/u-boot'
3354 control.WriteEntry(updated_fname, entry_name, expected,
3356 data = control.ReadEntry(updated_fname, entry_name)
3357 self.assertEqual(expected, data)
3359 def testReplaceResizeCbfs(self):
3360 """Test replacing a single file in CBFS with one of a different size"""
3362 expected = U_BOOT_DATA + b'x'
3363 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3364 updated_fname = tools.get_output_filename('image-updated.bin')
3365 tools.write_file(updated_fname, data)
3366 entry_name = 'section/cbfs/u-boot'
3367 control.WriteEntry(updated_fname, entry_name, expected,
3369 data = control.ReadEntry(updated_fname, entry_name)
3370 self.assertEqual(expected, data)
3372 def _SetupForReplace(self):
3373 """Set up some files to use to replace entries
3375 This generates an image, copies it to a new file, extracts all the files
3376 in it and updates some of them
3382 Expected values for updated entries, each a string
3384 data = self._DoReadFileRealDtb('143_replace_all.dts')
3386 updated_fname = tools.get_output_filename('image-updated.bin')
3387 tools.write_file(updated_fname, data)
3389 outdir = os.path.join(self._indir, 'extract')
3390 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3392 expected1 = b'x' + U_BOOT_DATA + b'y'
3393 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3394 tools.write_file(u_boot_fname1, expected1)
3396 expected2 = b'a' + U_BOOT_DATA + b'b'
3397 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3398 tools.write_file(u_boot_fname2, expected2)
3400 expected_text = b'not the same text'
3401 text_fname = os.path.join(outdir, 'text')
3402 tools.write_file(text_fname, expected_text)
3404 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3405 dtb = fdt.FdtScan(dtb_fname)
3406 node = dtb.GetNode('/binman/text')
3407 node.AddString('my-property', 'the value')
3408 dtb.Sync(auto_resize=True)
3411 return updated_fname, outdir, expected1, expected2, expected_text
3413 def _CheckReplaceMultiple(self, entry_paths):
3414 """Handle replacing the contents of multiple entries
3417 entry_paths: List of entry paths to replace
3421 Dict of entries in the image:
3424 Expected values for updated entries, each a string
3426 updated_fname, outdir, expected1, expected2, expected_text = (
3427 self._SetupForReplace())
3428 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3430 image = Image.FromFile(updated_fname)
3432 return image.GetEntries(), expected1, expected2, expected_text
3434 def testReplaceAll(self):
3435 """Test replacing the contents of all entries"""
3436 entries, expected1, expected2, expected_text = (
3437 self._CheckReplaceMultiple([]))
3438 data = entries['u-boot'].data
3439 self.assertEqual(expected1, data)
3441 data = entries['u-boot2'].data
3442 self.assertEqual(expected2, data)
3444 data = entries['text'].data
3445 self.assertEqual(expected_text, data)
3447 # Check that the device tree is updated
3448 data = entries['u-boot-dtb'].data
3449 dtb = fdt.Fdt.FromData(data)
3451 node = dtb.GetNode('/binman/text')
3452 self.assertEqual('the value', node.props['my-property'].value)
3454 def testReplaceSome(self):
3455 """Test replacing the contents of a few entries"""
3456 entries, expected1, expected2, expected_text = (
3457 self._CheckReplaceMultiple(['u-boot2', 'text']))
3459 # This one should not change
3460 data = entries['u-boot'].data
3461 self.assertEqual(U_BOOT_DATA, data)
3463 data = entries['u-boot2'].data
3464 self.assertEqual(expected2, data)
3466 data = entries['text'].data
3467 self.assertEqual(expected_text, data)
3469 def testReplaceCmd(self):
3470 """Test replacing a file fron an image on the command line"""
3471 self._DoReadFileRealDtb('143_replace_all.dts')
3474 tmpdir, updated_fname = self._SetupImageInTmpdir()
3476 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3477 expected = b'x' * len(U_BOOT_DATA)
3478 tools.write_file(fname, expected)
3480 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3481 data = tools.read_file(updated_fname)
3482 self.assertEqual(expected, data[:len(expected)])
3483 map_fname = os.path.join(tmpdir, 'image-updated.map')
3484 self.assertFalse(os.path.exists(map_fname))
3486 shutil.rmtree(tmpdir)
3488 def testReplaceCmdSome(self):
3489 """Test replacing some files fron an image on the command line"""
3490 updated_fname, outdir, expected1, expected2, expected_text = (
3491 self._SetupForReplace())
3493 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3496 tools.prepare_output_dir(None)
3497 image = Image.FromFile(updated_fname)
3499 entries = image.GetEntries()
3501 # This one should not change
3502 data = entries['u-boot'].data
3503 self.assertEqual(U_BOOT_DATA, data)
3505 data = entries['u-boot2'].data
3506 self.assertEqual(expected2, data)
3508 data = entries['text'].data
3509 self.assertEqual(expected_text, data)
3511 def testReplaceMissing(self):
3512 """Test replacing entries where the file is missing"""
3513 updated_fname, outdir, expected1, expected2, expected_text = (
3514 self._SetupForReplace())
3516 # Remove one of the files, to generate a warning
3517 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3518 os.remove(u_boot_fname1)
3520 with test_util.capture_sys_output() as (stdout, stderr):
3521 control.ReplaceEntries(updated_fname, None, outdir, [])
3522 self.assertIn("Skipping entry '/u-boot' from missing file",
3525 def testReplaceCmdMap(self):
3526 """Test replacing a file fron an image on the command line"""
3527 self._DoReadFileRealDtb('143_replace_all.dts')
3530 tmpdir, updated_fname = self._SetupImageInTmpdir()
3532 fname = os.path.join(self._indir, 'update-u-boot.bin')
3533 expected = b'x' * len(U_BOOT_DATA)
3534 tools.write_file(fname, expected)
3536 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3538 map_fname = os.path.join(tmpdir, 'image-updated.map')
3539 self.assertTrue(os.path.exists(map_fname))
3541 shutil.rmtree(tmpdir)
3543 def testReplaceNoEntryPaths(self):
3544 """Test replacing an entry without an entry path"""
3545 self._DoReadFileRealDtb('143_replace_all.dts')
3546 image_fname = tools.get_output_filename('image.bin')
3547 with self.assertRaises(ValueError) as e:
3548 control.ReplaceEntries(image_fname, 'fname', None, [])
3549 self.assertIn('Must specify an entry path to read with -f',
3552 def testReplaceTooManyEntryPaths(self):
3553 """Test extracting some entries"""
3554 self._DoReadFileRealDtb('143_replace_all.dts')
3555 image_fname = tools.get_output_filename('image.bin')
3556 with self.assertRaises(ValueError) as e:
3557 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3558 self.assertIn('Must specify exactly one entry path to write with -f',
3561 def testPackReset16(self):
3562 """Test that an image with an x86 reset16 region can be created"""
3563 data = self._DoReadFile('144_x86_reset16.dts')
3564 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3566 def testPackReset16Spl(self):
3567 """Test that an image with an x86 reset16-spl region can be created"""
3568 data = self._DoReadFile('145_x86_reset16_spl.dts')
3569 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3571 def testPackReset16Tpl(self):
3572 """Test that an image with an x86 reset16-tpl region can be created"""
3573 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3574 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3576 def testPackIntelFit(self):
3577 """Test that an image with an Intel FIT and pointer can be created"""
3578 data = self._DoReadFile('147_intel_fit.dts')
3579 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3581 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3582 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3584 image = control.images['image']
3585 entries = image.GetEntries()
3586 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3587 self.assertEqual(expected_ptr, ptr)
3589 def testPackIntelFitMissing(self):
3590 """Test detection of a FIT pointer with not FIT region"""
3591 with self.assertRaises(ValueError) as e:
3592 self._DoReadFile('148_intel_fit_missing.dts')
3593 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3596 def _CheckSymbolsTplSection(self, dts, expected_vals):
3597 data = self._DoReadFile(dts)
3598 sym_values = struct.pack('<LQLL', *expected_vals)
3599 upto1 = 4 + len(U_BOOT_SPL_DATA)
3600 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3601 self.assertEqual(expected1, data[:upto1])
3603 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3604 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3605 self.assertEqual(expected2, data[upto1:upto2])
3607 upto3 = 0x34 + len(U_BOOT_DATA)
3608 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
3609 self.assertEqual(expected3, data[upto2:upto3])
3611 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3612 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3614 def testSymbolsTplSection(self):
3615 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3616 self._SetupSplElf('u_boot_binman_syms')
3617 self._SetupTplElf('u_boot_binman_syms')
3618 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3619 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3621 def testSymbolsTplSectionX86(self):
3622 """Test binman can assign symbols in a section with end-at-4gb"""
3623 self._SetupSplElf('u_boot_binman_syms_x86')
3624 self._SetupTplElf('u_boot_binman_syms_x86')
3625 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3626 [0xffffff04, 0xffffff1c, 0xffffff34,
3629 def testPackX86RomIfwiSectiom(self):
3630 """Test that a section can be placed in an IFWI region"""
3631 self._SetupIfwi('fitimage.bin')
3632 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3633 self._CheckIfwi(data)
3635 def testPackFspM(self):
3636 """Test that an image with a FSP memory-init binary can be created"""
3637 data = self._DoReadFile('152_intel_fsp_m.dts')
3638 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3640 def testPackFspS(self):
3641 """Test that an image with a FSP silicon-init binary can be created"""
3642 data = self._DoReadFile('153_intel_fsp_s.dts')
3643 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3645 def testPackFspT(self):
3646 """Test that an image with a FSP temp-ram-init binary can be created"""
3647 data = self._DoReadFile('154_intel_fsp_t.dts')
3648 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3650 def testMkimage(self):
3651 """Test using mkimage to build an image"""
3652 data = self._DoReadFile('156_mkimage.dts')
3654 # Just check that the data appears in the file somewhere
3655 self.assertIn(U_BOOT_SPL_DATA, data)
3657 def testMkimageMissing(self):
3658 """Test that binman still produces an image if mkimage is missing"""
3659 with test_util.capture_sys_output() as (_, stderr):
3660 self._DoTestFile('156_mkimage.dts',
3661 force_missing_bintools='mkimage')
3662 err = stderr.getvalue()
3663 self.assertRegex(err,
3664 "Image 'main-section'.*missing bintools.*: mkimage")
3666 def testExtblob(self):
3667 """Test an image with an external blob"""
3668 data = self._DoReadFile('157_blob_ext.dts')
3669 self.assertEqual(REFCODE_DATA, data)
3671 def testExtblobMissing(self):
3672 """Test an image with a missing external blob"""
3673 with self.assertRaises(ValueError) as e:
3674 self._DoReadFile('158_blob_ext_missing.dts')
3675 self.assertIn("Filename 'missing-file' not found in input path",
3678 def testExtblobMissingOk(self):
3679 """Test an image with an missing external blob that is allowed"""
3680 with test_util.capture_sys_output() as (stdout, stderr):
3681 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3682 err = stderr.getvalue()
3683 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3685 def testExtblobMissingOkSect(self):
3686 """Test an image with an missing external blob that is allowed"""
3687 with test_util.capture_sys_output() as (stdout, stderr):
3688 self._DoTestFile('159_blob_ext_missing_sect.dts',
3690 err = stderr.getvalue()
3691 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3692 "blob-ext blob-ext2")
3694 def testPackX86RomMeMissingDesc(self):
3695 """Test that an missing Intel descriptor entry is allowed"""
3696 with test_util.capture_sys_output() as (stdout, stderr):
3697 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3698 err = stderr.getvalue()
3699 self.assertRegex(err,
3700 "Image 'main-section'.*missing.*: intel-descriptor")
3702 def testPackX86RomMissingIfwi(self):
3703 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3704 self._SetupIfwi('fitimage.bin')
3705 pathname = os.path.join(self._indir, 'fitimage.bin')
3707 with test_util.capture_sys_output() as (stdout, stderr):
3708 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3709 err = stderr.getvalue()
3710 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3712 def testPackOverlap(self):
3713 """Test that zero-size overlapping regions are ignored"""
3714 self._DoTestFile('160_pack_overlap_zero.dts')
3716 def testSimpleFit(self):
3717 """Test an image with a FIT inside"""
3718 data = self._DoReadFile('161_fit.dts')
3719 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3720 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3721 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3723 # The data should be inside the FIT
3724 dtb = fdt.Fdt.FromData(fit_data)
3726 fnode = dtb.GetNode('/images/kernel')
3727 self.assertIn('data', fnode.props)
3729 fname = os.path.join(self._indir, 'fit_data.fit')
3730 tools.write_file(fname, fit_data)
3731 out = tools.run('dumpimage', '-l', fname)
3733 # Check a few features to make sure the plumbing works. We don't need
3734 # to test the operation of mkimage or dumpimage here. First convert the
3735 # output into a dict where the keys are the fields printed by dumpimage
3736 # and the values are a list of values for each field
3737 lines = out.splitlines()
3739 # Converts "Compression: gzip compressed" into two groups:
3740 # 'Compression' and 'gzip compressed'
3741 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3742 vals = collections.defaultdict(list)
3744 mat = re_line.match(line)
3745 vals[mat.group(1)].append(mat.group(2))
3747 self.assertEquals('FIT description: test-desc', lines[0])
3748 self.assertIn('Created:', lines[1])
3749 self.assertIn('Image 0 (kernel)', vals)
3750 self.assertIn('Hash value', vals)
3751 data_sizes = vals.get('Data Size')
3752 self.assertIsNotNone(data_sizes)
3753 self.assertEqual(2, len(data_sizes))
3754 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3755 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3756 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3758 def testFitExternal(self):
3759 """Test an image with an FIT with external images"""
3760 data = self._DoReadFile('162_fit_external.dts')
3761 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3763 # Size of the external-data region as set up by mkimage
3764 external_data_size = len(U_BOOT_DATA) + 2
3765 expected_size = (len(U_BOOT_DATA) + 0x400 +
3766 tools.align(external_data_size, 4) +
3767 len(U_BOOT_NODTB_DATA))
3769 # The data should be outside the FIT
3770 dtb = fdt.Fdt.FromData(fit_data)
3772 fnode = dtb.GetNode('/images/kernel')
3773 self.assertNotIn('data', fnode.props)
3774 self.assertEqual(len(U_BOOT_DATA),
3775 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3779 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3781 self.assertEquals(expected_size, len(data))
3782 actual_pos = len(U_BOOT_DATA) + fit_pos
3783 self.assertEqual(U_BOOT_DATA + b'aa',
3784 data[actual_pos:actual_pos + external_data_size])
3786 def testFitMissing(self):
3787 """Test that binman still produces a FIT image if mkimage is missing"""
3788 with test_util.capture_sys_output() as (_, stderr):
3789 self._DoTestFile('162_fit_external.dts',
3790 force_missing_bintools='mkimage')
3791 err = stderr.getvalue()
3792 self.assertRegex(err,
3793 "Image 'main-section'.*missing bintools.*: mkimage")
3795 def testSectionIgnoreHashSignature(self):
3796 """Test that sections ignore hash, signature nodes for its data"""
3797 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3798 expected = (U_BOOT_DATA + U_BOOT_DATA)
3799 self.assertEqual(expected, data)
3801 def testPadInSections(self):
3802 """Test pad-before, pad-after for entries in sections"""
3803 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3804 '166_pad_in_sections.dts', update_dtb=True)
3805 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3806 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
3808 self.assertEqual(expected, data)
3810 dtb = fdt.Fdt(out_dtb_fname)
3812 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3816 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3818 'section:image-pos': 0,
3819 'section:offset': 0,
3820 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3822 'section/before:image-pos': 0,
3823 'section/before:offset': 0,
3824 'section/before:size': len(U_BOOT_DATA),
3826 'section/u-boot:image-pos': 4,
3827 'section/u-boot:offset': 4,
3828 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3830 'section/after:image-pos': 26,
3831 'section/after:offset': 26,
3832 'section/after:size': len(U_BOOT_DATA),
3834 self.assertEqual(expected, props)
3836 def testFitImageSubentryAlignment(self):
3837 """Test relative alignability of FIT image subentries"""
3839 'test-id': TEXT_DATA,
3841 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3842 entry_args=entry_args)
3843 dtb = fdt.Fdt.FromData(data)
3846 node = dtb.GetNode('/images/kernel')
3847 data = dtb.GetProps(node)["data"].bytes
3848 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3849 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3850 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
3851 self.assertEqual(expected, data)
3853 node = dtb.GetNode('/images/fdt-1')
3854 data = dtb.GetProps(node)["data"].bytes
3855 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
3856 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
3858 self.assertEqual(expected, data)
3860 def testFitExtblobMissingOk(self):
3861 """Test a FIT with a missing external blob that is allowed"""
3862 with test_util.capture_sys_output() as (stdout, stderr):
3863 self._DoTestFile('168_fit_missing_blob.dts',
3865 err = stderr.getvalue()
3866 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3868 def testBlobNamedByArgMissing(self):
3869 """Test handling of a missing entry arg"""
3870 with self.assertRaises(ValueError) as e:
3871 self._DoReadFile('068_blob_named_by_arg.dts')
3872 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3875 def testPackBl31(self):
3876 """Test that an image with an ATF BL31 binary can be created"""
3877 data = self._DoReadFile('169_atf_bl31.dts')
3878 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3880 def testPackScp(self):
3881 """Test that an image with an SCP binary can be created"""
3882 data = self._DoReadFile('172_scp.dts')
3883 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3885 def testFitFdt(self):
3886 """Test an image with an FIT with multiple FDT images"""
3887 def _CheckFdt(seq, expected_data):
3888 """Check the FDT nodes
3891 seq: Sequence number to check (0 or 1)
3892 expected_data: Expected contents of 'data' property
3894 name = 'fdt-%d' % seq
3895 fnode = dtb.GetNode('/images/%s' % name)
3896 self.assertIsNotNone(fnode)
3897 self.assertEqual({'description','type', 'compression', 'data'},
3898 set(fnode.props.keys()))
3899 self.assertEqual(expected_data, fnode.props['data'].bytes)
3900 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3901 fnode.props['description'].value)
3903 def _CheckConfig(seq, expected_data):
3904 """Check the configuration nodes
3907 seq: Sequence number to check (0 or 1)
3908 expected_data: Expected contents of 'data' property
3910 cnode = dtb.GetNode('/configurations')
3911 self.assertIn('default', cnode.props)
3912 self.assertEqual('config-2', cnode.props['default'].value)
3914 name = 'config-%d' % seq
3915 fnode = dtb.GetNode('/configurations/%s' % name)
3916 self.assertIsNotNone(fnode)
3917 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3918 set(fnode.props.keys()))
3919 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3920 fnode.props['description'].value)
3921 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3924 'of-list': 'test-fdt1 test-fdt2',
3925 'default-dt': 'test-fdt2',
3927 data = self._DoReadFileDtb(
3929 entry_args=entry_args,
3930 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3931 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3932 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3934 dtb = fdt.Fdt.FromData(fit_data)
3936 fnode = dtb.GetNode('/images/kernel')
3937 self.assertIn('data', fnode.props)
3939 # Check all the properties in fdt-1 and fdt-2
3940 _CheckFdt(1, TEST_FDT1_DATA)
3941 _CheckFdt(2, TEST_FDT2_DATA)
3943 # Check configurations
3944 _CheckConfig(1, TEST_FDT1_DATA)
3945 _CheckConfig(2, TEST_FDT2_DATA)
3947 def testFitFdtMissingList(self):
3948 """Test handling of a missing 'of-list' entry arg"""
3949 with self.assertRaises(ValueError) as e:
3950 self._DoReadFile('170_fit_fdt.dts')
3951 self.assertIn("Generator node requires 'of-list' entry argument",
3954 def testFitFdtEmptyList(self):
3955 """Test handling of an empty 'of-list' entry arg"""
3959 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3961 def testFitFdtMissingProp(self):
3962 """Test handling of a missing 'fit,fdt-list' property"""
3963 with self.assertRaises(ValueError) as e:
3964 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3965 self.assertIn("Generator node requires 'fit,fdt-list' property",
3968 def testFitFdtEmptyList(self):
3969 """Test handling of an empty 'of-list' entry arg"""
3973 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3975 def testFitFdtMissing(self):
3976 """Test handling of a missing 'default-dt' entry arg"""
3978 'of-list': 'test-fdt1 test-fdt2',
3980 with self.assertRaises(ValueError) as e:
3981 self._DoReadFileDtb(
3983 entry_args=entry_args,
3984 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3985 self.assertIn("Generated 'default' node requires default-dt entry argument",
3988 def testFitFdtNotInList(self):
3989 """Test handling of a default-dt that is not in the of-list"""
3991 'of-list': 'test-fdt1 test-fdt2',
3992 'default-dt': 'test-fdt3',
3994 with self.assertRaises(ValueError) as e:
3995 self._DoReadFileDtb(
3997 entry_args=entry_args,
3998 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3999 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4002 def testFitExtblobMissingHelp(self):
4003 """Test display of help messages when an external blob is missing"""
4004 control.missing_blob_help = control._ReadMissingBlobHelp()
4005 control.missing_blob_help['wibble'] = 'Wibble test'
4006 control.missing_blob_help['another'] = 'Another test'
4007 with test_util.capture_sys_output() as (stdout, stderr):
4008 self._DoTestFile('168_fit_missing_blob.dts',
4010 err = stderr.getvalue()
4012 # We can get the tag from the name, the type or the missing-msg
4013 # property. Check all three.
4014 self.assertIn('You may need to build ARM Trusted', err)
4015 self.assertIn('Wibble test', err)
4016 self.assertIn('Another test', err)
4018 def testMissingBlob(self):
4019 """Test handling of a blob containing a missing file"""
4020 with self.assertRaises(ValueError) as e:
4021 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4022 self.assertIn("Filename 'missing' not found in input path",
4025 def testEnvironment(self):
4026 """Test adding a U-Boot environment"""
4027 data = self._DoReadFile('174_env.dts')
4028 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4029 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4030 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4031 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4034 def testEnvironmentNoSize(self):
4035 """Test that a missing 'size' property is detected"""
4036 with self.assertRaises(ValueError) as e:
4037 self._DoTestFile('175_env_no_size.dts')
4038 self.assertIn("'u-boot-env' entry must have a size property",
4041 def testEnvironmentTooSmall(self):
4042 """Test handling of an environment that does not fit"""
4043 with self.assertRaises(ValueError) as e:
4044 self._DoTestFile('176_env_too_small.dts')
4046 # checksum, start byte, environment with \0 terminator, final \0
4047 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4049 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4052 def testSkipAtStart(self):
4053 """Test handling of skip-at-start section"""
4054 data = self._DoReadFile('177_skip_at_start.dts')
4055 self.assertEqual(U_BOOT_DATA, data)
4057 image = control.images['image']
4058 entries = image.GetEntries()
4059 section = entries['section']
4060 self.assertEqual(0, section.offset)
4061 self.assertEqual(len(U_BOOT_DATA), section.size)
4062 self.assertEqual(U_BOOT_DATA, section.GetData())
4064 entry = section.GetEntries()['u-boot']
4065 self.assertEqual(16, entry.offset)
4066 self.assertEqual(len(U_BOOT_DATA), entry.size)
4067 self.assertEqual(U_BOOT_DATA, entry.data)
4069 def testSkipAtStartPad(self):
4070 """Test handling of skip-at-start section with padded entry"""
4071 data = self._DoReadFile('178_skip_at_start_pad.dts')
4072 before = tools.get_bytes(0, 8)
4073 after = tools.get_bytes(0, 4)
4074 all = before + U_BOOT_DATA + after
4075 self.assertEqual(all, data)
4077 image = control.images['image']
4078 entries = image.GetEntries()
4079 section = entries['section']
4080 self.assertEqual(0, section.offset)
4081 self.assertEqual(len(all), section.size)
4082 self.assertEqual(all, section.GetData())
4084 entry = section.GetEntries()['u-boot']
4085 self.assertEqual(16, entry.offset)
4086 self.assertEqual(len(all), entry.size)
4087 self.assertEqual(U_BOOT_DATA, entry.data)
4089 def testSkipAtStartSectionPad(self):
4090 """Test handling of skip-at-start section with padding"""
4091 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4092 before = tools.get_bytes(0, 8)
4093 after = tools.get_bytes(0, 4)
4094 all = before + U_BOOT_DATA + after
4095 self.assertEqual(all, data)
4097 image = control.images['image']
4098 entries = image.GetEntries()
4099 section = entries['section']
4100 self.assertEqual(0, section.offset)
4101 self.assertEqual(len(all), section.size)
4102 self.assertEqual(U_BOOT_DATA, section.data)
4103 self.assertEqual(all, section.GetPaddedData())
4105 entry = section.GetEntries()['u-boot']
4106 self.assertEqual(16, entry.offset)
4107 self.assertEqual(len(U_BOOT_DATA), entry.size)
4108 self.assertEqual(U_BOOT_DATA, entry.data)
4110 def testSectionPad(self):
4111 """Testing padding with sections"""
4112 data = self._DoReadFile('180_section_pad.dts')
4113 expected = (tools.get_bytes(ord('&'), 3) +
4114 tools.get_bytes(ord('!'), 5) +
4116 tools.get_bytes(ord('!'), 1) +
4117 tools.get_bytes(ord('&'), 2))
4118 self.assertEqual(expected, data)
4120 def testSectionAlign(self):
4121 """Testing alignment with sections"""
4122 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4123 expected = (b'\0' + # fill section
4124 tools.get_bytes(ord('&'), 1) + # padding to section align
4125 b'\0' + # fill section
4126 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
4128 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4129 tools.get_bytes(ord('!'), 4)) # padding to section size
4130 self.assertEqual(expected, data)
4132 def testCompressImage(self):
4133 """Test compression of the entire image"""
4135 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4136 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4137 dtb = fdt.Fdt(out_dtb_fname)
4139 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4141 orig = self._decompress(data)
4142 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4144 # Do a sanity check on various fields
4145 image = control.images['image']
4146 entries = image.GetEntries()
4147 self.assertEqual(2, len(entries))
4149 entry = entries['blob']
4150 self.assertEqual(COMPRESS_DATA, entry.data)
4151 self.assertEqual(len(COMPRESS_DATA), entry.size)
4153 entry = entries['u-boot']
4154 self.assertEqual(U_BOOT_DATA, entry.data)
4155 self.assertEqual(len(U_BOOT_DATA), entry.size)
4157 self.assertEqual(len(data), image.size)
4158 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4159 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4160 orig = self._decompress(image.data)
4161 self.assertEqual(orig, image.uncomp_data)
4165 'blob:size': len(COMPRESS_DATA),
4166 'u-boot:offset': len(COMPRESS_DATA),
4167 'u-boot:size': len(U_BOOT_DATA),
4168 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4173 self.assertEqual(expected, props)
4175 def testCompressImageLess(self):
4176 """Test compression where compression reduces the image size"""
4178 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4179 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4180 dtb = fdt.Fdt(out_dtb_fname)
4182 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4184 orig = self._decompress(data)
4186 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4188 # Do a sanity check on various fields
4189 image = control.images['image']
4190 entries = image.GetEntries()
4191 self.assertEqual(2, len(entries))
4193 entry = entries['blob']
4194 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4195 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4197 entry = entries['u-boot']
4198 self.assertEqual(U_BOOT_DATA, entry.data)
4199 self.assertEqual(len(U_BOOT_DATA), entry.size)
4201 self.assertEqual(len(data), image.size)
4202 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4203 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4205 orig = self._decompress(image.data)
4206 self.assertEqual(orig, image.uncomp_data)
4210 'blob:size': len(COMPRESS_DATA_BIG),
4211 'u-boot:offset': len(COMPRESS_DATA_BIG),
4212 'u-boot:size': len(U_BOOT_DATA),
4213 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4218 self.assertEqual(expected, props)
4220 def testCompressSectionSize(self):
4221 """Test compression of a section with a fixed size"""
4223 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4224 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4225 dtb = fdt.Fdt(out_dtb_fname)
4227 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4229 orig = self._decompress(data)
4230 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4232 'section/blob:offset': 0,
4233 'section/blob:size': len(COMPRESS_DATA),
4234 'section/u-boot:offset': len(COMPRESS_DATA),
4235 'section/u-boot:size': len(U_BOOT_DATA),
4236 'section:offset': 0,
4237 'section:image-pos': 0,
4238 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4239 'section:size': 0x30,
4244 self.assertEqual(expected, props)
4246 def testCompressSection(self):
4247 """Test compression of a section with no fixed size"""
4249 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4250 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4251 dtb = fdt.Fdt(out_dtb_fname)
4253 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4255 orig = self._decompress(data)
4256 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4258 'section/blob:offset': 0,
4259 'section/blob:size': len(COMPRESS_DATA),
4260 'section/u-boot:offset': len(COMPRESS_DATA),
4261 'section/u-boot:size': len(U_BOOT_DATA),
4262 'section:offset': 0,
4263 'section:image-pos': 0,
4264 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4265 'section:size': len(data),
4270 self.assertEqual(expected, props)
4272 def testCompressExtra(self):
4273 """Test compression of a section with no fixed size"""
4275 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4276 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4277 dtb = fdt.Fdt(out_dtb_fname)
4279 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4282 base = data[len(U_BOOT_DATA):]
4283 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4284 rest = base[len(U_BOOT_DATA):]
4286 # Check compressed data
4287 section1 = self._decompress(rest)
4288 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4289 self.assertEquals(expect1, rest[:len(expect1)])
4290 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4291 rest1 = rest[len(expect1):]
4293 section2 = self._decompress(rest1)
4294 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4295 self.assertEquals(expect2, rest1[:len(expect2)])
4296 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4297 rest2 = rest1[len(expect2):]
4299 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4300 len(expect2) + len(U_BOOT_DATA))
4301 #self.assertEquals(expect_size, len(data))
4303 #self.assertEquals(U_BOOT_DATA, rest2)
4308 'u-boot:image-pos': 0,
4309 'u-boot:size': len(U_BOOT_DATA),
4311 'base:offset': len(U_BOOT_DATA),
4312 'base:image-pos': len(U_BOOT_DATA),
4313 'base:size': len(data) - len(U_BOOT_DATA),
4314 'base/u-boot:offset': 0,
4315 'base/u-boot:image-pos': len(U_BOOT_DATA),
4316 'base/u-boot:size': len(U_BOOT_DATA),
4317 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4319 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4321 'base/u-boot2:size': len(U_BOOT_DATA),
4323 'base/section:offset': len(U_BOOT_DATA),
4324 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4325 'base/section:size': len(expect1),
4326 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4327 'base/section/blob:offset': 0,
4328 'base/section/blob:size': len(COMPRESS_DATA),
4329 'base/section/u-boot:offset': len(COMPRESS_DATA),
4330 'base/section/u-boot:size': len(U_BOOT_DATA),
4332 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4333 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4334 'base/section2:size': len(expect2),
4335 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4336 'base/section2/blob:offset': 0,
4337 'base/section2/blob:size': len(COMPRESS_DATA),
4338 'base/section2/blob2:offset': len(COMPRESS_DATA),
4339 'base/section2/blob2:size': len(COMPRESS_DATA),
4345 self.assertEqual(expected, props)
4347 def testSymbolsSubsection(self):
4348 """Test binman can assign symbols from a subsection"""
4349 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4351 def testReadImageEntryArg(self):
4352 """Test reading an image that would need an entry arg to generate"""
4354 'cros-ec-rw-path': 'ecrw.bin',
4356 data = self.data = self._DoReadFileDtb(
4357 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4358 entry_args=entry_args)
4360 image_fname = tools.get_output_filename('image.bin')
4361 orig_image = control.images['image']
4363 # This should not generate an error about the missing 'cros-ec-rw-path'
4364 # since we are reading the image from a file. Compare with
4365 # testEntryArgsRequired()
4366 image = Image.FromFile(image_fname)
4367 self.assertEqual(orig_image.GetEntries().keys(),
4368 image.GetEntries().keys())
4370 def testFilesAlign(self):
4371 """Test alignment with files"""
4372 data = self._DoReadFile('190_files_align.dts')
4374 # The first string is 15 bytes so will align to 16
4375 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4376 self.assertEqual(expect, data)
4378 def testReadImageSkip(self):
4379 """Test reading an image and accessing its FDT map"""
4380 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4381 image_fname = tools.get_output_filename('image.bin')
4382 orig_image = control.images['image']
4383 image = Image.FromFile(image_fname)
4384 self.assertEqual(orig_image.GetEntries().keys(),
4385 image.GetEntries().keys())
4387 orig_entry = orig_image.GetEntries()['fdtmap']
4388 entry = image.GetEntries()['fdtmap']
4389 self.assertEqual(orig_entry.offset, entry.offset)
4390 self.assertEqual(orig_entry.size, entry.size)
4391 self.assertEqual(16, entry.image_pos)
4393 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4395 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4397 def testTplNoDtb(self):
4398 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4400 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4401 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4402 data[:len(U_BOOT_TPL_NODTB_DATA)])
4404 def testTplBssPad(self):
4405 """Test that we can pad TPL's BSS with zeros"""
4406 # ELF file with a '__bss_size' symbol
4408 data = self._DoReadFile('193_tpl_bss_pad.dts')
4409 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
4412 def testTplBssPadMissing(self):
4413 """Test that a missing symbol is detected"""
4414 self._SetupTplElf('u_boot_ucode_ptr')
4415 with self.assertRaises(ValueError) as e:
4416 self._DoReadFile('193_tpl_bss_pad.dts')
4417 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4420 def checkDtbSizes(self, data, pad_len, start):
4421 """Check the size arguments in a dtb embedded in an image
4424 data: The image data
4425 pad_len: Length of the pad section in the image, in bytes
4426 start: Start offset of the devicetree to examine, within the image
4429 Size of the devicetree in bytes
4431 dtb_data = data[start:]
4432 dtb = fdt.Fdt.FromData(dtb_data)
4433 fdt_size = dtb.GetFdtObj().totalsize()
4435 props = self._GetPropTree(dtb, 'size')
4438 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4439 'u-boot-spl/u-boot-spl-dtb:size': 801,
4440 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4441 'u-boot-spl:size': 860,
4442 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4443 'u-boot/u-boot-dtb:size': 781,
4444 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4449 def testExpanded(self):
4450 """Test that an expanded entry type is selected when needed"""
4454 # SPL has a devicetree, TPL does not
4460 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4461 entry_args=entry_args)
4462 image = control.images['image']
4463 entries = image.GetEntries()
4464 self.assertEqual(3, len(entries))
4466 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4467 self.assertIn('u-boot', entries)
4468 entry = entries['u-boot']
4469 self.assertEqual('u-boot-expanded', entry.etype)
4470 subent = entry.GetEntries()
4471 self.assertEqual(2, len(subent))
4472 self.assertIn('u-boot-nodtb', subent)
4473 self.assertIn('u-boot-dtb', subent)
4475 # Second, u-boot-spl, which should be expanded into three parts
4476 self.assertIn('u-boot-spl', entries)
4477 entry = entries['u-boot-spl']
4478 self.assertEqual('u-boot-spl-expanded', entry.etype)
4479 subent = entry.GetEntries()
4480 self.assertEqual(3, len(subent))
4481 self.assertIn('u-boot-spl-nodtb', subent)
4482 self.assertIn('u-boot-spl-bss-pad', subent)
4483 self.assertIn('u-boot-spl-dtb', subent)
4485 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4487 self.assertIn('u-boot-tpl', entries)
4488 entry = entries['u-boot-tpl']
4489 self.assertEqual('u-boot-tpl', entry.etype)
4490 self.assertEqual(None, entry.GetEntries())
4492 def testExpandedTpl(self):
4493 """Test that an expanded entry type is selected for TPL when needed"""
4500 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4501 entry_args=entry_args)
4502 image = control.images['image']
4503 entries = image.GetEntries()
4504 self.assertEqual(1, len(entries))
4506 # We only have u-boot-tpl, which be expanded
4507 self.assertIn('u-boot-tpl', entries)
4508 entry = entries['u-boot-tpl']
4509 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4510 subent = entry.GetEntries()
4511 self.assertEqual(3, len(subent))
4512 self.assertIn('u-boot-tpl-nodtb', subent)
4513 self.assertIn('u-boot-tpl-bss-pad', subent)
4514 self.assertIn('u-boot-tpl-dtb', subent)
4516 def testExpandedNoPad(self):
4517 """Test an expanded entry without BSS pad enabled"""
4521 # SPL has a devicetree, TPL does not
4523 'spl-dtb': 'something',
4527 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4528 entry_args=entry_args)
4529 image = control.images['image']
4530 entries = image.GetEntries()
4532 # Just check u-boot-spl, which should be expanded into two parts
4533 self.assertIn('u-boot-spl', entries)
4534 entry = entries['u-boot-spl']
4535 self.assertEqual('u-boot-spl-expanded', entry.etype)
4536 subent = entry.GetEntries()
4537 self.assertEqual(2, len(subent))
4538 self.assertIn('u-boot-spl-nodtb', subent)
4539 self.assertIn('u-boot-spl-dtb', subent)
4541 def testExpandedTplNoPad(self):
4542 """Test that an expanded entry type with padding disabled in TPL"""
4549 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4550 entry_args=entry_args)
4551 image = control.images['image']
4552 entries = image.GetEntries()
4553 self.assertEqual(1, len(entries))
4555 # We only have u-boot-tpl, which be expanded
4556 self.assertIn('u-boot-tpl', entries)
4557 entry = entries['u-boot-tpl']
4558 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4559 subent = entry.GetEntries()
4560 self.assertEqual(2, len(subent))
4561 self.assertIn('u-boot-tpl-nodtb', subent)
4562 self.assertIn('u-boot-tpl-dtb', subent)
4564 def testFdtInclude(self):
4565 """Test that an Fdt is update within all binaries"""
4569 # SPL has a devicetree, TPL does not
4576 # Build the image. It includes two separate devicetree binaries, each
4577 # with their own contents, but all contain the binman definition.
4578 data = self._DoReadFileDtb(
4579 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4580 update_dtb=True, entry_args=entry_args)[0]
4583 # Check the U-Boot dtb
4584 start = len(U_BOOT_NODTB_DATA)
4585 fdt_size = self.checkDtbSizes(data, pad_len, start)
4588 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4589 fdt_size = self.checkDtbSizes(data, pad_len, start)
4591 # TPL has no devicetree
4592 start += fdt_size + len(U_BOOT_TPL_DATA)
4593 self.assertEqual(len(data), start)
4595 def testSymbolsExpanded(self):
4596 """Test binman can assign symbols in expanded entries"""
4600 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4601 U_BOOT_SPL_DTB_DATA, 0x38,
4602 entry_args=entry_args, use_expanded=True)
4604 def testCollection(self):
4605 """Test a collection"""
4606 data = self._DoReadFile('198_collection.dts')
4607 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4608 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4609 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
4612 def testCollectionSection(self):
4613 """Test a collection where a section must be built first"""
4614 # Sections never have their contents when GetData() is called, but when
4615 # BuildSectionData() is called with required=True, a section will force
4616 # building the contents, producing an error is anything is still
4618 data = self._DoReadFile('199_collection_section.dts')
4619 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4620 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4621 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
4624 def testAlignDefault(self):
4625 """Test that default alignment works on sections"""
4626 data = self._DoReadFile('200_align_default.dts')
4627 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
4629 # Special alignment for section
4630 expected += tools.get_bytes(0, 32 - len(expected))
4631 # No alignment within the nested section
4632 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4633 # Now the final piece, which should be default-aligned
4634 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4635 self.assertEqual(expected, data)
4637 def testPackOpenSBI(self):
4638 """Test that an image with an OpenSBI binary can be created"""
4639 data = self._DoReadFile('201_opensbi.dts')
4640 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4642 def testSectionsSingleThread(self):
4643 """Test sections without multithreading"""
4644 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4645 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4646 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4647 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
4648 self.assertEqual(expected, data)
4650 def testThreadTimeout(self):
4651 """Test handling a thread that takes too long"""
4652 with self.assertRaises(ValueError) as e:
4653 self._DoTestFile('202_section_timeout.dts',
4654 test_section_timeout=True)
4655 self.assertIn("Timed out obtaining contents", str(e.exception))
4657 def testTiming(self):
4658 """Test output of timing information"""
4659 data = self._DoReadFile('055_sections.dts')
4660 with test_util.capture_sys_output() as (stdout, stderr):
4662 self.assertIn('read:', stdout.getvalue())
4663 self.assertIn('compress:', stdout.getvalue())
4665 def testUpdateFdtInElf(self):
4666 """Test that we can update the devicetree in an ELF file"""
4667 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4668 outfile = os.path.join(self._indir, 'u-boot.out')
4669 begin_sym = 'dtb_embed_begin'
4670 end_sym = 'dtb_embed_end'
4671 retcode = self._DoTestFile(
4672 '060_fdt_update.dts', update_dtb=True,
4673 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4674 self.assertEqual(0, retcode)
4676 # Check that the output file does in fact contact a dtb with the binman
4677 # definition in the correct place
4678 syms = elf.GetSymbolFileOffset(infile,
4679 ['dtb_embed_begin', 'dtb_embed_end'])
4680 data = tools.read_file(outfile)
4681 dtb_data = data[syms['dtb_embed_begin'].offset:
4682 syms['dtb_embed_end'].offset]
4684 dtb = fdt.Fdt.FromData(dtb_data)
4686 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4690 '_testing:offset': 32,
4692 '_testing:image-pos': 32,
4693 'section@0/u-boot:offset': 0,
4694 'section@0/u-boot:size': len(U_BOOT_DATA),
4695 'section@0/u-boot:image-pos': 0,
4696 'section@0:offset': 0,
4697 'section@0:size': 16,
4698 'section@0:image-pos': 0,
4700 'section@1/u-boot:offset': 0,
4701 'section@1/u-boot:size': len(U_BOOT_DATA),
4702 'section@1/u-boot:image-pos': 16,
4703 'section@1:offset': 16,
4704 'section@1:size': 16,
4705 'section@1:image-pos': 16,
4709 def testUpdateFdtInElfInvalid(self):
4710 """Test that invalid args are detected with --update-fdt-in-elf"""
4711 with self.assertRaises(ValueError) as e:
4712 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4713 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4716 def testUpdateFdtInElfNoSyms(self):
4717 """Test that missing symbols are detected with --update-fdt-in-elf"""
4718 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4720 begin_sym = 'wrong_begin'
4721 end_sym = 'wrong_end'
4722 with self.assertRaises(ValueError) as e:
4724 '060_fdt_update.dts',
4725 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4726 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4729 def testUpdateFdtInElfTooSmall(self):
4730 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4731 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4732 outfile = os.path.join(self._indir, 'u-boot.out')
4733 begin_sym = 'dtb_embed_begin'
4734 end_sym = 'dtb_embed_end'
4735 with self.assertRaises(ValueError) as e:
4737 '060_fdt_update.dts', update_dtb=True,
4738 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4741 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4743 def testVersion(self):
4744 """Test we can get the binman version"""
4745 version = '(unreleased)'
4746 self.assertEqual(version, state.GetVersion(self._indir))
4748 with self.assertRaises(SystemExit):
4749 with test_util.capture_sys_output() as (_, stderr):
4750 self._DoBinman('-V')
4751 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4753 # Try running the tool too, just to be safe
4754 result = self._RunBinman('-V')
4755 self.assertEqual('Binman %s\n' % version, result.stderr)
4757 # Set up a version file to make sure that works
4758 version = 'v2025.01-rc2'
4759 tools.write_file(os.path.join(self._indir, 'version'), version,
4761 self.assertEqual(version, state.GetVersion(self._indir))
4763 def testAltFormat(self):
4764 """Test that alternative formats can be used to extract"""
4765 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4768 tmpdir, updated_fname = self._SetupImageInTmpdir()
4769 with test_util.capture_sys_output() as (stdout, _):
4770 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4772 '''Flag (-F) Entry type Description
4773 fdt fdtmap Extract the devicetree blob from the fdtmap
4777 dtb = os.path.join(tmpdir, 'fdt.dtb')
4778 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4781 # Check that we can read it and it can be scanning, meaning it does
4782 # not have a 16-byte fdtmap header
4783 data = tools.read_file(dtb)
4784 dtb = fdt.Fdt.FromData(data)
4787 # Now check u-boot which has no alt_format
4788 fname = os.path.join(tmpdir, 'fdt.dtb')
4789 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4790 '-f', fname, 'u-boot')
4791 data = tools.read_file(fname)
4792 self.assertEqual(U_BOOT_DATA, data)
4795 shutil.rmtree(tmpdir)
4797 def testExtblobList(self):
4798 """Test an image with an external blob list"""
4799 data = self._DoReadFile('215_blob_ext_list.dts')
4800 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4802 def testExtblobListMissing(self):
4803 """Test an image with a missing external blob"""
4804 with self.assertRaises(ValueError) as e:
4805 self._DoReadFile('216_blob_ext_list_missing.dts')
4806 self.assertIn("Filename 'missing-file' not found in input path",
4809 def testExtblobListMissingOk(self):
4810 """Test an image with an missing external blob that is allowed"""
4811 with test_util.capture_sys_output() as (stdout, stderr):
4812 self._DoTestFile('216_blob_ext_list_missing.dts',
4814 err = stderr.getvalue()
4815 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4818 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4819 data = self._DoReadFile('203_fip.dts')
4820 hdr, fents = fip_util.decode_fip(data)
4821 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4822 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4823 self.assertEqual(0x123, hdr.flags)
4825 self.assertEqual(2, len(fents))
4829 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4830 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4831 self.assertEqual('soc-fw', fent.fip_type)
4832 self.assertEqual(0x88, fent.offset)
4833 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4834 self.assertEqual(0x123456789abcdef, fent.flags)
4835 self.assertEqual(ATF_BL31_DATA, fent.data)
4836 self.assertEqual(True, fent.valid)
4840 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4841 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4842 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4843 self.assertEqual(0x8c, fent.offset)
4844 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4845 self.assertEqual(0, fent.flags)
4846 self.assertEqual(ATF_BL2U_DATA, fent.data)
4847 self.assertEqual(True, fent.valid)
4849 def testFipOther(self):
4850 """Basic FIP with something that isn't a external blob"""
4851 data = self._DoReadFile('204_fip_other.dts')
4852 hdr, fents = fip_util.decode_fip(data)
4854 self.assertEqual(2, len(fents))
4856 self.assertEqual('rot-cert', fent.fip_type)
4857 self.assertEqual(b'aa', fent.data)
4859 def testFipOther(self):
4860 """Basic FIP with something that isn't a external blob"""
4861 data = self._DoReadFile('204_fip_other.dts')
4862 hdr, fents = fip_util.decode_fip(data)
4864 self.assertEqual(2, len(fents))
4866 self.assertEqual('rot-cert', fent.fip_type)
4867 self.assertEqual(b'aa', fent.data)
4869 def testFipNoType(self):
4870 """FIP with an entry of an unknown type"""
4871 with self.assertRaises(ValueError) as e:
4872 self._DoReadFile('205_fip_no_type.dts')
4873 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4876 def testFipUuid(self):
4877 """Basic FIP with a manual uuid"""
4878 data = self._DoReadFile('206_fip_uuid.dts')
4879 hdr, fents = fip_util.decode_fip(data)
4881 self.assertEqual(2, len(fents))
4883 self.assertEqual(None, fent.fip_type)
4885 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4886 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4888 self.assertEqual(U_BOOT_DATA, fent.data)
4890 def testFipLs(self):
4891 """Test listing a FIP"""
4892 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4893 hdr, fents = fip_util.decode_fip(data)
4896 tmpdir, updated_fname = self._SetupImageInTmpdir()
4897 with test_util.capture_sys_output() as (stdout, stderr):
4898 self._DoBinman('ls', '-i', updated_fname)
4900 shutil.rmtree(tmpdir)
4901 lines = stdout.getvalue().splitlines()
4903 'Name Image-pos Size Entry-type Offset Uncomp-size',
4904 '----------------------------------------------------------------',
4905 'main-section 0 2d3 section 0',
4906 ' atf-fip 0 90 atf-fip 0',
4907 ' soc-fw 88 4 blob-ext 88',
4908 ' u-boot 8c 4 u-boot 8c',
4909 ' fdtmap 90 243 fdtmap 90',
4911 self.assertEqual(expected, lines)
4913 image = control.images['image']
4914 entries = image.GetEntries()
4915 fdtmap = entries['fdtmap']
4917 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4918 magic = fdtmap_data[:8]
4919 self.assertEqual(b'_FDTMAP_', magic)
4920 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
4922 fdt_data = fdtmap_data[16:]
4923 dtb = fdt.Fdt.FromData(fdt_data)
4925 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4927 'atf-fip/soc-fw:image-pos': 136,
4928 'atf-fip/soc-fw:offset': 136,
4929 'atf-fip/soc-fw:size': 4,
4930 'atf-fip/u-boot:image-pos': 140,
4931 'atf-fip/u-boot:offset': 140,
4932 'atf-fip/u-boot:size': 4,
4933 'atf-fip:image-pos': 0,
4934 'atf-fip:offset': 0,
4935 'atf-fip:size': 144,
4938 'fdtmap:image-pos': fdtmap.image_pos,
4939 'fdtmap:offset': fdtmap.offset,
4940 'fdtmap:size': len(fdtmap_data),
4944 def testFipExtractOneEntry(self):
4945 """Test extracting a single entry fron an FIP"""
4946 self._DoReadFileRealDtb('207_fip_ls.dts')
4947 image_fname = tools.get_output_filename('image.bin')
4948 fname = os.path.join(self._indir, 'output.extact')
4949 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4950 data = tools.read_file(fname)
4951 self.assertEqual(U_BOOT_DATA, data)
4953 def testFipReplace(self):
4954 """Test replacing a single file in a FIP"""
4955 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
4956 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4957 updated_fname = tools.get_output_filename('image-updated.bin')
4958 tools.write_file(updated_fname, data)
4959 entry_name = 'atf-fip/u-boot'
4960 control.WriteEntry(updated_fname, entry_name, expected,
4962 actual = control.ReadEntry(updated_fname, entry_name)
4963 self.assertEqual(expected, actual)
4965 new_data = tools.read_file(updated_fname)
4966 hdr, fents = fip_util.decode_fip(new_data)
4968 self.assertEqual(2, len(fents))
4970 # Check that the FIP entry is updated
4972 self.assertEqual(0x8c, fent.offset)
4973 self.assertEqual(len(expected), fent.size)
4974 self.assertEqual(0, fent.flags)
4975 self.assertEqual(expected, fent.data)
4976 self.assertEqual(True, fent.valid)
4978 def testFipMissing(self):
4979 with test_util.capture_sys_output() as (stdout, stderr):
4980 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4981 err = stderr.getvalue()
4982 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4984 def testFipSize(self):
4985 """Test a FIP with a size property"""
4986 data = self._DoReadFile('210_fip_size.dts')
4987 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4988 hdr, fents = fip_util.decode_fip(data)
4989 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4990 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4992 self.assertEqual(1, len(fents))
4995 self.assertEqual('soc-fw', fent.fip_type)
4996 self.assertEqual(0x60, fent.offset)
4997 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4998 self.assertEqual(ATF_BL31_DATA, fent.data)
4999 self.assertEqual(True, fent.valid)
5001 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
5002 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
5004 def testFipBadAlign(self):
5005 """Test that an invalid alignment value in a FIP is detected"""
5006 with self.assertRaises(ValueError) as e:
5007 self._DoTestFile('211_fip_bad_align.dts')
5009 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5012 def testFipCollection(self):
5013 """Test using a FIP in a collection"""
5014 data = self._DoReadFile('212_fip_collection.dts')
5015 entry1 = control.images['image'].GetEntries()['collection']
5016 data1 = data[:entry1.size]
5017 hdr1, fents2 = fip_util.decode_fip(data1)
5019 entry2 = control.images['image'].GetEntries()['atf-fip']
5020 data2 = data[entry2.offset:entry2.offset + entry2.size]
5021 hdr1, fents2 = fip_util.decode_fip(data2)
5023 # The 'collection' entry should have U-Boot included at the end
5024 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5025 self.assertEqual(data1, data2 + U_BOOT_DATA)
5026 self.assertEqual(U_BOOT_DATA, data1[-4:])
5028 # There should be a U-Boot after the final FIP
5029 self.assertEqual(U_BOOT_DATA, data[-4:])
5031 def testFakeBlob(self):
5032 """Test handling of faking an external blob"""
5033 with test_util.capture_sys_output() as (stdout, stderr):
5034 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5035 allow_fake_blobs=True)
5036 err = stderr.getvalue()
5039 "Image '.*' has faked external blobs and is non-functional: .*")
5041 def testExtblobListFaked(self):
5042 """Test an extblob with missing external blob that are faked"""
5043 with test_util.capture_sys_output() as (stdout, stderr):
5044 self._DoTestFile('216_blob_ext_list_missing.dts',
5045 allow_fake_blobs=True)
5046 err = stderr.getvalue()
5047 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5049 def testListBintools(self):
5050 args = ['tool', '--list']
5051 with test_util.capture_sys_output() as (stdout, _):
5052 self._DoBinman(*args)
5053 out = stdout.getvalue().splitlines()
5054 self.assertTrue(len(out) >= 2)
5056 def testFetchBintools(self):
5057 def fail_download(url):
5058 """Take the tools.download() function by raising an exception"""
5059 raise urllib.error.URLError('my error')
5062 with self.assertRaises(ValueError) as e:
5063 self._DoBinman(*args)
5064 self.assertIn("Invalid arguments to 'tool' subcommand",
5067 args = ['tool', '--fetch']
5068 with self.assertRaises(ValueError) as e:
5069 self._DoBinman(*args)
5070 self.assertIn('Please specify bintools to fetch', str(e.exception))
5072 args = ['tool', '--fetch', '_testing']
5073 with unittest.mock.patch.object(tools, 'download',
5074 side_effect=fail_download):
5075 with test_util.capture_sys_output() as (stdout, _):
5076 self._DoBinman(*args)
5077 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5079 def testInvalidCompress(self):
5080 with self.assertRaises(ValueError) as e:
5081 comp_util.compress(b'', 'invalid')
5082 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5084 with self.assertRaises(ValueError) as e:
5085 comp_util.decompress(b'1234', 'invalid')
5086 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5088 def testBintoolDocs(self):
5089 """Test for creation of bintool documentation"""
5090 with test_util.capture_sys_output() as (stdout, stderr):
5091 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5092 self.assertTrue(len(stdout.getvalue()) > 0)
5094 def testBintoolDocsMissing(self):
5095 """Test handling of missing bintool documentation"""
5096 with self.assertRaises(ValueError) as e:
5097 with test_util.capture_sys_output() as (stdout, stderr):
5098 control.write_bintool_docs(
5099 control.bintool.Bintool.get_tool_list(), 'mkimage')
5100 self.assertIn('Documentation is missing for modules: mkimage',
5103 def testListWithGenNode(self):
5104 """Check handling of an FDT map when the section cannot be found"""
5106 'of-list': 'test-fdt1 test-fdt2',
5108 data = self._DoReadFileDtb(
5109 '219_fit_gennode.dts',
5110 entry_args=entry_args,
5112 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5115 tmpdir, updated_fname = self._SetupImageInTmpdir()
5116 with test_util.capture_sys_output() as (stdout, stderr):
5117 self._RunBinman('ls', '-i', updated_fname)
5119 shutil.rmtree(tmpdir)
5122 if __name__ == "__main__":