1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # To run a single test, change to this directory, and:
7 # python -m unittest func_test.TestFunctional.testHelp
12 from optparse import OptionParser
23 from binman import bintool
24 from binman import cbfs_util
25 from binman import cmdline
26 from binman import control
27 from binman import elf
28 from binman import elf_test
29 from binman import fip_util
30 from binman import fmap_util
31 from binman import state
33 from dtoc import fdt_util
34 from binman.etype import fdtmap
35 from binman.etype import image_header
36 from binman.image import Image
37 from patman import command
38 from patman import test_util
39 from patman import tools
40 from patman import tout
42 # Contents of test files, corresponding to different entry types
44 U_BOOT_IMG_DATA = b'img'
45 U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
46 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
50 U_BOOT_DTB_DATA = b'udtb'
51 U_BOOT_SPL_DTB_DATA = b'spldtb'
52 U_BOOT_TPL_DTB_DATA = b'tpldtb'
53 X86_START16_DATA = b'start16'
54 X86_START16_SPL_DATA = b'start16spl'
55 X86_START16_TPL_DATA = b'start16tpl'
56 X86_RESET16_DATA = b'reset16'
57 X86_RESET16_SPL_DATA = b'reset16spl'
58 X86_RESET16_TPL_DATA = b'reset16tpl'
59 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
60 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
61 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
62 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
70 CROS_EC_RW_DATA = b'ecrw'
74 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
75 b"sorry you're alive\n")
76 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
77 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
78 REFCODE_DATA = b'refcode'
82 ATF_BL31_DATA = b'bl31'
83 ATF_BL2U_DATA = b'bl2u'
84 OPENSBI_DATA = b'opensbi'
86 TEST_FDT1_DATA = b'fdt1'
87 TEST_FDT2_DATA = b'test-fdt2'
88 ENV_DATA = b'var1=1\nvar2="2"'
90 # Subdirectory of the input dir to use to put test FDTs
91 TEST_FDT_SUBDIR = 'fdts'
93 # The expected size for the device tree in some tests
94 EXTRACT_DTB_SIZE = 0x3c9
96 # Properties expected to be in the device tree when update_dtb is used
97 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
99 # Extra properties expected to be in the device tree when allow-repack is used
100 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
103 class TestFunctional(unittest.TestCase):
104 """Functional tests for binman
106 Most of these use a sample .dts file to build an image and then check
107 that it looks correct. The sample files are in the test/ subdirectory
110 For each entry type a very small test file is created using fixed
111 string contents. This makes it easy to test that things look right, and
114 In some cases a 'real' file must be used - these are also supplied in
115 the test/ diurectory.
120 from binman import entry
122 # Handle the case where argv[0] is 'python'
123 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
124 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
126 # Create a temporary directory for input files
127 cls._indir = tempfile.mkdtemp(prefix='binmant.')
129 # Create some test files
130 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
131 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
132 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
133 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
134 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
135 TestFunctional._MakeInputFile('me.bin', ME_DATA)
136 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
139 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
141 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
142 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
143 X86_START16_SPL_DATA)
144 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
145 X86_START16_TPL_DATA)
147 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
149 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
150 X86_RESET16_SPL_DATA)
151 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
152 X86_RESET16_TPL_DATA)
154 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
155 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
156 U_BOOT_SPL_NODTB_DATA)
157 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
158 U_BOOT_TPL_NODTB_DATA)
159 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
160 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
161 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
162 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
163 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
164 TestFunctional._MakeInputDir('devkeys')
165 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
166 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
167 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
168 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
169 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
171 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
172 elf_test.BuildElfTestFiles(cls._elf_testdir)
174 # ELF file with a '_dt_ucode_base_size' symbol
175 TestFunctional._MakeInputFile('u-boot',
176 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
178 # Intel flash descriptor file
179 cls._SetupDescriptor()
181 shutil.copytree(cls.TestFile('files'),
182 os.path.join(cls._indir, 'files'))
184 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
185 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
186 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
187 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
188 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
189 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
191 # Add a few .dtb files for testing
192 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
194 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
197 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
199 # Travis-CI may have an old lz4
202 tools.Run('lz4', '--no-frame-crc', '-c',
203 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
208 def tearDownClass(cls):
209 """Remove the temporary input directory and its contents"""
210 if cls.preserve_indir:
211 print('Preserving input dir: %s' % cls._indir)
214 shutil.rmtree(cls._indir)
218 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
219 toolpath=None, verbosity=None):
220 """Accept arguments controlling test execution
223 preserve_indir: Preserve the shared input directory used by all
225 preserve_outdir: Preserve the output directories used by tests. Each
226 test has its own, so this is normally only useful when running a
228 toolpath: ist of paths to use for tools
230 cls.preserve_indir = preserve_indir
231 cls.preserve_outdirs = preserve_outdirs
232 cls.toolpath = toolpath
233 cls.verbosity = verbosity
236 if not self.have_lz4:
237 self.skipTest('lz4 --no-frame-crc not available')
239 def _CleanupOutputDir(self):
240 """Remove the temporary output directory"""
241 if self.preserve_outdirs:
242 print('Preserving output dir: %s' % tools.outdir)
244 tools._FinaliseForTest()
247 # Enable this to turn on debugging output
248 # tout.Init(tout.DEBUG)
249 command.test_result = None
252 """Remove the temporary output directory"""
253 self._CleanupOutputDir()
255 def _SetupImageInTmpdir(self):
256 """Set up the output image in a new temporary directory
258 This is used when an image has been generated in the output directory,
259 but we want to run binman again. This will create a new output
260 directory and fail to delete the original one.
262 This creates a new temporary directory, copies the image to it (with a
263 new name) and removes the old output directory.
267 Temporary directory to use
270 image_fname = tools.GetOutputFilename('image.bin')
271 tmpdir = tempfile.mkdtemp(prefix='binman.')
272 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
273 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
274 self._CleanupOutputDir()
275 return tmpdir, updated_fname
279 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
280 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
281 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
283 def _RunBinman(self, *args, **kwargs):
284 """Run binman using the command line
287 Arguments to pass, as a list of strings
288 kwargs: Arguments to pass to Command.RunPipe()
290 result = command.RunPipe([[self._binman_pathname] + list(args)],
291 capture=True, capture_stderr=True, raise_on_error=False)
292 if result.return_code and kwargs.get('raise_on_error', True):
293 raise Exception("Error running '%s': %s" % (' '.join(args),
294 result.stdout + result.stderr))
297 def _DoBinman(self, *argv):
298 """Run binman using directly (in the same process)
301 Arguments to pass, as a list of strings
303 Return value (0 for success)
306 args = cmdline.ParseArgs(argv)
307 args.pager = 'binman-invalid-pager'
308 args.build_dir = self._indir
310 # For testing, you can force an increase in verbosity here
311 # args.verbosity = tout.DEBUG
312 return control.Binman(args)
314 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
315 entry_args=None, images=None, use_real_dtb=False,
316 use_expanded=False, verbosity=None, allow_missing=False,
317 allow_fake_blobs=False, extra_indirs=None, threads=None,
318 test_section_timeout=False, update_fdt_in_elf=None):
319 """Run binman with a given test file
322 fname: Device-tree source filename to use (e.g. 005_simple.dts)
323 debug: True to enable debugging output
324 map: True to output map files for the images
325 update_dtb: Update the offset and size of each entry in the device
326 tree before packing it into the image
327 entry_args: Dict of entry args to supply to binman
329 value: value of that arg
330 images: List of image names to build
331 use_real_dtb: True to use the test file as the contents of
332 the u-boot-dtb entry. Normally this is not needed and the
333 test contents (the U_BOOT_DTB_DATA string) can be used.
334 But in some test we need the real contents.
335 use_expanded: True to use expanded entries where available, e.g.
336 'u-boot-expanded' instead of 'u-boot'
337 verbosity: Verbosity level to use (0-3, None=don't set it)
338 allow_missing: Set the '--allow-missing' flag so that missing
339 external binaries just produce a warning instead of an error
340 allow_fake_blobs: Set the '--fake-ext-blobs' flag
341 extra_indirs: Extra input directories to add using -I
342 threads: Number of threads to use (None for default, 0 for
344 test_section_timeout: True to force the first time to timeout, as
345 used in testThreadTimeout()
346 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
349 int return code, 0 on success
354 if verbosity is not None:
355 args.append('-v%d' % verbosity)
357 args.append('-v%d' % self.verbosity)
359 for path in self.toolpath:
360 args += ['--toolpath', path]
361 if threads is not None:
362 args.append('-T%d' % threads)
363 if test_section_timeout:
364 args.append('--test-section-timeout')
365 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
371 args.append('--fake-dtb')
373 args.append('--no-expanded')
375 for arg, value in entry_args.items():
376 args.append('-a%s=%s' % (arg, value))
380 args.append('--fake-ext-blobs')
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.GetOutputFilename('u-boot.dtb.out')
497 # Find the (only) image, read it and return its contents
498 image = control.images['image']
499 image_fname = tools.GetOutputFilename('image.bin')
500 self.assertTrue(os.path.exists(image_fname))
502 map_fname = tools.GetOutputFilename('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.ReadFile(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.ReadFile(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.GetOutputFilename('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.GetOutputFilename('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.GetBytes(0, 3), data[:3])
773 self.assertEqual(tools.GetBytes(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.GetBytes(0, 3) + U_BOOT_DATA +
842 tools.GetBytes(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.GetBytes(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.GetBytes(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.GetBytes(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.GetBytes(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.GetOutputFilename('test-name')
1009 self.assertTrue(os.path.exists(fname))
1011 image = control.images['image2']
1012 fname = tools.GetOutputFilename('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.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1025 tools.GetBytes(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.GetBytes(0, 3) + U_BOOT_SPL_DATA +
1069 tools.GetBytes(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.ReadFile(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.GetOutputFilename('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.ReadFile(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.ReadFile(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.ReadFile(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.GetBytes(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.GetBytes(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.GetBytes(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.GetBytes(ord('!'), 12) +
1430 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1431 U_BOOT_DATA + tools.GetBytes(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.ToBytes(TEXT_DATA) +
1597 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1598 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(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.GetBytes(ord('!'), 12) +
1621 U_BOOT_DATA + tools.GetBytes(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.GetBytes(0xff, 8) + tools.GetBytes(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.GetBytes(0, 8) +
1704 tools.GetBytes(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 _HandleVblockCommand(self, pipe_list):
1722 """Fake calls to the futility utility
1724 The expected pipe is:
1726 [('futility', 'vbutil_firmware', '--vblock',
1727 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1728 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1729 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1730 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1732 This writes to the output file (here, 'vblock.vblock'). If
1733 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1734 of the input data (here, 'input.vblock').
1736 if pipe_list[0][0] == 'futility':
1737 fname = pipe_list[0][3]
1738 with open(fname, 'wb') as fd:
1740 infile = pipe_list[0][11]
1741 m = hashlib.sha256()
1742 data = tools.ReadFile(infile)
1744 fd.write(m.digest())
1746 fd.write(VBLOCK_DATA)
1748 return command.CommandResult()
1750 def testVblock(self):
1751 """Test for the Chromium OS Verified Boot Block"""
1752 self._hash_data = False
1753 command.test_result = self._HandleVblockCommand
1755 'keydir': 'devkeys',
1757 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1758 entry_args=entry_args)
1759 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1760 self.assertEqual(expected, data)
1762 def testVblockNoContent(self):
1763 """Test we detect a vblock which has no content to sign"""
1764 with self.assertRaises(ValueError) as e:
1765 self._DoReadFile('075_vblock_no_content.dts')
1766 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1767 'property', str(e.exception))
1769 def testVblockBadPhandle(self):
1770 """Test that we detect a vblock with an invalid phandle in contents"""
1771 with self.assertRaises(ValueError) as e:
1772 self._DoReadFile('076_vblock_bad_phandle.dts')
1773 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1774 '1000', str(e.exception))
1776 def testVblockBadEntry(self):
1777 """Test that we detect an entry that points to a non-entry"""
1778 with self.assertRaises(ValueError) as e:
1779 self._DoReadFile('077_vblock_bad_entry.dts')
1780 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1781 "'other'", str(e.exception))
1783 def testVblockContent(self):
1784 """Test that the vblock signs the right data"""
1785 self._hash_data = True
1786 command.test_result = self._HandleVblockCommand
1788 'keydir': 'devkeys',
1790 data = self._DoReadFileDtb(
1791 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1792 entry_args=entry_args)[0]
1793 hashlen = 32 # SHA256 hash is 32 bytes
1794 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1795 hashval = data[-hashlen:]
1796 dtb = data[len(U_BOOT_DATA):-hashlen]
1798 expected_data = U_BOOT_DATA + dtb
1800 # The hashval should be a hash of the dtb
1801 m = hashlib.sha256()
1802 m.update(expected_data)
1803 expected_hashval = m.digest()
1804 self.assertEqual(expected_hashval, hashval)
1807 """Test that an image with TPL and its device tree can be created"""
1808 # ELF file with a '__bss_size' symbol
1810 data = self._DoReadFile('078_u_boot_tpl.dts')
1811 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1813 def testUsesPos(self):
1814 """Test that the 'pos' property cannot be used anymore"""
1815 with self.assertRaises(ValueError) as e:
1816 data = self._DoReadFile('079_uses_pos.dts')
1817 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1818 "'pos'", str(e.exception))
1820 def testFillZero(self):
1821 """Test for an fill entry type with a size of 0"""
1822 data = self._DoReadFile('080_fill_empty.dts')
1823 self.assertEqual(tools.GetBytes(0, 16), data)
1825 def testTextMissing(self):
1826 """Test for a text entry type where there is no text"""
1827 with self.assertRaises(ValueError) as e:
1828 self._DoReadFileDtb('066_text.dts',)
1829 self.assertIn("Node '/binman/text': No value provided for text label "
1830 "'test-id'", str(e.exception))
1832 def testPackStart16Tpl(self):
1833 """Test that an image with an x86 start16 TPL region can be created"""
1834 data = self._DoReadFile('081_x86_start16_tpl.dts')
1835 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1837 def testSelectImage(self):
1838 """Test that we can select which images to build"""
1839 expected = 'Skipping images: image1'
1841 # We should only get the expected message in verbose mode
1842 for verbosity in (0, 2):
1843 with test_util.capture_sys_output() as (stdout, stderr):
1844 retcode = self._DoTestFile('006_dual_image.dts',
1845 verbosity=verbosity,
1847 self.assertEqual(0, retcode)
1849 self.assertIn(expected, stdout.getvalue())
1851 self.assertNotIn(expected, stdout.getvalue())
1853 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1854 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1855 self._CleanupOutputDir()
1857 def testUpdateFdtAll(self):
1858 """Test that all device trees are updated with offset/size info"""
1859 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1862 'section:image-pos': 0,
1863 'u-boot-tpl-dtb:size': 513,
1864 'u-boot-spl-dtb:size': 513,
1865 'u-boot-spl-dtb:offset': 493,
1867 'section/u-boot-dtb:image-pos': 0,
1868 'u-boot-spl-dtb:image-pos': 493,
1869 'section/u-boot-dtb:size': 493,
1870 'u-boot-tpl-dtb:image-pos': 1006,
1871 'section/u-boot-dtb:offset': 0,
1872 'section:size': 493,
1874 'section:offset': 0,
1875 'u-boot-tpl-dtb:offset': 1006,
1879 # We expect three device-tree files in the output, one after the other.
1880 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1881 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1882 # main U-Boot tree. All three should have the same postions and offset.
1884 for item in ['', 'spl', 'tpl']:
1885 dtb = fdt.Fdt.FromData(data[start:])
1887 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1889 expected = dict(base_expected)
1892 self.assertEqual(expected, props)
1893 start += dtb._fdt_obj.totalsize()
1895 def testUpdateFdtOutput(self):
1896 """Test that output DTB files are updated"""
1898 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1899 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1901 # Unfortunately, compiling a source file always results in a file
1902 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1903 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1904 # binman as a file called u-boot.dtb. To fix this, copy the file
1905 # over to the expected place.
1907 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1908 'tpl/u-boot-tpl.dtb.out']:
1909 dtb = fdt.Fdt.FromData(data[start:])
1910 size = dtb._fdt_obj.totalsize()
1911 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1912 outdata = tools.ReadFile(pathname)
1913 name = os.path.split(fname)[0]
1916 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1918 orig_indata = dtb_data
1919 self.assertNotEqual(outdata, orig_indata,
1920 "Expected output file '%s' be updated" % pathname)
1921 self.assertEqual(outdata, data[start:start + size],
1922 "Expected output file '%s' to match output image" %
1928 def _decompress(self, data):
1929 return tools.Decompress(data, 'lz4')
1931 def testCompress(self):
1932 """Test compression of blobs"""
1934 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1935 use_real_dtb=True, update_dtb=True)
1936 dtb = fdt.Fdt(out_dtb_fname)
1938 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1939 orig = self._decompress(data)
1940 self.assertEquals(COMPRESS_DATA, orig)
1942 # Do a sanity check on various fields
1943 image = control.images['image']
1944 entries = image.GetEntries()
1945 self.assertEqual(1, len(entries))
1947 entry = entries['blob']
1948 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1949 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1950 orig = self._decompress(entry.data)
1951 self.assertEqual(orig, entry.uncomp_data)
1953 self.assertEqual(image.data, entry.data)
1956 'blob:uncomp-size': len(COMPRESS_DATA),
1957 'blob:size': len(data),
1960 self.assertEqual(expected, props)
1962 def testFiles(self):
1963 """Test bringing in multiple files"""
1964 data = self._DoReadFile('084_files.dts')
1965 self.assertEqual(FILES_DATA, data)
1967 def testFilesCompress(self):
1968 """Test bringing in multiple files and compressing them"""
1970 data = self._DoReadFile('085_files_compress.dts')
1972 image = control.images['image']
1973 entries = image.GetEntries()
1974 files = entries['files']
1975 entries = files._entries
1978 for i in range(1, 3):
1980 start = entries[key].image_pos
1981 len = entries[key].size
1982 chunk = data[start:start + len]
1983 orig += self._decompress(chunk)
1985 self.assertEqual(FILES_DATA, orig)
1987 def testFilesMissing(self):
1988 """Test missing files"""
1989 with self.assertRaises(ValueError) as e:
1990 data = self._DoReadFile('086_files_none.dts')
1991 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1992 'no files', str(e.exception))
1994 def testFilesNoPattern(self):
1995 """Test missing files"""
1996 with self.assertRaises(ValueError) as e:
1997 data = self._DoReadFile('087_files_no_pattern.dts')
1998 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2001 def testExpandSize(self):
2002 """Test an expanding entry"""
2003 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
2005 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2006 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2007 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2008 tools.GetBytes(ord('d'), 8))
2009 self.assertEqual(expect, data)
2010 self.assertEqual('''ImagePos Offset Size Name
2011 00000000 00000000 00000028 main-section
2012 00000000 00000000 00000008 fill
2013 00000008 00000008 00000004 u-boot
2014 0000000c 0000000c 00000004 section
2015 0000000c 00000000 00000003 intel-mrc
2016 00000010 00000010 00000004 u-boot2
2017 00000014 00000014 0000000c section2
2018 00000014 00000000 00000008 fill
2019 0000001c 00000008 00000004 u-boot
2020 00000020 00000020 00000008 fill2
2023 def testExpandSizeBad(self):
2024 """Test an expanding entry which fails to provide contents"""
2025 with test_util.capture_sys_output() as (stdout, stderr):
2026 with self.assertRaises(ValueError) as e:
2027 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
2028 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2029 'expanding entry', str(e.exception))
2032 """Test hashing of the contents of an entry"""
2033 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2034 use_real_dtb=True, update_dtb=True)
2035 dtb = fdt.Fdt(out_dtb_fname)
2037 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2038 m = hashlib.sha256()
2039 m.update(U_BOOT_DATA)
2040 self.assertEqual(m.digest(), b''.join(hash_node.value))
2042 def testHashNoAlgo(self):
2043 with self.assertRaises(ValueError) as e:
2044 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2045 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2046 'hash node', str(e.exception))
2048 def testHashBadAlgo(self):
2049 with self.assertRaises(ValueError) as e:
2050 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2051 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2054 def testHashSection(self):
2055 """Test hashing of the contents of an entry"""
2056 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2057 use_real_dtb=True, update_dtb=True)
2058 dtb = fdt.Fdt(out_dtb_fname)
2060 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2061 m = hashlib.sha256()
2062 m.update(U_BOOT_DATA)
2063 m.update(tools.GetBytes(ord('a'), 16))
2064 self.assertEqual(m.digest(), b''.join(hash_node.value))
2066 def testPackUBootTplMicrocode(self):
2067 """Test that x86 microcode can be handled correctly in TPL
2069 We expect to see the following in the image, in order:
2070 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2072 u-boot-tpl.dtb with the microcode removed
2075 self._SetupTplElf('u_boot_ucode_ptr')
2076 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2077 U_BOOT_TPL_NODTB_DATA)
2078 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2079 b'ter somewhere in here', first)
2081 def testFmapX86(self):
2082 """Basic test of generation of a flashrom fmap"""
2083 data = self._DoReadFile('094_fmap_x86.dts')
2084 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2085 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
2086 self.assertEqual(expected, data[:32])
2087 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2089 self.assertEqual(0x100, fhdr.image_size)
2091 self.assertEqual(0, fentries[0].offset)
2092 self.assertEqual(4, fentries[0].size)
2093 self.assertEqual(b'U_BOOT', fentries[0].name)
2095 self.assertEqual(4, fentries[1].offset)
2096 self.assertEqual(3, fentries[1].size)
2097 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2099 self.assertEqual(32, fentries[2].offset)
2100 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2101 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2102 self.assertEqual(b'FMAP', fentries[2].name)
2104 def testFmapX86Section(self):
2105 """Basic test of generation of a flashrom fmap"""
2106 data = self._DoReadFile('095_fmap_x86_section.dts')
2107 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
2108 self.assertEqual(expected, data[:32])
2109 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2111 self.assertEqual(0x180, fhdr.image_size)
2112 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2113 fiter = iter(fentries)
2115 fentry = next(fiter)
2116 self.assertEqual(b'U_BOOT', fentry.name)
2117 self.assertEqual(0, fentry.offset)
2118 self.assertEqual(4, fentry.size)
2120 fentry = next(fiter)
2121 self.assertEqual(b'SECTION', fentry.name)
2122 self.assertEqual(4, fentry.offset)
2123 self.assertEqual(0x20 + expect_size, fentry.size)
2125 fentry = next(fiter)
2126 self.assertEqual(b'INTEL_MRC', fentry.name)
2127 self.assertEqual(4, fentry.offset)
2128 self.assertEqual(3, fentry.size)
2130 fentry = next(fiter)
2131 self.assertEqual(b'FMAP', fentry.name)
2132 self.assertEqual(36, fentry.offset)
2133 self.assertEqual(expect_size, fentry.size)
2136 """Basic test of ELF entries"""
2139 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2140 TestFunctional._MakeInputFile('-boot', fd.read())
2141 data = self._DoReadFile('096_elf.dts')
2143 def testElfStrip(self):
2144 """Basic test of ELF entries"""
2146 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2147 TestFunctional._MakeInputFile('-boot', fd.read())
2148 data = self._DoReadFile('097_elf_strip.dts')
2150 def testPackOverlapMap(self):
2151 """Test that overlapping regions are detected"""
2152 with test_util.capture_sys_output() as (stdout, stderr):
2153 with self.assertRaises(ValueError) as e:
2154 self._DoTestFile('014_pack_overlap.dts', map=True)
2155 map_fname = tools.GetOutputFilename('image.map')
2156 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2159 # We should not get an inmage, but there should be a map file
2160 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2161 self.assertTrue(os.path.exists(map_fname))
2162 map_data = tools.ReadFile(map_fname, binary=False)
2163 self.assertEqual('''ImagePos Offset Size Name
2164 <none> 00000000 00000008 main-section
2165 <none> 00000000 00000004 u-boot
2166 <none> 00000003 00000004 u-boot-align
2169 def testPackRefCode(self):
2170 """Test that an image with an Intel Reference code binary works"""
2171 data = self._DoReadFile('100_intel_refcode.dts')
2172 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2174 def testSectionOffset(self):
2175 """Tests use of a section with an offset"""
2176 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2178 self.assertEqual('''ImagePos Offset Size Name
2179 00000000 00000000 00000038 main-section
2180 00000004 00000004 00000010 section@0
2181 00000004 00000000 00000004 u-boot
2182 00000018 00000018 00000010 section@1
2183 00000018 00000000 00000004 u-boot
2184 0000002c 0000002c 00000004 section@2
2185 0000002c 00000000 00000004 u-boot
2187 self.assertEqual(data,
2188 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2189 tools.GetBytes(0x21, 12) +
2190 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2191 tools.GetBytes(0x61, 12) +
2192 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2193 tools.GetBytes(0x26, 8))
2195 def testCbfsRaw(self):
2196 """Test base handling of a Coreboot Filesystem (CBFS)
2198 The exact contents of the CBFS is verified by similar tests in
2199 cbfs_util_test.py. The tests here merely check that the files added to
2200 the CBFS can be found in the final image.
2202 data = self._DoReadFile('102_cbfs_raw.dts')
2205 cbfs = cbfs_util.CbfsReader(data)
2206 self.assertEqual(size, cbfs.rom_size)
2208 self.assertIn('u-boot-dtb', cbfs.files)
2209 cfile = cbfs.files['u-boot-dtb']
2210 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2212 def testCbfsArch(self):
2213 """Test on non-x86 architecture"""
2214 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2217 cbfs = cbfs_util.CbfsReader(data)
2218 self.assertEqual(size, cbfs.rom_size)
2220 self.assertIn('u-boot-dtb', cbfs.files)
2221 cfile = cbfs.files['u-boot-dtb']
2222 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2224 def testCbfsStage(self):
2225 """Tests handling of a Coreboot Filesystem (CBFS)"""
2226 if not elf.ELF_TOOLS:
2227 self.skipTest('Python elftools not available')
2228 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2229 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2232 data = self._DoReadFile('104_cbfs_stage.dts')
2233 cbfs = cbfs_util.CbfsReader(data)
2234 self.assertEqual(size, cbfs.rom_size)
2236 self.assertIn('u-boot', cbfs.files)
2237 cfile = cbfs.files['u-boot']
2238 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2240 def testCbfsRawCompress(self):
2241 """Test handling of compressing raw files"""
2243 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2246 cbfs = cbfs_util.CbfsReader(data)
2247 self.assertIn('u-boot', cbfs.files)
2248 cfile = cbfs.files['u-boot']
2249 self.assertEqual(COMPRESS_DATA, cfile.data)
2251 def testCbfsBadArch(self):
2252 """Test handling of a bad architecture"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('106_cbfs_bad_arch.dts')
2255 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2257 def testCbfsNoSize(self):
2258 """Test handling of a missing size property"""
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFile('107_cbfs_no_size.dts')
2261 self.assertIn('entry must have a size property', str(e.exception))
2263 def testCbfsNoContents(self):
2264 """Test handling of a CBFS entry which does not provide contentsy"""
2265 with self.assertRaises(ValueError) as e:
2266 self._DoReadFile('108_cbfs_no_contents.dts')
2267 self.assertIn('Could not complete processing of contents',
2270 def testCbfsBadCompress(self):
2271 """Test handling of a bad architecture"""
2272 with self.assertRaises(ValueError) as e:
2273 self._DoReadFile('109_cbfs_bad_compress.dts')
2274 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2277 def testCbfsNamedEntries(self):
2278 """Test handling of named entries"""
2279 data = self._DoReadFile('110_cbfs_name.dts')
2281 cbfs = cbfs_util.CbfsReader(data)
2282 self.assertIn('FRED', cbfs.files)
2283 cfile1 = cbfs.files['FRED']
2284 self.assertEqual(U_BOOT_DATA, cfile1.data)
2286 self.assertIn('hello', cbfs.files)
2287 cfile2 = cbfs.files['hello']
2288 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2290 def _SetupIfwi(self, fname):
2291 """Set up to run an IFWI test
2294 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2299 # Intel Integrated Firmware Image (IFWI) file
2300 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2302 TestFunctional._MakeInputFile(fname,data)
2304 def _CheckIfwi(self, data):
2305 """Check that an image with an IFWI contains the correct output
2308 data: Conents of output file
2310 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2311 if data[:0x1000] != expected_desc:
2312 self.fail('Expected descriptor binary at start of image')
2314 # We expect to find the TPL wil in subpart IBBP entry IBBL
2315 image_fname = tools.GetOutputFilename('image.bin')
2316 tpl_fname = tools.GetOutputFilename('tpl.out')
2317 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2318 subpart='IBBP', entry_name='IBBL')
2320 tpl_data = tools.ReadFile(tpl_fname)
2321 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2323 def testPackX86RomIfwi(self):
2324 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2325 self._SetupIfwi('fitimage.bin')
2326 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2327 self._CheckIfwi(data)
2329 def testPackX86RomIfwiNoDesc(self):
2330 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2331 self._SetupIfwi('ifwi.bin')
2332 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2333 self._CheckIfwi(data)
2335 def testPackX86RomIfwiNoData(self):
2336 """Test that an x86 ROM with IFWI handles missing data"""
2337 self._SetupIfwi('ifwi.bin')
2338 with self.assertRaises(ValueError) as e:
2339 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2340 self.assertIn('Could not complete processing of contents',
2343 def testCbfsOffset(self):
2344 """Test a CBFS with files at particular offsets
2346 Like all CFBS tests, this is just checking the logic that calls
2347 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2349 data = self._DoReadFile('114_cbfs_offset.dts')
2352 cbfs = cbfs_util.CbfsReader(data)
2353 self.assertEqual(size, cbfs.rom_size)
2355 self.assertIn('u-boot', cbfs.files)
2356 cfile = cbfs.files['u-boot']
2357 self.assertEqual(U_BOOT_DATA, cfile.data)
2358 self.assertEqual(0x40, cfile.cbfs_offset)
2360 self.assertIn('u-boot-dtb', cbfs.files)
2361 cfile2 = cbfs.files['u-boot-dtb']
2362 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2363 self.assertEqual(0x140, cfile2.cbfs_offset)
2365 def testFdtmap(self):
2366 """Test an FDT map can be inserted in the image"""
2367 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2368 fdtmap_data = data[len(U_BOOT_DATA):]
2369 magic = fdtmap_data[:8]
2370 self.assertEqual(b'_FDTMAP_', magic)
2371 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2373 fdt_data = fdtmap_data[16:]
2374 dtb = fdt.Fdt.FromData(fdt_data)
2376 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2381 'u-boot:size': len(U_BOOT_DATA),
2382 'u-boot:image-pos': 0,
2383 'fdtmap:image-pos': 4,
2385 'fdtmap:size': len(fdtmap_data),
2389 def testFdtmapNoMatch(self):
2390 """Check handling of an FDT map when the section cannot be found"""
2391 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2393 # Mangle the section name, which should cause a mismatch between the
2394 # correct FDT path and the one expected by the section
2395 image = control.images['image']
2396 image._node.path += '-suffix'
2397 entries = image.GetEntries()
2398 fdtmap = entries['fdtmap']
2399 with self.assertRaises(ValueError) as e:
2401 self.assertIn("Cannot locate node for path '/binman-suffix'",
2404 def testFdtmapHeader(self):
2405 """Test an FDT map and image header can be inserted in the image"""
2406 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2407 fdtmap_pos = len(U_BOOT_DATA)
2408 fdtmap_data = data[fdtmap_pos:]
2409 fdt_data = fdtmap_data[16:]
2410 dtb = fdt.Fdt.FromData(fdt_data)
2411 fdt_size = dtb.GetFdtObj().totalsize()
2412 hdr_data = data[-8:]
2413 self.assertEqual(b'BinM', hdr_data[:4])
2414 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2415 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2417 def testFdtmapHeaderStart(self):
2418 """Test an image header can be inserted at the image start"""
2419 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2420 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2422 self.assertEqual(b'BinM', hdr_data[:4])
2423 offset = struct.unpack('<I', hdr_data[4:])[0]
2424 self.assertEqual(fdtmap_pos, offset)
2426 def testFdtmapHeaderPos(self):
2427 """Test an image header can be inserted at a chosen position"""
2428 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2429 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2430 hdr_data = data[0x80:0x88]
2431 self.assertEqual(b'BinM', hdr_data[:4])
2432 offset = struct.unpack('<I', hdr_data[4:])[0]
2433 self.assertEqual(fdtmap_pos, offset)
2435 def testHeaderMissingFdtmap(self):
2436 """Test an image header requires an fdtmap"""
2437 with self.assertRaises(ValueError) as e:
2438 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2439 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2442 def testHeaderNoLocation(self):
2443 """Test an image header with a no specified location is detected"""
2444 with self.assertRaises(ValueError) as e:
2445 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2446 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2449 def testEntryExpand(self):
2450 """Test expanding an entry after it is packed"""
2451 data = self._DoReadFile('121_entry_expand.dts')
2452 self.assertEqual(b'aaa', data[:3])
2453 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2454 self.assertEqual(b'aaa', data[-3:])
2456 def testEntryExpandBad(self):
2457 """Test expanding an entry after it is packed, twice"""
2458 with self.assertRaises(ValueError) as e:
2459 self._DoReadFile('122_entry_expand_twice.dts')
2460 self.assertIn("Image '/binman': Entries changed size after packing",
2463 def testEntryExpandSection(self):
2464 """Test expanding an entry within a section after it is packed"""
2465 data = self._DoReadFile('123_entry_expand_section.dts')
2466 self.assertEqual(b'aaa', data[:3])
2467 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2468 self.assertEqual(b'aaa', data[-3:])
2470 def testCompressDtb(self):
2471 """Test that compress of device-tree files is supported"""
2473 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2474 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2475 comp_data = data[len(U_BOOT_DATA):]
2476 orig = self._decompress(comp_data)
2477 dtb = fdt.Fdt.FromData(orig)
2479 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2481 'u-boot:size': len(U_BOOT_DATA),
2482 'u-boot-dtb:uncomp-size': len(orig),
2483 'u-boot-dtb:size': len(comp_data),
2486 self.assertEqual(expected, props)
2488 def testCbfsUpdateFdt(self):
2489 """Test that we can update the device tree with CBFS offset/size info"""
2491 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2493 dtb = fdt.Fdt(out_dtb_fname)
2495 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2496 del props['cbfs/u-boot:size']
2502 'cbfs:size': len(data),
2503 'cbfs:image-pos': 0,
2504 'cbfs/u-boot:offset': 0x38,
2505 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2506 'cbfs/u-boot:image-pos': 0x38,
2507 'cbfs/u-boot-dtb:offset': 0xb8,
2508 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2509 'cbfs/u-boot-dtb:image-pos': 0xb8,
2512 def testCbfsBadType(self):
2513 """Test an image header with a no specified location is detected"""
2514 with self.assertRaises(ValueError) as e:
2515 self._DoReadFile('126_cbfs_bad_type.dts')
2516 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2519 """Test listing the files in an image"""
2521 data = self._DoReadFile('127_list.dts')
2522 image = control.images['image']
2523 entries = image.BuildEntryList()
2524 self.assertEqual(7, len(entries))
2527 self.assertEqual(0, ent.indent)
2528 self.assertEqual('main-section', ent.name)
2529 self.assertEqual('section', ent.etype)
2530 self.assertEqual(len(data), ent.size)
2531 self.assertEqual(0, ent.image_pos)
2532 self.assertEqual(None, ent.uncomp_size)
2533 self.assertEqual(0, ent.offset)
2536 self.assertEqual(1, ent.indent)
2537 self.assertEqual('u-boot', ent.name)
2538 self.assertEqual('u-boot', ent.etype)
2539 self.assertEqual(len(U_BOOT_DATA), ent.size)
2540 self.assertEqual(0, ent.image_pos)
2541 self.assertEqual(None, ent.uncomp_size)
2542 self.assertEqual(0, ent.offset)
2545 self.assertEqual(1, ent.indent)
2546 self.assertEqual('section', ent.name)
2547 self.assertEqual('section', ent.etype)
2548 section_size = ent.size
2549 self.assertEqual(0x100, ent.image_pos)
2550 self.assertEqual(None, ent.uncomp_size)
2551 self.assertEqual(0x100, ent.offset)
2554 self.assertEqual(2, ent.indent)
2555 self.assertEqual('cbfs', ent.name)
2556 self.assertEqual('cbfs', ent.etype)
2557 self.assertEqual(0x400, ent.size)
2558 self.assertEqual(0x100, ent.image_pos)
2559 self.assertEqual(None, ent.uncomp_size)
2560 self.assertEqual(0, ent.offset)
2563 self.assertEqual(3, ent.indent)
2564 self.assertEqual('u-boot', ent.name)
2565 self.assertEqual('u-boot', ent.etype)
2566 self.assertEqual(len(U_BOOT_DATA), ent.size)
2567 self.assertEqual(0x138, ent.image_pos)
2568 self.assertEqual(None, ent.uncomp_size)
2569 self.assertEqual(0x38, ent.offset)
2572 self.assertEqual(3, ent.indent)
2573 self.assertEqual('u-boot-dtb', ent.name)
2574 self.assertEqual('text', ent.etype)
2575 self.assertGreater(len(COMPRESS_DATA), ent.size)
2576 self.assertEqual(0x178, ent.image_pos)
2577 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2578 self.assertEqual(0x78, ent.offset)
2581 self.assertEqual(2, ent.indent)
2582 self.assertEqual('u-boot-dtb', ent.name)
2583 self.assertEqual('u-boot-dtb', ent.etype)
2584 self.assertEqual(0x500, ent.image_pos)
2585 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2587 # Compressing this data expands it since headers are added
2588 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2589 self.assertEqual(0x400, ent.offset)
2591 self.assertEqual(len(data), 0x100 + section_size)
2592 self.assertEqual(section_size, 0x400 + dtb_size)
2594 def testFindFdtmap(self):
2595 """Test locating an FDT map in an image"""
2597 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2598 image = control.images['image']
2599 entries = image.GetEntries()
2600 entry = entries['fdtmap']
2601 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2603 def testFindFdtmapMissing(self):
2604 """Test failing to locate an FDP map"""
2605 data = self._DoReadFile('005_simple.dts')
2606 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2608 def testFindImageHeader(self):
2609 """Test locating a image header"""
2611 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2612 image = control.images['image']
2613 entries = image.GetEntries()
2614 entry = entries['fdtmap']
2615 # The header should point to the FDT map
2616 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2618 def testFindImageHeaderStart(self):
2619 """Test locating a image header located at the start of an image"""
2620 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2621 image = control.images['image']
2622 entries = image.GetEntries()
2623 entry = entries['fdtmap']
2624 # The header should point to the FDT map
2625 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2627 def testFindImageHeaderMissing(self):
2628 """Test failing to locate an image header"""
2629 data = self._DoReadFile('005_simple.dts')
2630 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2632 def testReadImage(self):
2633 """Test reading an image and accessing its FDT map"""
2635 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2636 image_fname = tools.GetOutputFilename('image.bin')
2637 orig_image = control.images['image']
2638 image = Image.FromFile(image_fname)
2639 self.assertEqual(orig_image.GetEntries().keys(),
2640 image.GetEntries().keys())
2642 orig_entry = orig_image.GetEntries()['fdtmap']
2643 entry = image.GetEntries()['fdtmap']
2644 self.assertEquals(orig_entry.offset, entry.offset)
2645 self.assertEquals(orig_entry.size, entry.size)
2646 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2648 def testReadImageNoHeader(self):
2649 """Test accessing an image's FDT map without an image header"""
2651 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2652 image_fname = tools.GetOutputFilename('image.bin')
2653 image = Image.FromFile(image_fname)
2654 self.assertTrue(isinstance(image, Image))
2655 self.assertEqual('image', image.image_name[-5:])
2657 def testReadImageFail(self):
2658 """Test failing to read an image image's FDT map"""
2659 self._DoReadFile('005_simple.dts')
2660 image_fname = tools.GetOutputFilename('image.bin')
2661 with self.assertRaises(ValueError) as e:
2662 image = Image.FromFile(image_fname)
2663 self.assertIn("Cannot find FDT map in image", str(e.exception))
2665 def testListCmd(self):
2666 """Test listing the files in an image using an Fdtmap"""
2668 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2670 # lz4 compression size differs depending on the version
2671 image = control.images['image']
2672 entries = image.GetEntries()
2673 section_size = entries['section'].size
2674 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2675 fdtmap_offset = entries['fdtmap'].offset
2678 tmpdir, updated_fname = self._SetupImageInTmpdir()
2679 with test_util.capture_sys_output() as (stdout, stderr):
2680 self._DoBinman('ls', '-i', updated_fname)
2682 shutil.rmtree(tmpdir)
2683 lines = stdout.getvalue().splitlines()
2685 'Name Image-pos Size Entry-type Offset Uncomp-size',
2686 '----------------------------------------------------------------------',
2687 'main-section 0 c00 section 0',
2688 ' u-boot 0 4 u-boot 0',
2689 ' section 100 %x section 100' % section_size,
2690 ' cbfs 100 400 cbfs 0',
2691 ' u-boot 138 4 u-boot 38',
2692 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2693 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2694 ' fdtmap %x 3bd fdtmap %x' %
2695 (fdtmap_offset, fdtmap_offset),
2696 ' image-header bf8 8 image-header bf8',
2698 self.assertEqual(expected, lines)
2700 def testListCmdFail(self):
2701 """Test failing to list an image"""
2702 self._DoReadFile('005_simple.dts')
2704 tmpdir, updated_fname = self._SetupImageInTmpdir()
2705 with self.assertRaises(ValueError) as e:
2706 self._DoBinman('ls', '-i', updated_fname)
2708 shutil.rmtree(tmpdir)
2709 self.assertIn("Cannot find FDT map in image", str(e.exception))
2711 def _RunListCmd(self, paths, expected):
2712 """List out entries and check the result
2715 paths: List of paths to pass to the list command
2716 expected: Expected list of filenames to be returned, in order
2719 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2720 image_fname = tools.GetOutputFilename('image.bin')
2721 image = Image.FromFile(image_fname)
2722 lines = image.GetListEntries(paths)[1]
2723 files = [line[0].strip() for line in lines[1:]]
2724 self.assertEqual(expected, files)
2726 def testListCmdSection(self):
2727 """Test listing the files in a section"""
2728 self._RunListCmd(['section'],
2729 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2731 def testListCmdFile(self):
2732 """Test listing a particular file"""
2733 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2735 def testListCmdWildcard(self):
2736 """Test listing a wildcarded file"""
2737 self._RunListCmd(['*boot*'],
2738 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2740 def testListCmdWildcardMulti(self):
2741 """Test listing a wildcarded file"""
2742 self._RunListCmd(['*cb*', '*head*'],
2743 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2745 def testListCmdEmpty(self):
2746 """Test listing a wildcarded file"""
2747 self._RunListCmd(['nothing'], [])
2749 def testListCmdPath(self):
2750 """Test listing the files in a sub-entry of a section"""
2751 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2753 def _RunExtractCmd(self, entry_name, decomp=True):
2754 """Extract an entry from an image
2757 entry_name: Entry name to extract
2758 decomp: True to decompress the data if compressed, False to leave
2759 it in its raw uncompressed format
2765 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2766 image_fname = tools.GetOutputFilename('image.bin')
2767 return control.ReadEntry(image_fname, entry_name, decomp)
2769 def testExtractSimple(self):
2770 """Test extracting a single file"""
2771 data = self._RunExtractCmd('u-boot')
2772 self.assertEqual(U_BOOT_DATA, data)
2774 def testExtractSection(self):
2775 """Test extracting the files in a section"""
2776 data = self._RunExtractCmd('section')
2777 cbfs_data = data[:0x400]
2778 cbfs = cbfs_util.CbfsReader(cbfs_data)
2779 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2780 dtb_data = data[0x400:]
2781 dtb = self._decompress(dtb_data)
2782 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2784 def testExtractCompressed(self):
2785 """Test extracting compressed data"""
2786 data = self._RunExtractCmd('section/u-boot-dtb')
2787 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2789 def testExtractRaw(self):
2790 """Test extracting compressed data without decompressing it"""
2791 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2792 dtb = self._decompress(data)
2793 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2795 def testExtractCbfs(self):
2796 """Test extracting CBFS data"""
2797 data = self._RunExtractCmd('section/cbfs/u-boot')
2798 self.assertEqual(U_BOOT_DATA, data)
2800 def testExtractCbfsCompressed(self):
2801 """Test extracting CBFS compressed data"""
2802 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2803 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2805 def testExtractCbfsRaw(self):
2806 """Test extracting CBFS compressed data without decompressing it"""
2807 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2808 dtb = tools.Decompress(data, 'lzma', with_header=False)
2809 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2811 def testExtractBadEntry(self):
2812 """Test extracting a bad section path"""
2813 with self.assertRaises(ValueError) as e:
2814 self._RunExtractCmd('section/does-not-exist')
2815 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2818 def testExtractMissingFile(self):
2819 """Test extracting file that does not exist"""
2820 with self.assertRaises(IOError) as e:
2821 control.ReadEntry('missing-file', 'name')
2823 def testExtractBadFile(self):
2824 """Test extracting an invalid file"""
2825 fname = os.path.join(self._indir, 'badfile')
2826 tools.WriteFile(fname, b'')
2827 with self.assertRaises(ValueError) as e:
2828 control.ReadEntry(fname, 'name')
2830 def testExtractCmd(self):
2831 """Test extracting a file fron an image on the command line"""
2833 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2834 fname = os.path.join(self._indir, 'output.extact')
2836 tmpdir, updated_fname = self._SetupImageInTmpdir()
2837 with test_util.capture_sys_output() as (stdout, stderr):
2838 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2841 shutil.rmtree(tmpdir)
2842 data = tools.ReadFile(fname)
2843 self.assertEqual(U_BOOT_DATA, data)
2845 def testExtractOneEntry(self):
2846 """Test extracting a single entry fron an image """
2848 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2849 image_fname = tools.GetOutputFilename('image.bin')
2850 fname = os.path.join(self._indir, 'output.extact')
2851 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2852 data = tools.ReadFile(fname)
2853 self.assertEqual(U_BOOT_DATA, data)
2855 def _CheckExtractOutput(self, decomp):
2856 """Helper to test file output with and without decompression
2859 decomp: True to decompress entry data, False to output it raw
2861 def _CheckPresent(entry_path, expect_data, expect_size=None):
2862 """Check and remove expected file
2864 This checks the data/size of a file and removes the file both from
2865 the outfiles set and from the output directory. Once all files are
2866 processed, both the set and directory should be empty.
2869 entry_path: Entry path
2870 expect_data: Data to expect in file, or None to skip check
2871 expect_size: Size of data to expect in file, or None to skip
2873 path = os.path.join(outdir, entry_path)
2874 data = tools.ReadFile(path)
2877 self.assertEqual(expect_data, data)
2879 self.assertEqual(expect_size, len(data))
2880 outfiles.remove(path)
2882 def _CheckDirPresent(name):
2883 """Remove expected directory
2885 This gives an error if the directory does not exist as expected
2888 name: Name of directory to remove
2890 path = os.path.join(outdir, name)
2893 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2894 image_fname = tools.GetOutputFilename('image.bin')
2895 outdir = os.path.join(self._indir, 'extract')
2896 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2898 # Create a set of all file that were output (should be 9)
2900 for root, dirs, files in os.walk(outdir):
2901 outfiles |= set([os.path.join(root, fname) for fname in files])
2902 self.assertEqual(9, len(outfiles))
2903 self.assertEqual(9, len(einfos))
2905 image = control.images['image']
2906 entries = image.GetEntries()
2908 # Check the 9 files in various ways
2909 section = entries['section']
2910 section_entries = section.GetEntries()
2911 cbfs_entries = section_entries['cbfs'].GetEntries()
2912 _CheckPresent('u-boot', U_BOOT_DATA)
2913 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2914 dtb_len = EXTRACT_DTB_SIZE
2916 dtb_len = cbfs_entries['u-boot-dtb'].size
2917 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2919 dtb_len = section_entries['u-boot-dtb'].size
2920 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2922 fdtmap = entries['fdtmap']
2923 _CheckPresent('fdtmap', fdtmap.data)
2924 hdr = entries['image-header']
2925 _CheckPresent('image-header', hdr.data)
2927 _CheckPresent('section/root', section.data)
2928 cbfs = section_entries['cbfs']
2929 _CheckPresent('section/cbfs/root', cbfs.data)
2930 data = tools.ReadFile(image_fname)
2931 _CheckPresent('root', data)
2933 # There should be no files left. Remove all the directories to check.
2934 # If there are any files/dirs remaining, one of these checks will fail.
2935 self.assertEqual(0, len(outfiles))
2936 _CheckDirPresent('section/cbfs')
2937 _CheckDirPresent('section')
2938 _CheckDirPresent('')
2939 self.assertFalse(os.path.exists(outdir))
2941 def testExtractAllEntries(self):
2942 """Test extracting all entries"""
2944 self._CheckExtractOutput(decomp=True)
2946 def testExtractAllEntriesRaw(self):
2947 """Test extracting all entries without decompressing them"""
2949 self._CheckExtractOutput(decomp=False)
2951 def testExtractSelectedEntries(self):
2952 """Test extracting some entries"""
2954 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2955 image_fname = tools.GetOutputFilename('image.bin')
2956 outdir = os.path.join(self._indir, 'extract')
2957 einfos = control.ExtractEntries(image_fname, None, outdir,
2960 # File output is tested by testExtractAllEntries(), so just check that
2961 # the expected entries are selected
2962 names = [einfo.name for einfo in einfos]
2963 self.assertEqual(names,
2964 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2966 def testExtractNoEntryPaths(self):
2967 """Test extracting some entries"""
2969 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2970 image_fname = tools.GetOutputFilename('image.bin')
2971 with self.assertRaises(ValueError) as e:
2972 control.ExtractEntries(image_fname, 'fname', None, [])
2973 self.assertIn('Must specify an entry path to write with -f',
2976 def testExtractTooManyEntryPaths(self):
2977 """Test extracting some entries"""
2979 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2980 image_fname = tools.GetOutputFilename('image.bin')
2981 with self.assertRaises(ValueError) as e:
2982 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2983 self.assertIn('Must specify exactly one entry path to write with -f',
2986 def testPackAlignSection(self):
2987 """Test that sections can have alignment"""
2988 self._DoReadFile('131_pack_align_section.dts')
2990 self.assertIn('image', control.images)
2991 image = control.images['image']
2992 entries = image.GetEntries()
2993 self.assertEqual(3, len(entries))
2996 self.assertIn('u-boot', entries)
2997 entry = entries['u-boot']
2998 self.assertEqual(0, entry.offset)
2999 self.assertEqual(0, entry.image_pos)
3000 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3001 self.assertEqual(len(U_BOOT_DATA), entry.size)
3004 self.assertIn('section0', entries)
3005 section0 = entries['section0']
3006 self.assertEqual(0x10, section0.offset)
3007 self.assertEqual(0x10, section0.image_pos)
3008 self.assertEqual(len(U_BOOT_DATA), section0.size)
3011 section_entries = section0.GetEntries()
3012 self.assertIn('u-boot', section_entries)
3013 entry = section_entries['u-boot']
3014 self.assertEqual(0, entry.offset)
3015 self.assertEqual(0x10, entry.image_pos)
3016 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3017 self.assertEqual(len(U_BOOT_DATA), entry.size)
3020 self.assertIn('section1', entries)
3021 section1 = entries['section1']
3022 self.assertEqual(0x14, section1.offset)
3023 self.assertEqual(0x14, section1.image_pos)
3024 self.assertEqual(0x20, section1.size)
3027 section_entries = section1.GetEntries()
3028 self.assertIn('u-boot', section_entries)
3029 entry = section_entries['u-boot']
3030 self.assertEqual(0, entry.offset)
3031 self.assertEqual(0x14, entry.image_pos)
3032 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3033 self.assertEqual(len(U_BOOT_DATA), entry.size)
3036 self.assertIn('section2', section_entries)
3037 section2 = section_entries['section2']
3038 self.assertEqual(0x4, section2.offset)
3039 self.assertEqual(0x18, section2.image_pos)
3040 self.assertEqual(4, section2.size)
3043 section_entries = section2.GetEntries()
3044 self.assertIn('u-boot', section_entries)
3045 entry = section_entries['u-boot']
3046 self.assertEqual(0, entry.offset)
3047 self.assertEqual(0x18, entry.image_pos)
3048 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3049 self.assertEqual(len(U_BOOT_DATA), entry.size)
3051 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3052 dts='132_replace.dts'):
3053 """Replace an entry in an image
3055 This writes the entry data to update it, then opens the updated file and
3056 returns the value that it now finds there.
3059 entry_name: Entry name to replace
3060 data: Data to replace it with
3061 decomp: True to compress the data if needed, False if data is
3062 already compressed so should be used as is
3063 allow_resize: True to allow entries to change size, False to raise
3069 data from fdtmap (excluding header)
3070 Image object that was modified
3072 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3075 self.assertIn('image', control.images)
3076 image = control.images['image']
3077 entries = image.GetEntries()
3078 orig_dtb_data = entries['u-boot-dtb'].data
3079 orig_fdtmap_data = entries['fdtmap'].data
3081 image_fname = tools.GetOutputFilename('image.bin')
3082 updated_fname = tools.GetOutputFilename('image-updated.bin')
3083 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3084 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3086 data = control.ReadEntry(updated_fname, entry_name, decomp)
3088 # The DT data should not change unless resized:
3089 if not allow_resize:
3090 new_dtb_data = entries['u-boot-dtb'].data
3091 self.assertEqual(new_dtb_data, orig_dtb_data)
3092 new_fdtmap_data = entries['fdtmap'].data
3093 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3095 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3097 def testReplaceSimple(self):
3098 """Test replacing a single file"""
3099 expected = b'x' * len(U_BOOT_DATA)
3100 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3102 self.assertEqual(expected, data)
3104 # Test that the state looks right. There should be an FDT for the fdtmap
3105 # that we jsut read back in, and it should match what we find in the
3106 # 'control' tables. Checking for an FDT that does not exist should
3108 path, fdtmap = state.GetFdtContents('fdtmap')
3109 self.assertIsNotNone(path)
3110 self.assertEqual(expected_fdtmap, fdtmap)
3112 dtb = state.GetFdtForEtype('fdtmap')
3113 self.assertEqual(dtb.GetContents(), fdtmap)
3115 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3116 self.assertIsNone(missing_path)
3117 self.assertIsNone(missing_fdtmap)
3119 missing_dtb = state.GetFdtForEtype('missing')
3120 self.assertIsNone(missing_dtb)
3122 self.assertEqual('/binman', state.fdt_path_prefix)
3124 def testReplaceResizeFail(self):
3125 """Test replacing a file by something larger"""
3126 expected = U_BOOT_DATA + b'x'
3127 with self.assertRaises(ValueError) as e:
3128 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3129 dts='139_replace_repack.dts')
3130 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3133 def testReplaceMulti(self):
3134 """Test replacing entry data where multiple images are generated"""
3135 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3137 expected = b'x' * len(U_BOOT_DATA)
3138 updated_fname = tools.GetOutputFilename('image-updated.bin')
3139 tools.WriteFile(updated_fname, data)
3140 entry_name = 'u-boot'
3141 control.WriteEntry(updated_fname, entry_name, expected,
3143 data = control.ReadEntry(updated_fname, entry_name)
3144 self.assertEqual(expected, data)
3146 # Check the state looks right.
3147 self.assertEqual('/binman/image', state.fdt_path_prefix)
3149 # Now check we can write the first image
3150 image_fname = tools.GetOutputFilename('first-image.bin')
3151 updated_fname = tools.GetOutputFilename('first-updated.bin')
3152 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3153 entry_name = 'u-boot'
3154 control.WriteEntry(updated_fname, entry_name, expected,
3156 data = control.ReadEntry(updated_fname, entry_name)
3157 self.assertEqual(expected, data)
3159 # Check the state looks right.
3160 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3162 def testUpdateFdtAllRepack(self):
3163 """Test that all device trees are updated with offset/size info"""
3164 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3165 SECTION_SIZE = 0x300
3170 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3172 'section:offset': 0,
3173 'section:size': SECTION_SIZE,
3174 'section:image-pos': 0,
3175 'section/u-boot-dtb:offset': 4,
3176 'section/u-boot-dtb:size': 636,
3177 'section/u-boot-dtb:image-pos': 4,
3178 'u-boot-spl-dtb:offset': SECTION_SIZE,
3179 'u-boot-spl-dtb:size': DTB_SIZE,
3180 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3181 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3182 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3183 'u-boot-tpl-dtb:size': DTB_SIZE,
3184 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3185 'fdtmap:size': FDTMAP_SIZE,
3186 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3189 'section:orig-size': SECTION_SIZE,
3190 'section/u-boot-dtb:orig-offset': 4,
3193 # We expect three device-tree files in the output, with the first one
3194 # within a fixed-size section.
3195 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3196 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3197 # main U-Boot tree. All three should have the same positions and offset
3198 # except that the main tree should include the main_expected properties
3200 for item in ['', 'spl', 'tpl', None]:
3202 start += 16 # Move past fdtmap header
3203 dtb = fdt.Fdt.FromData(data[start:])
3205 props = self._GetPropTree(dtb,
3206 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3207 prefix='/' if item is None else '/binman/')
3208 expected = dict(base_expected)
3212 # Main DTB and fdtdec should include the 'orig-' properties
3213 expected.update(main_expected)
3214 # Helpful for debugging:
3215 #for prop in sorted(props):
3216 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3217 self.assertEqual(expected, props)
3219 start = SECTION_SIZE
3221 start += dtb._fdt_obj.totalsize()
3223 def testFdtmapHeaderMiddle(self):
3224 """Test an FDT map in the middle of an image when it should be at end"""
3225 with self.assertRaises(ValueError) as e:
3226 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3227 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3230 def testFdtmapHeaderStartBad(self):
3231 """Test an FDT map in middle of an image when it should be at start"""
3232 with self.assertRaises(ValueError) as e:
3233 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3234 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3237 def testFdtmapHeaderEndBad(self):
3238 """Test an FDT map at the start of an image when it should be at end"""
3239 with self.assertRaises(ValueError) as e:
3240 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3241 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3244 def testFdtmapHeaderNoSize(self):
3245 """Test an image header at the end of an image with undefined size"""
3246 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3248 def testReplaceResize(self):
3249 """Test replacing a single file in an entry with a larger file"""
3250 expected = U_BOOT_DATA + b'x'
3251 data, _, image = self._RunReplaceCmd('u-boot', expected,
3252 dts='139_replace_repack.dts')
3253 self.assertEqual(expected, data)
3255 entries = image.GetEntries()
3256 dtb_data = entries['u-boot-dtb'].data
3257 dtb = fdt.Fdt.FromData(dtb_data)
3260 # The u-boot section should now be larger in the dtb
3261 node = dtb.GetNode('/binman/u-boot')
3262 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3264 # Same for the fdtmap
3265 fdata = entries['fdtmap'].data
3266 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3268 fnode = fdtb.GetNode('/u-boot')
3269 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3271 def testReplaceResizeNoRepack(self):
3272 """Test replacing an entry with a larger file when not allowed"""
3273 expected = U_BOOT_DATA + b'x'
3274 with self.assertRaises(ValueError) as e:
3275 self._RunReplaceCmd('u-boot', expected)
3276 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3279 def testEntryShrink(self):
3280 """Test contracting an entry after it is packed"""
3282 state.SetAllowEntryContraction(True)
3283 data = self._DoReadFileDtb('140_entry_shrink.dts',
3286 state.SetAllowEntryContraction(False)
3287 self.assertEqual(b'a', data[:1])
3288 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3289 self.assertEqual(b'a', data[-1:])
3291 def testEntryShrinkFail(self):
3292 """Test not being allowed to contract an entry after it is packed"""
3293 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3295 # In this case there is a spare byte at the end of the data. The size of
3296 # the contents is only 1 byte but we still have the size before it
3298 self.assertEqual(b'a\0', data[:2])
3299 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3300 self.assertEqual(b'a\0', data[-2:])
3302 def testDescriptorOffset(self):
3303 """Test that the Intel descriptor is always placed at at the start"""
3304 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3305 image = control.images['image']
3306 entries = image.GetEntries()
3307 desc = entries['intel-descriptor']
3308 self.assertEqual(0xff800000, desc.offset);
3309 self.assertEqual(0xff800000, desc.image_pos);
3311 def testReplaceCbfs(self):
3312 """Test replacing a single file in CBFS without changing the size"""
3314 expected = b'x' * len(U_BOOT_DATA)
3315 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3316 updated_fname = tools.GetOutputFilename('image-updated.bin')
3317 tools.WriteFile(updated_fname, data)
3318 entry_name = 'section/cbfs/u-boot'
3319 control.WriteEntry(updated_fname, entry_name, expected,
3321 data = control.ReadEntry(updated_fname, entry_name)
3322 self.assertEqual(expected, data)
3324 def testReplaceResizeCbfs(self):
3325 """Test replacing a single file in CBFS with one of a different size"""
3327 expected = U_BOOT_DATA + b'x'
3328 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3329 updated_fname = tools.GetOutputFilename('image-updated.bin')
3330 tools.WriteFile(updated_fname, data)
3331 entry_name = 'section/cbfs/u-boot'
3332 control.WriteEntry(updated_fname, entry_name, expected,
3334 data = control.ReadEntry(updated_fname, entry_name)
3335 self.assertEqual(expected, data)
3337 def _SetupForReplace(self):
3338 """Set up some files to use to replace entries
3340 This generates an image, copies it to a new file, extracts all the files
3341 in it and updates some of them
3347 Expected values for updated entries, each a string
3349 data = self._DoReadFileRealDtb('143_replace_all.dts')
3351 updated_fname = tools.GetOutputFilename('image-updated.bin')
3352 tools.WriteFile(updated_fname, data)
3354 outdir = os.path.join(self._indir, 'extract')
3355 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3357 expected1 = b'x' + U_BOOT_DATA + b'y'
3358 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3359 tools.WriteFile(u_boot_fname1, expected1)
3361 expected2 = b'a' + U_BOOT_DATA + b'b'
3362 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3363 tools.WriteFile(u_boot_fname2, expected2)
3365 expected_text = b'not the same text'
3366 text_fname = os.path.join(outdir, 'text')
3367 tools.WriteFile(text_fname, expected_text)
3369 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3370 dtb = fdt.FdtScan(dtb_fname)
3371 node = dtb.GetNode('/binman/text')
3372 node.AddString('my-property', 'the value')
3373 dtb.Sync(auto_resize=True)
3376 return updated_fname, outdir, expected1, expected2, expected_text
3378 def _CheckReplaceMultiple(self, entry_paths):
3379 """Handle replacing the contents of multiple entries
3382 entry_paths: List of entry paths to replace
3386 Dict of entries in the image:
3389 Expected values for updated entries, each a string
3391 updated_fname, outdir, expected1, expected2, expected_text = (
3392 self._SetupForReplace())
3393 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3395 image = Image.FromFile(updated_fname)
3397 return image.GetEntries(), expected1, expected2, expected_text
3399 def testReplaceAll(self):
3400 """Test replacing the contents of all entries"""
3401 entries, expected1, expected2, expected_text = (
3402 self._CheckReplaceMultiple([]))
3403 data = entries['u-boot'].data
3404 self.assertEqual(expected1, data)
3406 data = entries['u-boot2'].data
3407 self.assertEqual(expected2, data)
3409 data = entries['text'].data
3410 self.assertEqual(expected_text, data)
3412 # Check that the device tree is updated
3413 data = entries['u-boot-dtb'].data
3414 dtb = fdt.Fdt.FromData(data)
3416 node = dtb.GetNode('/binman/text')
3417 self.assertEqual('the value', node.props['my-property'].value)
3419 def testReplaceSome(self):
3420 """Test replacing the contents of a few entries"""
3421 entries, expected1, expected2, expected_text = (
3422 self._CheckReplaceMultiple(['u-boot2', 'text']))
3424 # This one should not change
3425 data = entries['u-boot'].data
3426 self.assertEqual(U_BOOT_DATA, data)
3428 data = entries['u-boot2'].data
3429 self.assertEqual(expected2, data)
3431 data = entries['text'].data
3432 self.assertEqual(expected_text, data)
3434 def testReplaceCmd(self):
3435 """Test replacing a file fron an image on the command line"""
3436 self._DoReadFileRealDtb('143_replace_all.dts')
3439 tmpdir, updated_fname = self._SetupImageInTmpdir()
3441 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3442 expected = b'x' * len(U_BOOT_DATA)
3443 tools.WriteFile(fname, expected)
3445 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3446 data = tools.ReadFile(updated_fname)
3447 self.assertEqual(expected, data[:len(expected)])
3448 map_fname = os.path.join(tmpdir, 'image-updated.map')
3449 self.assertFalse(os.path.exists(map_fname))
3451 shutil.rmtree(tmpdir)
3453 def testReplaceCmdSome(self):
3454 """Test replacing some files fron an image on the command line"""
3455 updated_fname, outdir, expected1, expected2, expected_text = (
3456 self._SetupForReplace())
3458 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3461 tools.PrepareOutputDir(None)
3462 image = Image.FromFile(updated_fname)
3464 entries = image.GetEntries()
3466 # This one should not change
3467 data = entries['u-boot'].data
3468 self.assertEqual(U_BOOT_DATA, data)
3470 data = entries['u-boot2'].data
3471 self.assertEqual(expected2, data)
3473 data = entries['text'].data
3474 self.assertEqual(expected_text, data)
3476 def testReplaceMissing(self):
3477 """Test replacing entries where the file is missing"""
3478 updated_fname, outdir, expected1, expected2, expected_text = (
3479 self._SetupForReplace())
3481 # Remove one of the files, to generate a warning
3482 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3483 os.remove(u_boot_fname1)
3485 with test_util.capture_sys_output() as (stdout, stderr):
3486 control.ReplaceEntries(updated_fname, None, outdir, [])
3487 self.assertIn("Skipping entry '/u-boot' from missing file",
3490 def testReplaceCmdMap(self):
3491 """Test replacing a file fron an image on the command line"""
3492 self._DoReadFileRealDtb('143_replace_all.dts')
3495 tmpdir, updated_fname = self._SetupImageInTmpdir()
3497 fname = os.path.join(self._indir, 'update-u-boot.bin')
3498 expected = b'x' * len(U_BOOT_DATA)
3499 tools.WriteFile(fname, expected)
3501 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3503 map_fname = os.path.join(tmpdir, 'image-updated.map')
3504 self.assertTrue(os.path.exists(map_fname))
3506 shutil.rmtree(tmpdir)
3508 def testReplaceNoEntryPaths(self):
3509 """Test replacing an entry without an entry path"""
3510 self._DoReadFileRealDtb('143_replace_all.dts')
3511 image_fname = tools.GetOutputFilename('image.bin')
3512 with self.assertRaises(ValueError) as e:
3513 control.ReplaceEntries(image_fname, 'fname', None, [])
3514 self.assertIn('Must specify an entry path to read with -f',
3517 def testReplaceTooManyEntryPaths(self):
3518 """Test extracting some entries"""
3519 self._DoReadFileRealDtb('143_replace_all.dts')
3520 image_fname = tools.GetOutputFilename('image.bin')
3521 with self.assertRaises(ValueError) as e:
3522 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3523 self.assertIn('Must specify exactly one entry path to write with -f',
3526 def testPackReset16(self):
3527 """Test that an image with an x86 reset16 region can be created"""
3528 data = self._DoReadFile('144_x86_reset16.dts')
3529 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3531 def testPackReset16Spl(self):
3532 """Test that an image with an x86 reset16-spl region can be created"""
3533 data = self._DoReadFile('145_x86_reset16_spl.dts')
3534 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3536 def testPackReset16Tpl(self):
3537 """Test that an image with an x86 reset16-tpl region can be created"""
3538 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3539 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3541 def testPackIntelFit(self):
3542 """Test that an image with an Intel FIT and pointer can be created"""
3543 data = self._DoReadFile('147_intel_fit.dts')
3544 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3546 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3547 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3549 image = control.images['image']
3550 entries = image.GetEntries()
3551 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3552 self.assertEqual(expected_ptr, ptr)
3554 def testPackIntelFitMissing(self):
3555 """Test detection of a FIT pointer with not FIT region"""
3556 with self.assertRaises(ValueError) as e:
3557 self._DoReadFile('148_intel_fit_missing.dts')
3558 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3561 def _CheckSymbolsTplSection(self, dts, expected_vals):
3562 data = self._DoReadFile(dts)
3563 sym_values = struct.pack('<LQLL', *expected_vals)
3564 upto1 = 4 + len(U_BOOT_SPL_DATA)
3565 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3566 self.assertEqual(expected1, data[:upto1])
3568 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3569 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3570 self.assertEqual(expected2, data[upto1:upto2])
3572 upto3 = 0x34 + len(U_BOOT_DATA)
3573 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3574 self.assertEqual(expected3, data[upto2:upto3])
3576 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3577 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3579 def testSymbolsTplSection(self):
3580 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3581 self._SetupSplElf('u_boot_binman_syms')
3582 self._SetupTplElf('u_boot_binman_syms')
3583 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3584 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3586 def testSymbolsTplSectionX86(self):
3587 """Test binman can assign symbols in a section with end-at-4gb"""
3588 self._SetupSplElf('u_boot_binman_syms_x86')
3589 self._SetupTplElf('u_boot_binman_syms_x86')
3590 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3591 [0xffffff04, 0xffffff1c, 0xffffff34,
3594 def testPackX86RomIfwiSectiom(self):
3595 """Test that a section can be placed in an IFWI region"""
3596 self._SetupIfwi('fitimage.bin')
3597 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3598 self._CheckIfwi(data)
3600 def testPackFspM(self):
3601 """Test that an image with a FSP memory-init binary can be created"""
3602 data = self._DoReadFile('152_intel_fsp_m.dts')
3603 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3605 def testPackFspS(self):
3606 """Test that an image with a FSP silicon-init binary can be created"""
3607 data = self._DoReadFile('153_intel_fsp_s.dts')
3608 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3610 def testPackFspT(self):
3611 """Test that an image with a FSP temp-ram-init binary can be created"""
3612 data = self._DoReadFile('154_intel_fsp_t.dts')
3613 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3615 def testMkimage(self):
3616 """Test using mkimage to build an image"""
3617 data = self._DoReadFile('156_mkimage.dts')
3619 # Just check that the data appears in the file somewhere
3620 self.assertIn(U_BOOT_SPL_DATA, data)
3622 def testExtblob(self):
3623 """Test an image with an external blob"""
3624 data = self._DoReadFile('157_blob_ext.dts')
3625 self.assertEqual(REFCODE_DATA, data)
3627 def testExtblobMissing(self):
3628 """Test an image with a missing external blob"""
3629 with self.assertRaises(ValueError) as e:
3630 self._DoReadFile('158_blob_ext_missing.dts')
3631 self.assertIn("Filename 'missing-file' not found in input path",
3634 def testExtblobMissingOk(self):
3635 """Test an image with an missing external blob that is allowed"""
3636 with test_util.capture_sys_output() as (stdout, stderr):
3637 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3638 err = stderr.getvalue()
3639 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3641 def testExtblobMissingOkSect(self):
3642 """Test an image with an missing external blob that is allowed"""
3643 with test_util.capture_sys_output() as (stdout, stderr):
3644 self._DoTestFile('159_blob_ext_missing_sect.dts',
3646 err = stderr.getvalue()
3647 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3648 "blob-ext blob-ext2")
3650 def testPackX86RomMeMissingDesc(self):
3651 """Test that an missing Intel descriptor entry is allowed"""
3652 with test_util.capture_sys_output() as (stdout, stderr):
3653 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3654 err = stderr.getvalue()
3655 self.assertRegex(err,
3656 "Image 'main-section'.*missing.*: intel-descriptor")
3658 def testPackX86RomMissingIfwi(self):
3659 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3660 self._SetupIfwi('fitimage.bin')
3661 pathname = os.path.join(self._indir, 'fitimage.bin')
3663 with test_util.capture_sys_output() as (stdout, stderr):
3664 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3665 err = stderr.getvalue()
3666 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3668 def testPackOverlap(self):
3669 """Test that zero-size overlapping regions are ignored"""
3670 self._DoTestFile('160_pack_overlap_zero.dts')
3672 def testSimpleFit(self):
3673 """Test an image with a FIT inside"""
3674 data = self._DoReadFile('161_fit.dts')
3675 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3676 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3677 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3679 # The data should be inside the FIT
3680 dtb = fdt.Fdt.FromData(fit_data)
3682 fnode = dtb.GetNode('/images/kernel')
3683 self.assertIn('data', fnode.props)
3685 fname = os.path.join(self._indir, 'fit_data.fit')
3686 tools.WriteFile(fname, fit_data)
3687 out = tools.Run('dumpimage', '-l', fname)
3689 # Check a few features to make sure the plumbing works. We don't need
3690 # to test the operation of mkimage or dumpimage here. First convert the
3691 # output into a dict where the keys are the fields printed by dumpimage
3692 # and the values are a list of values for each field
3693 lines = out.splitlines()
3695 # Converts "Compression: gzip compressed" into two groups:
3696 # 'Compression' and 'gzip compressed'
3697 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3698 vals = collections.defaultdict(list)
3700 mat = re_line.match(line)
3701 vals[mat.group(1)].append(mat.group(2))
3703 self.assertEquals('FIT description: test-desc', lines[0])
3704 self.assertIn('Created:', lines[1])
3705 self.assertIn('Image 0 (kernel)', vals)
3706 self.assertIn('Hash value', vals)
3707 data_sizes = vals.get('Data Size')
3708 self.assertIsNotNone(data_sizes)
3709 self.assertEqual(2, len(data_sizes))
3710 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3711 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3712 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3714 def testFitExternal(self):
3715 """Test an image with an FIT with external images"""
3716 data = self._DoReadFile('162_fit_external.dts')
3717 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3719 # Size of the external-data region as set up by mkimage
3720 external_data_size = len(U_BOOT_DATA) + 2
3721 expected_size = (len(U_BOOT_DATA) + 0x400 +
3722 tools.Align(external_data_size, 4) +
3723 len(U_BOOT_NODTB_DATA))
3725 # The data should be outside the FIT
3726 dtb = fdt.Fdt.FromData(fit_data)
3728 fnode = dtb.GetNode('/images/kernel')
3729 self.assertNotIn('data', fnode.props)
3730 self.assertEqual(len(U_BOOT_DATA),
3731 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3735 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3737 self.assertEquals(expected_size, len(data))
3738 actual_pos = len(U_BOOT_DATA) + fit_pos
3739 self.assertEqual(U_BOOT_DATA + b'aa',
3740 data[actual_pos:actual_pos + external_data_size])
3742 def testSectionIgnoreHashSignature(self):
3743 """Test that sections ignore hash, signature nodes for its data"""
3744 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3745 expected = (U_BOOT_DATA + U_BOOT_DATA)
3746 self.assertEqual(expected, data)
3748 def testPadInSections(self):
3749 """Test pad-before, pad-after for entries in sections"""
3750 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3751 '166_pad_in_sections.dts', update_dtb=True)
3752 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3753 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3755 self.assertEqual(expected, data)
3757 dtb = fdt.Fdt(out_dtb_fname)
3759 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3763 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3765 'section:image-pos': 0,
3766 'section:offset': 0,
3767 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3769 'section/before:image-pos': 0,
3770 'section/before:offset': 0,
3771 'section/before:size': len(U_BOOT_DATA),
3773 'section/u-boot:image-pos': 4,
3774 'section/u-boot:offset': 4,
3775 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3777 'section/after:image-pos': 26,
3778 'section/after:offset': 26,
3779 'section/after:size': len(U_BOOT_DATA),
3781 self.assertEqual(expected, props)
3783 def testFitImageSubentryAlignment(self):
3784 """Test relative alignability of FIT image subentries"""
3786 'test-id': TEXT_DATA,
3788 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3789 entry_args=entry_args)
3790 dtb = fdt.Fdt.FromData(data)
3793 node = dtb.GetNode('/images/kernel')
3794 data = dtb.GetProps(node)["data"].bytes
3795 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3796 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3797 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3798 self.assertEqual(expected, data)
3800 node = dtb.GetNode('/images/fdt-1')
3801 data = dtb.GetProps(node)["data"].bytes
3802 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3803 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3805 self.assertEqual(expected, data)
3807 def testFitExtblobMissingOk(self):
3808 """Test a FIT with a missing external blob that is allowed"""
3809 with test_util.capture_sys_output() as (stdout, stderr):
3810 self._DoTestFile('168_fit_missing_blob.dts',
3812 err = stderr.getvalue()
3813 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3815 def testBlobNamedByArgMissing(self):
3816 """Test handling of a missing entry arg"""
3817 with self.assertRaises(ValueError) as e:
3818 self._DoReadFile('068_blob_named_by_arg.dts')
3819 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3822 def testPackBl31(self):
3823 """Test that an image with an ATF BL31 binary can be created"""
3824 data = self._DoReadFile('169_atf_bl31.dts')
3825 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3827 def testPackScp(self):
3828 """Test that an image with an SCP binary can be created"""
3829 data = self._DoReadFile('172_scp.dts')
3830 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3832 def testFitFdt(self):
3833 """Test an image with an FIT with multiple FDT images"""
3834 def _CheckFdt(seq, expected_data):
3835 """Check the FDT nodes
3838 seq: Sequence number to check (0 or 1)
3839 expected_data: Expected contents of 'data' property
3841 name = 'fdt-%d' % seq
3842 fnode = dtb.GetNode('/images/%s' % name)
3843 self.assertIsNotNone(fnode)
3844 self.assertEqual({'description','type', 'compression', 'data'},
3845 set(fnode.props.keys()))
3846 self.assertEqual(expected_data, fnode.props['data'].bytes)
3847 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3848 fnode.props['description'].value)
3850 def _CheckConfig(seq, expected_data):
3851 """Check the configuration nodes
3854 seq: Sequence number to check (0 or 1)
3855 expected_data: Expected contents of 'data' property
3857 cnode = dtb.GetNode('/configurations')
3858 self.assertIn('default', cnode.props)
3859 self.assertEqual('config-2', cnode.props['default'].value)
3861 name = 'config-%d' % seq
3862 fnode = dtb.GetNode('/configurations/%s' % name)
3863 self.assertIsNotNone(fnode)
3864 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3865 set(fnode.props.keys()))
3866 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3867 fnode.props['description'].value)
3868 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3871 'of-list': 'test-fdt1 test-fdt2',
3872 'default-dt': 'test-fdt2',
3874 data = self._DoReadFileDtb(
3876 entry_args=entry_args,
3877 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3878 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3879 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3881 dtb = fdt.Fdt.FromData(fit_data)
3883 fnode = dtb.GetNode('/images/kernel')
3884 self.assertIn('data', fnode.props)
3886 # Check all the properties in fdt-1 and fdt-2
3887 _CheckFdt(1, TEST_FDT1_DATA)
3888 _CheckFdt(2, TEST_FDT2_DATA)
3890 # Check configurations
3891 _CheckConfig(1, TEST_FDT1_DATA)
3892 _CheckConfig(2, TEST_FDT2_DATA)
3894 def testFitFdtMissingList(self):
3895 """Test handling of a missing 'of-list' entry arg"""
3896 with self.assertRaises(ValueError) as e:
3897 self._DoReadFile('170_fit_fdt.dts')
3898 self.assertIn("Generator node requires 'of-list' entry argument",
3901 def testFitFdtEmptyList(self):
3902 """Test handling of an empty 'of-list' entry arg"""
3906 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3908 def testFitFdtMissingProp(self):
3909 """Test handling of a missing 'fit,fdt-list' property"""
3910 with self.assertRaises(ValueError) as e:
3911 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3912 self.assertIn("Generator node requires 'fit,fdt-list' property",
3915 def testFitFdtEmptyList(self):
3916 """Test handling of an empty 'of-list' entry arg"""
3920 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3922 def testFitFdtMissing(self):
3923 """Test handling of a missing 'default-dt' entry arg"""
3925 'of-list': 'test-fdt1 test-fdt2',
3927 with self.assertRaises(ValueError) as e:
3928 self._DoReadFileDtb(
3930 entry_args=entry_args,
3931 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3932 self.assertIn("Generated 'default' node requires default-dt entry argument",
3935 def testFitFdtNotInList(self):
3936 """Test handling of a default-dt that is not in the of-list"""
3938 'of-list': 'test-fdt1 test-fdt2',
3939 'default-dt': 'test-fdt3',
3941 with self.assertRaises(ValueError) as e:
3942 self._DoReadFileDtb(
3944 entry_args=entry_args,
3945 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3946 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3949 def testFitExtblobMissingHelp(self):
3950 """Test display of help messages when an external blob is missing"""
3951 control.missing_blob_help = control._ReadMissingBlobHelp()
3952 control.missing_blob_help['wibble'] = 'Wibble test'
3953 control.missing_blob_help['another'] = 'Another test'
3954 with test_util.capture_sys_output() as (stdout, stderr):
3955 self._DoTestFile('168_fit_missing_blob.dts',
3957 err = stderr.getvalue()
3959 # We can get the tag from the name, the type or the missing-msg
3960 # property. Check all three.
3961 self.assertIn('You may need to build ARM Trusted', err)
3962 self.assertIn('Wibble test', err)
3963 self.assertIn('Another test', err)
3965 def testMissingBlob(self):
3966 """Test handling of a blob containing a missing file"""
3967 with self.assertRaises(ValueError) as e:
3968 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3969 self.assertIn("Filename 'missing' not found in input path",
3972 def testEnvironment(self):
3973 """Test adding a U-Boot environment"""
3974 data = self._DoReadFile('174_env.dts')
3975 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3976 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3977 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3978 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3981 def testEnvironmentNoSize(self):
3982 """Test that a missing 'size' property is detected"""
3983 with self.assertRaises(ValueError) as e:
3984 self._DoTestFile('175_env_no_size.dts')
3985 self.assertIn("'u-boot-env' entry must have a size property",
3988 def testEnvironmentTooSmall(self):
3989 """Test handling of an environment that does not fit"""
3990 with self.assertRaises(ValueError) as e:
3991 self._DoTestFile('176_env_too_small.dts')
3993 # checksum, start byte, environment with \0 terminator, final \0
3994 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3996 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3999 def testSkipAtStart(self):
4000 """Test handling of skip-at-start section"""
4001 data = self._DoReadFile('177_skip_at_start.dts')
4002 self.assertEqual(U_BOOT_DATA, data)
4004 image = control.images['image']
4005 entries = image.GetEntries()
4006 section = entries['section']
4007 self.assertEqual(0, section.offset)
4008 self.assertEqual(len(U_BOOT_DATA), section.size)
4009 self.assertEqual(U_BOOT_DATA, section.GetData())
4011 entry = section.GetEntries()['u-boot']
4012 self.assertEqual(16, entry.offset)
4013 self.assertEqual(len(U_BOOT_DATA), entry.size)
4014 self.assertEqual(U_BOOT_DATA, entry.data)
4016 def testSkipAtStartPad(self):
4017 """Test handling of skip-at-start section with padded entry"""
4018 data = self._DoReadFile('178_skip_at_start_pad.dts')
4019 before = tools.GetBytes(0, 8)
4020 after = tools.GetBytes(0, 4)
4021 all = before + U_BOOT_DATA + after
4022 self.assertEqual(all, data)
4024 image = control.images['image']
4025 entries = image.GetEntries()
4026 section = entries['section']
4027 self.assertEqual(0, section.offset)
4028 self.assertEqual(len(all), section.size)
4029 self.assertEqual(all, section.GetData())
4031 entry = section.GetEntries()['u-boot']
4032 self.assertEqual(16, entry.offset)
4033 self.assertEqual(len(all), entry.size)
4034 self.assertEqual(U_BOOT_DATA, entry.data)
4036 def testSkipAtStartSectionPad(self):
4037 """Test handling of skip-at-start section with padding"""
4038 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4039 before = tools.GetBytes(0, 8)
4040 after = tools.GetBytes(0, 4)
4041 all = before + U_BOOT_DATA + after
4042 self.assertEqual(all, data)
4044 image = control.images['image']
4045 entries = image.GetEntries()
4046 section = entries['section']
4047 self.assertEqual(0, section.offset)
4048 self.assertEqual(len(all), section.size)
4049 self.assertEqual(U_BOOT_DATA, section.data)
4050 self.assertEqual(all, section.GetPaddedData())
4052 entry = section.GetEntries()['u-boot']
4053 self.assertEqual(16, entry.offset)
4054 self.assertEqual(len(U_BOOT_DATA), entry.size)
4055 self.assertEqual(U_BOOT_DATA, entry.data)
4057 def testSectionPad(self):
4058 """Testing padding with sections"""
4059 data = self._DoReadFile('180_section_pad.dts')
4060 expected = (tools.GetBytes(ord('&'), 3) +
4061 tools.GetBytes(ord('!'), 5) +
4063 tools.GetBytes(ord('!'), 1) +
4064 tools.GetBytes(ord('&'), 2))
4065 self.assertEqual(expected, data)
4067 def testSectionAlign(self):
4068 """Testing alignment with sections"""
4069 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4070 expected = (b'\0' + # fill section
4071 tools.GetBytes(ord('&'), 1) + # padding to section align
4072 b'\0' + # fill section
4073 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4075 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4076 tools.GetBytes(ord('!'), 4)) # padding to section size
4077 self.assertEqual(expected, data)
4079 def testCompressImage(self):
4080 """Test compression of the entire image"""
4082 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4083 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4084 dtb = fdt.Fdt(out_dtb_fname)
4086 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4088 orig = self._decompress(data)
4089 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4091 # Do a sanity check on various fields
4092 image = control.images['image']
4093 entries = image.GetEntries()
4094 self.assertEqual(2, len(entries))
4096 entry = entries['blob']
4097 self.assertEqual(COMPRESS_DATA, entry.data)
4098 self.assertEqual(len(COMPRESS_DATA), entry.size)
4100 entry = entries['u-boot']
4101 self.assertEqual(U_BOOT_DATA, entry.data)
4102 self.assertEqual(len(U_BOOT_DATA), entry.size)
4104 self.assertEqual(len(data), image.size)
4105 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4106 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4107 orig = self._decompress(image.data)
4108 self.assertEqual(orig, image.uncomp_data)
4112 'blob:size': len(COMPRESS_DATA),
4113 'u-boot:offset': len(COMPRESS_DATA),
4114 'u-boot:size': len(U_BOOT_DATA),
4115 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4120 self.assertEqual(expected, props)
4122 def testCompressImageLess(self):
4123 """Test compression where compression reduces the image size"""
4125 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4126 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4127 dtb = fdt.Fdt(out_dtb_fname)
4129 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4131 orig = self._decompress(data)
4133 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4135 # Do a sanity check on various fields
4136 image = control.images['image']
4137 entries = image.GetEntries()
4138 self.assertEqual(2, len(entries))
4140 entry = entries['blob']
4141 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4142 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4144 entry = entries['u-boot']
4145 self.assertEqual(U_BOOT_DATA, entry.data)
4146 self.assertEqual(len(U_BOOT_DATA), entry.size)
4148 self.assertEqual(len(data), image.size)
4149 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4150 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4152 orig = self._decompress(image.data)
4153 self.assertEqual(orig, image.uncomp_data)
4157 'blob:size': len(COMPRESS_DATA_BIG),
4158 'u-boot:offset': len(COMPRESS_DATA_BIG),
4159 'u-boot:size': len(U_BOOT_DATA),
4160 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4165 self.assertEqual(expected, props)
4167 def testCompressSectionSize(self):
4168 """Test compression of a section with a fixed size"""
4170 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4171 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4172 dtb = fdt.Fdt(out_dtb_fname)
4174 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4176 orig = self._decompress(data)
4177 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4179 'section/blob:offset': 0,
4180 'section/blob:size': len(COMPRESS_DATA),
4181 'section/u-boot:offset': len(COMPRESS_DATA),
4182 'section/u-boot:size': len(U_BOOT_DATA),
4183 'section:offset': 0,
4184 'section:image-pos': 0,
4185 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4186 'section:size': 0x30,
4191 self.assertEqual(expected, props)
4193 def testCompressSection(self):
4194 """Test compression of a section with no fixed size"""
4196 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4197 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4198 dtb = fdt.Fdt(out_dtb_fname)
4200 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4202 orig = self._decompress(data)
4203 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4205 'section/blob:offset': 0,
4206 'section/blob:size': len(COMPRESS_DATA),
4207 'section/u-boot:offset': len(COMPRESS_DATA),
4208 'section/u-boot:size': len(U_BOOT_DATA),
4209 'section:offset': 0,
4210 'section:image-pos': 0,
4211 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4212 'section:size': len(data),
4217 self.assertEqual(expected, props)
4219 def testCompressExtra(self):
4220 """Test compression of a section with no fixed size"""
4222 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4223 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4224 dtb = fdt.Fdt(out_dtb_fname)
4226 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4229 base = data[len(U_BOOT_DATA):]
4230 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4231 rest = base[len(U_BOOT_DATA):]
4233 # Check compressed data
4234 section1 = self._decompress(rest)
4235 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4236 self.assertEquals(expect1, rest[:len(expect1)])
4237 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4238 rest1 = rest[len(expect1):]
4240 section2 = self._decompress(rest1)
4241 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4242 self.assertEquals(expect2, rest1[:len(expect2)])
4243 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4244 rest2 = rest1[len(expect2):]
4246 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4247 len(expect2) + len(U_BOOT_DATA))
4248 #self.assertEquals(expect_size, len(data))
4250 #self.assertEquals(U_BOOT_DATA, rest2)
4255 'u-boot:image-pos': 0,
4256 'u-boot:size': len(U_BOOT_DATA),
4258 'base:offset': len(U_BOOT_DATA),
4259 'base:image-pos': len(U_BOOT_DATA),
4260 'base:size': len(data) - len(U_BOOT_DATA),
4261 'base/u-boot:offset': 0,
4262 'base/u-boot:image-pos': len(U_BOOT_DATA),
4263 'base/u-boot:size': len(U_BOOT_DATA),
4264 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4266 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4268 'base/u-boot2:size': len(U_BOOT_DATA),
4270 'base/section:offset': len(U_BOOT_DATA),
4271 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4272 'base/section:size': len(expect1),
4273 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4274 'base/section/blob:offset': 0,
4275 'base/section/blob:size': len(COMPRESS_DATA),
4276 'base/section/u-boot:offset': len(COMPRESS_DATA),
4277 'base/section/u-boot:size': len(U_BOOT_DATA),
4279 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4280 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4281 'base/section2:size': len(expect2),
4282 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4283 'base/section2/blob:offset': 0,
4284 'base/section2/blob:size': len(COMPRESS_DATA),
4285 'base/section2/blob2:offset': len(COMPRESS_DATA),
4286 'base/section2/blob2:size': len(COMPRESS_DATA),
4292 self.assertEqual(expected, props)
4294 def testSymbolsSubsection(self):
4295 """Test binman can assign symbols from a subsection"""
4296 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4298 def testReadImageEntryArg(self):
4299 """Test reading an image that would need an entry arg to generate"""
4301 'cros-ec-rw-path': 'ecrw.bin',
4303 data = self.data = self._DoReadFileDtb(
4304 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4305 entry_args=entry_args)
4307 image_fname = tools.GetOutputFilename('image.bin')
4308 orig_image = control.images['image']
4310 # This should not generate an error about the missing 'cros-ec-rw-path'
4311 # since we are reading the image from a file. Compare with
4312 # testEntryArgsRequired()
4313 image = Image.FromFile(image_fname)
4314 self.assertEqual(orig_image.GetEntries().keys(),
4315 image.GetEntries().keys())
4317 def testFilesAlign(self):
4318 """Test alignment with files"""
4319 data = self._DoReadFile('190_files_align.dts')
4321 # The first string is 15 bytes so will align to 16
4322 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4323 self.assertEqual(expect, data)
4325 def testReadImageSkip(self):
4326 """Test reading an image and accessing its FDT map"""
4327 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4328 image_fname = tools.GetOutputFilename('image.bin')
4329 orig_image = control.images['image']
4330 image = Image.FromFile(image_fname)
4331 self.assertEqual(orig_image.GetEntries().keys(),
4332 image.GetEntries().keys())
4334 orig_entry = orig_image.GetEntries()['fdtmap']
4335 entry = image.GetEntries()['fdtmap']
4336 self.assertEqual(orig_entry.offset, entry.offset)
4337 self.assertEqual(orig_entry.size, entry.size)
4338 self.assertEqual(16, entry.image_pos)
4340 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4342 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4344 def testTplNoDtb(self):
4345 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4347 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4348 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4349 data[:len(U_BOOT_TPL_NODTB_DATA)])
4351 def testTplBssPad(self):
4352 """Test that we can pad TPL's BSS with zeros"""
4353 # ELF file with a '__bss_size' symbol
4355 data = self._DoReadFile('193_tpl_bss_pad.dts')
4356 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4359 def testTplBssPadMissing(self):
4360 """Test that a missing symbol is detected"""
4361 self._SetupTplElf('u_boot_ucode_ptr')
4362 with self.assertRaises(ValueError) as e:
4363 self._DoReadFile('193_tpl_bss_pad.dts')
4364 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4367 def checkDtbSizes(self, data, pad_len, start):
4368 """Check the size arguments in a dtb embedded in an image
4371 data: The image data
4372 pad_len: Length of the pad section in the image, in bytes
4373 start: Start offset of the devicetree to examine, within the image
4376 Size of the devicetree in bytes
4378 dtb_data = data[start:]
4379 dtb = fdt.Fdt.FromData(dtb_data)
4380 fdt_size = dtb.GetFdtObj().totalsize()
4382 props = self._GetPropTree(dtb, 'size')
4385 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4386 'u-boot-spl/u-boot-spl-dtb:size': 801,
4387 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4388 'u-boot-spl:size': 860,
4389 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4390 'u-boot/u-boot-dtb:size': 781,
4391 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4396 def testExpanded(self):
4397 """Test that an expanded entry type is selected when needed"""
4401 # SPL has a devicetree, TPL does not
4407 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4408 entry_args=entry_args)
4409 image = control.images['image']
4410 entries = image.GetEntries()
4411 self.assertEqual(3, len(entries))
4413 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4414 self.assertIn('u-boot', entries)
4415 entry = entries['u-boot']
4416 self.assertEqual('u-boot-expanded', entry.etype)
4417 subent = entry.GetEntries()
4418 self.assertEqual(2, len(subent))
4419 self.assertIn('u-boot-nodtb', subent)
4420 self.assertIn('u-boot-dtb', subent)
4422 # Second, u-boot-spl, which should be expanded into three parts
4423 self.assertIn('u-boot-spl', entries)
4424 entry = entries['u-boot-spl']
4425 self.assertEqual('u-boot-spl-expanded', entry.etype)
4426 subent = entry.GetEntries()
4427 self.assertEqual(3, len(subent))
4428 self.assertIn('u-boot-spl-nodtb', subent)
4429 self.assertIn('u-boot-spl-bss-pad', subent)
4430 self.assertIn('u-boot-spl-dtb', subent)
4432 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4434 self.assertIn('u-boot-tpl', entries)
4435 entry = entries['u-boot-tpl']
4436 self.assertEqual('u-boot-tpl', entry.etype)
4437 self.assertEqual(None, entry.GetEntries())
4439 def testExpandedTpl(self):
4440 """Test that an expanded entry type is selected for TPL when needed"""
4447 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4448 entry_args=entry_args)
4449 image = control.images['image']
4450 entries = image.GetEntries()
4451 self.assertEqual(1, len(entries))
4453 # We only have u-boot-tpl, which be expanded
4454 self.assertIn('u-boot-tpl', entries)
4455 entry = entries['u-boot-tpl']
4456 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4457 subent = entry.GetEntries()
4458 self.assertEqual(3, len(subent))
4459 self.assertIn('u-boot-tpl-nodtb', subent)
4460 self.assertIn('u-boot-tpl-bss-pad', subent)
4461 self.assertIn('u-boot-tpl-dtb', subent)
4463 def testExpandedNoPad(self):
4464 """Test an expanded entry without BSS pad enabled"""
4468 # SPL has a devicetree, TPL does not
4470 'spl-dtb': 'something',
4474 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4475 entry_args=entry_args)
4476 image = control.images['image']
4477 entries = image.GetEntries()
4479 # Just check u-boot-spl, which should be expanded into two parts
4480 self.assertIn('u-boot-spl', entries)
4481 entry = entries['u-boot-spl']
4482 self.assertEqual('u-boot-spl-expanded', entry.etype)
4483 subent = entry.GetEntries()
4484 self.assertEqual(2, len(subent))
4485 self.assertIn('u-boot-spl-nodtb', subent)
4486 self.assertIn('u-boot-spl-dtb', subent)
4488 def testExpandedTplNoPad(self):
4489 """Test that an expanded entry type with padding disabled in TPL"""
4496 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4497 entry_args=entry_args)
4498 image = control.images['image']
4499 entries = image.GetEntries()
4500 self.assertEqual(1, len(entries))
4502 # We only have u-boot-tpl, which be expanded
4503 self.assertIn('u-boot-tpl', entries)
4504 entry = entries['u-boot-tpl']
4505 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4506 subent = entry.GetEntries()
4507 self.assertEqual(2, len(subent))
4508 self.assertIn('u-boot-tpl-nodtb', subent)
4509 self.assertIn('u-boot-tpl-dtb', subent)
4511 def testFdtInclude(self):
4512 """Test that an Fdt is update within all binaries"""
4516 # SPL has a devicetree, TPL does not
4523 # Build the image. It includes two separate devicetree binaries, each
4524 # with their own contents, but all contain the binman definition.
4525 data = self._DoReadFileDtb(
4526 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4527 update_dtb=True, entry_args=entry_args)[0]
4530 # Check the U-Boot dtb
4531 start = len(U_BOOT_NODTB_DATA)
4532 fdt_size = self.checkDtbSizes(data, pad_len, start)
4535 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4536 fdt_size = self.checkDtbSizes(data, pad_len, start)
4538 # TPL has no devicetree
4539 start += fdt_size + len(U_BOOT_TPL_DATA)
4540 self.assertEqual(len(data), start)
4542 def testSymbolsExpanded(self):
4543 """Test binman can assign symbols in expanded entries"""
4547 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4548 U_BOOT_SPL_DTB_DATA, 0x38,
4549 entry_args=entry_args, use_expanded=True)
4551 def testCollection(self):
4552 """Test a collection"""
4553 data = self._DoReadFile('198_collection.dts')
4554 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4555 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4556 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4559 def testCollectionSection(self):
4560 """Test a collection where a section must be built first"""
4561 # Sections never have their contents when GetData() is called, but when
4562 # BuildSectionData() is called with required=True, a section will force
4563 # building the contents, producing an error is anything is still
4565 data = self._DoReadFile('199_collection_section.dts')
4566 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4567 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4568 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4571 def testAlignDefault(self):
4572 """Test that default alignment works on sections"""
4573 data = self._DoReadFile('200_align_default.dts')
4574 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4576 # Special alignment for section
4577 expected += tools.GetBytes(0, 32 - len(expected))
4578 # No alignment within the nested section
4579 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4580 # Now the final piece, which should be default-aligned
4581 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4582 self.assertEqual(expected, data)
4584 def testPackOpenSBI(self):
4585 """Test that an image with an OpenSBI binary can be created"""
4586 data = self._DoReadFile('201_opensbi.dts')
4587 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4589 def testSectionsSingleThread(self):
4590 """Test sections without multithreading"""
4591 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4592 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4593 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4594 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4595 self.assertEqual(expected, data)
4597 def testThreadTimeout(self):
4598 """Test handling a thread that takes too long"""
4599 with self.assertRaises(ValueError) as e:
4600 self._DoTestFile('202_section_timeout.dts',
4601 test_section_timeout=True)
4602 self.assertIn("Timed out obtaining contents", str(e.exception))
4604 def testTiming(self):
4605 """Test output of timing information"""
4606 data = self._DoReadFile('055_sections.dts')
4607 with test_util.capture_sys_output() as (stdout, stderr):
4609 self.assertIn('read:', stdout.getvalue())
4610 self.assertIn('compress:', stdout.getvalue())
4612 def testUpdateFdtInElf(self):
4613 """Test that we can update the devicetree in an ELF file"""
4614 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4615 outfile = os.path.join(self._indir, 'u-boot.out')
4616 begin_sym = 'dtb_embed_begin'
4617 end_sym = 'dtb_embed_end'
4618 retcode = self._DoTestFile(
4619 '060_fdt_update.dts', update_dtb=True,
4620 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4621 self.assertEqual(0, retcode)
4623 # Check that the output file does in fact contact a dtb with the binman
4624 # definition in the correct place
4625 syms = elf.GetSymbolFileOffset(infile,
4626 ['dtb_embed_begin', 'dtb_embed_end'])
4627 data = tools.ReadFile(outfile)
4628 dtb_data = data[syms['dtb_embed_begin'].offset:
4629 syms['dtb_embed_end'].offset]
4631 dtb = fdt.Fdt.FromData(dtb_data)
4633 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4637 '_testing:offset': 32,
4639 '_testing:image-pos': 32,
4640 'section@0/u-boot:offset': 0,
4641 'section@0/u-boot:size': len(U_BOOT_DATA),
4642 'section@0/u-boot:image-pos': 0,
4643 'section@0:offset': 0,
4644 'section@0:size': 16,
4645 'section@0:image-pos': 0,
4647 'section@1/u-boot:offset': 0,
4648 'section@1/u-boot:size': len(U_BOOT_DATA),
4649 'section@1/u-boot:image-pos': 16,
4650 'section@1:offset': 16,
4651 'section@1:size': 16,
4652 'section@1:image-pos': 16,
4656 def testUpdateFdtInElfInvalid(self):
4657 """Test that invalid args are detected with --update-fdt-in-elf"""
4658 with self.assertRaises(ValueError) as e:
4659 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4660 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4663 def testUpdateFdtInElfNoSyms(self):
4664 """Test that missing symbols are detected with --update-fdt-in-elf"""
4665 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4667 begin_sym = 'wrong_begin'
4668 end_sym = 'wrong_end'
4669 with self.assertRaises(ValueError) as e:
4671 '060_fdt_update.dts',
4672 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4673 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4676 def testUpdateFdtInElfTooSmall(self):
4677 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4678 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4679 outfile = os.path.join(self._indir, 'u-boot.out')
4680 begin_sym = 'dtb_embed_begin'
4681 end_sym = 'dtb_embed_end'
4682 with self.assertRaises(ValueError) as e:
4684 '060_fdt_update.dts', update_dtb=True,
4685 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4688 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4690 def testVersion(self):
4691 """Test we can get the binman version"""
4692 version = '(unreleased)'
4693 self.assertEqual(version, state.GetVersion(self._indir))
4695 with self.assertRaises(SystemExit):
4696 with test_util.capture_sys_output() as (_, stderr):
4697 self._DoBinman('-V')
4698 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4700 # Try running the tool too, just to be safe
4701 result = self._RunBinman('-V')
4702 self.assertEqual('Binman %s\n' % version, result.stderr)
4704 # Set up a version file to make sure that works
4705 version = 'v2025.01-rc2'
4706 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4708 self.assertEqual(version, state.GetVersion(self._indir))
4710 def testAltFormat(self):
4711 """Test that alternative formats can be used to extract"""
4712 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4715 tmpdir, updated_fname = self._SetupImageInTmpdir()
4716 with test_util.capture_sys_output() as (stdout, _):
4717 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4719 '''Flag (-F) Entry type Description
4720 fdt fdtmap Extract the devicetree blob from the fdtmap
4724 dtb = os.path.join(tmpdir, 'fdt.dtb')
4725 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4728 # Check that we can read it and it can be scanning, meaning it does
4729 # not have a 16-byte fdtmap header
4730 data = tools.ReadFile(dtb)
4731 dtb = fdt.Fdt.FromData(data)
4734 # Now check u-boot which has no alt_format
4735 fname = os.path.join(tmpdir, 'fdt.dtb')
4736 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4737 '-f', fname, 'u-boot')
4738 data = tools.ReadFile(fname)
4739 self.assertEqual(U_BOOT_DATA, data)
4742 shutil.rmtree(tmpdir)
4744 def testExtblobList(self):
4745 """Test an image with an external blob list"""
4746 data = self._DoReadFile('215_blob_ext_list.dts')
4747 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4749 def testExtblobListMissing(self):
4750 """Test an image with a missing external blob"""
4751 with self.assertRaises(ValueError) as e:
4752 self._DoReadFile('216_blob_ext_list_missing.dts')
4753 self.assertIn("Filename 'missing-file' not found in input path",
4756 def testExtblobListMissingOk(self):
4757 """Test an image with an missing external blob that is allowed"""
4758 with test_util.capture_sys_output() as (stdout, stderr):
4759 self._DoTestFile('216_blob_ext_list_missing.dts',
4761 err = stderr.getvalue()
4762 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4765 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4766 data = self._DoReadFile('203_fip.dts')
4767 hdr, fents = fip_util.decode_fip(data)
4768 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4769 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4770 self.assertEqual(0x123, hdr.flags)
4772 self.assertEqual(2, len(fents))
4776 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4777 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4778 self.assertEqual('soc-fw', fent.fip_type)
4779 self.assertEqual(0x88, fent.offset)
4780 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4781 self.assertEqual(0x123456789abcdef, fent.flags)
4782 self.assertEqual(ATF_BL31_DATA, fent.data)
4783 self.assertEqual(True, fent.valid)
4787 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4788 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4789 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4790 self.assertEqual(0x8c, fent.offset)
4791 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4792 self.assertEqual(0, fent.flags)
4793 self.assertEqual(ATF_BL2U_DATA, fent.data)
4794 self.assertEqual(True, fent.valid)
4796 def testFipOther(self):
4797 """Basic FIP with something that isn't a external blob"""
4798 data = self._DoReadFile('204_fip_other.dts')
4799 hdr, fents = fip_util.decode_fip(data)
4801 self.assertEqual(2, len(fents))
4803 self.assertEqual('rot-cert', fent.fip_type)
4804 self.assertEqual(b'aa', fent.data)
4806 def testFipOther(self):
4807 """Basic FIP with something that isn't a external blob"""
4808 data = self._DoReadFile('204_fip_other.dts')
4809 hdr, fents = fip_util.decode_fip(data)
4811 self.assertEqual(2, len(fents))
4813 self.assertEqual('rot-cert', fent.fip_type)
4814 self.assertEqual(b'aa', fent.data)
4816 def testFipNoType(self):
4817 """FIP with an entry of an unknown type"""
4818 with self.assertRaises(ValueError) as e:
4819 self._DoReadFile('205_fip_no_type.dts')
4820 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4823 def testFipUuid(self):
4824 """Basic FIP with a manual uuid"""
4825 data = self._DoReadFile('206_fip_uuid.dts')
4826 hdr, fents = fip_util.decode_fip(data)
4828 self.assertEqual(2, len(fents))
4830 self.assertEqual(None, fent.fip_type)
4832 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4833 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4835 self.assertEqual(U_BOOT_DATA, fent.data)
4837 def testFipLs(self):
4838 """Test listing a FIP"""
4839 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4840 hdr, fents = fip_util.decode_fip(data)
4843 tmpdir, updated_fname = self._SetupImageInTmpdir()
4844 with test_util.capture_sys_output() as (stdout, stderr):
4845 self._DoBinman('ls', '-i', updated_fname)
4847 shutil.rmtree(tmpdir)
4848 lines = stdout.getvalue().splitlines()
4850 'Name Image-pos Size Entry-type Offset Uncomp-size',
4851 '----------------------------------------------------------------',
4852 'main-section 0 2d3 section 0',
4853 ' atf-fip 0 90 atf-fip 0',
4854 ' soc-fw 88 4 blob-ext 88',
4855 ' u-boot 8c 4 u-boot 8c',
4856 ' fdtmap 90 243 fdtmap 90',
4858 self.assertEqual(expected, lines)
4860 image = control.images['image']
4861 entries = image.GetEntries()
4862 fdtmap = entries['fdtmap']
4864 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4865 magic = fdtmap_data[:8]
4866 self.assertEqual(b'_FDTMAP_', magic)
4867 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
4869 fdt_data = fdtmap_data[16:]
4870 dtb = fdt.Fdt.FromData(fdt_data)
4872 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4874 'atf-fip/soc-fw:image-pos': 136,
4875 'atf-fip/soc-fw:offset': 136,
4876 'atf-fip/soc-fw:size': 4,
4877 'atf-fip/u-boot:image-pos': 140,
4878 'atf-fip/u-boot:offset': 140,
4879 'atf-fip/u-boot:size': 4,
4880 'atf-fip:image-pos': 0,
4881 'atf-fip:offset': 0,
4882 'atf-fip:size': 144,
4885 'fdtmap:image-pos': fdtmap.image_pos,
4886 'fdtmap:offset': fdtmap.offset,
4887 'fdtmap:size': len(fdtmap_data),
4891 def testFipExtractOneEntry(self):
4892 """Test extracting a single entry fron an FIP"""
4893 self._DoReadFileRealDtb('207_fip_ls.dts')
4894 image_fname = tools.GetOutputFilename('image.bin')
4895 fname = os.path.join(self._indir, 'output.extact')
4896 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4897 data = tools.ReadFile(fname)
4898 self.assertEqual(U_BOOT_DATA, data)
4900 def testFipReplace(self):
4901 """Test replacing a single file in a FIP"""
4902 expected = U_BOOT_DATA + tools.GetBytes(0x78, 50)
4903 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4904 updated_fname = tools.GetOutputFilename('image-updated.bin')
4905 tools.WriteFile(updated_fname, data)
4906 entry_name = 'atf-fip/u-boot'
4907 control.WriteEntry(updated_fname, entry_name, expected,
4909 actual = control.ReadEntry(updated_fname, entry_name)
4910 self.assertEqual(expected, actual)
4912 new_data = tools.ReadFile(updated_fname)
4913 hdr, fents = fip_util.decode_fip(new_data)
4915 self.assertEqual(2, len(fents))
4917 # Check that the FIP entry is updated
4919 self.assertEqual(0x8c, fent.offset)
4920 self.assertEqual(len(expected), fent.size)
4921 self.assertEqual(0, fent.flags)
4922 self.assertEqual(expected, fent.data)
4923 self.assertEqual(True, fent.valid)
4925 def testFipMissing(self):
4926 with test_util.capture_sys_output() as (stdout, stderr):
4927 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4928 err = stderr.getvalue()
4929 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4931 def testFipSize(self):
4932 """Test a FIP with a size property"""
4933 data = self._DoReadFile('210_fip_size.dts')
4934 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4935 hdr, fents = fip_util.decode_fip(data)
4936 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4937 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4939 self.assertEqual(1, len(fents))
4942 self.assertEqual('soc-fw', fent.fip_type)
4943 self.assertEqual(0x60, fent.offset)
4944 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4945 self.assertEqual(ATF_BL31_DATA, fent.data)
4946 self.assertEqual(True, fent.valid)
4948 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
4949 self.assertEqual(tools.GetBytes(0xff, len(rest)), rest)
4951 def testFipBadAlign(self):
4952 """Test that an invalid alignment value in a FIP is detected"""
4953 with self.assertRaises(ValueError) as e:
4954 self._DoTestFile('211_fip_bad_align.dts')
4956 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
4959 def testFipCollection(self):
4960 """Test using a FIP in a collection"""
4961 data = self._DoReadFile('212_fip_collection.dts')
4962 entry1 = control.images['image'].GetEntries()['collection']
4963 data1 = data[:entry1.size]
4964 hdr1, fents2 = fip_util.decode_fip(data1)
4966 entry2 = control.images['image'].GetEntries()['atf-fip']
4967 data2 = data[entry2.offset:entry2.offset + entry2.size]
4968 hdr1, fents2 = fip_util.decode_fip(data2)
4970 # The 'collection' entry should have U-Boot included at the end
4971 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
4972 self.assertEqual(data1, data2 + U_BOOT_DATA)
4973 self.assertEqual(U_BOOT_DATA, data1[-4:])
4975 # There should be a U-Boot after the final FIP
4976 self.assertEqual(U_BOOT_DATA, data[-4:])
4978 def testFakeBlob(self):
4979 """Test handling of faking an external blob"""
4980 with test_util.capture_sys_output() as (stdout, stderr):
4981 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
4982 allow_fake_blobs=True)
4983 err = stderr.getvalue()
4986 "Image '.*' has faked external blobs and is non-functional: .*")
4988 def testExtblobListFaked(self):
4989 """Test an extblob with missing external blob that are faked"""
4990 with test_util.capture_sys_output() as (stdout, stderr):
4991 self._DoTestFile('216_blob_ext_list_missing.dts',
4992 allow_fake_blobs=True)
4993 err = stderr.getvalue()
4994 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
4996 def testListBintools(self):
4997 args = ['tool', '--list']
4998 with test_util.capture_sys_output() as (stdout, _):
4999 self._DoBinman(*args)
5000 out = stdout.getvalue().splitlines()
5001 self.assertTrue(len(out) >= 2)
5003 def testFetchBintools(self):
5004 def fail_download(url):
5005 """Take the tools.Download() function by raising an exception"""
5006 raise urllib.error.URLError('my error')
5009 with self.assertRaises(ValueError) as e:
5010 self._DoBinman(*args)
5011 self.assertIn("Invalid arguments to 'tool' subcommand",
5014 args = ['tool', '--fetch']
5015 with self.assertRaises(ValueError) as e:
5016 self._DoBinman(*args)
5017 self.assertIn('Please specify bintools to fetch', str(e.exception))
5019 args = ['tool', '--fetch', '_testing']
5020 with unittest.mock.patch.object(tools, 'Download',
5021 side_effect=fail_download):
5022 with test_util.capture_sys_output() as (stdout, _):
5023 self._DoBinman(*args)
5024 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5027 if __name__ == "__main__":