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
21 from binman import bintool
22 from binman import cbfs_util
23 from binman import cmdline
24 from binman import control
25 from binman import elf
26 from binman import elf_test
27 from binman import fip_util
28 from binman import fmap_util
29 from binman import state
31 from dtoc import fdt_util
32 from binman.etype import fdtmap
33 from binman.etype import image_header
34 from binman.image import Image
35 from patman import command
36 from patman import test_util
37 from patman import tools
38 from patman import tout
40 # Contents of test files, corresponding to different entry types
42 U_BOOT_IMG_DATA = b'img'
43 U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
44 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
48 U_BOOT_DTB_DATA = b'udtb'
49 U_BOOT_SPL_DTB_DATA = b'spldtb'
50 U_BOOT_TPL_DTB_DATA = b'tpldtb'
51 X86_START16_DATA = b'start16'
52 X86_START16_SPL_DATA = b'start16spl'
53 X86_START16_TPL_DATA = b'start16tpl'
54 X86_RESET16_DATA = b'reset16'
55 X86_RESET16_SPL_DATA = b'reset16spl'
56 X86_RESET16_TPL_DATA = b'reset16tpl'
57 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
58 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
59 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
60 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
68 CROS_EC_RW_DATA = b'ecrw'
72 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
73 b"sorry you're alive\n")
74 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
75 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
76 REFCODE_DATA = b'refcode'
80 ATF_BL31_DATA = b'bl31'
81 ATF_BL2U_DATA = b'bl2u'
82 OPENSBI_DATA = b'opensbi'
84 TEST_FDT1_DATA = b'fdt1'
85 TEST_FDT2_DATA = b'test-fdt2'
86 ENV_DATA = b'var1=1\nvar2="2"'
88 # Subdirectory of the input dir to use to put test FDTs
89 TEST_FDT_SUBDIR = 'fdts'
91 # The expected size for the device tree in some tests
92 EXTRACT_DTB_SIZE = 0x3c9
94 # Properties expected to be in the device tree when update_dtb is used
95 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
97 # Extra properties expected to be in the device tree when allow-repack is used
98 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
101 class TestFunctional(unittest.TestCase):
102 """Functional tests for binman
104 Most of these use a sample .dts file to build an image and then check
105 that it looks correct. The sample files are in the test/ subdirectory
108 For each entry type a very small test file is created using fixed
109 string contents. This makes it easy to test that things look right, and
112 In some cases a 'real' file must be used - these are also supplied in
113 the test/ diurectory.
118 from binman import entry
120 # Handle the case where argv[0] is 'python'
121 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
122 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
124 # Create a temporary directory for input files
125 cls._indir = tempfile.mkdtemp(prefix='binmant.')
127 # Create some test files
128 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
129 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
130 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
131 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
132 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
133 TestFunctional._MakeInputFile('me.bin', ME_DATA)
134 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
137 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
139 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
140 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
141 X86_START16_SPL_DATA)
142 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
143 X86_START16_TPL_DATA)
145 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
147 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
148 X86_RESET16_SPL_DATA)
149 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
150 X86_RESET16_TPL_DATA)
152 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
153 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
154 U_BOOT_SPL_NODTB_DATA)
155 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
156 U_BOOT_TPL_NODTB_DATA)
157 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
158 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
159 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
160 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
161 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
162 TestFunctional._MakeInputDir('devkeys')
163 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
164 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
165 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
166 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
167 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
169 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
170 elf_test.BuildElfTestFiles(cls._elf_testdir)
172 # ELF file with a '_dt_ucode_base_size' symbol
173 TestFunctional._MakeInputFile('u-boot',
174 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
176 # Intel flash descriptor file
177 cls._SetupDescriptor()
179 shutil.copytree(cls.TestFile('files'),
180 os.path.join(cls._indir, 'files'))
182 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
183 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
184 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
185 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
186 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
187 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
189 # Add a few .dtb files for testing
190 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
192 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
195 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
197 # Travis-CI may have an old lz4
200 tools.Run('lz4', '--no-frame-crc', '-c',
201 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
206 def tearDownClass(cls):
207 """Remove the temporary input directory and its contents"""
208 if cls.preserve_indir:
209 print('Preserving input dir: %s' % cls._indir)
212 shutil.rmtree(cls._indir)
216 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
217 toolpath=None, verbosity=None):
218 """Accept arguments controlling test execution
221 preserve_indir: Preserve the shared input directory used by all
223 preserve_outdir: Preserve the output directories used by tests. Each
224 test has its own, so this is normally only useful when running a
226 toolpath: ist of paths to use for tools
228 cls.preserve_indir = preserve_indir
229 cls.preserve_outdirs = preserve_outdirs
230 cls.toolpath = toolpath
231 cls.verbosity = verbosity
234 if not self.have_lz4:
235 self.skipTest('lz4 --no-frame-crc not available')
237 def _CleanupOutputDir(self):
238 """Remove the temporary output directory"""
239 if self.preserve_outdirs:
240 print('Preserving output dir: %s' % tools.outdir)
242 tools._FinaliseForTest()
245 # Enable this to turn on debugging output
246 # tout.Init(tout.DEBUG)
247 command.test_result = None
250 """Remove the temporary output directory"""
251 self._CleanupOutputDir()
253 def _SetupImageInTmpdir(self):
254 """Set up the output image in a new temporary directory
256 This is used when an image has been generated in the output directory,
257 but we want to run binman again. This will create a new output
258 directory and fail to delete the original one.
260 This creates a new temporary directory, copies the image to it (with a
261 new name) and removes the old output directory.
265 Temporary directory to use
268 image_fname = tools.GetOutputFilename('image.bin')
269 tmpdir = tempfile.mkdtemp(prefix='binman.')
270 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
271 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
272 self._CleanupOutputDir()
273 return tmpdir, updated_fname
277 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
278 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
279 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
281 def _RunBinman(self, *args, **kwargs):
282 """Run binman using the command line
285 Arguments to pass, as a list of strings
286 kwargs: Arguments to pass to Command.RunPipe()
288 result = command.RunPipe([[self._binman_pathname] + list(args)],
289 capture=True, capture_stderr=True, raise_on_error=False)
290 if result.return_code and kwargs.get('raise_on_error', True):
291 raise Exception("Error running '%s': %s" % (' '.join(args),
292 result.stdout + result.stderr))
295 def _DoBinman(self, *argv):
296 """Run binman using directly (in the same process)
299 Arguments to pass, as a list of strings
301 Return value (0 for success)
304 args = cmdline.ParseArgs(argv)
305 args.pager = 'binman-invalid-pager'
306 args.build_dir = self._indir
308 # For testing, you can force an increase in verbosity here
309 # args.verbosity = tout.DEBUG
310 return control.Binman(args)
312 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
313 entry_args=None, images=None, use_real_dtb=False,
314 use_expanded=False, verbosity=None, allow_missing=False,
315 allow_fake_blobs=False, extra_indirs=None, threads=None,
316 test_section_timeout=False, update_fdt_in_elf=None):
317 """Run binman with a given test file
320 fname: Device-tree source filename to use (e.g. 005_simple.dts)
321 debug: True to enable debugging output
322 map: True to output map files for the images
323 update_dtb: Update the offset and size of each entry in the device
324 tree before packing it into the image
325 entry_args: Dict of entry args to supply to binman
327 value: value of that arg
328 images: List of image names to build
329 use_real_dtb: True to use the test file as the contents of
330 the u-boot-dtb entry. Normally this is not needed and the
331 test contents (the U_BOOT_DTB_DATA string) can be used.
332 But in some test we need the real contents.
333 use_expanded: True to use expanded entries where available, e.g.
334 'u-boot-expanded' instead of 'u-boot'
335 verbosity: Verbosity level to use (0-3, None=don't set it)
336 allow_missing: Set the '--allow-missing' flag so that missing
337 external binaries just produce a warning instead of an error
338 allow_fake_blobs: Set the '--fake-ext-blobs' flag
339 extra_indirs: Extra input directories to add using -I
340 threads: Number of threads to use (None for default, 0 for
342 test_section_timeout: True to force the first time to timeout, as
343 used in testThreadTimeout()
344 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
347 int return code, 0 on success
352 if verbosity is not None:
353 args.append('-v%d' % verbosity)
355 args.append('-v%d' % self.verbosity)
357 for path in self.toolpath:
358 args += ['--toolpath', path]
359 if threads is not None:
360 args.append('-T%d' % threads)
361 if test_section_timeout:
362 args.append('--test-section-timeout')
363 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
369 args.append('--fake-dtb')
371 args.append('--no-expanded')
373 for arg, value in entry_args.items():
374 args.append('-a%s=%s' % (arg, value))
378 args.append('--fake-ext-blobs')
379 if update_fdt_in_elf:
380 args += ['--update-fdt-in-elf', update_fdt_in_elf]
383 args += ['-i', image]
385 for indir in extra_indirs:
386 args += ['-I', indir]
387 return self._DoBinman(*args)
389 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
390 """Set up a new test device-tree file
392 The given file is compiled and set up as the device tree to be used
396 fname: Filename of .dts file to read
397 outfile: Output filename for compiled device-tree binary
400 Contents of device-tree binary
402 tmpdir = tempfile.mkdtemp(prefix='binmant.')
403 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
404 with open(dtb, 'rb') as fd:
406 TestFunctional._MakeInputFile(outfile, data)
407 shutil.rmtree(tmpdir)
410 def _GetDtbContentsForSplTpl(self, dtb_data, name):
411 """Create a version of the main DTB for SPL or SPL
413 For testing we don't actually have different versions of the DTB. With
414 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
415 we don't normally have any unwanted nodes.
417 We still want the DTBs for SPL and TPL to be different though, since
418 otherwise it is confusing to know which one we are looking at. So add
419 an 'spl' or 'tpl' property to the top-level node.
422 dtb_data: dtb data to modify (this should be a value devicetree)
423 name: Name of a new property to add
426 New dtb data with the property added
428 dtb = fdt.Fdt.FromData(dtb_data)
430 dtb.GetNode('/binman').AddZeroProp(name)
431 dtb.Sync(auto_resize=True)
433 return dtb.GetContents()
435 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
436 map=False, update_dtb=False, entry_args=None,
437 reset_dtbs=True, extra_indirs=None, threads=None):
438 """Run binman and return the resulting image
440 This runs binman with a given test file and then reads the resulting
441 output file. It is a shortcut function since most tests need to do
444 Raises an assertion failure if binman returns a non-zero exit code.
447 fname: Device-tree source filename to use (e.g. 005_simple.dts)
448 use_real_dtb: True to use the test file as the contents of
449 the u-boot-dtb entry. Normally this is not needed and the
450 test contents (the U_BOOT_DTB_DATA string) can be used.
451 But in some test we need the real contents.
452 use_expanded: True to use expanded entries where available, e.g.
453 'u-boot-expanded' instead of 'u-boot'
454 map: True to output map files for the images
455 update_dtb: Update the offset and size of each entry in the device
456 tree before packing it into the image
457 entry_args: Dict of entry args to supply to binman
459 value: value of that arg
460 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
461 function. If reset_dtbs is True, then the original test dtb
462 is written back before this function finishes
463 extra_indirs: Extra input directories to add using -I
464 threads: Number of threads to use (None for default, 0 for
469 Resulting image contents
471 Map data showing contents of image (or None if none)
472 Output device tree binary filename ('u-boot.dtb' path)
475 # Use the compiled test file as the u-boot-dtb input
477 dtb_data = self._SetupDtb(fname)
479 # For testing purposes, make a copy of the DT for SPL and TPL. Add
480 # a node indicating which it is, so aid verification.
481 for name in ['spl', 'tpl']:
482 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
483 outfile = os.path.join(self._indir, dtb_fname)
484 TestFunctional._MakeInputFile(dtb_fname,
485 self._GetDtbContentsForSplTpl(dtb_data, name))
488 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
489 entry_args=entry_args, use_real_dtb=use_real_dtb,
490 use_expanded=use_expanded, extra_indirs=extra_indirs,
492 self.assertEqual(0, retcode)
493 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
495 # Find the (only) image, read it and return its contents
496 image = control.images['image']
497 image_fname = tools.GetOutputFilename('image.bin')
498 self.assertTrue(os.path.exists(image_fname))
500 map_fname = tools.GetOutputFilename('image.map')
501 with open(map_fname) as fd:
505 with open(image_fname, 'rb') as fd:
506 return fd.read(), dtb_data, map_data, out_dtb_fname
508 # Put the test file back
509 if reset_dtbs and use_real_dtb:
512 def _DoReadFileRealDtb(self, fname):
513 """Run binman with a real .dtb file and return the resulting data
516 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
519 Resulting image contents
521 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
523 def _DoReadFile(self, fname, use_real_dtb=False):
524 """Helper function which discards the device-tree binary
527 fname: Device-tree source filename to use (e.g. 005_simple.dts)
528 use_real_dtb: True to use the test file as the contents of
529 the u-boot-dtb entry. Normally this is not needed and the
530 test contents (the U_BOOT_DTB_DATA string) can be used.
531 But in some test we need the real contents.
534 Resulting image contents
536 return self._DoReadFileDtb(fname, use_real_dtb)[0]
539 def _MakeInputFile(cls, fname, contents):
540 """Create a new test input file, creating directories as needed
543 fname: Filename to create
544 contents: File contents to write in to the file
546 Full pathname of file created
548 pathname = os.path.join(cls._indir, fname)
549 dirname = os.path.dirname(pathname)
550 if dirname and not os.path.exists(dirname):
552 with open(pathname, 'wb') as fd:
557 def _MakeInputDir(cls, dirname):
558 """Create a new test input directory, creating directories as needed
561 dirname: Directory name to create
564 Full pathname of directory created
566 pathname = os.path.join(cls._indir, dirname)
567 if not os.path.exists(pathname):
568 os.makedirs(pathname)
572 def _SetupSplElf(cls, src_fname='bss_data'):
573 """Set up an ELF file with a '_dt_ucode_base_size' symbol
576 Filename of ELF file to use as SPL
578 TestFunctional._MakeInputFile('spl/u-boot-spl',
579 tools.ReadFile(cls.ElfTestFile(src_fname)))
582 def _SetupTplElf(cls, src_fname='bss_data'):
583 """Set up an ELF file with a '_dt_ucode_base_size' symbol
586 Filename of ELF file to use as TPL
588 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
589 tools.ReadFile(cls.ElfTestFile(src_fname)))
592 def _SetupDescriptor(cls):
593 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
594 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
597 def TestFile(cls, fname):
598 return os.path.join(cls._binman_dir, 'test', fname)
601 def ElfTestFile(cls, fname):
602 return os.path.join(cls._elf_testdir, fname)
604 def AssertInList(self, grep_list, target):
605 """Assert that at least one of a list of things is in a target
608 grep_list: List of strings to check
609 target: Target string
611 for grep in grep_list:
614 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
616 def CheckNoGaps(self, entries):
617 """Check that all entries fit together without gaps
620 entries: List of entries to check
623 for entry in entries.values():
624 self.assertEqual(offset, entry.offset)
627 def GetFdtLen(self, dtb):
628 """Get the totalsize field from a device-tree binary
631 dtb: Device-tree binary contents
634 Total size of device-tree binary, from the header
636 return struct.unpack('>L', dtb[4:8])[0]
638 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
639 def AddNode(node, path):
641 path += '/' + node.name
642 for prop in node.props.values():
643 if prop.name in prop_names:
644 prop_path = path + ':' + prop.name
645 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
647 for subnode in node.subnodes:
648 AddNode(subnode, path)
651 AddNode(dtb.GetRoot(), '')
655 """Test a basic run with valid args"""
656 result = self._RunBinman('-h')
658 def testFullHelp(self):
659 """Test that the full help is displayed with -H"""
660 result = self._RunBinman('-H')
661 help_file = os.path.join(self._binman_dir, 'README.rst')
662 # Remove possible extraneous strings
663 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
664 gothelp = result.stdout.replace(extra, '')
665 self.assertEqual(len(gothelp), os.path.getsize(help_file))
666 self.assertEqual(0, len(result.stderr))
667 self.assertEqual(0, result.return_code)
669 def testFullHelpInternal(self):
670 """Test that the full help is displayed with -H"""
672 command.test_result = command.CommandResult()
673 result = self._DoBinman('-H')
674 help_file = os.path.join(self._binman_dir, 'README.rst')
676 command.test_result = None
679 """Test that the basic help is displayed with -h"""
680 result = self._RunBinman('-h')
681 self.assertTrue(len(result.stdout) > 200)
682 self.assertEqual(0, len(result.stderr))
683 self.assertEqual(0, result.return_code)
686 """Test that we can run it with a specific board"""
687 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
688 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
689 result = self._DoBinman('build', '-n', '-b', 'sandbox')
690 self.assertEqual(0, result)
692 def testNeedBoard(self):
693 """Test that we get an error when no board ius supplied"""
694 with self.assertRaises(ValueError) as e:
695 result = self._DoBinman('build')
696 self.assertIn("Must provide a board to process (use -b <board>)",
699 def testMissingDt(self):
700 """Test that an invalid device-tree file generates an error"""
701 with self.assertRaises(Exception) as e:
702 self._RunBinman('build', '-d', 'missing_file')
703 # We get one error from libfdt, and a different one from fdtget.
704 self.AssertInList(["Couldn't open blob from 'missing_file'",
705 'No such file or directory'], str(e.exception))
707 def testBrokenDt(self):
708 """Test that an invalid device-tree source file generates an error
710 Since this is a source file it should be compiled and the error
711 will come from the device-tree compiler (dtc).
713 with self.assertRaises(Exception) as e:
714 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
715 self.assertIn("FATAL ERROR: Unable to parse input tree",
718 def testMissingNode(self):
719 """Test that a device tree without a 'binman' node generates an error"""
720 with self.assertRaises(Exception) as e:
721 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
722 self.assertIn("does not have a 'binman' node", str(e.exception))
725 """Test that an empty binman node works OK (i.e. does nothing)"""
726 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
727 self.assertEqual(0, len(result.stderr))
728 self.assertEqual(0, result.return_code)
730 def testInvalidEntry(self):
731 """Test that an invalid entry is flagged"""
732 with self.assertRaises(Exception) as e:
733 result = self._RunBinman('build', '-d',
734 self.TestFile('004_invalid_entry.dts'))
735 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
736 "'/binman/not-a-valid-type'", str(e.exception))
738 def testSimple(self):
739 """Test a simple binman with a single file"""
740 data = self._DoReadFile('005_simple.dts')
741 self.assertEqual(U_BOOT_DATA, data)
743 def testSimpleDebug(self):
744 """Test a simple binman run with debugging enabled"""
745 self._DoTestFile('005_simple.dts', debug=True)
748 """Test that we can handle creating two images
750 This also tests image padding.
752 retcode = self._DoTestFile('006_dual_image.dts')
753 self.assertEqual(0, retcode)
755 image = control.images['image1']
756 self.assertEqual(len(U_BOOT_DATA), image.size)
757 fname = tools.GetOutputFilename('image1.bin')
758 self.assertTrue(os.path.exists(fname))
759 with open(fname, 'rb') as fd:
761 self.assertEqual(U_BOOT_DATA, data)
763 image = control.images['image2']
764 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
765 fname = tools.GetOutputFilename('image2.bin')
766 self.assertTrue(os.path.exists(fname))
767 with open(fname, 'rb') as fd:
769 self.assertEqual(U_BOOT_DATA, data[3:7])
770 self.assertEqual(tools.GetBytes(0, 3), data[:3])
771 self.assertEqual(tools.GetBytes(0, 5), data[7:])
773 def testBadAlign(self):
774 """Test that an invalid alignment value is detected"""
775 with self.assertRaises(ValueError) as e:
776 self._DoTestFile('007_bad_align.dts')
777 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
778 "of two", str(e.exception))
780 def testPackSimple(self):
781 """Test that packing works as expected"""
782 retcode = self._DoTestFile('008_pack.dts')
783 self.assertEqual(0, retcode)
784 self.assertIn('image', control.images)
785 image = control.images['image']
786 entries = image.GetEntries()
787 self.assertEqual(5, len(entries))
790 self.assertIn('u-boot', entries)
791 entry = entries['u-boot']
792 self.assertEqual(0, entry.offset)
793 self.assertEqual(len(U_BOOT_DATA), entry.size)
795 # Second u-boot, aligned to 16-byte boundary
796 self.assertIn('u-boot-align', entries)
797 entry = entries['u-boot-align']
798 self.assertEqual(16, entry.offset)
799 self.assertEqual(len(U_BOOT_DATA), entry.size)
801 # Third u-boot, size 23 bytes
802 self.assertIn('u-boot-size', entries)
803 entry = entries['u-boot-size']
804 self.assertEqual(20, entry.offset)
805 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
806 self.assertEqual(23, entry.size)
808 # Fourth u-boot, placed immediate after the above
809 self.assertIn('u-boot-next', entries)
810 entry = entries['u-boot-next']
811 self.assertEqual(43, entry.offset)
812 self.assertEqual(len(U_BOOT_DATA), entry.size)
814 # Fifth u-boot, placed at a fixed offset
815 self.assertIn('u-boot-fixed', entries)
816 entry = entries['u-boot-fixed']
817 self.assertEqual(61, entry.offset)
818 self.assertEqual(len(U_BOOT_DATA), entry.size)
820 self.assertEqual(65, image.size)
822 def testPackExtra(self):
823 """Test that extra packing feature works as expected"""
824 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
827 self.assertIn('image', control.images)
828 image = control.images['image']
829 entries = image.GetEntries()
830 self.assertEqual(5, len(entries))
832 # First u-boot with padding before and after
833 self.assertIn('u-boot', entries)
834 entry = entries['u-boot']
835 self.assertEqual(0, entry.offset)
836 self.assertEqual(3, entry.pad_before)
837 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
838 self.assertEqual(U_BOOT_DATA, entry.data)
839 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
840 tools.GetBytes(0, 5), data[:entry.size])
843 # Second u-boot has an aligned size, but it has no effect
844 self.assertIn('u-boot-align-size-nop', entries)
845 entry = entries['u-boot-align-size-nop']
846 self.assertEqual(pos, entry.offset)
847 self.assertEqual(len(U_BOOT_DATA), entry.size)
848 self.assertEqual(U_BOOT_DATA, entry.data)
849 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
852 # Third u-boot has an aligned size too
853 self.assertIn('u-boot-align-size', entries)
854 entry = entries['u-boot-align-size']
855 self.assertEqual(pos, entry.offset)
856 self.assertEqual(32, entry.size)
857 self.assertEqual(U_BOOT_DATA, entry.data)
858 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
859 data[pos:pos + entry.size])
862 # Fourth u-boot has an aligned end
863 self.assertIn('u-boot-align-end', entries)
864 entry = entries['u-boot-align-end']
865 self.assertEqual(48, entry.offset)
866 self.assertEqual(16, entry.size)
867 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
868 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
869 data[pos:pos + entry.size])
872 # Fifth u-boot immediately afterwards
873 self.assertIn('u-boot-align-both', entries)
874 entry = entries['u-boot-align-both']
875 self.assertEqual(64, entry.offset)
876 self.assertEqual(64, entry.size)
877 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
878 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
879 data[pos:pos + entry.size])
881 self.CheckNoGaps(entries)
882 self.assertEqual(128, image.size)
884 dtb = fdt.Fdt(out_dtb_fname)
886 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
892 'u-boot:image-pos': 0,
894 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
896 'u-boot-align-size-nop:image-pos': 12,
897 'u-boot-align-size-nop:offset': 12,
898 'u-boot-align-size-nop:size': 4,
900 'u-boot-align-size:image-pos': 16,
901 'u-boot-align-size:offset': 16,
902 'u-boot-align-size:size': 32,
904 'u-boot-align-end:image-pos': 48,
905 'u-boot-align-end:offset': 48,
906 'u-boot-align-end:size': 16,
908 'u-boot-align-both:image-pos': 64,
909 'u-boot-align-both:offset': 64,
910 'u-boot-align-both:size': 64,
912 self.assertEqual(expected, props)
914 def testPackAlignPowerOf2(self):
915 """Test that invalid entry alignment is detected"""
916 with self.assertRaises(ValueError) as e:
917 self._DoTestFile('010_pack_align_power2.dts')
918 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
919 "of two", str(e.exception))
921 def testPackAlignSizePowerOf2(self):
922 """Test that invalid entry size alignment is detected"""
923 with self.assertRaises(ValueError) as e:
924 self._DoTestFile('011_pack_align_size_power2.dts')
925 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
926 "power of two", str(e.exception))
928 def testPackInvalidAlign(self):
929 """Test detection of an offset that does not match its alignment"""
930 with self.assertRaises(ValueError) as e:
931 self._DoTestFile('012_pack_inv_align.dts')
932 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
933 "align 0x4 (4)", str(e.exception))
935 def testPackInvalidSizeAlign(self):
936 """Test that invalid entry size alignment is detected"""
937 with self.assertRaises(ValueError) as e:
938 self._DoTestFile('013_pack_inv_size_align.dts')
939 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
940 "align-size 0x4 (4)", str(e.exception))
942 def testPackOverlap(self):
943 """Test that overlapping regions are detected"""
944 with self.assertRaises(ValueError) as e:
945 self._DoTestFile('014_pack_overlap.dts')
946 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
947 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
950 def testPackEntryOverflow(self):
951 """Test that entries that overflow their size are detected"""
952 with self.assertRaises(ValueError) as e:
953 self._DoTestFile('015_pack_overflow.dts')
954 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
955 "but entry size is 0x3 (3)", str(e.exception))
957 def testPackImageOverflow(self):
958 """Test that entries which overflow the image size are detected"""
959 with self.assertRaises(ValueError) as e:
960 self._DoTestFile('016_pack_image_overflow.dts')
961 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
962 "size 0x3 (3)", str(e.exception))
964 def testPackImageSize(self):
965 """Test that the image size can be set"""
966 retcode = self._DoTestFile('017_pack_image_size.dts')
967 self.assertEqual(0, retcode)
968 self.assertIn('image', control.images)
969 image = control.images['image']
970 self.assertEqual(7, image.size)
972 def testPackImageSizeAlign(self):
973 """Test that image size alignemnt works as expected"""
974 retcode = self._DoTestFile('018_pack_image_align.dts')
975 self.assertEqual(0, retcode)
976 self.assertIn('image', control.images)
977 image = control.images['image']
978 self.assertEqual(16, image.size)
980 def testPackInvalidImageAlign(self):
981 """Test that invalid image alignment is detected"""
982 with self.assertRaises(ValueError) as e:
983 self._DoTestFile('019_pack_inv_image_align.dts')
984 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
985 "align-size 0x8 (8)", str(e.exception))
987 def testPackAlignPowerOf2(self):
988 """Test that invalid image alignment is detected"""
989 with self.assertRaises(ValueError) as e:
990 self._DoTestFile('020_pack_inv_image_align_power2.dts')
991 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
992 "two", str(e.exception))
994 def testImagePadByte(self):
995 """Test that the image pad byte can be specified"""
997 data = self._DoReadFile('021_image_pad.dts')
998 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
1001 def testImageName(self):
1002 """Test that image files can be named"""
1003 retcode = self._DoTestFile('022_image_name.dts')
1004 self.assertEqual(0, retcode)
1005 image = control.images['image1']
1006 fname = tools.GetOutputFilename('test-name')
1007 self.assertTrue(os.path.exists(fname))
1009 image = control.images['image2']
1010 fname = tools.GetOutputFilename('test-name.xx')
1011 self.assertTrue(os.path.exists(fname))
1013 def testBlobFilename(self):
1014 """Test that generic blobs can be provided by filename"""
1015 data = self._DoReadFile('023_blob.dts')
1016 self.assertEqual(BLOB_DATA, data)
1018 def testPackSorted(self):
1019 """Test that entries can be sorted"""
1021 data = self._DoReadFile('024_sorted.dts')
1022 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1023 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
1025 def testPackZeroOffset(self):
1026 """Test that an entry at offset 0 is not given a new offset"""
1027 with self.assertRaises(ValueError) as e:
1028 self._DoTestFile('025_pack_zero_size.dts')
1029 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1030 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1033 def testPackUbootDtb(self):
1034 """Test that a device tree can be added to U-Boot"""
1035 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1036 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1038 def testPackX86RomNoSize(self):
1039 """Test that the end-at-4gb property requires a size property"""
1040 with self.assertRaises(ValueError) as e:
1041 self._DoTestFile('027_pack_4gb_no_size.dts')
1042 self.assertIn("Image '/binman': Section size must be provided when "
1043 "using end-at-4gb", str(e.exception))
1045 def test4gbAndSkipAtStartTogether(self):
1046 """Test that the end-at-4gb and skip-at-size property can't be used
1048 with self.assertRaises(ValueError) as e:
1049 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1050 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1051 "'skip-at-start'", str(e.exception))
1053 def testPackX86RomOutside(self):
1054 """Test that the end-at-4gb property checks for offset boundaries"""
1055 with self.assertRaises(ValueError) as e:
1056 self._DoTestFile('028_pack_4gb_outside.dts')
1057 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1058 "is outside the section '/binman' starting at "
1059 '0xffffffe0 (4294967264) of size 0x20 (32)',
1062 def testPackX86Rom(self):
1063 """Test that a basic x86 ROM can be created"""
1065 data = self._DoReadFile('029_x86_rom.dts')
1066 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
1067 tools.GetBytes(0, 2), data)
1069 def testPackX86RomMeNoDesc(self):
1070 """Test that an invalid Intel descriptor entry is detected"""
1072 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1073 with self.assertRaises(ValueError) as e:
1074 self._DoTestFile('163_x86_rom_me_empty.dts')
1075 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1078 self._SetupDescriptor()
1080 def testPackX86RomBadDesc(self):
1081 """Test that the Intel requires a descriptor entry"""
1082 with self.assertRaises(ValueError) as e:
1083 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1084 self.assertIn("Node '/binman/intel-me': No offset set with "
1085 "offset-unset: should another entry provide this correct "
1086 "offset?", str(e.exception))
1088 def testPackX86RomMe(self):
1089 """Test that an x86 ROM with an ME region can be created"""
1090 data = self._DoReadFile('031_x86_rom_me.dts')
1091 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1092 if data[:0x1000] != expected_desc:
1093 self.fail('Expected descriptor binary at start of image')
1094 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1096 def testPackVga(self):
1097 """Test that an image with a VGA binary can be created"""
1098 data = self._DoReadFile('032_intel_vga.dts')
1099 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1101 def testPackStart16(self):
1102 """Test that an image with an x86 start16 region can be created"""
1103 data = self._DoReadFile('033_x86_start16.dts')
1104 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1106 def testPackPowerpcMpc85xxBootpgResetvec(self):
1107 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1109 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1110 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1112 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1113 """Handle running a test for insertion of microcode
1116 dts_fname: Name of test .dts file
1117 nodtb_data: Data that we expect in the first section
1118 ucode_second: True if the microsecond entry is second instead of
1123 Contents of first region (U-Boot or SPL)
1124 Offset and size components of microcode pointer, as inserted
1125 in the above (two 4-byte words)
1127 data = self._DoReadFile(dts_fname, True)
1129 # Now check the device tree has no microcode
1131 ucode_content = data[len(nodtb_data):]
1132 ucode_pos = len(nodtb_data)
1133 dtb_with_ucode = ucode_content[16:]
1134 fdt_len = self.GetFdtLen(dtb_with_ucode)
1136 dtb_with_ucode = data[len(nodtb_data):]
1137 fdt_len = self.GetFdtLen(dtb_with_ucode)
1138 ucode_content = dtb_with_ucode[fdt_len:]
1139 ucode_pos = len(nodtb_data) + fdt_len
1140 fname = tools.GetOutputFilename('test.dtb')
1141 with open(fname, 'wb') as fd:
1142 fd.write(dtb_with_ucode)
1143 dtb = fdt.FdtScan(fname)
1144 ucode = dtb.GetNode('/microcode')
1145 self.assertTrue(ucode)
1146 for node in ucode.subnodes:
1147 self.assertFalse(node.props.get('data'))
1149 # Check that the microcode appears immediately after the Fdt
1150 # This matches the concatenation of the data properties in
1151 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1152 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1154 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1156 # Check that the microcode pointer was inserted. It should match the
1157 # expected offset and size
1158 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1160 u_boot = data[:len(nodtb_data)]
1161 return u_boot, pos_and_size
1163 def testPackUbootMicrocode(self):
1164 """Test that x86 microcode can be handled correctly
1166 We expect to see the following in the image, in order:
1167 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1169 u-boot.dtb with the microcode removed
1172 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1174 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1175 b' somewhere in here', first)
1177 def _RunPackUbootSingleMicrocode(self):
1178 """Test that x86 microcode can be handled correctly
1180 We expect to see the following in the image, in order:
1181 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1183 u-boot.dtb with the microcode
1184 an empty microcode region
1186 # We need the libfdt library to run this test since only that allows
1187 # finding the offset of a property. This is required by
1188 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1189 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1191 second = data[len(U_BOOT_NODTB_DATA):]
1193 fdt_len = self.GetFdtLen(second)
1194 third = second[fdt_len:]
1195 second = second[:fdt_len]
1197 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1198 self.assertIn(ucode_data, second)
1199 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1201 # Check that the microcode pointer was inserted. It should match the
1202 # expected offset and size
1203 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1205 first = data[:len(U_BOOT_NODTB_DATA)]
1206 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1207 b' somewhere in here', first)
1209 def testPackUbootSingleMicrocode(self):
1210 """Test that x86 microcode can be handled correctly with fdt_normal.
1212 self._RunPackUbootSingleMicrocode()
1214 def testUBootImg(self):
1215 """Test that u-boot.img can be put in a file"""
1216 data = self._DoReadFile('036_u_boot_img.dts')
1217 self.assertEqual(U_BOOT_IMG_DATA, data)
1219 def testNoMicrocode(self):
1220 """Test that a missing microcode region is detected"""
1221 with self.assertRaises(ValueError) as e:
1222 self._DoReadFile('037_x86_no_ucode.dts', True)
1223 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1224 "node found in ", str(e.exception))
1226 def testMicrocodeWithoutNode(self):
1227 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1228 with self.assertRaises(ValueError) as e:
1229 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1230 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1231 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1233 def testMicrocodeWithoutNode2(self):
1234 """Test that a missing u-boot-ucode node is detected"""
1235 with self.assertRaises(ValueError) as e:
1236 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1237 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1238 "microcode region u-boot-ucode", str(e.exception))
1240 def testMicrocodeWithoutPtrInElf(self):
1241 """Test that a U-Boot binary without the microcode symbol is detected"""
1242 # ELF file without a '_dt_ucode_base_size' symbol
1244 TestFunctional._MakeInputFile('u-boot',
1245 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1247 with self.assertRaises(ValueError) as e:
1248 self._RunPackUbootSingleMicrocode()
1249 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1250 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1253 # Put the original file back
1254 TestFunctional._MakeInputFile('u-boot',
1255 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1257 def testMicrocodeNotInImage(self):
1258 """Test that microcode must be placed within the image"""
1259 with self.assertRaises(ValueError) as e:
1260 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1261 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1262 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1263 "section ranging from 00000000 to 0000002e", str(e.exception))
1265 def testWithoutMicrocode(self):
1266 """Test that we can cope with an image without microcode (e.g. qemu)"""
1267 TestFunctional._MakeInputFile('u-boot',
1268 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1269 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1271 # Now check the device tree has no microcode
1272 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1273 second = data[len(U_BOOT_NODTB_DATA):]
1275 fdt_len = self.GetFdtLen(second)
1276 self.assertEqual(dtb, second[:fdt_len])
1278 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1279 third = data[used_len:]
1280 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1282 def testUnknownPosSize(self):
1283 """Test that microcode must be placed within the image"""
1284 with self.assertRaises(ValueError) as e:
1285 self._DoReadFile('041_unknown_pos_size.dts', True)
1286 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1287 "entry 'invalid-entry'", str(e.exception))
1289 def testPackFsp(self):
1290 """Test that an image with a FSP binary can be created"""
1291 data = self._DoReadFile('042_intel_fsp.dts')
1292 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1294 def testPackCmc(self):
1295 """Test that an image with a CMC binary can be created"""
1296 data = self._DoReadFile('043_intel_cmc.dts')
1297 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1299 def testPackVbt(self):
1300 """Test that an image with a VBT binary can be created"""
1301 data = self._DoReadFile('046_intel_vbt.dts')
1302 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1304 def testSplBssPad(self):
1305 """Test that we can pad SPL's BSS with zeros"""
1306 # ELF file with a '__bss_size' symbol
1308 data = self._DoReadFile('047_spl_bss_pad.dts')
1309 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1312 def testSplBssPadMissing(self):
1313 """Test that a missing symbol is detected"""
1314 self._SetupSplElf('u_boot_ucode_ptr')
1315 with self.assertRaises(ValueError) as e:
1316 self._DoReadFile('047_spl_bss_pad.dts')
1317 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1320 def testPackStart16Spl(self):
1321 """Test that an image with an x86 start16 SPL region can be created"""
1322 data = self._DoReadFile('048_x86_start16_spl.dts')
1323 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1325 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1326 """Helper function for microcode tests
1328 We expect to see the following in the image, in order:
1329 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1331 u-boot.dtb with the microcode removed
1335 dts: Device tree file to use for test
1336 ucode_second: True if the microsecond entry is second instead of
1339 self._SetupSplElf('u_boot_ucode_ptr')
1340 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1341 ucode_second=ucode_second)
1342 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1343 b'ter somewhere in here', first)
1345 def testPackUbootSplMicrocode(self):
1346 """Test that x86 microcode can be handled correctly in SPL"""
1347 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1349 def testPackUbootSplMicrocodeReorder(self):
1350 """Test that order doesn't matter for microcode entries
1352 This is the same as testPackUbootSplMicrocode but when we process the
1353 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1354 entry, so we reply on binman to try later.
1356 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1359 def testPackMrc(self):
1360 """Test that an image with an MRC binary can be created"""
1361 data = self._DoReadFile('050_intel_mrc.dts')
1362 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1364 def testSplDtb(self):
1365 """Test that an image with spl/u-boot-spl.dtb can be created"""
1366 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1367 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1369 def testSplNoDtb(self):
1370 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1372 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1373 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1375 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1376 use_expanded=False):
1377 """Check the image contains the expected symbol values
1380 dts: Device tree file to use for test
1381 base_data: Data before and after 'u-boot' section
1382 u_boot_offset: Offset of 'u-boot' section in image
1383 entry_args: Dict of entry args to supply to binman
1385 value: value of that arg
1386 use_expanded: True to use expanded entries where available, e.g.
1387 'u-boot-expanded' instead of 'u-boot'
1389 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1390 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1391 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1392 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1395 self._SetupSplElf('u_boot_binman_syms')
1396 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1397 use_expanded=use_expanded)[0]
1398 # The image should contain the symbols from u_boot_binman_syms.c
1399 # Note that image_pos is adjusted by the base address of the image,
1400 # which is 0x10 in our test image
1401 sym_values = struct.pack('<LQLL', 0x00,
1402 u_boot_offset + len(U_BOOT_DATA),
1403 0x10 + u_boot_offset, 0x04)
1404 expected = (sym_values + base_data[20:] +
1405 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1407 self.assertEqual(expected, data)
1409 def testSymbols(self):
1410 """Test binman can assign symbols embedded in U-Boot"""
1411 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1413 def testSymbolsNoDtb(self):
1414 """Test binman can assign symbols embedded in U-Boot SPL"""
1415 self.checkSymbols('196_symbols_nodtb.dts',
1416 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1419 def testPackUnitAddress(self):
1420 """Test that we support multiple binaries with the same name"""
1421 data = self._DoReadFile('054_unit_address.dts')
1422 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1424 def testSections(self):
1425 """Basic test of sections"""
1426 data = self._DoReadFile('055_sections.dts')
1427 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1428 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1429 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1430 self.assertEqual(expected, data)
1433 """Tests outputting a map of the images"""
1434 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1435 self.assertEqual('''ImagePos Offset Size Name
1436 00000000 00000000 00000028 main-section
1437 00000000 00000000 00000010 section@0
1438 00000000 00000000 00000004 u-boot
1439 00000010 00000010 00000010 section@1
1440 00000010 00000000 00000004 u-boot
1441 00000020 00000020 00000004 section@2
1442 00000020 00000000 00000004 u-boot
1445 def testNamePrefix(self):
1446 """Tests that name prefixes are used"""
1447 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1448 self.assertEqual('''ImagePos Offset Size Name
1449 00000000 00000000 00000028 main-section
1450 00000000 00000000 00000010 section@0
1451 00000000 00000000 00000004 ro-u-boot
1452 00000010 00000010 00000010 section@1
1453 00000010 00000000 00000004 rw-u-boot
1456 def testUnknownContents(self):
1457 """Test that obtaining the contents works as expected"""
1458 with self.assertRaises(ValueError) as e:
1459 self._DoReadFile('057_unknown_contents.dts', True)
1460 self.assertIn("Image '/binman': Internal error: Could not complete "
1461 "processing of contents: remaining ["
1462 "<binman.etype._testing.Entry__testing ", str(e.exception))
1464 def testBadChangeSize(self):
1465 """Test that trying to change the size of an entry fails"""
1467 state.SetAllowEntryExpansion(False)
1468 with self.assertRaises(ValueError) as e:
1469 self._DoReadFile('059_change_size.dts', True)
1470 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1473 state.SetAllowEntryExpansion(True)
1475 def testUpdateFdt(self):
1476 """Test that we can update the device tree with offset/size info"""
1477 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1479 dtb = fdt.Fdt(out_dtb_fname)
1481 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1485 '_testing:offset': 32,
1487 '_testing:image-pos': 32,
1488 'section@0/u-boot:offset': 0,
1489 'section@0/u-boot:size': len(U_BOOT_DATA),
1490 'section@0/u-boot:image-pos': 0,
1491 'section@0:offset': 0,
1492 'section@0:size': 16,
1493 'section@0:image-pos': 0,
1495 'section@1/u-boot:offset': 0,
1496 'section@1/u-boot:size': len(U_BOOT_DATA),
1497 'section@1/u-boot:image-pos': 16,
1498 'section@1:offset': 16,
1499 'section@1:size': 16,
1500 'section@1:image-pos': 16,
1504 def testUpdateFdtBad(self):
1505 """Test that we detect when ProcessFdt never completes"""
1506 with self.assertRaises(ValueError) as e:
1507 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1508 self.assertIn('Could not complete processing of Fdt: remaining '
1509 '[<binman.etype._testing.Entry__testing',
1512 def testEntryArgs(self):
1513 """Test passing arguments to entries from the command line"""
1515 'test-str-arg': 'test1',
1516 'test-int-arg': '456',
1518 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1519 self.assertIn('image', control.images)
1520 entry = control.images['image'].GetEntries()['_testing']
1521 self.assertEqual('test0', entry.test_str_fdt)
1522 self.assertEqual('test1', entry.test_str_arg)
1523 self.assertEqual(123, entry.test_int_fdt)
1524 self.assertEqual(456, entry.test_int_arg)
1526 def testEntryArgsMissing(self):
1527 """Test missing arguments and properties"""
1529 'test-int-arg': '456',
1531 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1532 entry = control.images['image'].GetEntries()['_testing']
1533 self.assertEqual('test0', entry.test_str_fdt)
1534 self.assertEqual(None, entry.test_str_arg)
1535 self.assertEqual(None, entry.test_int_fdt)
1536 self.assertEqual(456, entry.test_int_arg)
1538 def testEntryArgsRequired(self):
1539 """Test missing arguments and properties"""
1541 'test-int-arg': '456',
1543 with self.assertRaises(ValueError) as e:
1544 self._DoReadFileDtb('064_entry_args_required.dts')
1545 self.assertIn("Node '/binman/_testing': "
1546 'Missing required properties/entry args: test-str-arg, '
1547 'test-int-fdt, test-int-arg',
1550 def testEntryArgsInvalidFormat(self):
1551 """Test that an invalid entry-argument format is detected"""
1552 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1554 with self.assertRaises(ValueError) as e:
1555 self._DoBinman(*args)
1556 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1558 def testEntryArgsInvalidInteger(self):
1559 """Test that an invalid entry-argument integer is detected"""
1561 'test-int-arg': 'abc',
1563 with self.assertRaises(ValueError) as e:
1564 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1565 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1566 "'test-int-arg' (value 'abc') to integer",
1569 def testEntryArgsInvalidDatatype(self):
1570 """Test that an invalid entry-argument datatype is detected
1572 This test could be written in entry_test.py except that it needs
1573 access to control.entry_args, which seems more than that module should
1577 'test-bad-datatype-arg': '12',
1579 with self.assertRaises(ValueError) as e:
1580 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1581 entry_args=entry_args)
1582 self.assertIn('GetArg() internal error: Unknown data type ',
1586 """Test for a text entry type"""
1588 'test-id': TEXT_DATA,
1589 'test-id2': TEXT_DATA2,
1590 'test-id3': TEXT_DATA3,
1592 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1593 entry_args=entry_args)
1594 expected = (tools.ToBytes(TEXT_DATA) +
1595 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1596 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1597 b'some text' + b'more text')
1598 self.assertEqual(expected, data)
1600 def testEntryDocs(self):
1601 """Test for creation of entry documentation"""
1602 with test_util.capture_sys_output() as (stdout, stderr):
1603 control.WriteEntryDocs(control.GetEntryModules())
1604 self.assertTrue(len(stdout.getvalue()) > 0)
1606 def testEntryDocsMissing(self):
1607 """Test handling of missing entry documentation"""
1608 with self.assertRaises(ValueError) as e:
1609 with test_util.capture_sys_output() as (stdout, stderr):
1610 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1611 self.assertIn('Documentation is missing for modules: u_boot',
1615 """Basic test of generation of a flashrom fmap"""
1616 data = self._DoReadFile('067_fmap.dts')
1617 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1618 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1619 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1620 self.assertEqual(expected, data[:32])
1621 self.assertEqual(b'__FMAP__', fhdr.signature)
1622 self.assertEqual(1, fhdr.ver_major)
1623 self.assertEqual(0, fhdr.ver_minor)
1624 self.assertEqual(0, fhdr.base)
1625 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1626 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1627 self.assertEqual(b'FMAP', fhdr.name)
1628 self.assertEqual(5, fhdr.nareas)
1629 fiter = iter(fentries)
1631 fentry = next(fiter)
1632 self.assertEqual(b'SECTION0', fentry.name)
1633 self.assertEqual(0, fentry.offset)
1634 self.assertEqual(16, fentry.size)
1635 self.assertEqual(0, fentry.flags)
1637 fentry = next(fiter)
1638 self.assertEqual(b'RO_U_BOOT', fentry.name)
1639 self.assertEqual(0, fentry.offset)
1640 self.assertEqual(4, fentry.size)
1641 self.assertEqual(0, fentry.flags)
1643 fentry = next(fiter)
1644 self.assertEqual(b'SECTION1', fentry.name)
1645 self.assertEqual(16, fentry.offset)
1646 self.assertEqual(16, fentry.size)
1647 self.assertEqual(0, fentry.flags)
1649 fentry = next(fiter)
1650 self.assertEqual(b'RW_U_BOOT', fentry.name)
1651 self.assertEqual(16, fentry.offset)
1652 self.assertEqual(4, fentry.size)
1653 self.assertEqual(0, fentry.flags)
1655 fentry = next(fiter)
1656 self.assertEqual(b'FMAP', fentry.name)
1657 self.assertEqual(32, fentry.offset)
1658 self.assertEqual(expect_size, fentry.size)
1659 self.assertEqual(0, fentry.flags)
1661 def testBlobNamedByArg(self):
1662 """Test we can add a blob with the filename coming from an entry arg"""
1664 'cros-ec-rw-path': 'ecrw.bin',
1666 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1669 """Test for an fill entry type"""
1670 data = self._DoReadFile('069_fill.dts')
1671 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1672 self.assertEqual(expected, data)
1674 def testFillNoSize(self):
1675 """Test for an fill entry type with no size"""
1676 with self.assertRaises(ValueError) as e:
1677 self._DoReadFile('070_fill_no_size.dts')
1678 self.assertIn("'fill' entry must have a size property",
1681 def _HandleGbbCommand(self, pipe_list):
1682 """Fake calls to the futility utility"""
1683 if pipe_list[0][0] == 'futility':
1684 fname = pipe_list[0][-1]
1685 # Append our GBB data to the file, which will happen every time the
1686 # futility command is called.
1687 with open(fname, 'ab') as fd:
1689 return command.CommandResult()
1692 """Test for the Chromium OS Google Binary Block"""
1693 command.test_result = self._HandleGbbCommand
1695 'keydir': 'devkeys',
1696 'bmpblk': 'bmpblk.bin',
1698 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1701 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1702 tools.GetBytes(0, 0x2180 - 16))
1703 self.assertEqual(expected, data)
1705 def testGbbTooSmall(self):
1706 """Test for the Chromium OS Google Binary Block being large enough"""
1707 with self.assertRaises(ValueError) as e:
1708 self._DoReadFileDtb('072_gbb_too_small.dts')
1709 self.assertIn("Node '/binman/gbb': GBB is too small",
1712 def testGbbNoSize(self):
1713 """Test for the Chromium OS Google Binary Block having a size"""
1714 with self.assertRaises(ValueError) as e:
1715 self._DoReadFileDtb('073_gbb_no_size.dts')
1716 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1719 def _HandleVblockCommand(self, pipe_list):
1720 """Fake calls to the futility utility
1722 The expected pipe is:
1724 [('futility', 'vbutil_firmware', '--vblock',
1725 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1726 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1727 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1728 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1730 This writes to the output file (here, 'vblock.vblock'). If
1731 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1732 of the input data (here, 'input.vblock').
1734 if pipe_list[0][0] == 'futility':
1735 fname = pipe_list[0][3]
1736 with open(fname, 'wb') as fd:
1738 infile = pipe_list[0][11]
1739 m = hashlib.sha256()
1740 data = tools.ReadFile(infile)
1742 fd.write(m.digest())
1744 fd.write(VBLOCK_DATA)
1746 return command.CommandResult()
1748 def testVblock(self):
1749 """Test for the Chromium OS Verified Boot Block"""
1750 self._hash_data = False
1751 command.test_result = self._HandleVblockCommand
1753 'keydir': 'devkeys',
1755 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1756 entry_args=entry_args)
1757 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1758 self.assertEqual(expected, data)
1760 def testVblockNoContent(self):
1761 """Test we detect a vblock which has no content to sign"""
1762 with self.assertRaises(ValueError) as e:
1763 self._DoReadFile('075_vblock_no_content.dts')
1764 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1765 'property', str(e.exception))
1767 def testVblockBadPhandle(self):
1768 """Test that we detect a vblock with an invalid phandle in contents"""
1769 with self.assertRaises(ValueError) as e:
1770 self._DoReadFile('076_vblock_bad_phandle.dts')
1771 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1772 '1000', str(e.exception))
1774 def testVblockBadEntry(self):
1775 """Test that we detect an entry that points to a non-entry"""
1776 with self.assertRaises(ValueError) as e:
1777 self._DoReadFile('077_vblock_bad_entry.dts')
1778 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1779 "'other'", str(e.exception))
1781 def testVblockContent(self):
1782 """Test that the vblock signs the right data"""
1783 self._hash_data = True
1784 command.test_result = self._HandleVblockCommand
1786 'keydir': 'devkeys',
1788 data = self._DoReadFileDtb(
1789 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1790 entry_args=entry_args)[0]
1791 hashlen = 32 # SHA256 hash is 32 bytes
1792 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1793 hashval = data[-hashlen:]
1794 dtb = data[len(U_BOOT_DATA):-hashlen]
1796 expected_data = U_BOOT_DATA + dtb
1798 # The hashval should be a hash of the dtb
1799 m = hashlib.sha256()
1800 m.update(expected_data)
1801 expected_hashval = m.digest()
1802 self.assertEqual(expected_hashval, hashval)
1805 """Test that an image with TPL and its device tree can be created"""
1806 # ELF file with a '__bss_size' symbol
1808 data = self._DoReadFile('078_u_boot_tpl.dts')
1809 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1811 def testUsesPos(self):
1812 """Test that the 'pos' property cannot be used anymore"""
1813 with self.assertRaises(ValueError) as e:
1814 data = self._DoReadFile('079_uses_pos.dts')
1815 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1816 "'pos'", str(e.exception))
1818 def testFillZero(self):
1819 """Test for an fill entry type with a size of 0"""
1820 data = self._DoReadFile('080_fill_empty.dts')
1821 self.assertEqual(tools.GetBytes(0, 16), data)
1823 def testTextMissing(self):
1824 """Test for a text entry type where there is no text"""
1825 with self.assertRaises(ValueError) as e:
1826 self._DoReadFileDtb('066_text.dts',)
1827 self.assertIn("Node '/binman/text': No value provided for text label "
1828 "'test-id'", str(e.exception))
1830 def testPackStart16Tpl(self):
1831 """Test that an image with an x86 start16 TPL region can be created"""
1832 data = self._DoReadFile('081_x86_start16_tpl.dts')
1833 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1835 def testSelectImage(self):
1836 """Test that we can select which images to build"""
1837 expected = 'Skipping images: image1'
1839 # We should only get the expected message in verbose mode
1840 for verbosity in (0, 2):
1841 with test_util.capture_sys_output() as (stdout, stderr):
1842 retcode = self._DoTestFile('006_dual_image.dts',
1843 verbosity=verbosity,
1845 self.assertEqual(0, retcode)
1847 self.assertIn(expected, stdout.getvalue())
1849 self.assertNotIn(expected, stdout.getvalue())
1851 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1852 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1853 self._CleanupOutputDir()
1855 def testUpdateFdtAll(self):
1856 """Test that all device trees are updated with offset/size info"""
1857 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1860 'section:image-pos': 0,
1861 'u-boot-tpl-dtb:size': 513,
1862 'u-boot-spl-dtb:size': 513,
1863 'u-boot-spl-dtb:offset': 493,
1865 'section/u-boot-dtb:image-pos': 0,
1866 'u-boot-spl-dtb:image-pos': 493,
1867 'section/u-boot-dtb:size': 493,
1868 'u-boot-tpl-dtb:image-pos': 1006,
1869 'section/u-boot-dtb:offset': 0,
1870 'section:size': 493,
1872 'section:offset': 0,
1873 'u-boot-tpl-dtb:offset': 1006,
1877 # We expect three device-tree files in the output, one after the other.
1878 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1879 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1880 # main U-Boot tree. All three should have the same postions and offset.
1882 for item in ['', 'spl', 'tpl']:
1883 dtb = fdt.Fdt.FromData(data[start:])
1885 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1887 expected = dict(base_expected)
1890 self.assertEqual(expected, props)
1891 start += dtb._fdt_obj.totalsize()
1893 def testUpdateFdtOutput(self):
1894 """Test that output DTB files are updated"""
1896 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1897 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1899 # Unfortunately, compiling a source file always results in a file
1900 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1901 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1902 # binman as a file called u-boot.dtb. To fix this, copy the file
1903 # over to the expected place.
1905 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1906 'tpl/u-boot-tpl.dtb.out']:
1907 dtb = fdt.Fdt.FromData(data[start:])
1908 size = dtb._fdt_obj.totalsize()
1909 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1910 outdata = tools.ReadFile(pathname)
1911 name = os.path.split(fname)[0]
1914 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1916 orig_indata = dtb_data
1917 self.assertNotEqual(outdata, orig_indata,
1918 "Expected output file '%s' be updated" % pathname)
1919 self.assertEqual(outdata, data[start:start + size],
1920 "Expected output file '%s' to match output image" %
1926 def _decompress(self, data):
1927 return tools.Decompress(data, 'lz4')
1929 def testCompress(self):
1930 """Test compression of blobs"""
1932 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1933 use_real_dtb=True, update_dtb=True)
1934 dtb = fdt.Fdt(out_dtb_fname)
1936 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1937 orig = self._decompress(data)
1938 self.assertEquals(COMPRESS_DATA, orig)
1940 # Do a sanity check on various fields
1941 image = control.images['image']
1942 entries = image.GetEntries()
1943 self.assertEqual(1, len(entries))
1945 entry = entries['blob']
1946 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1947 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1948 orig = self._decompress(entry.data)
1949 self.assertEqual(orig, entry.uncomp_data)
1951 self.assertEqual(image.data, entry.data)
1954 'blob:uncomp-size': len(COMPRESS_DATA),
1955 'blob:size': len(data),
1958 self.assertEqual(expected, props)
1960 def testFiles(self):
1961 """Test bringing in multiple files"""
1962 data = self._DoReadFile('084_files.dts')
1963 self.assertEqual(FILES_DATA, data)
1965 def testFilesCompress(self):
1966 """Test bringing in multiple files and compressing them"""
1968 data = self._DoReadFile('085_files_compress.dts')
1970 image = control.images['image']
1971 entries = image.GetEntries()
1972 files = entries['files']
1973 entries = files._entries
1976 for i in range(1, 3):
1978 start = entries[key].image_pos
1979 len = entries[key].size
1980 chunk = data[start:start + len]
1981 orig += self._decompress(chunk)
1983 self.assertEqual(FILES_DATA, orig)
1985 def testFilesMissing(self):
1986 """Test missing files"""
1987 with self.assertRaises(ValueError) as e:
1988 data = self._DoReadFile('086_files_none.dts')
1989 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1990 'no files', str(e.exception))
1992 def testFilesNoPattern(self):
1993 """Test missing files"""
1994 with self.assertRaises(ValueError) as e:
1995 data = self._DoReadFile('087_files_no_pattern.dts')
1996 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1999 def testExpandSize(self):
2000 """Test an expanding entry"""
2001 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
2003 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2004 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2005 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2006 tools.GetBytes(ord('d'), 8))
2007 self.assertEqual(expect, data)
2008 self.assertEqual('''ImagePos Offset Size Name
2009 00000000 00000000 00000028 main-section
2010 00000000 00000000 00000008 fill
2011 00000008 00000008 00000004 u-boot
2012 0000000c 0000000c 00000004 section
2013 0000000c 00000000 00000003 intel-mrc
2014 00000010 00000010 00000004 u-boot2
2015 00000014 00000014 0000000c section2
2016 00000014 00000000 00000008 fill
2017 0000001c 00000008 00000004 u-boot
2018 00000020 00000020 00000008 fill2
2021 def testExpandSizeBad(self):
2022 """Test an expanding entry which fails to provide contents"""
2023 with test_util.capture_sys_output() as (stdout, stderr):
2024 with self.assertRaises(ValueError) as e:
2025 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
2026 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2027 'expanding entry', str(e.exception))
2030 """Test hashing of the contents of an entry"""
2031 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2032 use_real_dtb=True, update_dtb=True)
2033 dtb = fdt.Fdt(out_dtb_fname)
2035 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2036 m = hashlib.sha256()
2037 m.update(U_BOOT_DATA)
2038 self.assertEqual(m.digest(), b''.join(hash_node.value))
2040 def testHashNoAlgo(self):
2041 with self.assertRaises(ValueError) as e:
2042 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2043 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2044 'hash node', str(e.exception))
2046 def testHashBadAlgo(self):
2047 with self.assertRaises(ValueError) as e:
2048 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2049 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2052 def testHashSection(self):
2053 """Test hashing of the contents of an entry"""
2054 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2055 use_real_dtb=True, update_dtb=True)
2056 dtb = fdt.Fdt(out_dtb_fname)
2058 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2059 m = hashlib.sha256()
2060 m.update(U_BOOT_DATA)
2061 m.update(tools.GetBytes(ord('a'), 16))
2062 self.assertEqual(m.digest(), b''.join(hash_node.value))
2064 def testPackUBootTplMicrocode(self):
2065 """Test that x86 microcode can be handled correctly in TPL
2067 We expect to see the following in the image, in order:
2068 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2070 u-boot-tpl.dtb with the microcode removed
2073 self._SetupTplElf('u_boot_ucode_ptr')
2074 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2075 U_BOOT_TPL_NODTB_DATA)
2076 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2077 b'ter somewhere in here', first)
2079 def testFmapX86(self):
2080 """Basic test of generation of a flashrom fmap"""
2081 data = self._DoReadFile('094_fmap_x86.dts')
2082 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2083 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
2084 self.assertEqual(expected, data[:32])
2085 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2087 self.assertEqual(0x100, fhdr.image_size)
2089 self.assertEqual(0, fentries[0].offset)
2090 self.assertEqual(4, fentries[0].size)
2091 self.assertEqual(b'U_BOOT', fentries[0].name)
2093 self.assertEqual(4, fentries[1].offset)
2094 self.assertEqual(3, fentries[1].size)
2095 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2097 self.assertEqual(32, fentries[2].offset)
2098 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2099 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2100 self.assertEqual(b'FMAP', fentries[2].name)
2102 def testFmapX86Section(self):
2103 """Basic test of generation of a flashrom fmap"""
2104 data = self._DoReadFile('095_fmap_x86_section.dts')
2105 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
2106 self.assertEqual(expected, data[:32])
2107 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2109 self.assertEqual(0x180, fhdr.image_size)
2110 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2111 fiter = iter(fentries)
2113 fentry = next(fiter)
2114 self.assertEqual(b'U_BOOT', fentry.name)
2115 self.assertEqual(0, fentry.offset)
2116 self.assertEqual(4, fentry.size)
2118 fentry = next(fiter)
2119 self.assertEqual(b'SECTION', fentry.name)
2120 self.assertEqual(4, fentry.offset)
2121 self.assertEqual(0x20 + expect_size, fentry.size)
2123 fentry = next(fiter)
2124 self.assertEqual(b'INTEL_MRC', fentry.name)
2125 self.assertEqual(4, fentry.offset)
2126 self.assertEqual(3, fentry.size)
2128 fentry = next(fiter)
2129 self.assertEqual(b'FMAP', fentry.name)
2130 self.assertEqual(36, fentry.offset)
2131 self.assertEqual(expect_size, fentry.size)
2134 """Basic test of ELF entries"""
2137 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2138 TestFunctional._MakeInputFile('-boot', fd.read())
2139 data = self._DoReadFile('096_elf.dts')
2141 def testElfStrip(self):
2142 """Basic test of ELF entries"""
2144 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2145 TestFunctional._MakeInputFile('-boot', fd.read())
2146 data = self._DoReadFile('097_elf_strip.dts')
2148 def testPackOverlapMap(self):
2149 """Test that overlapping regions are detected"""
2150 with test_util.capture_sys_output() as (stdout, stderr):
2151 with self.assertRaises(ValueError) as e:
2152 self._DoTestFile('014_pack_overlap.dts', map=True)
2153 map_fname = tools.GetOutputFilename('image.map')
2154 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2157 # We should not get an inmage, but there should be a map file
2158 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2159 self.assertTrue(os.path.exists(map_fname))
2160 map_data = tools.ReadFile(map_fname, binary=False)
2161 self.assertEqual('''ImagePos Offset Size Name
2162 <none> 00000000 00000008 main-section
2163 <none> 00000000 00000004 u-boot
2164 <none> 00000003 00000004 u-boot-align
2167 def testPackRefCode(self):
2168 """Test that an image with an Intel Reference code binary works"""
2169 data = self._DoReadFile('100_intel_refcode.dts')
2170 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2172 def testSectionOffset(self):
2173 """Tests use of a section with an offset"""
2174 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2176 self.assertEqual('''ImagePos Offset Size Name
2177 00000000 00000000 00000038 main-section
2178 00000004 00000004 00000010 section@0
2179 00000004 00000000 00000004 u-boot
2180 00000018 00000018 00000010 section@1
2181 00000018 00000000 00000004 u-boot
2182 0000002c 0000002c 00000004 section@2
2183 0000002c 00000000 00000004 u-boot
2185 self.assertEqual(data,
2186 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2187 tools.GetBytes(0x21, 12) +
2188 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2189 tools.GetBytes(0x61, 12) +
2190 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2191 tools.GetBytes(0x26, 8))
2193 def testCbfsRaw(self):
2194 """Test base handling of a Coreboot Filesystem (CBFS)
2196 The exact contents of the CBFS is verified by similar tests in
2197 cbfs_util_test.py. The tests here merely check that the files added to
2198 the CBFS can be found in the final image.
2200 data = self._DoReadFile('102_cbfs_raw.dts')
2203 cbfs = cbfs_util.CbfsReader(data)
2204 self.assertEqual(size, cbfs.rom_size)
2206 self.assertIn('u-boot-dtb', cbfs.files)
2207 cfile = cbfs.files['u-boot-dtb']
2208 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2210 def testCbfsArch(self):
2211 """Test on non-x86 architecture"""
2212 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2215 cbfs = cbfs_util.CbfsReader(data)
2216 self.assertEqual(size, cbfs.rom_size)
2218 self.assertIn('u-boot-dtb', cbfs.files)
2219 cfile = cbfs.files['u-boot-dtb']
2220 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2222 def testCbfsStage(self):
2223 """Tests handling of a Coreboot Filesystem (CBFS)"""
2224 if not elf.ELF_TOOLS:
2225 self.skipTest('Python elftools not available')
2226 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2227 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2230 data = self._DoReadFile('104_cbfs_stage.dts')
2231 cbfs = cbfs_util.CbfsReader(data)
2232 self.assertEqual(size, cbfs.rom_size)
2234 self.assertIn('u-boot', cbfs.files)
2235 cfile = cbfs.files['u-boot']
2236 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2238 def testCbfsRawCompress(self):
2239 """Test handling of compressing raw files"""
2241 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2244 cbfs = cbfs_util.CbfsReader(data)
2245 self.assertIn('u-boot', cbfs.files)
2246 cfile = cbfs.files['u-boot']
2247 self.assertEqual(COMPRESS_DATA, cfile.data)
2249 def testCbfsBadArch(self):
2250 """Test handling of a bad architecture"""
2251 with self.assertRaises(ValueError) as e:
2252 self._DoReadFile('106_cbfs_bad_arch.dts')
2253 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2255 def testCbfsNoSize(self):
2256 """Test handling of a missing size property"""
2257 with self.assertRaises(ValueError) as e:
2258 self._DoReadFile('107_cbfs_no_size.dts')
2259 self.assertIn('entry must have a size property', str(e.exception))
2261 def testCbfsNoContents(self):
2262 """Test handling of a CBFS entry which does not provide contentsy"""
2263 with self.assertRaises(ValueError) as e:
2264 self._DoReadFile('108_cbfs_no_contents.dts')
2265 self.assertIn('Could not complete processing of contents',
2268 def testCbfsBadCompress(self):
2269 """Test handling of a bad architecture"""
2270 with self.assertRaises(ValueError) as e:
2271 self._DoReadFile('109_cbfs_bad_compress.dts')
2272 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2275 def testCbfsNamedEntries(self):
2276 """Test handling of named entries"""
2277 data = self._DoReadFile('110_cbfs_name.dts')
2279 cbfs = cbfs_util.CbfsReader(data)
2280 self.assertIn('FRED', cbfs.files)
2281 cfile1 = cbfs.files['FRED']
2282 self.assertEqual(U_BOOT_DATA, cfile1.data)
2284 self.assertIn('hello', cbfs.files)
2285 cfile2 = cbfs.files['hello']
2286 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2288 def _SetupIfwi(self, fname):
2289 """Set up to run an IFWI test
2292 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2297 # Intel Integrated Firmware Image (IFWI) file
2298 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2300 TestFunctional._MakeInputFile(fname,data)
2302 def _CheckIfwi(self, data):
2303 """Check that an image with an IFWI contains the correct output
2306 data: Conents of output file
2308 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2309 if data[:0x1000] != expected_desc:
2310 self.fail('Expected descriptor binary at start of image')
2312 # We expect to find the TPL wil in subpart IBBP entry IBBL
2313 image_fname = tools.GetOutputFilename('image.bin')
2314 tpl_fname = tools.GetOutputFilename('tpl.out')
2315 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2316 subpart='IBBP', entry_name='IBBL')
2318 tpl_data = tools.ReadFile(tpl_fname)
2319 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2321 def testPackX86RomIfwi(self):
2322 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2323 self._SetupIfwi('fitimage.bin')
2324 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2325 self._CheckIfwi(data)
2327 def testPackX86RomIfwiNoDesc(self):
2328 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2329 self._SetupIfwi('ifwi.bin')
2330 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2331 self._CheckIfwi(data)
2333 def testPackX86RomIfwiNoData(self):
2334 """Test that an x86 ROM with IFWI handles missing data"""
2335 self._SetupIfwi('ifwi.bin')
2336 with self.assertRaises(ValueError) as e:
2337 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2338 self.assertIn('Could not complete processing of contents',
2341 def testCbfsOffset(self):
2342 """Test a CBFS with files at particular offsets
2344 Like all CFBS tests, this is just checking the logic that calls
2345 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2347 data = self._DoReadFile('114_cbfs_offset.dts')
2350 cbfs = cbfs_util.CbfsReader(data)
2351 self.assertEqual(size, cbfs.rom_size)
2353 self.assertIn('u-boot', cbfs.files)
2354 cfile = cbfs.files['u-boot']
2355 self.assertEqual(U_BOOT_DATA, cfile.data)
2356 self.assertEqual(0x40, cfile.cbfs_offset)
2358 self.assertIn('u-boot-dtb', cbfs.files)
2359 cfile2 = cbfs.files['u-boot-dtb']
2360 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2361 self.assertEqual(0x140, cfile2.cbfs_offset)
2363 def testFdtmap(self):
2364 """Test an FDT map can be inserted in the image"""
2365 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2366 fdtmap_data = data[len(U_BOOT_DATA):]
2367 magic = fdtmap_data[:8]
2368 self.assertEqual(b'_FDTMAP_', magic)
2369 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2371 fdt_data = fdtmap_data[16:]
2372 dtb = fdt.Fdt.FromData(fdt_data)
2374 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2379 'u-boot:size': len(U_BOOT_DATA),
2380 'u-boot:image-pos': 0,
2381 'fdtmap:image-pos': 4,
2383 'fdtmap:size': len(fdtmap_data),
2387 def testFdtmapNoMatch(self):
2388 """Check handling of an FDT map when the section cannot be found"""
2389 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2391 # Mangle the section name, which should cause a mismatch between the
2392 # correct FDT path and the one expected by the section
2393 image = control.images['image']
2394 image._node.path += '-suffix'
2395 entries = image.GetEntries()
2396 fdtmap = entries['fdtmap']
2397 with self.assertRaises(ValueError) as e:
2399 self.assertIn("Cannot locate node for path '/binman-suffix'",
2402 def testFdtmapHeader(self):
2403 """Test an FDT map and image header can be inserted in the image"""
2404 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2405 fdtmap_pos = len(U_BOOT_DATA)
2406 fdtmap_data = data[fdtmap_pos:]
2407 fdt_data = fdtmap_data[16:]
2408 dtb = fdt.Fdt.FromData(fdt_data)
2409 fdt_size = dtb.GetFdtObj().totalsize()
2410 hdr_data = data[-8:]
2411 self.assertEqual(b'BinM', hdr_data[:4])
2412 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2413 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2415 def testFdtmapHeaderStart(self):
2416 """Test an image header can be inserted at the image start"""
2417 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2418 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2420 self.assertEqual(b'BinM', hdr_data[:4])
2421 offset = struct.unpack('<I', hdr_data[4:])[0]
2422 self.assertEqual(fdtmap_pos, offset)
2424 def testFdtmapHeaderPos(self):
2425 """Test an image header can be inserted at a chosen position"""
2426 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2427 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2428 hdr_data = data[0x80:0x88]
2429 self.assertEqual(b'BinM', hdr_data[:4])
2430 offset = struct.unpack('<I', hdr_data[4:])[0]
2431 self.assertEqual(fdtmap_pos, offset)
2433 def testHeaderMissingFdtmap(self):
2434 """Test an image header requires an fdtmap"""
2435 with self.assertRaises(ValueError) as e:
2436 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2437 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2440 def testHeaderNoLocation(self):
2441 """Test an image header with a no specified location is detected"""
2442 with self.assertRaises(ValueError) as e:
2443 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2444 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2447 def testEntryExpand(self):
2448 """Test expanding an entry after it is packed"""
2449 data = self._DoReadFile('121_entry_expand.dts')
2450 self.assertEqual(b'aaa', data[:3])
2451 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2452 self.assertEqual(b'aaa', data[-3:])
2454 def testEntryExpandBad(self):
2455 """Test expanding an entry after it is packed, twice"""
2456 with self.assertRaises(ValueError) as e:
2457 self._DoReadFile('122_entry_expand_twice.dts')
2458 self.assertIn("Image '/binman': Entries changed size after packing",
2461 def testEntryExpandSection(self):
2462 """Test expanding an entry within a section after it is packed"""
2463 data = self._DoReadFile('123_entry_expand_section.dts')
2464 self.assertEqual(b'aaa', data[:3])
2465 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2466 self.assertEqual(b'aaa', data[-3:])
2468 def testCompressDtb(self):
2469 """Test that compress of device-tree files is supported"""
2471 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2472 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2473 comp_data = data[len(U_BOOT_DATA):]
2474 orig = self._decompress(comp_data)
2475 dtb = fdt.Fdt.FromData(orig)
2477 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2479 'u-boot:size': len(U_BOOT_DATA),
2480 'u-boot-dtb:uncomp-size': len(orig),
2481 'u-boot-dtb:size': len(comp_data),
2484 self.assertEqual(expected, props)
2486 def testCbfsUpdateFdt(self):
2487 """Test that we can update the device tree with CBFS offset/size info"""
2489 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2491 dtb = fdt.Fdt(out_dtb_fname)
2493 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2494 del props['cbfs/u-boot:size']
2500 'cbfs:size': len(data),
2501 'cbfs:image-pos': 0,
2502 'cbfs/u-boot:offset': 0x38,
2503 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2504 'cbfs/u-boot:image-pos': 0x38,
2505 'cbfs/u-boot-dtb:offset': 0xb8,
2506 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2507 'cbfs/u-boot-dtb:image-pos': 0xb8,
2510 def testCbfsBadType(self):
2511 """Test an image header with a no specified location is detected"""
2512 with self.assertRaises(ValueError) as e:
2513 self._DoReadFile('126_cbfs_bad_type.dts')
2514 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2517 """Test listing the files in an image"""
2519 data = self._DoReadFile('127_list.dts')
2520 image = control.images['image']
2521 entries = image.BuildEntryList()
2522 self.assertEqual(7, len(entries))
2525 self.assertEqual(0, ent.indent)
2526 self.assertEqual('main-section', ent.name)
2527 self.assertEqual('section', ent.etype)
2528 self.assertEqual(len(data), ent.size)
2529 self.assertEqual(0, ent.image_pos)
2530 self.assertEqual(None, ent.uncomp_size)
2531 self.assertEqual(0, ent.offset)
2534 self.assertEqual(1, ent.indent)
2535 self.assertEqual('u-boot', ent.name)
2536 self.assertEqual('u-boot', ent.etype)
2537 self.assertEqual(len(U_BOOT_DATA), ent.size)
2538 self.assertEqual(0, ent.image_pos)
2539 self.assertEqual(None, ent.uncomp_size)
2540 self.assertEqual(0, ent.offset)
2543 self.assertEqual(1, ent.indent)
2544 self.assertEqual('section', ent.name)
2545 self.assertEqual('section', ent.etype)
2546 section_size = ent.size
2547 self.assertEqual(0x100, ent.image_pos)
2548 self.assertEqual(None, ent.uncomp_size)
2549 self.assertEqual(0x100, ent.offset)
2552 self.assertEqual(2, ent.indent)
2553 self.assertEqual('cbfs', ent.name)
2554 self.assertEqual('cbfs', ent.etype)
2555 self.assertEqual(0x400, ent.size)
2556 self.assertEqual(0x100, ent.image_pos)
2557 self.assertEqual(None, ent.uncomp_size)
2558 self.assertEqual(0, ent.offset)
2561 self.assertEqual(3, ent.indent)
2562 self.assertEqual('u-boot', ent.name)
2563 self.assertEqual('u-boot', ent.etype)
2564 self.assertEqual(len(U_BOOT_DATA), ent.size)
2565 self.assertEqual(0x138, ent.image_pos)
2566 self.assertEqual(None, ent.uncomp_size)
2567 self.assertEqual(0x38, ent.offset)
2570 self.assertEqual(3, ent.indent)
2571 self.assertEqual('u-boot-dtb', ent.name)
2572 self.assertEqual('text', ent.etype)
2573 self.assertGreater(len(COMPRESS_DATA), ent.size)
2574 self.assertEqual(0x178, ent.image_pos)
2575 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2576 self.assertEqual(0x78, ent.offset)
2579 self.assertEqual(2, ent.indent)
2580 self.assertEqual('u-boot-dtb', ent.name)
2581 self.assertEqual('u-boot-dtb', ent.etype)
2582 self.assertEqual(0x500, ent.image_pos)
2583 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2585 # Compressing this data expands it since headers are added
2586 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2587 self.assertEqual(0x400, ent.offset)
2589 self.assertEqual(len(data), 0x100 + section_size)
2590 self.assertEqual(section_size, 0x400 + dtb_size)
2592 def testFindFdtmap(self):
2593 """Test locating an FDT map in an image"""
2595 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2596 image = control.images['image']
2597 entries = image.GetEntries()
2598 entry = entries['fdtmap']
2599 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2601 def testFindFdtmapMissing(self):
2602 """Test failing to locate an FDP map"""
2603 data = self._DoReadFile('005_simple.dts')
2604 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2606 def testFindImageHeader(self):
2607 """Test locating a image header"""
2609 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2610 image = control.images['image']
2611 entries = image.GetEntries()
2612 entry = entries['fdtmap']
2613 # The header should point to the FDT map
2614 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2616 def testFindImageHeaderStart(self):
2617 """Test locating a image header located at the start of an image"""
2618 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2619 image = control.images['image']
2620 entries = image.GetEntries()
2621 entry = entries['fdtmap']
2622 # The header should point to the FDT map
2623 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2625 def testFindImageHeaderMissing(self):
2626 """Test failing to locate an image header"""
2627 data = self._DoReadFile('005_simple.dts')
2628 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2630 def testReadImage(self):
2631 """Test reading an image and accessing its FDT map"""
2633 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2634 image_fname = tools.GetOutputFilename('image.bin')
2635 orig_image = control.images['image']
2636 image = Image.FromFile(image_fname)
2637 self.assertEqual(orig_image.GetEntries().keys(),
2638 image.GetEntries().keys())
2640 orig_entry = orig_image.GetEntries()['fdtmap']
2641 entry = image.GetEntries()['fdtmap']
2642 self.assertEquals(orig_entry.offset, entry.offset)
2643 self.assertEquals(orig_entry.size, entry.size)
2644 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2646 def testReadImageNoHeader(self):
2647 """Test accessing an image's FDT map without an image header"""
2649 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2650 image_fname = tools.GetOutputFilename('image.bin')
2651 image = Image.FromFile(image_fname)
2652 self.assertTrue(isinstance(image, Image))
2653 self.assertEqual('image', image.image_name[-5:])
2655 def testReadImageFail(self):
2656 """Test failing to read an image image's FDT map"""
2657 self._DoReadFile('005_simple.dts')
2658 image_fname = tools.GetOutputFilename('image.bin')
2659 with self.assertRaises(ValueError) as e:
2660 image = Image.FromFile(image_fname)
2661 self.assertIn("Cannot find FDT map in image", str(e.exception))
2663 def testListCmd(self):
2664 """Test listing the files in an image using an Fdtmap"""
2666 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2668 # lz4 compression size differs depending on the version
2669 image = control.images['image']
2670 entries = image.GetEntries()
2671 section_size = entries['section'].size
2672 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2673 fdtmap_offset = entries['fdtmap'].offset
2676 tmpdir, updated_fname = self._SetupImageInTmpdir()
2677 with test_util.capture_sys_output() as (stdout, stderr):
2678 self._DoBinman('ls', '-i', updated_fname)
2680 shutil.rmtree(tmpdir)
2681 lines = stdout.getvalue().splitlines()
2683 'Name Image-pos Size Entry-type Offset Uncomp-size',
2684 '----------------------------------------------------------------------',
2685 'main-section 0 c00 section 0',
2686 ' u-boot 0 4 u-boot 0',
2687 ' section 100 %x section 100' % section_size,
2688 ' cbfs 100 400 cbfs 0',
2689 ' u-boot 138 4 u-boot 38',
2690 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2691 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2692 ' fdtmap %x 3bd fdtmap %x' %
2693 (fdtmap_offset, fdtmap_offset),
2694 ' image-header bf8 8 image-header bf8',
2696 self.assertEqual(expected, lines)
2698 def testListCmdFail(self):
2699 """Test failing to list an image"""
2700 self._DoReadFile('005_simple.dts')
2702 tmpdir, updated_fname = self._SetupImageInTmpdir()
2703 with self.assertRaises(ValueError) as e:
2704 self._DoBinman('ls', '-i', updated_fname)
2706 shutil.rmtree(tmpdir)
2707 self.assertIn("Cannot find FDT map in image", str(e.exception))
2709 def _RunListCmd(self, paths, expected):
2710 """List out entries and check the result
2713 paths: List of paths to pass to the list command
2714 expected: Expected list of filenames to be returned, in order
2717 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2718 image_fname = tools.GetOutputFilename('image.bin')
2719 image = Image.FromFile(image_fname)
2720 lines = image.GetListEntries(paths)[1]
2721 files = [line[0].strip() for line in lines[1:]]
2722 self.assertEqual(expected, files)
2724 def testListCmdSection(self):
2725 """Test listing the files in a section"""
2726 self._RunListCmd(['section'],
2727 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2729 def testListCmdFile(self):
2730 """Test listing a particular file"""
2731 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2733 def testListCmdWildcard(self):
2734 """Test listing a wildcarded file"""
2735 self._RunListCmd(['*boot*'],
2736 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2738 def testListCmdWildcardMulti(self):
2739 """Test listing a wildcarded file"""
2740 self._RunListCmd(['*cb*', '*head*'],
2741 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2743 def testListCmdEmpty(self):
2744 """Test listing a wildcarded file"""
2745 self._RunListCmd(['nothing'], [])
2747 def testListCmdPath(self):
2748 """Test listing the files in a sub-entry of a section"""
2749 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2751 def _RunExtractCmd(self, entry_name, decomp=True):
2752 """Extract an entry from an image
2755 entry_name: Entry name to extract
2756 decomp: True to decompress the data if compressed, False to leave
2757 it in its raw uncompressed format
2763 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2764 image_fname = tools.GetOutputFilename('image.bin')
2765 return control.ReadEntry(image_fname, entry_name, decomp)
2767 def testExtractSimple(self):
2768 """Test extracting a single file"""
2769 data = self._RunExtractCmd('u-boot')
2770 self.assertEqual(U_BOOT_DATA, data)
2772 def testExtractSection(self):
2773 """Test extracting the files in a section"""
2774 data = self._RunExtractCmd('section')
2775 cbfs_data = data[:0x400]
2776 cbfs = cbfs_util.CbfsReader(cbfs_data)
2777 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2778 dtb_data = data[0x400:]
2779 dtb = self._decompress(dtb_data)
2780 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2782 def testExtractCompressed(self):
2783 """Test extracting compressed data"""
2784 data = self._RunExtractCmd('section/u-boot-dtb')
2785 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2787 def testExtractRaw(self):
2788 """Test extracting compressed data without decompressing it"""
2789 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2790 dtb = self._decompress(data)
2791 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2793 def testExtractCbfs(self):
2794 """Test extracting CBFS data"""
2795 data = self._RunExtractCmd('section/cbfs/u-boot')
2796 self.assertEqual(U_BOOT_DATA, data)
2798 def testExtractCbfsCompressed(self):
2799 """Test extracting CBFS compressed data"""
2800 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2801 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2803 def testExtractCbfsRaw(self):
2804 """Test extracting CBFS compressed data without decompressing it"""
2805 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2806 dtb = tools.Decompress(data, 'lzma', with_header=False)
2807 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2809 def testExtractBadEntry(self):
2810 """Test extracting a bad section path"""
2811 with self.assertRaises(ValueError) as e:
2812 self._RunExtractCmd('section/does-not-exist')
2813 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2816 def testExtractMissingFile(self):
2817 """Test extracting file that does not exist"""
2818 with self.assertRaises(IOError) as e:
2819 control.ReadEntry('missing-file', 'name')
2821 def testExtractBadFile(self):
2822 """Test extracting an invalid file"""
2823 fname = os.path.join(self._indir, 'badfile')
2824 tools.WriteFile(fname, b'')
2825 with self.assertRaises(ValueError) as e:
2826 control.ReadEntry(fname, 'name')
2828 def testExtractCmd(self):
2829 """Test extracting a file fron an image on the command line"""
2831 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2832 fname = os.path.join(self._indir, 'output.extact')
2834 tmpdir, updated_fname = self._SetupImageInTmpdir()
2835 with test_util.capture_sys_output() as (stdout, stderr):
2836 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2839 shutil.rmtree(tmpdir)
2840 data = tools.ReadFile(fname)
2841 self.assertEqual(U_BOOT_DATA, data)
2843 def testExtractOneEntry(self):
2844 """Test extracting a single entry fron an image """
2846 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2847 image_fname = tools.GetOutputFilename('image.bin')
2848 fname = os.path.join(self._indir, 'output.extact')
2849 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2850 data = tools.ReadFile(fname)
2851 self.assertEqual(U_BOOT_DATA, data)
2853 def _CheckExtractOutput(self, decomp):
2854 """Helper to test file output with and without decompression
2857 decomp: True to decompress entry data, False to output it raw
2859 def _CheckPresent(entry_path, expect_data, expect_size=None):
2860 """Check and remove expected file
2862 This checks the data/size of a file and removes the file both from
2863 the outfiles set and from the output directory. Once all files are
2864 processed, both the set and directory should be empty.
2867 entry_path: Entry path
2868 expect_data: Data to expect in file, or None to skip check
2869 expect_size: Size of data to expect in file, or None to skip
2871 path = os.path.join(outdir, entry_path)
2872 data = tools.ReadFile(path)
2875 self.assertEqual(expect_data, data)
2877 self.assertEqual(expect_size, len(data))
2878 outfiles.remove(path)
2880 def _CheckDirPresent(name):
2881 """Remove expected directory
2883 This gives an error if the directory does not exist as expected
2886 name: Name of directory to remove
2888 path = os.path.join(outdir, name)
2891 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2892 image_fname = tools.GetOutputFilename('image.bin')
2893 outdir = os.path.join(self._indir, 'extract')
2894 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2896 # Create a set of all file that were output (should be 9)
2898 for root, dirs, files in os.walk(outdir):
2899 outfiles |= set([os.path.join(root, fname) for fname in files])
2900 self.assertEqual(9, len(outfiles))
2901 self.assertEqual(9, len(einfos))
2903 image = control.images['image']
2904 entries = image.GetEntries()
2906 # Check the 9 files in various ways
2907 section = entries['section']
2908 section_entries = section.GetEntries()
2909 cbfs_entries = section_entries['cbfs'].GetEntries()
2910 _CheckPresent('u-boot', U_BOOT_DATA)
2911 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2912 dtb_len = EXTRACT_DTB_SIZE
2914 dtb_len = cbfs_entries['u-boot-dtb'].size
2915 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2917 dtb_len = section_entries['u-boot-dtb'].size
2918 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2920 fdtmap = entries['fdtmap']
2921 _CheckPresent('fdtmap', fdtmap.data)
2922 hdr = entries['image-header']
2923 _CheckPresent('image-header', hdr.data)
2925 _CheckPresent('section/root', section.data)
2926 cbfs = section_entries['cbfs']
2927 _CheckPresent('section/cbfs/root', cbfs.data)
2928 data = tools.ReadFile(image_fname)
2929 _CheckPresent('root', data)
2931 # There should be no files left. Remove all the directories to check.
2932 # If there are any files/dirs remaining, one of these checks will fail.
2933 self.assertEqual(0, len(outfiles))
2934 _CheckDirPresent('section/cbfs')
2935 _CheckDirPresent('section')
2936 _CheckDirPresent('')
2937 self.assertFalse(os.path.exists(outdir))
2939 def testExtractAllEntries(self):
2940 """Test extracting all entries"""
2942 self._CheckExtractOutput(decomp=True)
2944 def testExtractAllEntriesRaw(self):
2945 """Test extracting all entries without decompressing them"""
2947 self._CheckExtractOutput(decomp=False)
2949 def testExtractSelectedEntries(self):
2950 """Test extracting some entries"""
2952 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2953 image_fname = tools.GetOutputFilename('image.bin')
2954 outdir = os.path.join(self._indir, 'extract')
2955 einfos = control.ExtractEntries(image_fname, None, outdir,
2958 # File output is tested by testExtractAllEntries(), so just check that
2959 # the expected entries are selected
2960 names = [einfo.name for einfo in einfos]
2961 self.assertEqual(names,
2962 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2964 def testExtractNoEntryPaths(self):
2965 """Test extracting some entries"""
2967 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2968 image_fname = tools.GetOutputFilename('image.bin')
2969 with self.assertRaises(ValueError) as e:
2970 control.ExtractEntries(image_fname, 'fname', None, [])
2971 self.assertIn('Must specify an entry path to write with -f',
2974 def testExtractTooManyEntryPaths(self):
2975 """Test extracting some entries"""
2977 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2978 image_fname = tools.GetOutputFilename('image.bin')
2979 with self.assertRaises(ValueError) as e:
2980 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2981 self.assertIn('Must specify exactly one entry path to write with -f',
2984 def testPackAlignSection(self):
2985 """Test that sections can have alignment"""
2986 self._DoReadFile('131_pack_align_section.dts')
2988 self.assertIn('image', control.images)
2989 image = control.images['image']
2990 entries = image.GetEntries()
2991 self.assertEqual(3, len(entries))
2994 self.assertIn('u-boot', entries)
2995 entry = entries['u-boot']
2996 self.assertEqual(0, entry.offset)
2997 self.assertEqual(0, entry.image_pos)
2998 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2999 self.assertEqual(len(U_BOOT_DATA), entry.size)
3002 self.assertIn('section0', entries)
3003 section0 = entries['section0']
3004 self.assertEqual(0x10, section0.offset)
3005 self.assertEqual(0x10, section0.image_pos)
3006 self.assertEqual(len(U_BOOT_DATA), section0.size)
3009 section_entries = section0.GetEntries()
3010 self.assertIn('u-boot', section_entries)
3011 entry = section_entries['u-boot']
3012 self.assertEqual(0, entry.offset)
3013 self.assertEqual(0x10, entry.image_pos)
3014 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3015 self.assertEqual(len(U_BOOT_DATA), entry.size)
3018 self.assertIn('section1', entries)
3019 section1 = entries['section1']
3020 self.assertEqual(0x14, section1.offset)
3021 self.assertEqual(0x14, section1.image_pos)
3022 self.assertEqual(0x20, section1.size)
3025 section_entries = section1.GetEntries()
3026 self.assertIn('u-boot', section_entries)
3027 entry = section_entries['u-boot']
3028 self.assertEqual(0, entry.offset)
3029 self.assertEqual(0x14, entry.image_pos)
3030 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3031 self.assertEqual(len(U_BOOT_DATA), entry.size)
3034 self.assertIn('section2', section_entries)
3035 section2 = section_entries['section2']
3036 self.assertEqual(0x4, section2.offset)
3037 self.assertEqual(0x18, section2.image_pos)
3038 self.assertEqual(4, section2.size)
3041 section_entries = section2.GetEntries()
3042 self.assertIn('u-boot', section_entries)
3043 entry = section_entries['u-boot']
3044 self.assertEqual(0, entry.offset)
3045 self.assertEqual(0x18, entry.image_pos)
3046 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3047 self.assertEqual(len(U_BOOT_DATA), entry.size)
3049 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3050 dts='132_replace.dts'):
3051 """Replace an entry in an image
3053 This writes the entry data to update it, then opens the updated file and
3054 returns the value that it now finds there.
3057 entry_name: Entry name to replace
3058 data: Data to replace it with
3059 decomp: True to compress the data if needed, False if data is
3060 already compressed so should be used as is
3061 allow_resize: True to allow entries to change size, False to raise
3067 data from fdtmap (excluding header)
3068 Image object that was modified
3070 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3073 self.assertIn('image', control.images)
3074 image = control.images['image']
3075 entries = image.GetEntries()
3076 orig_dtb_data = entries['u-boot-dtb'].data
3077 orig_fdtmap_data = entries['fdtmap'].data
3079 image_fname = tools.GetOutputFilename('image.bin')
3080 updated_fname = tools.GetOutputFilename('image-updated.bin')
3081 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3082 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3084 data = control.ReadEntry(updated_fname, entry_name, decomp)
3086 # The DT data should not change unless resized:
3087 if not allow_resize:
3088 new_dtb_data = entries['u-boot-dtb'].data
3089 self.assertEqual(new_dtb_data, orig_dtb_data)
3090 new_fdtmap_data = entries['fdtmap'].data
3091 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3093 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3095 def testReplaceSimple(self):
3096 """Test replacing a single file"""
3097 expected = b'x' * len(U_BOOT_DATA)
3098 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3100 self.assertEqual(expected, data)
3102 # Test that the state looks right. There should be an FDT for the fdtmap
3103 # that we jsut read back in, and it should match what we find in the
3104 # 'control' tables. Checking for an FDT that does not exist should
3106 path, fdtmap = state.GetFdtContents('fdtmap')
3107 self.assertIsNotNone(path)
3108 self.assertEqual(expected_fdtmap, fdtmap)
3110 dtb = state.GetFdtForEtype('fdtmap')
3111 self.assertEqual(dtb.GetContents(), fdtmap)
3113 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3114 self.assertIsNone(missing_path)
3115 self.assertIsNone(missing_fdtmap)
3117 missing_dtb = state.GetFdtForEtype('missing')
3118 self.assertIsNone(missing_dtb)
3120 self.assertEqual('/binman', state.fdt_path_prefix)
3122 def testReplaceResizeFail(self):
3123 """Test replacing a file by something larger"""
3124 expected = U_BOOT_DATA + b'x'
3125 with self.assertRaises(ValueError) as e:
3126 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3127 dts='139_replace_repack.dts')
3128 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3131 def testReplaceMulti(self):
3132 """Test replacing entry data where multiple images are generated"""
3133 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3135 expected = b'x' * len(U_BOOT_DATA)
3136 updated_fname = tools.GetOutputFilename('image-updated.bin')
3137 tools.WriteFile(updated_fname, data)
3138 entry_name = 'u-boot'
3139 control.WriteEntry(updated_fname, entry_name, expected,
3141 data = control.ReadEntry(updated_fname, entry_name)
3142 self.assertEqual(expected, data)
3144 # Check the state looks right.
3145 self.assertEqual('/binman/image', state.fdt_path_prefix)
3147 # Now check we can write the first image
3148 image_fname = tools.GetOutputFilename('first-image.bin')
3149 updated_fname = tools.GetOutputFilename('first-updated.bin')
3150 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3151 entry_name = 'u-boot'
3152 control.WriteEntry(updated_fname, entry_name, expected,
3154 data = control.ReadEntry(updated_fname, entry_name)
3155 self.assertEqual(expected, data)
3157 # Check the state looks right.
3158 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3160 def testUpdateFdtAllRepack(self):
3161 """Test that all device trees are updated with offset/size info"""
3162 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3163 SECTION_SIZE = 0x300
3168 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3170 'section:offset': 0,
3171 'section:size': SECTION_SIZE,
3172 'section:image-pos': 0,
3173 'section/u-boot-dtb:offset': 4,
3174 'section/u-boot-dtb:size': 636,
3175 'section/u-boot-dtb:image-pos': 4,
3176 'u-boot-spl-dtb:offset': SECTION_SIZE,
3177 'u-boot-spl-dtb:size': DTB_SIZE,
3178 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3179 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3180 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3181 'u-boot-tpl-dtb:size': DTB_SIZE,
3182 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3183 'fdtmap:size': FDTMAP_SIZE,
3184 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3187 'section:orig-size': SECTION_SIZE,
3188 'section/u-boot-dtb:orig-offset': 4,
3191 # We expect three device-tree files in the output, with the first one
3192 # within a fixed-size section.
3193 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3194 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3195 # main U-Boot tree. All three should have the same positions and offset
3196 # except that the main tree should include the main_expected properties
3198 for item in ['', 'spl', 'tpl', None]:
3200 start += 16 # Move past fdtmap header
3201 dtb = fdt.Fdt.FromData(data[start:])
3203 props = self._GetPropTree(dtb,
3204 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3205 prefix='/' if item is None else '/binman/')
3206 expected = dict(base_expected)
3210 # Main DTB and fdtdec should include the 'orig-' properties
3211 expected.update(main_expected)
3212 # Helpful for debugging:
3213 #for prop in sorted(props):
3214 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3215 self.assertEqual(expected, props)
3217 start = SECTION_SIZE
3219 start += dtb._fdt_obj.totalsize()
3221 def testFdtmapHeaderMiddle(self):
3222 """Test an FDT map in the middle of an image when it should be at end"""
3223 with self.assertRaises(ValueError) as e:
3224 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3225 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3228 def testFdtmapHeaderStartBad(self):
3229 """Test an FDT map in middle of an image when it should be at start"""
3230 with self.assertRaises(ValueError) as e:
3231 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3232 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3235 def testFdtmapHeaderEndBad(self):
3236 """Test an FDT map at the start of an image when it should be at end"""
3237 with self.assertRaises(ValueError) as e:
3238 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3239 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3242 def testFdtmapHeaderNoSize(self):
3243 """Test an image header at the end of an image with undefined size"""
3244 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3246 def testReplaceResize(self):
3247 """Test replacing a single file in an entry with a larger file"""
3248 expected = U_BOOT_DATA + b'x'
3249 data, _, image = self._RunReplaceCmd('u-boot', expected,
3250 dts='139_replace_repack.dts')
3251 self.assertEqual(expected, data)
3253 entries = image.GetEntries()
3254 dtb_data = entries['u-boot-dtb'].data
3255 dtb = fdt.Fdt.FromData(dtb_data)
3258 # The u-boot section should now be larger in the dtb
3259 node = dtb.GetNode('/binman/u-boot')
3260 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3262 # Same for the fdtmap
3263 fdata = entries['fdtmap'].data
3264 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3266 fnode = fdtb.GetNode('/u-boot')
3267 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3269 def testReplaceResizeNoRepack(self):
3270 """Test replacing an entry with a larger file when not allowed"""
3271 expected = U_BOOT_DATA + b'x'
3272 with self.assertRaises(ValueError) as e:
3273 self._RunReplaceCmd('u-boot', expected)
3274 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3277 def testEntryShrink(self):
3278 """Test contracting an entry after it is packed"""
3280 state.SetAllowEntryContraction(True)
3281 data = self._DoReadFileDtb('140_entry_shrink.dts',
3284 state.SetAllowEntryContraction(False)
3285 self.assertEqual(b'a', data[:1])
3286 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3287 self.assertEqual(b'a', data[-1:])
3289 def testEntryShrinkFail(self):
3290 """Test not being allowed to contract an entry after it is packed"""
3291 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3293 # In this case there is a spare byte at the end of the data. The size of
3294 # the contents is only 1 byte but we still have the size before it
3296 self.assertEqual(b'a\0', data[:2])
3297 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3298 self.assertEqual(b'a\0', data[-2:])
3300 def testDescriptorOffset(self):
3301 """Test that the Intel descriptor is always placed at at the start"""
3302 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3303 image = control.images['image']
3304 entries = image.GetEntries()
3305 desc = entries['intel-descriptor']
3306 self.assertEqual(0xff800000, desc.offset);
3307 self.assertEqual(0xff800000, desc.image_pos);
3309 def testReplaceCbfs(self):
3310 """Test replacing a single file in CBFS without changing the size"""
3312 expected = b'x' * len(U_BOOT_DATA)
3313 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3314 updated_fname = tools.GetOutputFilename('image-updated.bin')
3315 tools.WriteFile(updated_fname, data)
3316 entry_name = 'section/cbfs/u-boot'
3317 control.WriteEntry(updated_fname, entry_name, expected,
3319 data = control.ReadEntry(updated_fname, entry_name)
3320 self.assertEqual(expected, data)
3322 def testReplaceResizeCbfs(self):
3323 """Test replacing a single file in CBFS with one of a different size"""
3325 expected = U_BOOT_DATA + b'x'
3326 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3327 updated_fname = tools.GetOutputFilename('image-updated.bin')
3328 tools.WriteFile(updated_fname, data)
3329 entry_name = 'section/cbfs/u-boot'
3330 control.WriteEntry(updated_fname, entry_name, expected,
3332 data = control.ReadEntry(updated_fname, entry_name)
3333 self.assertEqual(expected, data)
3335 def _SetupForReplace(self):
3336 """Set up some files to use to replace entries
3338 This generates an image, copies it to a new file, extracts all the files
3339 in it and updates some of them
3345 Expected values for updated entries, each a string
3347 data = self._DoReadFileRealDtb('143_replace_all.dts')
3349 updated_fname = tools.GetOutputFilename('image-updated.bin')
3350 tools.WriteFile(updated_fname, data)
3352 outdir = os.path.join(self._indir, 'extract')
3353 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3355 expected1 = b'x' + U_BOOT_DATA + b'y'
3356 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3357 tools.WriteFile(u_boot_fname1, expected1)
3359 expected2 = b'a' + U_BOOT_DATA + b'b'
3360 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3361 tools.WriteFile(u_boot_fname2, expected2)
3363 expected_text = b'not the same text'
3364 text_fname = os.path.join(outdir, 'text')
3365 tools.WriteFile(text_fname, expected_text)
3367 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3368 dtb = fdt.FdtScan(dtb_fname)
3369 node = dtb.GetNode('/binman/text')
3370 node.AddString('my-property', 'the value')
3371 dtb.Sync(auto_resize=True)
3374 return updated_fname, outdir, expected1, expected2, expected_text
3376 def _CheckReplaceMultiple(self, entry_paths):
3377 """Handle replacing the contents of multiple entries
3380 entry_paths: List of entry paths to replace
3384 Dict of entries in the image:
3387 Expected values for updated entries, each a string
3389 updated_fname, outdir, expected1, expected2, expected_text = (
3390 self._SetupForReplace())
3391 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3393 image = Image.FromFile(updated_fname)
3395 return image.GetEntries(), expected1, expected2, expected_text
3397 def testReplaceAll(self):
3398 """Test replacing the contents of all entries"""
3399 entries, expected1, expected2, expected_text = (
3400 self._CheckReplaceMultiple([]))
3401 data = entries['u-boot'].data
3402 self.assertEqual(expected1, data)
3404 data = entries['u-boot2'].data
3405 self.assertEqual(expected2, data)
3407 data = entries['text'].data
3408 self.assertEqual(expected_text, data)
3410 # Check that the device tree is updated
3411 data = entries['u-boot-dtb'].data
3412 dtb = fdt.Fdt.FromData(data)
3414 node = dtb.GetNode('/binman/text')
3415 self.assertEqual('the value', node.props['my-property'].value)
3417 def testReplaceSome(self):
3418 """Test replacing the contents of a few entries"""
3419 entries, expected1, expected2, expected_text = (
3420 self._CheckReplaceMultiple(['u-boot2', 'text']))
3422 # This one should not change
3423 data = entries['u-boot'].data
3424 self.assertEqual(U_BOOT_DATA, data)
3426 data = entries['u-boot2'].data
3427 self.assertEqual(expected2, data)
3429 data = entries['text'].data
3430 self.assertEqual(expected_text, data)
3432 def testReplaceCmd(self):
3433 """Test replacing a file fron an image on the command line"""
3434 self._DoReadFileRealDtb('143_replace_all.dts')
3437 tmpdir, updated_fname = self._SetupImageInTmpdir()
3439 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3440 expected = b'x' * len(U_BOOT_DATA)
3441 tools.WriteFile(fname, expected)
3443 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3444 data = tools.ReadFile(updated_fname)
3445 self.assertEqual(expected, data[:len(expected)])
3446 map_fname = os.path.join(tmpdir, 'image-updated.map')
3447 self.assertFalse(os.path.exists(map_fname))
3449 shutil.rmtree(tmpdir)
3451 def testReplaceCmdSome(self):
3452 """Test replacing some files fron an image on the command line"""
3453 updated_fname, outdir, expected1, expected2, expected_text = (
3454 self._SetupForReplace())
3456 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3459 tools.PrepareOutputDir(None)
3460 image = Image.FromFile(updated_fname)
3462 entries = image.GetEntries()
3464 # This one should not change
3465 data = entries['u-boot'].data
3466 self.assertEqual(U_BOOT_DATA, data)
3468 data = entries['u-boot2'].data
3469 self.assertEqual(expected2, data)
3471 data = entries['text'].data
3472 self.assertEqual(expected_text, data)
3474 def testReplaceMissing(self):
3475 """Test replacing entries where the file is missing"""
3476 updated_fname, outdir, expected1, expected2, expected_text = (
3477 self._SetupForReplace())
3479 # Remove one of the files, to generate a warning
3480 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3481 os.remove(u_boot_fname1)
3483 with test_util.capture_sys_output() as (stdout, stderr):
3484 control.ReplaceEntries(updated_fname, None, outdir, [])
3485 self.assertIn("Skipping entry '/u-boot' from missing file",
3488 def testReplaceCmdMap(self):
3489 """Test replacing a file fron an image on the command line"""
3490 self._DoReadFileRealDtb('143_replace_all.dts')
3493 tmpdir, updated_fname = self._SetupImageInTmpdir()
3495 fname = os.path.join(self._indir, 'update-u-boot.bin')
3496 expected = b'x' * len(U_BOOT_DATA)
3497 tools.WriteFile(fname, expected)
3499 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3501 map_fname = os.path.join(tmpdir, 'image-updated.map')
3502 self.assertTrue(os.path.exists(map_fname))
3504 shutil.rmtree(tmpdir)
3506 def testReplaceNoEntryPaths(self):
3507 """Test replacing an entry without an entry path"""
3508 self._DoReadFileRealDtb('143_replace_all.dts')
3509 image_fname = tools.GetOutputFilename('image.bin')
3510 with self.assertRaises(ValueError) as e:
3511 control.ReplaceEntries(image_fname, 'fname', None, [])
3512 self.assertIn('Must specify an entry path to read with -f',
3515 def testReplaceTooManyEntryPaths(self):
3516 """Test extracting some entries"""
3517 self._DoReadFileRealDtb('143_replace_all.dts')
3518 image_fname = tools.GetOutputFilename('image.bin')
3519 with self.assertRaises(ValueError) as e:
3520 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3521 self.assertIn('Must specify exactly one entry path to write with -f',
3524 def testPackReset16(self):
3525 """Test that an image with an x86 reset16 region can be created"""
3526 data = self._DoReadFile('144_x86_reset16.dts')
3527 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3529 def testPackReset16Spl(self):
3530 """Test that an image with an x86 reset16-spl region can be created"""
3531 data = self._DoReadFile('145_x86_reset16_spl.dts')
3532 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3534 def testPackReset16Tpl(self):
3535 """Test that an image with an x86 reset16-tpl region can be created"""
3536 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3537 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3539 def testPackIntelFit(self):
3540 """Test that an image with an Intel FIT and pointer can be created"""
3541 data = self._DoReadFile('147_intel_fit.dts')
3542 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3544 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3545 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3547 image = control.images['image']
3548 entries = image.GetEntries()
3549 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3550 self.assertEqual(expected_ptr, ptr)
3552 def testPackIntelFitMissing(self):
3553 """Test detection of a FIT pointer with not FIT region"""
3554 with self.assertRaises(ValueError) as e:
3555 self._DoReadFile('148_intel_fit_missing.dts')
3556 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3559 def _CheckSymbolsTplSection(self, dts, expected_vals):
3560 data = self._DoReadFile(dts)
3561 sym_values = struct.pack('<LQLL', *expected_vals)
3562 upto1 = 4 + len(U_BOOT_SPL_DATA)
3563 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3564 self.assertEqual(expected1, data[:upto1])
3566 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3567 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3568 self.assertEqual(expected2, data[upto1:upto2])
3570 upto3 = 0x34 + len(U_BOOT_DATA)
3571 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3572 self.assertEqual(expected3, data[upto2:upto3])
3574 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3575 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3577 def testSymbolsTplSection(self):
3578 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3579 self._SetupSplElf('u_boot_binman_syms')
3580 self._SetupTplElf('u_boot_binman_syms')
3581 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3582 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3584 def testSymbolsTplSectionX86(self):
3585 """Test binman can assign symbols in a section with end-at-4gb"""
3586 self._SetupSplElf('u_boot_binman_syms_x86')
3587 self._SetupTplElf('u_boot_binman_syms_x86')
3588 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3589 [0xffffff04, 0xffffff1c, 0xffffff34,
3592 def testPackX86RomIfwiSectiom(self):
3593 """Test that a section can be placed in an IFWI region"""
3594 self._SetupIfwi('fitimage.bin')
3595 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3596 self._CheckIfwi(data)
3598 def testPackFspM(self):
3599 """Test that an image with a FSP memory-init binary can be created"""
3600 data = self._DoReadFile('152_intel_fsp_m.dts')
3601 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3603 def testPackFspS(self):
3604 """Test that an image with a FSP silicon-init binary can be created"""
3605 data = self._DoReadFile('153_intel_fsp_s.dts')
3606 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3608 def testPackFspT(self):
3609 """Test that an image with a FSP temp-ram-init binary can be created"""
3610 data = self._DoReadFile('154_intel_fsp_t.dts')
3611 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3613 def testMkimage(self):
3614 """Test using mkimage to build an image"""
3615 data = self._DoReadFile('156_mkimage.dts')
3617 # Just check that the data appears in the file somewhere
3618 self.assertIn(U_BOOT_SPL_DATA, data)
3620 def testExtblob(self):
3621 """Test an image with an external blob"""
3622 data = self._DoReadFile('157_blob_ext.dts')
3623 self.assertEqual(REFCODE_DATA, data)
3625 def testExtblobMissing(self):
3626 """Test an image with a missing external blob"""
3627 with self.assertRaises(ValueError) as e:
3628 self._DoReadFile('158_blob_ext_missing.dts')
3629 self.assertIn("Filename 'missing-file' not found in input path",
3632 def testExtblobMissingOk(self):
3633 """Test an image with an missing external blob that is allowed"""
3634 with test_util.capture_sys_output() as (stdout, stderr):
3635 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3636 err = stderr.getvalue()
3637 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3639 def testExtblobMissingOkSect(self):
3640 """Test an image with an missing external blob that is allowed"""
3641 with test_util.capture_sys_output() as (stdout, stderr):
3642 self._DoTestFile('159_blob_ext_missing_sect.dts',
3644 err = stderr.getvalue()
3645 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3646 "blob-ext blob-ext2")
3648 def testPackX86RomMeMissingDesc(self):
3649 """Test that an missing Intel descriptor entry is allowed"""
3650 with test_util.capture_sys_output() as (stdout, stderr):
3651 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3652 err = stderr.getvalue()
3653 self.assertRegex(err,
3654 "Image 'main-section'.*missing.*: intel-descriptor")
3656 def testPackX86RomMissingIfwi(self):
3657 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3658 self._SetupIfwi('fitimage.bin')
3659 pathname = os.path.join(self._indir, 'fitimage.bin')
3661 with test_util.capture_sys_output() as (stdout, stderr):
3662 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3663 err = stderr.getvalue()
3664 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3666 def testPackOverlap(self):
3667 """Test that zero-size overlapping regions are ignored"""
3668 self._DoTestFile('160_pack_overlap_zero.dts')
3670 def testSimpleFit(self):
3671 """Test an image with a FIT inside"""
3672 data = self._DoReadFile('161_fit.dts')
3673 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3674 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3675 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3677 # The data should be inside the FIT
3678 dtb = fdt.Fdt.FromData(fit_data)
3680 fnode = dtb.GetNode('/images/kernel')
3681 self.assertIn('data', fnode.props)
3683 fname = os.path.join(self._indir, 'fit_data.fit')
3684 tools.WriteFile(fname, fit_data)
3685 out = tools.Run('dumpimage', '-l', fname)
3687 # Check a few features to make sure the plumbing works. We don't need
3688 # to test the operation of mkimage or dumpimage here. First convert the
3689 # output into a dict where the keys are the fields printed by dumpimage
3690 # and the values are a list of values for each field
3691 lines = out.splitlines()
3693 # Converts "Compression: gzip compressed" into two groups:
3694 # 'Compression' and 'gzip compressed'
3695 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3696 vals = collections.defaultdict(list)
3698 mat = re_line.match(line)
3699 vals[mat.group(1)].append(mat.group(2))
3701 self.assertEquals('FIT description: test-desc', lines[0])
3702 self.assertIn('Created:', lines[1])
3703 self.assertIn('Image 0 (kernel)', vals)
3704 self.assertIn('Hash value', vals)
3705 data_sizes = vals.get('Data Size')
3706 self.assertIsNotNone(data_sizes)
3707 self.assertEqual(2, len(data_sizes))
3708 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3709 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3710 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3712 def testFitExternal(self):
3713 """Test an image with an FIT with external images"""
3714 data = self._DoReadFile('162_fit_external.dts')
3715 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3717 # Size of the external-data region as set up by mkimage
3718 external_data_size = len(U_BOOT_DATA) + 2
3719 expected_size = (len(U_BOOT_DATA) + 0x400 +
3720 tools.Align(external_data_size, 4) +
3721 len(U_BOOT_NODTB_DATA))
3723 # The data should be outside the FIT
3724 dtb = fdt.Fdt.FromData(fit_data)
3726 fnode = dtb.GetNode('/images/kernel')
3727 self.assertNotIn('data', fnode.props)
3728 self.assertEqual(len(U_BOOT_DATA),
3729 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3733 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3735 self.assertEquals(expected_size, len(data))
3736 actual_pos = len(U_BOOT_DATA) + fit_pos
3737 self.assertEqual(U_BOOT_DATA + b'aa',
3738 data[actual_pos:actual_pos + external_data_size])
3740 def testSectionIgnoreHashSignature(self):
3741 """Test that sections ignore hash, signature nodes for its data"""
3742 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3743 expected = (U_BOOT_DATA + U_BOOT_DATA)
3744 self.assertEqual(expected, data)
3746 def testPadInSections(self):
3747 """Test pad-before, pad-after for entries in sections"""
3748 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3749 '166_pad_in_sections.dts', update_dtb=True)
3750 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3751 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3753 self.assertEqual(expected, data)
3755 dtb = fdt.Fdt(out_dtb_fname)
3757 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3761 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3763 'section:image-pos': 0,
3764 'section:offset': 0,
3765 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3767 'section/before:image-pos': 0,
3768 'section/before:offset': 0,
3769 'section/before:size': len(U_BOOT_DATA),
3771 'section/u-boot:image-pos': 4,
3772 'section/u-boot:offset': 4,
3773 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3775 'section/after:image-pos': 26,
3776 'section/after:offset': 26,
3777 'section/after:size': len(U_BOOT_DATA),
3779 self.assertEqual(expected, props)
3781 def testFitImageSubentryAlignment(self):
3782 """Test relative alignability of FIT image subentries"""
3784 'test-id': TEXT_DATA,
3786 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3787 entry_args=entry_args)
3788 dtb = fdt.Fdt.FromData(data)
3791 node = dtb.GetNode('/images/kernel')
3792 data = dtb.GetProps(node)["data"].bytes
3793 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3794 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3795 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3796 self.assertEqual(expected, data)
3798 node = dtb.GetNode('/images/fdt-1')
3799 data = dtb.GetProps(node)["data"].bytes
3800 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3801 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3803 self.assertEqual(expected, data)
3805 def testFitExtblobMissingOk(self):
3806 """Test a FIT with a missing external blob that is allowed"""
3807 with test_util.capture_sys_output() as (stdout, stderr):
3808 self._DoTestFile('168_fit_missing_blob.dts',
3810 err = stderr.getvalue()
3811 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3813 def testBlobNamedByArgMissing(self):
3814 """Test handling of a missing entry arg"""
3815 with self.assertRaises(ValueError) as e:
3816 self._DoReadFile('068_blob_named_by_arg.dts')
3817 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3820 def testPackBl31(self):
3821 """Test that an image with an ATF BL31 binary can be created"""
3822 data = self._DoReadFile('169_atf_bl31.dts')
3823 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3825 def testPackScp(self):
3826 """Test that an image with an SCP binary can be created"""
3827 data = self._DoReadFile('172_scp.dts')
3828 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3830 def testFitFdt(self):
3831 """Test an image with an FIT with multiple FDT images"""
3832 def _CheckFdt(seq, expected_data):
3833 """Check the FDT nodes
3836 seq: Sequence number to check (0 or 1)
3837 expected_data: Expected contents of 'data' property
3839 name = 'fdt-%d' % seq
3840 fnode = dtb.GetNode('/images/%s' % name)
3841 self.assertIsNotNone(fnode)
3842 self.assertEqual({'description','type', 'compression', 'data'},
3843 set(fnode.props.keys()))
3844 self.assertEqual(expected_data, fnode.props['data'].bytes)
3845 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3846 fnode.props['description'].value)
3848 def _CheckConfig(seq, expected_data):
3849 """Check the configuration nodes
3852 seq: Sequence number to check (0 or 1)
3853 expected_data: Expected contents of 'data' property
3855 cnode = dtb.GetNode('/configurations')
3856 self.assertIn('default', cnode.props)
3857 self.assertEqual('config-2', cnode.props['default'].value)
3859 name = 'config-%d' % seq
3860 fnode = dtb.GetNode('/configurations/%s' % name)
3861 self.assertIsNotNone(fnode)
3862 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3863 set(fnode.props.keys()))
3864 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3865 fnode.props['description'].value)
3866 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3869 'of-list': 'test-fdt1 test-fdt2',
3870 'default-dt': 'test-fdt2',
3872 data = self._DoReadFileDtb(
3874 entry_args=entry_args,
3875 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3876 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3877 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3879 dtb = fdt.Fdt.FromData(fit_data)
3881 fnode = dtb.GetNode('/images/kernel')
3882 self.assertIn('data', fnode.props)
3884 # Check all the properties in fdt-1 and fdt-2
3885 _CheckFdt(1, TEST_FDT1_DATA)
3886 _CheckFdt(2, TEST_FDT2_DATA)
3888 # Check configurations
3889 _CheckConfig(1, TEST_FDT1_DATA)
3890 _CheckConfig(2, TEST_FDT2_DATA)
3892 def testFitFdtMissingList(self):
3893 """Test handling of a missing 'of-list' entry arg"""
3894 with self.assertRaises(ValueError) as e:
3895 self._DoReadFile('170_fit_fdt.dts')
3896 self.assertIn("Generator node requires 'of-list' entry argument",
3899 def testFitFdtEmptyList(self):
3900 """Test handling of an empty 'of-list' entry arg"""
3904 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3906 def testFitFdtMissingProp(self):
3907 """Test handling of a missing 'fit,fdt-list' property"""
3908 with self.assertRaises(ValueError) as e:
3909 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3910 self.assertIn("Generator node requires 'fit,fdt-list' property",
3913 def testFitFdtEmptyList(self):
3914 """Test handling of an empty 'of-list' entry arg"""
3918 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3920 def testFitFdtMissing(self):
3921 """Test handling of a missing 'default-dt' entry arg"""
3923 'of-list': 'test-fdt1 test-fdt2',
3925 with self.assertRaises(ValueError) as e:
3926 self._DoReadFileDtb(
3928 entry_args=entry_args,
3929 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3930 self.assertIn("Generated 'default' node requires default-dt entry argument",
3933 def testFitFdtNotInList(self):
3934 """Test handling of a default-dt that is not in the of-list"""
3936 'of-list': 'test-fdt1 test-fdt2',
3937 'default-dt': 'test-fdt3',
3939 with self.assertRaises(ValueError) as e:
3940 self._DoReadFileDtb(
3942 entry_args=entry_args,
3943 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3944 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3947 def testFitExtblobMissingHelp(self):
3948 """Test display of help messages when an external blob is missing"""
3949 control.missing_blob_help = control._ReadMissingBlobHelp()
3950 control.missing_blob_help['wibble'] = 'Wibble test'
3951 control.missing_blob_help['another'] = 'Another test'
3952 with test_util.capture_sys_output() as (stdout, stderr):
3953 self._DoTestFile('168_fit_missing_blob.dts',
3955 err = stderr.getvalue()
3957 # We can get the tag from the name, the type or the missing-msg
3958 # property. Check all three.
3959 self.assertIn('You may need to build ARM Trusted', err)
3960 self.assertIn('Wibble test', err)
3961 self.assertIn('Another test', err)
3963 def testMissingBlob(self):
3964 """Test handling of a blob containing a missing file"""
3965 with self.assertRaises(ValueError) as e:
3966 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3967 self.assertIn("Filename 'missing' not found in input path",
3970 def testEnvironment(self):
3971 """Test adding a U-Boot environment"""
3972 data = self._DoReadFile('174_env.dts')
3973 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3974 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3975 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3976 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3979 def testEnvironmentNoSize(self):
3980 """Test that a missing 'size' property is detected"""
3981 with self.assertRaises(ValueError) as e:
3982 self._DoTestFile('175_env_no_size.dts')
3983 self.assertIn("'u-boot-env' entry must have a size property",
3986 def testEnvironmentTooSmall(self):
3987 """Test handling of an environment that does not fit"""
3988 with self.assertRaises(ValueError) as e:
3989 self._DoTestFile('176_env_too_small.dts')
3991 # checksum, start byte, environment with \0 terminator, final \0
3992 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3994 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3997 def testSkipAtStart(self):
3998 """Test handling of skip-at-start section"""
3999 data = self._DoReadFile('177_skip_at_start.dts')
4000 self.assertEqual(U_BOOT_DATA, data)
4002 image = control.images['image']
4003 entries = image.GetEntries()
4004 section = entries['section']
4005 self.assertEqual(0, section.offset)
4006 self.assertEqual(len(U_BOOT_DATA), section.size)
4007 self.assertEqual(U_BOOT_DATA, section.GetData())
4009 entry = section.GetEntries()['u-boot']
4010 self.assertEqual(16, entry.offset)
4011 self.assertEqual(len(U_BOOT_DATA), entry.size)
4012 self.assertEqual(U_BOOT_DATA, entry.data)
4014 def testSkipAtStartPad(self):
4015 """Test handling of skip-at-start section with padded entry"""
4016 data = self._DoReadFile('178_skip_at_start_pad.dts')
4017 before = tools.GetBytes(0, 8)
4018 after = tools.GetBytes(0, 4)
4019 all = before + U_BOOT_DATA + after
4020 self.assertEqual(all, data)
4022 image = control.images['image']
4023 entries = image.GetEntries()
4024 section = entries['section']
4025 self.assertEqual(0, section.offset)
4026 self.assertEqual(len(all), section.size)
4027 self.assertEqual(all, section.GetData())
4029 entry = section.GetEntries()['u-boot']
4030 self.assertEqual(16, entry.offset)
4031 self.assertEqual(len(all), entry.size)
4032 self.assertEqual(U_BOOT_DATA, entry.data)
4034 def testSkipAtStartSectionPad(self):
4035 """Test handling of skip-at-start section with padding"""
4036 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4037 before = tools.GetBytes(0, 8)
4038 after = tools.GetBytes(0, 4)
4039 all = before + U_BOOT_DATA + after
4040 self.assertEqual(all, data)
4042 image = control.images['image']
4043 entries = image.GetEntries()
4044 section = entries['section']
4045 self.assertEqual(0, section.offset)
4046 self.assertEqual(len(all), section.size)
4047 self.assertEqual(U_BOOT_DATA, section.data)
4048 self.assertEqual(all, section.GetPaddedData())
4050 entry = section.GetEntries()['u-boot']
4051 self.assertEqual(16, entry.offset)
4052 self.assertEqual(len(U_BOOT_DATA), entry.size)
4053 self.assertEqual(U_BOOT_DATA, entry.data)
4055 def testSectionPad(self):
4056 """Testing padding with sections"""
4057 data = self._DoReadFile('180_section_pad.dts')
4058 expected = (tools.GetBytes(ord('&'), 3) +
4059 tools.GetBytes(ord('!'), 5) +
4061 tools.GetBytes(ord('!'), 1) +
4062 tools.GetBytes(ord('&'), 2))
4063 self.assertEqual(expected, data)
4065 def testSectionAlign(self):
4066 """Testing alignment with sections"""
4067 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4068 expected = (b'\0' + # fill section
4069 tools.GetBytes(ord('&'), 1) + # padding to section align
4070 b'\0' + # fill section
4071 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4073 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4074 tools.GetBytes(ord('!'), 4)) # padding to section size
4075 self.assertEqual(expected, data)
4077 def testCompressImage(self):
4078 """Test compression of the entire image"""
4080 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4081 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4082 dtb = fdt.Fdt(out_dtb_fname)
4084 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4086 orig = self._decompress(data)
4087 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4089 # Do a sanity check on various fields
4090 image = control.images['image']
4091 entries = image.GetEntries()
4092 self.assertEqual(2, len(entries))
4094 entry = entries['blob']
4095 self.assertEqual(COMPRESS_DATA, entry.data)
4096 self.assertEqual(len(COMPRESS_DATA), entry.size)
4098 entry = entries['u-boot']
4099 self.assertEqual(U_BOOT_DATA, entry.data)
4100 self.assertEqual(len(U_BOOT_DATA), entry.size)
4102 self.assertEqual(len(data), image.size)
4103 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4104 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4105 orig = self._decompress(image.data)
4106 self.assertEqual(orig, image.uncomp_data)
4110 'blob:size': len(COMPRESS_DATA),
4111 'u-boot:offset': len(COMPRESS_DATA),
4112 'u-boot:size': len(U_BOOT_DATA),
4113 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4118 self.assertEqual(expected, props)
4120 def testCompressImageLess(self):
4121 """Test compression where compression reduces the image size"""
4123 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4124 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4125 dtb = fdt.Fdt(out_dtb_fname)
4127 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4129 orig = self._decompress(data)
4131 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4133 # Do a sanity check on various fields
4134 image = control.images['image']
4135 entries = image.GetEntries()
4136 self.assertEqual(2, len(entries))
4138 entry = entries['blob']
4139 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4140 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4142 entry = entries['u-boot']
4143 self.assertEqual(U_BOOT_DATA, entry.data)
4144 self.assertEqual(len(U_BOOT_DATA), entry.size)
4146 self.assertEqual(len(data), image.size)
4147 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4148 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4150 orig = self._decompress(image.data)
4151 self.assertEqual(orig, image.uncomp_data)
4155 'blob:size': len(COMPRESS_DATA_BIG),
4156 'u-boot:offset': len(COMPRESS_DATA_BIG),
4157 'u-boot:size': len(U_BOOT_DATA),
4158 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4163 self.assertEqual(expected, props)
4165 def testCompressSectionSize(self):
4166 """Test compression of a section with a fixed size"""
4168 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4169 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4170 dtb = fdt.Fdt(out_dtb_fname)
4172 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4174 orig = self._decompress(data)
4175 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4177 'section/blob:offset': 0,
4178 'section/blob:size': len(COMPRESS_DATA),
4179 'section/u-boot:offset': len(COMPRESS_DATA),
4180 'section/u-boot:size': len(U_BOOT_DATA),
4181 'section:offset': 0,
4182 'section:image-pos': 0,
4183 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4184 'section:size': 0x30,
4189 self.assertEqual(expected, props)
4191 def testCompressSection(self):
4192 """Test compression of a section with no fixed size"""
4194 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4195 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4196 dtb = fdt.Fdt(out_dtb_fname)
4198 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4200 orig = self._decompress(data)
4201 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4203 'section/blob:offset': 0,
4204 'section/blob:size': len(COMPRESS_DATA),
4205 'section/u-boot:offset': len(COMPRESS_DATA),
4206 'section/u-boot:size': len(U_BOOT_DATA),
4207 'section:offset': 0,
4208 'section:image-pos': 0,
4209 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4210 'section:size': len(data),
4215 self.assertEqual(expected, props)
4217 def testCompressExtra(self):
4218 """Test compression of a section with no fixed size"""
4220 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4221 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4222 dtb = fdt.Fdt(out_dtb_fname)
4224 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4227 base = data[len(U_BOOT_DATA):]
4228 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4229 rest = base[len(U_BOOT_DATA):]
4231 # Check compressed data
4232 section1 = self._decompress(rest)
4233 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4234 self.assertEquals(expect1, rest[:len(expect1)])
4235 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4236 rest1 = rest[len(expect1):]
4238 section2 = self._decompress(rest1)
4239 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4240 self.assertEquals(expect2, rest1[:len(expect2)])
4241 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4242 rest2 = rest1[len(expect2):]
4244 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4245 len(expect2) + len(U_BOOT_DATA))
4246 #self.assertEquals(expect_size, len(data))
4248 #self.assertEquals(U_BOOT_DATA, rest2)
4253 'u-boot:image-pos': 0,
4254 'u-boot:size': len(U_BOOT_DATA),
4256 'base:offset': len(U_BOOT_DATA),
4257 'base:image-pos': len(U_BOOT_DATA),
4258 'base:size': len(data) - len(U_BOOT_DATA),
4259 'base/u-boot:offset': 0,
4260 'base/u-boot:image-pos': len(U_BOOT_DATA),
4261 'base/u-boot:size': len(U_BOOT_DATA),
4262 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4264 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4266 'base/u-boot2:size': len(U_BOOT_DATA),
4268 'base/section:offset': len(U_BOOT_DATA),
4269 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4270 'base/section:size': len(expect1),
4271 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4272 'base/section/blob:offset': 0,
4273 'base/section/blob:size': len(COMPRESS_DATA),
4274 'base/section/u-boot:offset': len(COMPRESS_DATA),
4275 'base/section/u-boot:size': len(U_BOOT_DATA),
4277 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4278 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4279 'base/section2:size': len(expect2),
4280 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4281 'base/section2/blob:offset': 0,
4282 'base/section2/blob:size': len(COMPRESS_DATA),
4283 'base/section2/blob2:offset': len(COMPRESS_DATA),
4284 'base/section2/blob2:size': len(COMPRESS_DATA),
4290 self.assertEqual(expected, props)
4292 def testSymbolsSubsection(self):
4293 """Test binman can assign symbols from a subsection"""
4294 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4296 def testReadImageEntryArg(self):
4297 """Test reading an image that would need an entry arg to generate"""
4299 'cros-ec-rw-path': 'ecrw.bin',
4301 data = self.data = self._DoReadFileDtb(
4302 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4303 entry_args=entry_args)
4305 image_fname = tools.GetOutputFilename('image.bin')
4306 orig_image = control.images['image']
4308 # This should not generate an error about the missing 'cros-ec-rw-path'
4309 # since we are reading the image from a file. Compare with
4310 # testEntryArgsRequired()
4311 image = Image.FromFile(image_fname)
4312 self.assertEqual(orig_image.GetEntries().keys(),
4313 image.GetEntries().keys())
4315 def testFilesAlign(self):
4316 """Test alignment with files"""
4317 data = self._DoReadFile('190_files_align.dts')
4319 # The first string is 15 bytes so will align to 16
4320 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4321 self.assertEqual(expect, data)
4323 def testReadImageSkip(self):
4324 """Test reading an image and accessing its FDT map"""
4325 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4326 image_fname = tools.GetOutputFilename('image.bin')
4327 orig_image = control.images['image']
4328 image = Image.FromFile(image_fname)
4329 self.assertEqual(orig_image.GetEntries().keys(),
4330 image.GetEntries().keys())
4332 orig_entry = orig_image.GetEntries()['fdtmap']
4333 entry = image.GetEntries()['fdtmap']
4334 self.assertEqual(orig_entry.offset, entry.offset)
4335 self.assertEqual(orig_entry.size, entry.size)
4336 self.assertEqual(16, entry.image_pos)
4338 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4340 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4342 def testTplNoDtb(self):
4343 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4345 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4346 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4347 data[:len(U_BOOT_TPL_NODTB_DATA)])
4349 def testTplBssPad(self):
4350 """Test that we can pad TPL's BSS with zeros"""
4351 # ELF file with a '__bss_size' symbol
4353 data = self._DoReadFile('193_tpl_bss_pad.dts')
4354 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4357 def testTplBssPadMissing(self):
4358 """Test that a missing symbol is detected"""
4359 self._SetupTplElf('u_boot_ucode_ptr')
4360 with self.assertRaises(ValueError) as e:
4361 self._DoReadFile('193_tpl_bss_pad.dts')
4362 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4365 def checkDtbSizes(self, data, pad_len, start):
4366 """Check the size arguments in a dtb embedded in an image
4369 data: The image data
4370 pad_len: Length of the pad section in the image, in bytes
4371 start: Start offset of the devicetree to examine, within the image
4374 Size of the devicetree in bytes
4376 dtb_data = data[start:]
4377 dtb = fdt.Fdt.FromData(dtb_data)
4378 fdt_size = dtb.GetFdtObj().totalsize()
4380 props = self._GetPropTree(dtb, 'size')
4383 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4384 'u-boot-spl/u-boot-spl-dtb:size': 801,
4385 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4386 'u-boot-spl:size': 860,
4387 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4388 'u-boot/u-boot-dtb:size': 781,
4389 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4394 def testExpanded(self):
4395 """Test that an expanded entry type is selected when needed"""
4399 # SPL has a devicetree, TPL does not
4405 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4406 entry_args=entry_args)
4407 image = control.images['image']
4408 entries = image.GetEntries()
4409 self.assertEqual(3, len(entries))
4411 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4412 self.assertIn('u-boot', entries)
4413 entry = entries['u-boot']
4414 self.assertEqual('u-boot-expanded', entry.etype)
4415 subent = entry.GetEntries()
4416 self.assertEqual(2, len(subent))
4417 self.assertIn('u-boot-nodtb', subent)
4418 self.assertIn('u-boot-dtb', subent)
4420 # Second, u-boot-spl, which should be expanded into three parts
4421 self.assertIn('u-boot-spl', entries)
4422 entry = entries['u-boot-spl']
4423 self.assertEqual('u-boot-spl-expanded', entry.etype)
4424 subent = entry.GetEntries()
4425 self.assertEqual(3, len(subent))
4426 self.assertIn('u-boot-spl-nodtb', subent)
4427 self.assertIn('u-boot-spl-bss-pad', subent)
4428 self.assertIn('u-boot-spl-dtb', subent)
4430 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4432 self.assertIn('u-boot-tpl', entries)
4433 entry = entries['u-boot-tpl']
4434 self.assertEqual('u-boot-tpl', entry.etype)
4435 self.assertEqual(None, entry.GetEntries())
4437 def testExpandedTpl(self):
4438 """Test that an expanded entry type is selected for TPL when needed"""
4445 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4446 entry_args=entry_args)
4447 image = control.images['image']
4448 entries = image.GetEntries()
4449 self.assertEqual(1, len(entries))
4451 # We only have u-boot-tpl, which be expanded
4452 self.assertIn('u-boot-tpl', entries)
4453 entry = entries['u-boot-tpl']
4454 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4455 subent = entry.GetEntries()
4456 self.assertEqual(3, len(subent))
4457 self.assertIn('u-boot-tpl-nodtb', subent)
4458 self.assertIn('u-boot-tpl-bss-pad', subent)
4459 self.assertIn('u-boot-tpl-dtb', subent)
4461 def testExpandedNoPad(self):
4462 """Test an expanded entry without BSS pad enabled"""
4466 # SPL has a devicetree, TPL does not
4468 'spl-dtb': 'something',
4472 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4473 entry_args=entry_args)
4474 image = control.images['image']
4475 entries = image.GetEntries()
4477 # Just check u-boot-spl, which should be expanded into two parts
4478 self.assertIn('u-boot-spl', entries)
4479 entry = entries['u-boot-spl']
4480 self.assertEqual('u-boot-spl-expanded', entry.etype)
4481 subent = entry.GetEntries()
4482 self.assertEqual(2, len(subent))
4483 self.assertIn('u-boot-spl-nodtb', subent)
4484 self.assertIn('u-boot-spl-dtb', subent)
4486 def testExpandedTplNoPad(self):
4487 """Test that an expanded entry type with padding disabled in TPL"""
4494 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4495 entry_args=entry_args)
4496 image = control.images['image']
4497 entries = image.GetEntries()
4498 self.assertEqual(1, len(entries))
4500 # We only have u-boot-tpl, which be expanded
4501 self.assertIn('u-boot-tpl', entries)
4502 entry = entries['u-boot-tpl']
4503 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4504 subent = entry.GetEntries()
4505 self.assertEqual(2, len(subent))
4506 self.assertIn('u-boot-tpl-nodtb', subent)
4507 self.assertIn('u-boot-tpl-dtb', subent)
4509 def testFdtInclude(self):
4510 """Test that an Fdt is update within all binaries"""
4514 # SPL has a devicetree, TPL does not
4521 # Build the image. It includes two separate devicetree binaries, each
4522 # with their own contents, but all contain the binman definition.
4523 data = self._DoReadFileDtb(
4524 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4525 update_dtb=True, entry_args=entry_args)[0]
4528 # Check the U-Boot dtb
4529 start = len(U_BOOT_NODTB_DATA)
4530 fdt_size = self.checkDtbSizes(data, pad_len, start)
4533 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4534 fdt_size = self.checkDtbSizes(data, pad_len, start)
4536 # TPL has no devicetree
4537 start += fdt_size + len(U_BOOT_TPL_DATA)
4538 self.assertEqual(len(data), start)
4540 def testSymbolsExpanded(self):
4541 """Test binman can assign symbols in expanded entries"""
4545 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4546 U_BOOT_SPL_DTB_DATA, 0x38,
4547 entry_args=entry_args, use_expanded=True)
4549 def testCollection(self):
4550 """Test a collection"""
4551 data = self._DoReadFile('198_collection.dts')
4552 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4553 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4554 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4557 def testCollectionSection(self):
4558 """Test a collection where a section must be built first"""
4559 # Sections never have their contents when GetData() is called, but when
4560 # BuildSectionData() is called with required=True, a section will force
4561 # building the contents, producing an error is anything is still
4563 data = self._DoReadFile('199_collection_section.dts')
4564 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4565 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4566 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4569 def testAlignDefault(self):
4570 """Test that default alignment works on sections"""
4571 data = self._DoReadFile('200_align_default.dts')
4572 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4574 # Special alignment for section
4575 expected += tools.GetBytes(0, 32 - len(expected))
4576 # No alignment within the nested section
4577 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4578 # Now the final piece, which should be default-aligned
4579 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4580 self.assertEqual(expected, data)
4582 def testPackOpenSBI(self):
4583 """Test that an image with an OpenSBI binary can be created"""
4584 data = self._DoReadFile('201_opensbi.dts')
4585 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4587 def testSectionsSingleThread(self):
4588 """Test sections without multithreading"""
4589 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4590 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4591 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4592 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4593 self.assertEqual(expected, data)
4595 def testThreadTimeout(self):
4596 """Test handling a thread that takes too long"""
4597 with self.assertRaises(ValueError) as e:
4598 self._DoTestFile('202_section_timeout.dts',
4599 test_section_timeout=True)
4600 self.assertIn("Timed out obtaining contents", str(e.exception))
4602 def testTiming(self):
4603 """Test output of timing information"""
4604 data = self._DoReadFile('055_sections.dts')
4605 with test_util.capture_sys_output() as (stdout, stderr):
4607 self.assertIn('read:', stdout.getvalue())
4608 self.assertIn('compress:', stdout.getvalue())
4610 def testUpdateFdtInElf(self):
4611 """Test that we can update the devicetree in an ELF file"""
4612 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4613 outfile = os.path.join(self._indir, 'u-boot.out')
4614 begin_sym = 'dtb_embed_begin'
4615 end_sym = 'dtb_embed_end'
4616 retcode = self._DoTestFile(
4617 '060_fdt_update.dts', update_dtb=True,
4618 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4619 self.assertEqual(0, retcode)
4621 # Check that the output file does in fact contact a dtb with the binman
4622 # definition in the correct place
4623 syms = elf.GetSymbolFileOffset(infile,
4624 ['dtb_embed_begin', 'dtb_embed_end'])
4625 data = tools.ReadFile(outfile)
4626 dtb_data = data[syms['dtb_embed_begin'].offset:
4627 syms['dtb_embed_end'].offset]
4629 dtb = fdt.Fdt.FromData(dtb_data)
4631 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4635 '_testing:offset': 32,
4637 '_testing:image-pos': 32,
4638 'section@0/u-boot:offset': 0,
4639 'section@0/u-boot:size': len(U_BOOT_DATA),
4640 'section@0/u-boot:image-pos': 0,
4641 'section@0:offset': 0,
4642 'section@0:size': 16,
4643 'section@0:image-pos': 0,
4645 'section@1/u-boot:offset': 0,
4646 'section@1/u-boot:size': len(U_BOOT_DATA),
4647 'section@1/u-boot:image-pos': 16,
4648 'section@1:offset': 16,
4649 'section@1:size': 16,
4650 'section@1:image-pos': 16,
4654 def testUpdateFdtInElfInvalid(self):
4655 """Test that invalid args are detected with --update-fdt-in-elf"""
4656 with self.assertRaises(ValueError) as e:
4657 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4658 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4661 def testUpdateFdtInElfNoSyms(self):
4662 """Test that missing symbols are detected with --update-fdt-in-elf"""
4663 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4665 begin_sym = 'wrong_begin'
4666 end_sym = 'wrong_end'
4667 with self.assertRaises(ValueError) as e:
4669 '060_fdt_update.dts',
4670 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4671 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4674 def testUpdateFdtInElfTooSmall(self):
4675 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4676 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4677 outfile = os.path.join(self._indir, 'u-boot.out')
4678 begin_sym = 'dtb_embed_begin'
4679 end_sym = 'dtb_embed_end'
4680 with self.assertRaises(ValueError) as e:
4682 '060_fdt_update.dts', update_dtb=True,
4683 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4686 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4688 def testVersion(self):
4689 """Test we can get the binman version"""
4690 version = '(unreleased)'
4691 self.assertEqual(version, state.GetVersion(self._indir))
4693 with self.assertRaises(SystemExit):
4694 with test_util.capture_sys_output() as (_, stderr):
4695 self._DoBinman('-V')
4696 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4698 # Try running the tool too, just to be safe
4699 result = self._RunBinman('-V')
4700 self.assertEqual('Binman %s\n' % version, result.stderr)
4702 # Set up a version file to make sure that works
4703 version = 'v2025.01-rc2'
4704 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4706 self.assertEqual(version, state.GetVersion(self._indir))
4708 def testAltFormat(self):
4709 """Test that alternative formats can be used to extract"""
4710 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4713 tmpdir, updated_fname = self._SetupImageInTmpdir()
4714 with test_util.capture_sys_output() as (stdout, _):
4715 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4717 '''Flag (-F) Entry type Description
4718 fdt fdtmap Extract the devicetree blob from the fdtmap
4722 dtb = os.path.join(tmpdir, 'fdt.dtb')
4723 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4726 # Check that we can read it and it can be scanning, meaning it does
4727 # not have a 16-byte fdtmap header
4728 data = tools.ReadFile(dtb)
4729 dtb = fdt.Fdt.FromData(data)
4732 # Now check u-boot which has no alt_format
4733 fname = os.path.join(tmpdir, 'fdt.dtb')
4734 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4735 '-f', fname, 'u-boot')
4736 data = tools.ReadFile(fname)
4737 self.assertEqual(U_BOOT_DATA, data)
4740 shutil.rmtree(tmpdir)
4742 def testExtblobList(self):
4743 """Test an image with an external blob list"""
4744 data = self._DoReadFile('215_blob_ext_list.dts')
4745 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4747 def testExtblobListMissing(self):
4748 """Test an image with a missing external blob"""
4749 with self.assertRaises(ValueError) as e:
4750 self._DoReadFile('216_blob_ext_list_missing.dts')
4751 self.assertIn("Filename 'missing-file' not found in input path",
4754 def testExtblobListMissingOk(self):
4755 """Test an image with an missing external blob that is allowed"""
4756 with test_util.capture_sys_output() as (stdout, stderr):
4757 self._DoTestFile('216_blob_ext_list_missing.dts',
4759 err = stderr.getvalue()
4760 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4763 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4764 data = self._DoReadFile('203_fip.dts')
4765 hdr, fents = fip_util.decode_fip(data)
4766 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4767 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4768 self.assertEqual(0x123, hdr.flags)
4770 self.assertEqual(2, len(fents))
4774 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4775 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4776 self.assertEqual('soc-fw', fent.fip_type)
4777 self.assertEqual(0x88, fent.offset)
4778 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4779 self.assertEqual(0x123456789abcdef, fent.flags)
4780 self.assertEqual(ATF_BL31_DATA, fent.data)
4781 self.assertEqual(True, fent.valid)
4785 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4786 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4787 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4788 self.assertEqual(0x8c, fent.offset)
4789 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4790 self.assertEqual(0, fent.flags)
4791 self.assertEqual(ATF_BL2U_DATA, fent.data)
4792 self.assertEqual(True, fent.valid)
4794 def testFipOther(self):
4795 """Basic FIP with something that isn't a external blob"""
4796 data = self._DoReadFile('204_fip_other.dts')
4797 hdr, fents = fip_util.decode_fip(data)
4799 self.assertEqual(2, len(fents))
4801 self.assertEqual('rot-cert', fent.fip_type)
4802 self.assertEqual(b'aa', fent.data)
4804 def testFipOther(self):
4805 """Basic FIP with something that isn't a external blob"""
4806 data = self._DoReadFile('204_fip_other.dts')
4807 hdr, fents = fip_util.decode_fip(data)
4809 self.assertEqual(2, len(fents))
4811 self.assertEqual('rot-cert', fent.fip_type)
4812 self.assertEqual(b'aa', fent.data)
4814 def testFipNoType(self):
4815 """FIP with an entry of an unknown type"""
4816 with self.assertRaises(ValueError) as e:
4817 self._DoReadFile('205_fip_no_type.dts')
4818 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4821 def testFipUuid(self):
4822 """Basic FIP with a manual uuid"""
4823 data = self._DoReadFile('206_fip_uuid.dts')
4824 hdr, fents = fip_util.decode_fip(data)
4826 self.assertEqual(2, len(fents))
4828 self.assertEqual(None, fent.fip_type)
4830 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4831 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4833 self.assertEqual(U_BOOT_DATA, fent.data)
4835 def testFipLs(self):
4836 """Test listing a FIP"""
4837 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4838 hdr, fents = fip_util.decode_fip(data)
4841 tmpdir, updated_fname = self._SetupImageInTmpdir()
4842 with test_util.capture_sys_output() as (stdout, stderr):
4843 self._DoBinman('ls', '-i', updated_fname)
4845 shutil.rmtree(tmpdir)
4846 lines = stdout.getvalue().splitlines()
4848 'Name Image-pos Size Entry-type Offset Uncomp-size',
4849 '----------------------------------------------------------------',
4850 'main-section 0 2d3 section 0',
4851 ' atf-fip 0 90 atf-fip 0',
4852 ' soc-fw 88 4 blob-ext 88',
4853 ' u-boot 8c 4 u-boot 8c',
4854 ' fdtmap 90 243 fdtmap 90',
4856 self.assertEqual(expected, lines)
4858 image = control.images['image']
4859 entries = image.GetEntries()
4860 fdtmap = entries['fdtmap']
4862 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4863 magic = fdtmap_data[:8]
4864 self.assertEqual(b'_FDTMAP_', magic)
4865 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
4867 fdt_data = fdtmap_data[16:]
4868 dtb = fdt.Fdt.FromData(fdt_data)
4870 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4872 'atf-fip/soc-fw:image-pos': 136,
4873 'atf-fip/soc-fw:offset': 136,
4874 'atf-fip/soc-fw:size': 4,
4875 'atf-fip/u-boot:image-pos': 140,
4876 'atf-fip/u-boot:offset': 140,
4877 'atf-fip/u-boot:size': 4,
4878 'atf-fip:image-pos': 0,
4879 'atf-fip:offset': 0,
4880 'atf-fip:size': 144,
4883 'fdtmap:image-pos': fdtmap.image_pos,
4884 'fdtmap:offset': fdtmap.offset,
4885 'fdtmap:size': len(fdtmap_data),
4889 def testFipExtractOneEntry(self):
4890 """Test extracting a single entry fron an FIP"""
4891 self._DoReadFileRealDtb('207_fip_ls.dts')
4892 image_fname = tools.GetOutputFilename('image.bin')
4893 fname = os.path.join(self._indir, 'output.extact')
4894 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4895 data = tools.ReadFile(fname)
4896 self.assertEqual(U_BOOT_DATA, data)
4898 def testFipReplace(self):
4899 """Test replacing a single file in a FIP"""
4900 expected = U_BOOT_DATA + tools.GetBytes(0x78, 50)
4901 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4902 updated_fname = tools.GetOutputFilename('image-updated.bin')
4903 tools.WriteFile(updated_fname, data)
4904 entry_name = 'atf-fip/u-boot'
4905 control.WriteEntry(updated_fname, entry_name, expected,
4907 actual = control.ReadEntry(updated_fname, entry_name)
4908 self.assertEqual(expected, actual)
4910 new_data = tools.ReadFile(updated_fname)
4911 hdr, fents = fip_util.decode_fip(new_data)
4913 self.assertEqual(2, len(fents))
4915 # Check that the FIP entry is updated
4917 self.assertEqual(0x8c, fent.offset)
4918 self.assertEqual(len(expected), fent.size)
4919 self.assertEqual(0, fent.flags)
4920 self.assertEqual(expected, fent.data)
4921 self.assertEqual(True, fent.valid)
4923 def testFipMissing(self):
4924 with test_util.capture_sys_output() as (stdout, stderr):
4925 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4926 err = stderr.getvalue()
4927 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4929 def testFipSize(self):
4930 """Test a FIP with a size property"""
4931 data = self._DoReadFile('210_fip_size.dts')
4932 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4933 hdr, fents = fip_util.decode_fip(data)
4934 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4935 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4937 self.assertEqual(1, len(fents))
4940 self.assertEqual('soc-fw', fent.fip_type)
4941 self.assertEqual(0x60, fent.offset)
4942 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4943 self.assertEqual(ATF_BL31_DATA, fent.data)
4944 self.assertEqual(True, fent.valid)
4946 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
4947 self.assertEqual(tools.GetBytes(0xff, len(rest)), rest)
4949 def testFipBadAlign(self):
4950 """Test that an invalid alignment value in a FIP is detected"""
4951 with self.assertRaises(ValueError) as e:
4952 self._DoTestFile('211_fip_bad_align.dts')
4954 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
4957 def testFipCollection(self):
4958 """Test using a FIP in a collection"""
4959 data = self._DoReadFile('212_fip_collection.dts')
4960 entry1 = control.images['image'].GetEntries()['collection']
4961 data1 = data[:entry1.size]
4962 hdr1, fents2 = fip_util.decode_fip(data1)
4964 entry2 = control.images['image'].GetEntries()['atf-fip']
4965 data2 = data[entry2.offset:entry2.offset + entry2.size]
4966 hdr1, fents2 = fip_util.decode_fip(data2)
4968 # The 'collection' entry should have U-Boot included at the end
4969 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
4970 self.assertEqual(data1, data2 + U_BOOT_DATA)
4971 self.assertEqual(U_BOOT_DATA, data1[-4:])
4973 # There should be a U-Boot after the final FIP
4974 self.assertEqual(U_BOOT_DATA, data[-4:])
4976 def testFakeBlob(self):
4977 """Test handling of faking an external blob"""
4978 with test_util.capture_sys_output() as (stdout, stderr):
4979 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
4980 allow_fake_blobs=True)
4981 err = stderr.getvalue()
4984 "Image '.*' has faked external blobs and is non-functional: .*")
4986 def testExtblobListFaked(self):
4987 """Test an extblob with missing external blob that are faked"""
4988 with test_util.capture_sys_output() as (stdout, stderr):
4989 self._DoTestFile('216_blob_ext_list_missing.dts',
4990 allow_fake_blobs=True)
4991 err = stderr.getvalue()
4992 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
4995 if __name__ == "__main__":