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 cbfs_util
22 from binman import cmdline
23 from binman import control
24 from binman import elf
25 from binman import elf_test
26 from binman import fmap_util
27 from binman import state
29 from dtoc import fdt_util
30 from binman.etype import fdtmap
31 from binman.etype import image_header
32 from binman.image import Image
33 from patman import command
34 from patman import test_util
35 from patman import tools
36 from patman import tout
38 # Contents of test files, corresponding to different entry types
40 U_BOOT_IMG_DATA = b'img'
41 U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
46 U_BOOT_DTB_DATA = b'udtb'
47 U_BOOT_SPL_DTB_DATA = b'spldtb'
48 U_BOOT_TPL_DTB_DATA = b'tpldtb'
49 X86_START16_DATA = b'start16'
50 X86_START16_SPL_DATA = b'start16spl'
51 X86_START16_TPL_DATA = b'start16tpl'
52 X86_RESET16_DATA = b'reset16'
53 X86_RESET16_SPL_DATA = b'reset16spl'
54 X86_RESET16_TPL_DATA = b'reset16tpl'
55 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
66 CROS_EC_RW_DATA = b'ecrw'
70 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
72 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
73 COMPRESS_DATA_BIG = COMPRESS_DATA * 2
74 REFCODE_DATA = b'refcode'
78 ATF_BL31_DATA = b'bl31'
79 OPENSBI_DATA = b'opensbi'
81 TEST_FDT1_DATA = b'fdt1'
82 TEST_FDT2_DATA = b'test-fdt2'
83 ENV_DATA = b'var1=1\nvar2="2"'
85 # Subdirectory of the input dir to use to put test FDTs
86 TEST_FDT_SUBDIR = 'fdts'
88 # The expected size for the device tree in some tests
89 EXTRACT_DTB_SIZE = 0x3c9
91 # Properties expected to be in the device tree when update_dtb is used
92 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
94 # Extra properties expected to be in the device tree when allow-repack is used
95 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
98 class TestFunctional(unittest.TestCase):
99 """Functional tests for binman
101 Most of these use a sample .dts file to build an image and then check
102 that it looks correct. The sample files are in the test/ subdirectory
105 For each entry type a very small test file is created using fixed
106 string contents. This makes it easy to test that things look right, and
109 In some cases a 'real' file must be used - these are also supplied in
110 the test/ diurectory.
115 from binman import entry
117 # Handle the case where argv[0] is 'python'
118 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
119 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
121 # Create a temporary directory for input files
122 cls._indir = tempfile.mkdtemp(prefix='binmant.')
124 # Create some test files
125 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
126 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
127 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
128 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
129 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
130 TestFunctional._MakeInputFile('me.bin', ME_DATA)
131 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
134 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
136 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
138 X86_START16_SPL_DATA)
139 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
140 X86_START16_TPL_DATA)
142 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
144 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
145 X86_RESET16_SPL_DATA)
146 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
147 X86_RESET16_TPL_DATA)
149 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
150 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
151 U_BOOT_SPL_NODTB_DATA)
152 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
153 U_BOOT_TPL_NODTB_DATA)
154 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
155 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
156 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
157 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
158 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
159 TestFunctional._MakeInputDir('devkeys')
160 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
161 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
162 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
163 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
164 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
166 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
167 elf_test.BuildElfTestFiles(cls._elf_testdir)
169 # ELF file with a '_dt_ucode_base_size' symbol
170 TestFunctional._MakeInputFile('u-boot',
171 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
173 # Intel flash descriptor file
174 cls._SetupDescriptor()
176 shutil.copytree(cls.TestFile('files'),
177 os.path.join(cls._indir, 'files'))
179 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
180 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
181 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
182 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
183 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
185 # Add a few .dtb files for testing
186 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
188 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
191 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
193 # Travis-CI may have an old lz4
196 tools.Run('lz4', '--no-frame-crc', '-c',
197 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
202 def tearDownClass(cls):
203 """Remove the temporary input directory and its contents"""
204 if cls.preserve_indir:
205 print('Preserving input dir: %s' % cls._indir)
208 shutil.rmtree(cls._indir)
212 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
213 toolpath=None, verbosity=None):
214 """Accept arguments controlling test execution
217 preserve_indir: Preserve the shared input directory used by all
219 preserve_outdir: Preserve the output directories used by tests. Each
220 test has its own, so this is normally only useful when running a
222 toolpath: ist of paths to use for tools
224 cls.preserve_indir = preserve_indir
225 cls.preserve_outdirs = preserve_outdirs
226 cls.toolpath = toolpath
227 cls.verbosity = verbosity
230 if not self.have_lz4:
231 self.skipTest('lz4 --no-frame-crc not available')
233 def _CleanupOutputDir(self):
234 """Remove the temporary output directory"""
235 if self.preserve_outdirs:
236 print('Preserving output dir: %s' % tools.outdir)
238 tools._FinaliseForTest()
241 # Enable this to turn on debugging output
242 # tout.Init(tout.DEBUG)
243 command.test_result = None
246 """Remove the temporary output directory"""
247 self._CleanupOutputDir()
249 def _SetupImageInTmpdir(self):
250 """Set up the output image in a new temporary directory
252 This is used when an image has been generated in the output directory,
253 but we want to run binman again. This will create a new output
254 directory and fail to delete the original one.
256 This creates a new temporary directory, copies the image to it (with a
257 new name) and removes the old output directory.
261 Temporary directory to use
264 image_fname = tools.GetOutputFilename('image.bin')
265 tmpdir = tempfile.mkdtemp(prefix='binman.')
266 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
267 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
268 self._CleanupOutputDir()
269 return tmpdir, updated_fname
273 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
274 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
275 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
277 def _RunBinman(self, *args, **kwargs):
278 """Run binman using the command line
281 Arguments to pass, as a list of strings
282 kwargs: Arguments to pass to Command.RunPipe()
284 result = command.RunPipe([[self._binman_pathname] + list(args)],
285 capture=True, capture_stderr=True, raise_on_error=False)
286 if result.return_code and kwargs.get('raise_on_error', True):
287 raise Exception("Error running '%s': %s" % (' '.join(args),
288 result.stdout + result.stderr))
291 def _DoBinman(self, *argv):
292 """Run binman using directly (in the same process)
295 Arguments to pass, as a list of strings
297 Return value (0 for success)
300 args = cmdline.ParseArgs(argv)
301 args.pager = 'binman-invalid-pager'
302 args.build_dir = self._indir
304 # For testing, you can force an increase in verbosity here
305 # args.verbosity = tout.DEBUG
306 return control.Binman(args)
308 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
309 entry_args=None, images=None, use_real_dtb=False,
310 use_expanded=False, verbosity=None, allow_missing=False,
311 allow_fake_blobs=False, extra_indirs=None, threads=None,
312 test_section_timeout=False, update_fdt_in_elf=None):
313 """Run binman with a given test file
316 fname: Device-tree source filename to use (e.g. 005_simple.dts)
317 debug: True to enable debugging output
318 map: True to output map files for the images
319 update_dtb: Update the offset and size of each entry in the device
320 tree before packing it into the image
321 entry_args: Dict of entry args to supply to binman
323 value: value of that arg
324 images: List of image names to build
325 use_real_dtb: True to use the test file as the contents of
326 the u-boot-dtb entry. Normally this is not needed and the
327 test contents (the U_BOOT_DTB_DATA string) can be used.
328 But in some test we need the real contents.
329 use_expanded: True to use expanded entries where available, e.g.
330 'u-boot-expanded' instead of 'u-boot'
331 verbosity: Verbosity level to use (0-3, None=don't set it)
332 allow_missing: Set the '--allow-missing' flag so that missing
333 external binaries just produce a warning instead of an error
334 allow_fake_blobs: Set the '--fake-ext-blobs' flag
335 extra_indirs: Extra input directories to add using -I
336 threads: Number of threads to use (None for default, 0 for
338 test_section_timeout: True to force the first time to timeout, as
339 used in testThreadTimeout()
340 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
343 int return code, 0 on success
348 if verbosity is not None:
349 args.append('-v%d' % verbosity)
351 args.append('-v%d' % self.verbosity)
353 for path in self.toolpath:
354 args += ['--toolpath', path]
355 if threads is not None:
356 args.append('-T%d' % threads)
357 if test_section_timeout:
358 args.append('--test-section-timeout')
359 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
365 args.append('--fake-dtb')
367 args.append('--no-expanded')
369 for arg, value in entry_args.items():
370 args.append('-a%s=%s' % (arg, value))
374 args.append('--fake-ext-blobs')
375 if update_fdt_in_elf:
376 args += ['--update-fdt-in-elf', update_fdt_in_elf]
379 args += ['-i', image]
381 for indir in extra_indirs:
382 args += ['-I', indir]
383 return self._DoBinman(*args)
385 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
386 """Set up a new test device-tree file
388 The given file is compiled and set up as the device tree to be used
392 fname: Filename of .dts file to read
393 outfile: Output filename for compiled device-tree binary
396 Contents of device-tree binary
398 tmpdir = tempfile.mkdtemp(prefix='binmant.')
399 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
400 with open(dtb, 'rb') as fd:
402 TestFunctional._MakeInputFile(outfile, data)
403 shutil.rmtree(tmpdir)
406 def _GetDtbContentsForSplTpl(self, dtb_data, name):
407 """Create a version of the main DTB for SPL or SPL
409 For testing we don't actually have different versions of the DTB. With
410 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
411 we don't normally have any unwanted nodes.
413 We still want the DTBs for SPL and TPL to be different though, since
414 otherwise it is confusing to know which one we are looking at. So add
415 an 'spl' or 'tpl' property to the top-level node.
418 dtb_data: dtb data to modify (this should be a value devicetree)
419 name: Name of a new property to add
422 New dtb data with the property added
424 dtb = fdt.Fdt.FromData(dtb_data)
426 dtb.GetNode('/binman').AddZeroProp(name)
427 dtb.Sync(auto_resize=True)
429 return dtb.GetContents()
431 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
432 map=False, update_dtb=False, entry_args=None,
433 reset_dtbs=True, extra_indirs=None, threads=None):
434 """Run binman and return the resulting image
436 This runs binman with a given test file and then reads the resulting
437 output file. It is a shortcut function since most tests need to do
440 Raises an assertion failure if binman returns a non-zero exit code.
443 fname: Device-tree source filename to use (e.g. 005_simple.dts)
444 use_real_dtb: True to use the test file as the contents of
445 the u-boot-dtb entry. Normally this is not needed and the
446 test contents (the U_BOOT_DTB_DATA string) can be used.
447 But in some test we need the real contents.
448 use_expanded: True to use expanded entries where available, e.g.
449 'u-boot-expanded' instead of 'u-boot'
450 map: True to output map files for the images
451 update_dtb: Update the offset and size of each entry in the device
452 tree before packing it into the image
453 entry_args: Dict of entry args to supply to binman
455 value: value of that arg
456 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
457 function. If reset_dtbs is True, then the original test dtb
458 is written back before this function finishes
459 extra_indirs: Extra input directories to add using -I
460 threads: Number of threads to use (None for default, 0 for
465 Resulting image contents
467 Map data showing contents of image (or None if none)
468 Output device tree binary filename ('u-boot.dtb' path)
471 # Use the compiled test file as the u-boot-dtb input
473 dtb_data = self._SetupDtb(fname)
475 # For testing purposes, make a copy of the DT for SPL and TPL. Add
476 # a node indicating which it is, so aid verification.
477 for name in ['spl', 'tpl']:
478 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
479 outfile = os.path.join(self._indir, dtb_fname)
480 TestFunctional._MakeInputFile(dtb_fname,
481 self._GetDtbContentsForSplTpl(dtb_data, name))
484 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
485 entry_args=entry_args, use_real_dtb=use_real_dtb,
486 use_expanded=use_expanded, extra_indirs=extra_indirs,
488 self.assertEqual(0, retcode)
489 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
491 # Find the (only) image, read it and return its contents
492 image = control.images['image']
493 image_fname = tools.GetOutputFilename('image.bin')
494 self.assertTrue(os.path.exists(image_fname))
496 map_fname = tools.GetOutputFilename('image.map')
497 with open(map_fname) as fd:
501 with open(image_fname, 'rb') as fd:
502 return fd.read(), dtb_data, map_data, out_dtb_fname
504 # Put the test file back
505 if reset_dtbs and use_real_dtb:
508 def _DoReadFileRealDtb(self, fname):
509 """Run binman with a real .dtb file and return the resulting data
512 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
515 Resulting image contents
517 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
519 def _DoReadFile(self, fname, use_real_dtb=False):
520 """Helper function which discards the device-tree binary
523 fname: Device-tree source filename to use (e.g. 005_simple.dts)
524 use_real_dtb: True to use the test file as the contents of
525 the u-boot-dtb entry. Normally this is not needed and the
526 test contents (the U_BOOT_DTB_DATA string) can be used.
527 But in some test we need the real contents.
530 Resulting image contents
532 return self._DoReadFileDtb(fname, use_real_dtb)[0]
535 def _MakeInputFile(cls, fname, contents):
536 """Create a new test input file, creating directories as needed
539 fname: Filename to create
540 contents: File contents to write in to the file
542 Full pathname of file created
544 pathname = os.path.join(cls._indir, fname)
545 dirname = os.path.dirname(pathname)
546 if dirname and not os.path.exists(dirname):
548 with open(pathname, 'wb') as fd:
553 def _MakeInputDir(cls, dirname):
554 """Create a new test input directory, creating directories as needed
557 dirname: Directory name to create
560 Full pathname of directory created
562 pathname = os.path.join(cls._indir, dirname)
563 if not os.path.exists(pathname):
564 os.makedirs(pathname)
568 def _SetupSplElf(cls, src_fname='bss_data'):
569 """Set up an ELF file with a '_dt_ucode_base_size' symbol
572 Filename of ELF file to use as SPL
574 TestFunctional._MakeInputFile('spl/u-boot-spl',
575 tools.ReadFile(cls.ElfTestFile(src_fname)))
578 def _SetupTplElf(cls, src_fname='bss_data'):
579 """Set up an ELF file with a '_dt_ucode_base_size' symbol
582 Filename of ELF file to use as TPL
584 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
585 tools.ReadFile(cls.ElfTestFile(src_fname)))
588 def _SetupDescriptor(cls):
589 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
590 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
593 def TestFile(cls, fname):
594 return os.path.join(cls._binman_dir, 'test', fname)
597 def ElfTestFile(cls, fname):
598 return os.path.join(cls._elf_testdir, fname)
600 def AssertInList(self, grep_list, target):
601 """Assert that at least one of a list of things is in a target
604 grep_list: List of strings to check
605 target: Target string
607 for grep in grep_list:
610 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
612 def CheckNoGaps(self, entries):
613 """Check that all entries fit together without gaps
616 entries: List of entries to check
619 for entry in entries.values():
620 self.assertEqual(offset, entry.offset)
623 def GetFdtLen(self, dtb):
624 """Get the totalsize field from a device-tree binary
627 dtb: Device-tree binary contents
630 Total size of device-tree binary, from the header
632 return struct.unpack('>L', dtb[4:8])[0]
634 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
635 def AddNode(node, path):
637 path += '/' + node.name
638 for prop in node.props.values():
639 if prop.name in prop_names:
640 prop_path = path + ':' + prop.name
641 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
643 for subnode in node.subnodes:
644 AddNode(subnode, path)
647 AddNode(dtb.GetRoot(), '')
651 """Test a basic run with valid args"""
652 result = self._RunBinman('-h')
654 def testFullHelp(self):
655 """Test that the full help is displayed with -H"""
656 result = self._RunBinman('-H')
657 help_file = os.path.join(self._binman_dir, 'README.rst')
658 # Remove possible extraneous strings
659 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
660 gothelp = result.stdout.replace(extra, '')
661 self.assertEqual(len(gothelp), os.path.getsize(help_file))
662 self.assertEqual(0, len(result.stderr))
663 self.assertEqual(0, result.return_code)
665 def testFullHelpInternal(self):
666 """Test that the full help is displayed with -H"""
668 command.test_result = command.CommandResult()
669 result = self._DoBinman('-H')
670 help_file = os.path.join(self._binman_dir, 'README.rst')
672 command.test_result = None
675 """Test that the basic help is displayed with -h"""
676 result = self._RunBinman('-h')
677 self.assertTrue(len(result.stdout) > 200)
678 self.assertEqual(0, len(result.stderr))
679 self.assertEqual(0, result.return_code)
682 """Test that we can run it with a specific board"""
683 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
684 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
685 result = self._DoBinman('build', '-n', '-b', 'sandbox')
686 self.assertEqual(0, result)
688 def testNeedBoard(self):
689 """Test that we get an error when no board ius supplied"""
690 with self.assertRaises(ValueError) as e:
691 result = self._DoBinman('build')
692 self.assertIn("Must provide a board to process (use -b <board>)",
695 def testMissingDt(self):
696 """Test that an invalid device-tree file generates an error"""
697 with self.assertRaises(Exception) as e:
698 self._RunBinman('build', '-d', 'missing_file')
699 # We get one error from libfdt, and a different one from fdtget.
700 self.AssertInList(["Couldn't open blob from 'missing_file'",
701 'No such file or directory'], str(e.exception))
703 def testBrokenDt(self):
704 """Test that an invalid device-tree source file generates an error
706 Since this is a source file it should be compiled and the error
707 will come from the device-tree compiler (dtc).
709 with self.assertRaises(Exception) as e:
710 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
711 self.assertIn("FATAL ERROR: Unable to parse input tree",
714 def testMissingNode(self):
715 """Test that a device tree without a 'binman' node generates an error"""
716 with self.assertRaises(Exception) as e:
717 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
718 self.assertIn("does not have a 'binman' node", str(e.exception))
721 """Test that an empty binman node works OK (i.e. does nothing)"""
722 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
723 self.assertEqual(0, len(result.stderr))
724 self.assertEqual(0, result.return_code)
726 def testInvalidEntry(self):
727 """Test that an invalid entry is flagged"""
728 with self.assertRaises(Exception) as e:
729 result = self._RunBinman('build', '-d',
730 self.TestFile('004_invalid_entry.dts'))
731 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
732 "'/binman/not-a-valid-type'", str(e.exception))
734 def testSimple(self):
735 """Test a simple binman with a single file"""
736 data = self._DoReadFile('005_simple.dts')
737 self.assertEqual(U_BOOT_DATA, data)
739 def testSimpleDebug(self):
740 """Test a simple binman run with debugging enabled"""
741 self._DoTestFile('005_simple.dts', debug=True)
744 """Test that we can handle creating two images
746 This also tests image padding.
748 retcode = self._DoTestFile('006_dual_image.dts')
749 self.assertEqual(0, retcode)
751 image = control.images['image1']
752 self.assertEqual(len(U_BOOT_DATA), image.size)
753 fname = tools.GetOutputFilename('image1.bin')
754 self.assertTrue(os.path.exists(fname))
755 with open(fname, 'rb') as fd:
757 self.assertEqual(U_BOOT_DATA, data)
759 image = control.images['image2']
760 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
761 fname = tools.GetOutputFilename('image2.bin')
762 self.assertTrue(os.path.exists(fname))
763 with open(fname, 'rb') as fd:
765 self.assertEqual(U_BOOT_DATA, data[3:7])
766 self.assertEqual(tools.GetBytes(0, 3), data[:3])
767 self.assertEqual(tools.GetBytes(0, 5), data[7:])
769 def testBadAlign(self):
770 """Test that an invalid alignment value is detected"""
771 with self.assertRaises(ValueError) as e:
772 self._DoTestFile('007_bad_align.dts')
773 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
774 "of two", str(e.exception))
776 def testPackSimple(self):
777 """Test that packing works as expected"""
778 retcode = self._DoTestFile('008_pack.dts')
779 self.assertEqual(0, retcode)
780 self.assertIn('image', control.images)
781 image = control.images['image']
782 entries = image.GetEntries()
783 self.assertEqual(5, len(entries))
786 self.assertIn('u-boot', entries)
787 entry = entries['u-boot']
788 self.assertEqual(0, entry.offset)
789 self.assertEqual(len(U_BOOT_DATA), entry.size)
791 # Second u-boot, aligned to 16-byte boundary
792 self.assertIn('u-boot-align', entries)
793 entry = entries['u-boot-align']
794 self.assertEqual(16, entry.offset)
795 self.assertEqual(len(U_BOOT_DATA), entry.size)
797 # Third u-boot, size 23 bytes
798 self.assertIn('u-boot-size', entries)
799 entry = entries['u-boot-size']
800 self.assertEqual(20, entry.offset)
801 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
802 self.assertEqual(23, entry.size)
804 # Fourth u-boot, placed immediate after the above
805 self.assertIn('u-boot-next', entries)
806 entry = entries['u-boot-next']
807 self.assertEqual(43, entry.offset)
808 self.assertEqual(len(U_BOOT_DATA), entry.size)
810 # Fifth u-boot, placed at a fixed offset
811 self.assertIn('u-boot-fixed', entries)
812 entry = entries['u-boot-fixed']
813 self.assertEqual(61, entry.offset)
814 self.assertEqual(len(U_BOOT_DATA), entry.size)
816 self.assertEqual(65, image.size)
818 def testPackExtra(self):
819 """Test that extra packing feature works as expected"""
820 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
823 self.assertIn('image', control.images)
824 image = control.images['image']
825 entries = image.GetEntries()
826 self.assertEqual(5, len(entries))
828 # First u-boot with padding before and after
829 self.assertIn('u-boot', entries)
830 entry = entries['u-boot']
831 self.assertEqual(0, entry.offset)
832 self.assertEqual(3, entry.pad_before)
833 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
834 self.assertEqual(U_BOOT_DATA, entry.data)
835 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
836 tools.GetBytes(0, 5), data[:entry.size])
839 # Second u-boot has an aligned size, but it has no effect
840 self.assertIn('u-boot-align-size-nop', entries)
841 entry = entries['u-boot-align-size-nop']
842 self.assertEqual(pos, entry.offset)
843 self.assertEqual(len(U_BOOT_DATA), entry.size)
844 self.assertEqual(U_BOOT_DATA, entry.data)
845 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
848 # Third u-boot has an aligned size too
849 self.assertIn('u-boot-align-size', entries)
850 entry = entries['u-boot-align-size']
851 self.assertEqual(pos, entry.offset)
852 self.assertEqual(32, entry.size)
853 self.assertEqual(U_BOOT_DATA, entry.data)
854 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
855 data[pos:pos + entry.size])
858 # Fourth u-boot has an aligned end
859 self.assertIn('u-boot-align-end', entries)
860 entry = entries['u-boot-align-end']
861 self.assertEqual(48, entry.offset)
862 self.assertEqual(16, entry.size)
863 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
864 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
865 data[pos:pos + entry.size])
868 # Fifth u-boot immediately afterwards
869 self.assertIn('u-boot-align-both', entries)
870 entry = entries['u-boot-align-both']
871 self.assertEqual(64, entry.offset)
872 self.assertEqual(64, entry.size)
873 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
874 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
875 data[pos:pos + entry.size])
877 self.CheckNoGaps(entries)
878 self.assertEqual(128, image.size)
880 dtb = fdt.Fdt(out_dtb_fname)
882 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
888 'u-boot:image-pos': 0,
890 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
892 'u-boot-align-size-nop:image-pos': 12,
893 'u-boot-align-size-nop:offset': 12,
894 'u-boot-align-size-nop:size': 4,
896 'u-boot-align-size:image-pos': 16,
897 'u-boot-align-size:offset': 16,
898 'u-boot-align-size:size': 32,
900 'u-boot-align-end:image-pos': 48,
901 'u-boot-align-end:offset': 48,
902 'u-boot-align-end:size': 16,
904 'u-boot-align-both:image-pos': 64,
905 'u-boot-align-both:offset': 64,
906 'u-boot-align-both:size': 64,
908 self.assertEqual(expected, props)
910 def testPackAlignPowerOf2(self):
911 """Test that invalid entry alignment is detected"""
912 with self.assertRaises(ValueError) as e:
913 self._DoTestFile('010_pack_align_power2.dts')
914 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
915 "of two", str(e.exception))
917 def testPackAlignSizePowerOf2(self):
918 """Test that invalid entry size alignment is detected"""
919 with self.assertRaises(ValueError) as e:
920 self._DoTestFile('011_pack_align_size_power2.dts')
921 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
922 "power of two", str(e.exception))
924 def testPackInvalidAlign(self):
925 """Test detection of an offset that does not match its alignment"""
926 with self.assertRaises(ValueError) as e:
927 self._DoTestFile('012_pack_inv_align.dts')
928 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
929 "align 0x4 (4)", str(e.exception))
931 def testPackInvalidSizeAlign(self):
932 """Test that invalid entry size alignment is detected"""
933 with self.assertRaises(ValueError) as e:
934 self._DoTestFile('013_pack_inv_size_align.dts')
935 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
936 "align-size 0x4 (4)", str(e.exception))
938 def testPackOverlap(self):
939 """Test that overlapping regions are detected"""
940 with self.assertRaises(ValueError) as e:
941 self._DoTestFile('014_pack_overlap.dts')
942 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
943 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
946 def testPackEntryOverflow(self):
947 """Test that entries that overflow their size are detected"""
948 with self.assertRaises(ValueError) as e:
949 self._DoTestFile('015_pack_overflow.dts')
950 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
951 "but entry size is 0x3 (3)", str(e.exception))
953 def testPackImageOverflow(self):
954 """Test that entries which overflow the image size are detected"""
955 with self.assertRaises(ValueError) as e:
956 self._DoTestFile('016_pack_image_overflow.dts')
957 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
958 "size 0x3 (3)", str(e.exception))
960 def testPackImageSize(self):
961 """Test that the image size can be set"""
962 retcode = self._DoTestFile('017_pack_image_size.dts')
963 self.assertEqual(0, retcode)
964 self.assertIn('image', control.images)
965 image = control.images['image']
966 self.assertEqual(7, image.size)
968 def testPackImageSizeAlign(self):
969 """Test that image size alignemnt works as expected"""
970 retcode = self._DoTestFile('018_pack_image_align.dts')
971 self.assertEqual(0, retcode)
972 self.assertIn('image', control.images)
973 image = control.images['image']
974 self.assertEqual(16, image.size)
976 def testPackInvalidImageAlign(self):
977 """Test that invalid image alignment is detected"""
978 with self.assertRaises(ValueError) as e:
979 self._DoTestFile('019_pack_inv_image_align.dts')
980 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
981 "align-size 0x8 (8)", str(e.exception))
983 def testPackAlignPowerOf2(self):
984 """Test that invalid image alignment is detected"""
985 with self.assertRaises(ValueError) as e:
986 self._DoTestFile('020_pack_inv_image_align_power2.dts')
987 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
988 "two", str(e.exception))
990 def testImagePadByte(self):
991 """Test that the image pad byte can be specified"""
993 data = self._DoReadFile('021_image_pad.dts')
994 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
997 def testImageName(self):
998 """Test that image files can be named"""
999 retcode = self._DoTestFile('022_image_name.dts')
1000 self.assertEqual(0, retcode)
1001 image = control.images['image1']
1002 fname = tools.GetOutputFilename('test-name')
1003 self.assertTrue(os.path.exists(fname))
1005 image = control.images['image2']
1006 fname = tools.GetOutputFilename('test-name.xx')
1007 self.assertTrue(os.path.exists(fname))
1009 def testBlobFilename(self):
1010 """Test that generic blobs can be provided by filename"""
1011 data = self._DoReadFile('023_blob.dts')
1012 self.assertEqual(BLOB_DATA, data)
1014 def testPackSorted(self):
1015 """Test that entries can be sorted"""
1017 data = self._DoReadFile('024_sorted.dts')
1018 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1019 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
1021 def testPackZeroOffset(self):
1022 """Test that an entry at offset 0 is not given a new offset"""
1023 with self.assertRaises(ValueError) as e:
1024 self._DoTestFile('025_pack_zero_size.dts')
1025 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1026 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1029 def testPackUbootDtb(self):
1030 """Test that a device tree can be added to U-Boot"""
1031 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1032 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1034 def testPackX86RomNoSize(self):
1035 """Test that the end-at-4gb property requires a size property"""
1036 with self.assertRaises(ValueError) as e:
1037 self._DoTestFile('027_pack_4gb_no_size.dts')
1038 self.assertIn("Image '/binman': Section size must be provided when "
1039 "using end-at-4gb", str(e.exception))
1041 def test4gbAndSkipAtStartTogether(self):
1042 """Test that the end-at-4gb and skip-at-size property can't be used
1044 with self.assertRaises(ValueError) as e:
1045 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1046 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1047 "'skip-at-start'", str(e.exception))
1049 def testPackX86RomOutside(self):
1050 """Test that the end-at-4gb property checks for offset boundaries"""
1051 with self.assertRaises(ValueError) as e:
1052 self._DoTestFile('028_pack_4gb_outside.dts')
1053 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1054 "is outside the section '/binman' starting at "
1055 '0xffffffe0 (4294967264) of size 0x20 (32)',
1058 def testPackX86Rom(self):
1059 """Test that a basic x86 ROM can be created"""
1061 data = self._DoReadFile('029_x86_rom.dts')
1062 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
1063 tools.GetBytes(0, 2), data)
1065 def testPackX86RomMeNoDesc(self):
1066 """Test that an invalid Intel descriptor entry is detected"""
1068 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1069 with self.assertRaises(ValueError) as e:
1070 self._DoTestFile('163_x86_rom_me_empty.dts')
1071 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1074 self._SetupDescriptor()
1076 def testPackX86RomBadDesc(self):
1077 """Test that the Intel requires a descriptor entry"""
1078 with self.assertRaises(ValueError) as e:
1079 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1080 self.assertIn("Node '/binman/intel-me': No offset set with "
1081 "offset-unset: should another entry provide this correct "
1082 "offset?", str(e.exception))
1084 def testPackX86RomMe(self):
1085 """Test that an x86 ROM with an ME region can be created"""
1086 data = self._DoReadFile('031_x86_rom_me.dts')
1087 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1088 if data[:0x1000] != expected_desc:
1089 self.fail('Expected descriptor binary at start of image')
1090 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1092 def testPackVga(self):
1093 """Test that an image with a VGA binary can be created"""
1094 data = self._DoReadFile('032_intel_vga.dts')
1095 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1097 def testPackStart16(self):
1098 """Test that an image with an x86 start16 region can be created"""
1099 data = self._DoReadFile('033_x86_start16.dts')
1100 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1102 def testPackPowerpcMpc85xxBootpgResetvec(self):
1103 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1105 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1106 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1108 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1109 """Handle running a test for insertion of microcode
1112 dts_fname: Name of test .dts file
1113 nodtb_data: Data that we expect in the first section
1114 ucode_second: True if the microsecond entry is second instead of
1119 Contents of first region (U-Boot or SPL)
1120 Offset and size components of microcode pointer, as inserted
1121 in the above (two 4-byte words)
1123 data = self._DoReadFile(dts_fname, True)
1125 # Now check the device tree has no microcode
1127 ucode_content = data[len(nodtb_data):]
1128 ucode_pos = len(nodtb_data)
1129 dtb_with_ucode = ucode_content[16:]
1130 fdt_len = self.GetFdtLen(dtb_with_ucode)
1132 dtb_with_ucode = data[len(nodtb_data):]
1133 fdt_len = self.GetFdtLen(dtb_with_ucode)
1134 ucode_content = dtb_with_ucode[fdt_len:]
1135 ucode_pos = len(nodtb_data) + fdt_len
1136 fname = tools.GetOutputFilename('test.dtb')
1137 with open(fname, 'wb') as fd:
1138 fd.write(dtb_with_ucode)
1139 dtb = fdt.FdtScan(fname)
1140 ucode = dtb.GetNode('/microcode')
1141 self.assertTrue(ucode)
1142 for node in ucode.subnodes:
1143 self.assertFalse(node.props.get('data'))
1145 # Check that the microcode appears immediately after the Fdt
1146 # This matches the concatenation of the data properties in
1147 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1148 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1150 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1152 # Check that the microcode pointer was inserted. It should match the
1153 # expected offset and size
1154 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1156 u_boot = data[:len(nodtb_data)]
1157 return u_boot, pos_and_size
1159 def testPackUbootMicrocode(self):
1160 """Test that x86 microcode can be handled correctly
1162 We expect to see the following in the image, in order:
1163 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1165 u-boot.dtb with the microcode removed
1168 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1170 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1171 b' somewhere in here', first)
1173 def _RunPackUbootSingleMicrocode(self):
1174 """Test that x86 microcode can be handled correctly
1176 We expect to see the following in the image, in order:
1177 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1179 u-boot.dtb with the microcode
1180 an empty microcode region
1182 # We need the libfdt library to run this test since only that allows
1183 # finding the offset of a property. This is required by
1184 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1185 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1187 second = data[len(U_BOOT_NODTB_DATA):]
1189 fdt_len = self.GetFdtLen(second)
1190 third = second[fdt_len:]
1191 second = second[:fdt_len]
1193 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1194 self.assertIn(ucode_data, second)
1195 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1197 # Check that the microcode pointer was inserted. It should match the
1198 # expected offset and size
1199 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1201 first = data[:len(U_BOOT_NODTB_DATA)]
1202 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1203 b' somewhere in here', first)
1205 def testPackUbootSingleMicrocode(self):
1206 """Test that x86 microcode can be handled correctly with fdt_normal.
1208 self._RunPackUbootSingleMicrocode()
1210 def testUBootImg(self):
1211 """Test that u-boot.img can be put in a file"""
1212 data = self._DoReadFile('036_u_boot_img.dts')
1213 self.assertEqual(U_BOOT_IMG_DATA, data)
1215 def testNoMicrocode(self):
1216 """Test that a missing microcode region is detected"""
1217 with self.assertRaises(ValueError) as e:
1218 self._DoReadFile('037_x86_no_ucode.dts', True)
1219 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1220 "node found in ", str(e.exception))
1222 def testMicrocodeWithoutNode(self):
1223 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1224 with self.assertRaises(ValueError) as e:
1225 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1226 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1227 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1229 def testMicrocodeWithoutNode2(self):
1230 """Test that a missing u-boot-ucode node is detected"""
1231 with self.assertRaises(ValueError) as e:
1232 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1233 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1234 "microcode region u-boot-ucode", str(e.exception))
1236 def testMicrocodeWithoutPtrInElf(self):
1237 """Test that a U-Boot binary without the microcode symbol is detected"""
1238 # ELF file without a '_dt_ucode_base_size' symbol
1240 TestFunctional._MakeInputFile('u-boot',
1241 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1243 with self.assertRaises(ValueError) as e:
1244 self._RunPackUbootSingleMicrocode()
1245 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1246 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1249 # Put the original file back
1250 TestFunctional._MakeInputFile('u-boot',
1251 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1253 def testMicrocodeNotInImage(self):
1254 """Test that microcode must be placed within the image"""
1255 with self.assertRaises(ValueError) as e:
1256 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1257 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1258 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1259 "section ranging from 00000000 to 0000002e", str(e.exception))
1261 def testWithoutMicrocode(self):
1262 """Test that we can cope with an image without microcode (e.g. qemu)"""
1263 TestFunctional._MakeInputFile('u-boot',
1264 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1265 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1267 # Now check the device tree has no microcode
1268 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1269 second = data[len(U_BOOT_NODTB_DATA):]
1271 fdt_len = self.GetFdtLen(second)
1272 self.assertEqual(dtb, second[:fdt_len])
1274 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1275 third = data[used_len:]
1276 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1278 def testUnknownPosSize(self):
1279 """Test that microcode must be placed within the image"""
1280 with self.assertRaises(ValueError) as e:
1281 self._DoReadFile('041_unknown_pos_size.dts', True)
1282 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1283 "entry 'invalid-entry'", str(e.exception))
1285 def testPackFsp(self):
1286 """Test that an image with a FSP binary can be created"""
1287 data = self._DoReadFile('042_intel_fsp.dts')
1288 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1290 def testPackCmc(self):
1291 """Test that an image with a CMC binary can be created"""
1292 data = self._DoReadFile('043_intel_cmc.dts')
1293 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1295 def testPackVbt(self):
1296 """Test that an image with a VBT binary can be created"""
1297 data = self._DoReadFile('046_intel_vbt.dts')
1298 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1300 def testSplBssPad(self):
1301 """Test that we can pad SPL's BSS with zeros"""
1302 # ELF file with a '__bss_size' symbol
1304 data = self._DoReadFile('047_spl_bss_pad.dts')
1305 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1308 def testSplBssPadMissing(self):
1309 """Test that a missing symbol is detected"""
1310 self._SetupSplElf('u_boot_ucode_ptr')
1311 with self.assertRaises(ValueError) as e:
1312 self._DoReadFile('047_spl_bss_pad.dts')
1313 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1316 def testPackStart16Spl(self):
1317 """Test that an image with an x86 start16 SPL region can be created"""
1318 data = self._DoReadFile('048_x86_start16_spl.dts')
1319 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1321 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1322 """Helper function for microcode tests
1324 We expect to see the following in the image, in order:
1325 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1327 u-boot.dtb with the microcode removed
1331 dts: Device tree file to use for test
1332 ucode_second: True if the microsecond entry is second instead of
1335 self._SetupSplElf('u_boot_ucode_ptr')
1336 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1337 ucode_second=ucode_second)
1338 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1339 b'ter somewhere in here', first)
1341 def testPackUbootSplMicrocode(self):
1342 """Test that x86 microcode can be handled correctly in SPL"""
1343 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1345 def testPackUbootSplMicrocodeReorder(self):
1346 """Test that order doesn't matter for microcode entries
1348 This is the same as testPackUbootSplMicrocode but when we process the
1349 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1350 entry, so we reply on binman to try later.
1352 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1355 def testPackMrc(self):
1356 """Test that an image with an MRC binary can be created"""
1357 data = self._DoReadFile('050_intel_mrc.dts')
1358 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1360 def testSplDtb(self):
1361 """Test that an image with spl/u-boot-spl.dtb can be created"""
1362 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1363 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1365 def testSplNoDtb(self):
1366 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1368 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1369 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1371 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1372 use_expanded=False):
1373 """Check the image contains the expected symbol values
1376 dts: Device tree file to use for test
1377 base_data: Data before and after 'u-boot' section
1378 u_boot_offset: Offset of 'u-boot' section in image
1379 entry_args: Dict of entry args to supply to binman
1381 value: value of that arg
1382 use_expanded: True to use expanded entries where available, e.g.
1383 'u-boot-expanded' instead of 'u-boot'
1385 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1386 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1387 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1388 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1391 self._SetupSplElf('u_boot_binman_syms')
1392 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1393 use_expanded=use_expanded)[0]
1394 # The image should contain the symbols from u_boot_binman_syms.c
1395 # Note that image_pos is adjusted by the base address of the image,
1396 # which is 0x10 in our test image
1397 sym_values = struct.pack('<LQLL', 0x00,
1398 u_boot_offset + len(U_BOOT_DATA),
1399 0x10 + u_boot_offset, 0x04)
1400 expected = (sym_values + base_data[20:] +
1401 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1403 self.assertEqual(expected, data)
1405 def testSymbols(self):
1406 """Test binman can assign symbols embedded in U-Boot"""
1407 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1409 def testSymbolsNoDtb(self):
1410 """Test binman can assign symbols embedded in U-Boot SPL"""
1411 self.checkSymbols('196_symbols_nodtb.dts',
1412 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1415 def testPackUnitAddress(self):
1416 """Test that we support multiple binaries with the same name"""
1417 data = self._DoReadFile('054_unit_address.dts')
1418 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1420 def testSections(self):
1421 """Basic test of sections"""
1422 data = self._DoReadFile('055_sections.dts')
1423 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1424 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1425 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1426 self.assertEqual(expected, data)
1429 """Tests outputting a map of the images"""
1430 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1431 self.assertEqual('''ImagePos Offset Size Name
1432 00000000 00000000 00000028 main-section
1433 00000000 00000000 00000010 section@0
1434 00000000 00000000 00000004 u-boot
1435 00000010 00000010 00000010 section@1
1436 00000010 00000000 00000004 u-boot
1437 00000020 00000020 00000004 section@2
1438 00000020 00000000 00000004 u-boot
1441 def testNamePrefix(self):
1442 """Tests that name prefixes are used"""
1443 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1444 self.assertEqual('''ImagePos Offset Size Name
1445 00000000 00000000 00000028 main-section
1446 00000000 00000000 00000010 section@0
1447 00000000 00000000 00000004 ro-u-boot
1448 00000010 00000010 00000010 section@1
1449 00000010 00000000 00000004 rw-u-boot
1452 def testUnknownContents(self):
1453 """Test that obtaining the contents works as expected"""
1454 with self.assertRaises(ValueError) as e:
1455 self._DoReadFile('057_unknown_contents.dts', True)
1456 self.assertIn("Image '/binman': Internal error: Could not complete "
1457 "processing of contents: remaining ["
1458 "<binman.etype._testing.Entry__testing ", str(e.exception))
1460 def testBadChangeSize(self):
1461 """Test that trying to change the size of an entry fails"""
1463 state.SetAllowEntryExpansion(False)
1464 with self.assertRaises(ValueError) as e:
1465 self._DoReadFile('059_change_size.dts', True)
1466 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1469 state.SetAllowEntryExpansion(True)
1471 def testUpdateFdt(self):
1472 """Test that we can update the device tree with offset/size info"""
1473 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1475 dtb = fdt.Fdt(out_dtb_fname)
1477 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1481 '_testing:offset': 32,
1483 '_testing:image-pos': 32,
1484 'section@0/u-boot:offset': 0,
1485 'section@0/u-boot:size': len(U_BOOT_DATA),
1486 'section@0/u-boot:image-pos': 0,
1487 'section@0:offset': 0,
1488 'section@0:size': 16,
1489 'section@0:image-pos': 0,
1491 'section@1/u-boot:offset': 0,
1492 'section@1/u-boot:size': len(U_BOOT_DATA),
1493 'section@1/u-boot:image-pos': 16,
1494 'section@1:offset': 16,
1495 'section@1:size': 16,
1496 'section@1:image-pos': 16,
1500 def testUpdateFdtBad(self):
1501 """Test that we detect when ProcessFdt never completes"""
1502 with self.assertRaises(ValueError) as e:
1503 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1504 self.assertIn('Could not complete processing of Fdt: remaining '
1505 '[<binman.etype._testing.Entry__testing',
1508 def testEntryArgs(self):
1509 """Test passing arguments to entries from the command line"""
1511 'test-str-arg': 'test1',
1512 'test-int-arg': '456',
1514 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1515 self.assertIn('image', control.images)
1516 entry = control.images['image'].GetEntries()['_testing']
1517 self.assertEqual('test0', entry.test_str_fdt)
1518 self.assertEqual('test1', entry.test_str_arg)
1519 self.assertEqual(123, entry.test_int_fdt)
1520 self.assertEqual(456, entry.test_int_arg)
1522 def testEntryArgsMissing(self):
1523 """Test missing arguments and properties"""
1525 'test-int-arg': '456',
1527 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1528 entry = control.images['image'].GetEntries()['_testing']
1529 self.assertEqual('test0', entry.test_str_fdt)
1530 self.assertEqual(None, entry.test_str_arg)
1531 self.assertEqual(None, entry.test_int_fdt)
1532 self.assertEqual(456, entry.test_int_arg)
1534 def testEntryArgsRequired(self):
1535 """Test missing arguments and properties"""
1537 'test-int-arg': '456',
1539 with self.assertRaises(ValueError) as e:
1540 self._DoReadFileDtb('064_entry_args_required.dts')
1541 self.assertIn("Node '/binman/_testing': "
1542 'Missing required properties/entry args: test-str-arg, '
1543 'test-int-fdt, test-int-arg',
1546 def testEntryArgsInvalidFormat(self):
1547 """Test that an invalid entry-argument format is detected"""
1548 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1550 with self.assertRaises(ValueError) as e:
1551 self._DoBinman(*args)
1552 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1554 def testEntryArgsInvalidInteger(self):
1555 """Test that an invalid entry-argument integer is detected"""
1557 'test-int-arg': 'abc',
1559 with self.assertRaises(ValueError) as e:
1560 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1561 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1562 "'test-int-arg' (value 'abc') to integer",
1565 def testEntryArgsInvalidDatatype(self):
1566 """Test that an invalid entry-argument datatype is detected
1568 This test could be written in entry_test.py except that it needs
1569 access to control.entry_args, which seems more than that module should
1573 'test-bad-datatype-arg': '12',
1575 with self.assertRaises(ValueError) as e:
1576 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1577 entry_args=entry_args)
1578 self.assertIn('GetArg() internal error: Unknown data type ',
1582 """Test for a text entry type"""
1584 'test-id': TEXT_DATA,
1585 'test-id2': TEXT_DATA2,
1586 'test-id3': TEXT_DATA3,
1588 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1589 entry_args=entry_args)
1590 expected = (tools.ToBytes(TEXT_DATA) +
1591 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1592 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1593 b'some text' + b'more text')
1594 self.assertEqual(expected, data)
1596 def testEntryDocs(self):
1597 """Test for creation of entry documentation"""
1598 with test_util.capture_sys_output() as (stdout, stderr):
1599 control.WriteEntryDocs(control.GetEntryModules())
1600 self.assertTrue(len(stdout.getvalue()) > 0)
1602 def testEntryDocsMissing(self):
1603 """Test handling of missing entry documentation"""
1604 with self.assertRaises(ValueError) as e:
1605 with test_util.capture_sys_output() as (stdout, stderr):
1606 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1607 self.assertIn('Documentation is missing for modules: u_boot',
1611 """Basic test of generation of a flashrom fmap"""
1612 data = self._DoReadFile('067_fmap.dts')
1613 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1614 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1615 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1616 self.assertEqual(expected, data[:32])
1617 self.assertEqual(b'__FMAP__', fhdr.signature)
1618 self.assertEqual(1, fhdr.ver_major)
1619 self.assertEqual(0, fhdr.ver_minor)
1620 self.assertEqual(0, fhdr.base)
1621 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1622 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1623 self.assertEqual(b'FMAP', fhdr.name)
1624 self.assertEqual(5, fhdr.nareas)
1625 fiter = iter(fentries)
1627 fentry = next(fiter)
1628 self.assertEqual(b'SECTION0', fentry.name)
1629 self.assertEqual(0, fentry.offset)
1630 self.assertEqual(16, fentry.size)
1631 self.assertEqual(0, fentry.flags)
1633 fentry = next(fiter)
1634 self.assertEqual(b'RO_U_BOOT', fentry.name)
1635 self.assertEqual(0, fentry.offset)
1636 self.assertEqual(4, fentry.size)
1637 self.assertEqual(0, fentry.flags)
1639 fentry = next(fiter)
1640 self.assertEqual(b'SECTION1', fentry.name)
1641 self.assertEqual(16, fentry.offset)
1642 self.assertEqual(16, fentry.size)
1643 self.assertEqual(0, fentry.flags)
1645 fentry = next(fiter)
1646 self.assertEqual(b'RW_U_BOOT', fentry.name)
1647 self.assertEqual(16, fentry.offset)
1648 self.assertEqual(4, fentry.size)
1649 self.assertEqual(0, fentry.flags)
1651 fentry = next(fiter)
1652 self.assertEqual(b'FMAP', fentry.name)
1653 self.assertEqual(32, fentry.offset)
1654 self.assertEqual(expect_size, fentry.size)
1655 self.assertEqual(0, fentry.flags)
1657 def testBlobNamedByArg(self):
1658 """Test we can add a blob with the filename coming from an entry arg"""
1660 'cros-ec-rw-path': 'ecrw.bin',
1662 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1665 """Test for an fill entry type"""
1666 data = self._DoReadFile('069_fill.dts')
1667 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1668 self.assertEqual(expected, data)
1670 def testFillNoSize(self):
1671 """Test for an fill entry type with no size"""
1672 with self.assertRaises(ValueError) as e:
1673 self._DoReadFile('070_fill_no_size.dts')
1674 self.assertIn("'fill' entry must have a size property",
1677 def _HandleGbbCommand(self, pipe_list):
1678 """Fake calls to the futility utility"""
1679 if pipe_list[0][0] == 'futility':
1680 fname = pipe_list[0][-1]
1681 # Append our GBB data to the file, which will happen every time the
1682 # futility command is called.
1683 with open(fname, 'ab') as fd:
1685 return command.CommandResult()
1688 """Test for the Chromium OS Google Binary Block"""
1689 command.test_result = self._HandleGbbCommand
1691 'keydir': 'devkeys',
1692 'bmpblk': 'bmpblk.bin',
1694 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1697 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1698 tools.GetBytes(0, 0x2180 - 16))
1699 self.assertEqual(expected, data)
1701 def testGbbTooSmall(self):
1702 """Test for the Chromium OS Google Binary Block being large enough"""
1703 with self.assertRaises(ValueError) as e:
1704 self._DoReadFileDtb('072_gbb_too_small.dts')
1705 self.assertIn("Node '/binman/gbb': GBB is too small",
1708 def testGbbNoSize(self):
1709 """Test for the Chromium OS Google Binary Block having a size"""
1710 with self.assertRaises(ValueError) as e:
1711 self._DoReadFileDtb('073_gbb_no_size.dts')
1712 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1715 def _HandleVblockCommand(self, pipe_list):
1716 """Fake calls to the futility utility
1718 The expected pipe is:
1720 [('futility', 'vbutil_firmware', '--vblock',
1721 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1722 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1723 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1724 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1726 This writes to the output file (here, 'vblock.vblock'). If
1727 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1728 of the input data (here, 'input.vblock').
1730 if pipe_list[0][0] == 'futility':
1731 fname = pipe_list[0][3]
1732 with open(fname, 'wb') as fd:
1734 infile = pipe_list[0][11]
1735 m = hashlib.sha256()
1736 data = tools.ReadFile(infile)
1738 fd.write(m.digest())
1740 fd.write(VBLOCK_DATA)
1742 return command.CommandResult()
1744 def testVblock(self):
1745 """Test for the Chromium OS Verified Boot Block"""
1746 self._hash_data = False
1747 command.test_result = self._HandleVblockCommand
1749 'keydir': 'devkeys',
1751 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1752 entry_args=entry_args)
1753 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1754 self.assertEqual(expected, data)
1756 def testVblockNoContent(self):
1757 """Test we detect a vblock which has no content to sign"""
1758 with self.assertRaises(ValueError) as e:
1759 self._DoReadFile('075_vblock_no_content.dts')
1760 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1761 'property', str(e.exception))
1763 def testVblockBadPhandle(self):
1764 """Test that we detect a vblock with an invalid phandle in contents"""
1765 with self.assertRaises(ValueError) as e:
1766 self._DoReadFile('076_vblock_bad_phandle.dts')
1767 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1768 '1000', str(e.exception))
1770 def testVblockBadEntry(self):
1771 """Test that we detect an entry that points to a non-entry"""
1772 with self.assertRaises(ValueError) as e:
1773 self._DoReadFile('077_vblock_bad_entry.dts')
1774 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1775 "'other'", str(e.exception))
1777 def testVblockContent(self):
1778 """Test that the vblock signs the right data"""
1779 self._hash_data = True
1780 command.test_result = self._HandleVblockCommand
1782 'keydir': 'devkeys',
1784 data = self._DoReadFileDtb(
1785 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1786 entry_args=entry_args)[0]
1787 hashlen = 32 # SHA256 hash is 32 bytes
1788 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1789 hashval = data[-hashlen:]
1790 dtb = data[len(U_BOOT_DATA):-hashlen]
1792 expected_data = U_BOOT_DATA + dtb
1794 # The hashval should be a hash of the dtb
1795 m = hashlib.sha256()
1796 m.update(expected_data)
1797 expected_hashval = m.digest()
1798 self.assertEqual(expected_hashval, hashval)
1801 """Test that an image with TPL and its device tree can be created"""
1802 # ELF file with a '__bss_size' symbol
1804 data = self._DoReadFile('078_u_boot_tpl.dts')
1805 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1807 def testUsesPos(self):
1808 """Test that the 'pos' property cannot be used anymore"""
1809 with self.assertRaises(ValueError) as e:
1810 data = self._DoReadFile('079_uses_pos.dts')
1811 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1812 "'pos'", str(e.exception))
1814 def testFillZero(self):
1815 """Test for an fill entry type with a size of 0"""
1816 data = self._DoReadFile('080_fill_empty.dts')
1817 self.assertEqual(tools.GetBytes(0, 16), data)
1819 def testTextMissing(self):
1820 """Test for a text entry type where there is no text"""
1821 with self.assertRaises(ValueError) as e:
1822 self._DoReadFileDtb('066_text.dts',)
1823 self.assertIn("Node '/binman/text': No value provided for text label "
1824 "'test-id'", str(e.exception))
1826 def testPackStart16Tpl(self):
1827 """Test that an image with an x86 start16 TPL region can be created"""
1828 data = self._DoReadFile('081_x86_start16_tpl.dts')
1829 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1831 def testSelectImage(self):
1832 """Test that we can select which images to build"""
1833 expected = 'Skipping images: image1'
1835 # We should only get the expected message in verbose mode
1836 for verbosity in (0, 2):
1837 with test_util.capture_sys_output() as (stdout, stderr):
1838 retcode = self._DoTestFile('006_dual_image.dts',
1839 verbosity=verbosity,
1841 self.assertEqual(0, retcode)
1843 self.assertIn(expected, stdout.getvalue())
1845 self.assertNotIn(expected, stdout.getvalue())
1847 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1848 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1849 self._CleanupOutputDir()
1851 def testUpdateFdtAll(self):
1852 """Test that all device trees are updated with offset/size info"""
1853 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1856 'section:image-pos': 0,
1857 'u-boot-tpl-dtb:size': 513,
1858 'u-boot-spl-dtb:size': 513,
1859 'u-boot-spl-dtb:offset': 493,
1861 'section/u-boot-dtb:image-pos': 0,
1862 'u-boot-spl-dtb:image-pos': 493,
1863 'section/u-boot-dtb:size': 493,
1864 'u-boot-tpl-dtb:image-pos': 1006,
1865 'section/u-boot-dtb:offset': 0,
1866 'section:size': 493,
1868 'section:offset': 0,
1869 'u-boot-tpl-dtb:offset': 1006,
1873 # We expect three device-tree files in the output, one after the other.
1874 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1875 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1876 # main U-Boot tree. All three should have the same postions and offset.
1878 for item in ['', 'spl', 'tpl']:
1879 dtb = fdt.Fdt.FromData(data[start:])
1881 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1883 expected = dict(base_expected)
1886 self.assertEqual(expected, props)
1887 start += dtb._fdt_obj.totalsize()
1889 def testUpdateFdtOutput(self):
1890 """Test that output DTB files are updated"""
1892 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1893 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1895 # Unfortunately, compiling a source file always results in a file
1896 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1897 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1898 # binman as a file called u-boot.dtb. To fix this, copy the file
1899 # over to the expected place.
1901 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1902 'tpl/u-boot-tpl.dtb.out']:
1903 dtb = fdt.Fdt.FromData(data[start:])
1904 size = dtb._fdt_obj.totalsize()
1905 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1906 outdata = tools.ReadFile(pathname)
1907 name = os.path.split(fname)[0]
1910 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1912 orig_indata = dtb_data
1913 self.assertNotEqual(outdata, orig_indata,
1914 "Expected output file '%s' be updated" % pathname)
1915 self.assertEqual(outdata, data[start:start + size],
1916 "Expected output file '%s' to match output image" %
1922 def _decompress(self, data):
1923 return tools.Decompress(data, 'lz4')
1925 def testCompress(self):
1926 """Test compression of blobs"""
1928 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1929 use_real_dtb=True, update_dtb=True)
1930 dtb = fdt.Fdt(out_dtb_fname)
1932 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1933 orig = self._decompress(data)
1934 self.assertEquals(COMPRESS_DATA, orig)
1936 # Do a sanity check on various fields
1937 image = control.images['image']
1938 entries = image.GetEntries()
1939 self.assertEqual(1, len(entries))
1941 entry = entries['blob']
1942 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1943 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1944 orig = self._decompress(entry.data)
1945 self.assertEqual(orig, entry.uncomp_data)
1947 self.assertEqual(image.data, entry.data)
1950 'blob:uncomp-size': len(COMPRESS_DATA),
1951 'blob:size': len(data),
1954 self.assertEqual(expected, props)
1956 def testFiles(self):
1957 """Test bringing in multiple files"""
1958 data = self._DoReadFile('084_files.dts')
1959 self.assertEqual(FILES_DATA, data)
1961 def testFilesCompress(self):
1962 """Test bringing in multiple files and compressing them"""
1964 data = self._DoReadFile('085_files_compress.dts')
1966 image = control.images['image']
1967 entries = image.GetEntries()
1968 files = entries['files']
1969 entries = files._entries
1972 for i in range(1, 3):
1974 start = entries[key].image_pos
1975 len = entries[key].size
1976 chunk = data[start:start + len]
1977 orig += self._decompress(chunk)
1979 self.assertEqual(FILES_DATA, orig)
1981 def testFilesMissing(self):
1982 """Test missing files"""
1983 with self.assertRaises(ValueError) as e:
1984 data = self._DoReadFile('086_files_none.dts')
1985 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1986 'no files', str(e.exception))
1988 def testFilesNoPattern(self):
1989 """Test missing files"""
1990 with self.assertRaises(ValueError) as e:
1991 data = self._DoReadFile('087_files_no_pattern.dts')
1992 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1995 def testExpandSize(self):
1996 """Test an expanding entry"""
1997 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1999 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2000 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2001 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2002 tools.GetBytes(ord('d'), 8))
2003 self.assertEqual(expect, data)
2004 self.assertEqual('''ImagePos Offset Size Name
2005 00000000 00000000 00000028 main-section
2006 00000000 00000000 00000008 fill
2007 00000008 00000008 00000004 u-boot
2008 0000000c 0000000c 00000004 section
2009 0000000c 00000000 00000003 intel-mrc
2010 00000010 00000010 00000004 u-boot2
2011 00000014 00000014 0000000c section2
2012 00000014 00000000 00000008 fill
2013 0000001c 00000008 00000004 u-boot
2014 00000020 00000020 00000008 fill2
2017 def testExpandSizeBad(self):
2018 """Test an expanding entry which fails to provide contents"""
2019 with test_util.capture_sys_output() as (stdout, stderr):
2020 with self.assertRaises(ValueError) as e:
2021 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
2022 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2023 'expanding entry', str(e.exception))
2026 """Test hashing of the contents of an entry"""
2027 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2028 use_real_dtb=True, update_dtb=True)
2029 dtb = fdt.Fdt(out_dtb_fname)
2031 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2032 m = hashlib.sha256()
2033 m.update(U_BOOT_DATA)
2034 self.assertEqual(m.digest(), b''.join(hash_node.value))
2036 def testHashNoAlgo(self):
2037 with self.assertRaises(ValueError) as e:
2038 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2039 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2040 'hash node', str(e.exception))
2042 def testHashBadAlgo(self):
2043 with self.assertRaises(ValueError) as e:
2044 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2045 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2048 def testHashSection(self):
2049 """Test hashing of the contents of an entry"""
2050 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2051 use_real_dtb=True, update_dtb=True)
2052 dtb = fdt.Fdt(out_dtb_fname)
2054 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2055 m = hashlib.sha256()
2056 m.update(U_BOOT_DATA)
2057 m.update(tools.GetBytes(ord('a'), 16))
2058 self.assertEqual(m.digest(), b''.join(hash_node.value))
2060 def testPackUBootTplMicrocode(self):
2061 """Test that x86 microcode can be handled correctly in TPL
2063 We expect to see the following in the image, in order:
2064 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2066 u-boot-tpl.dtb with the microcode removed
2069 self._SetupTplElf('u_boot_ucode_ptr')
2070 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2071 U_BOOT_TPL_NODTB_DATA)
2072 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2073 b'ter somewhere in here', first)
2075 def testFmapX86(self):
2076 """Basic test of generation of a flashrom fmap"""
2077 data = self._DoReadFile('094_fmap_x86.dts')
2078 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2079 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
2080 self.assertEqual(expected, data[:32])
2081 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2083 self.assertEqual(0x100, fhdr.image_size)
2085 self.assertEqual(0, fentries[0].offset)
2086 self.assertEqual(4, fentries[0].size)
2087 self.assertEqual(b'U_BOOT', fentries[0].name)
2089 self.assertEqual(4, fentries[1].offset)
2090 self.assertEqual(3, fentries[1].size)
2091 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2093 self.assertEqual(32, fentries[2].offset)
2094 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2095 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2096 self.assertEqual(b'FMAP', fentries[2].name)
2098 def testFmapX86Section(self):
2099 """Basic test of generation of a flashrom fmap"""
2100 data = self._DoReadFile('095_fmap_x86_section.dts')
2101 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
2102 self.assertEqual(expected, data[:32])
2103 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2105 self.assertEqual(0x180, fhdr.image_size)
2106 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2107 fiter = iter(fentries)
2109 fentry = next(fiter)
2110 self.assertEqual(b'U_BOOT', fentry.name)
2111 self.assertEqual(0, fentry.offset)
2112 self.assertEqual(4, fentry.size)
2114 fentry = next(fiter)
2115 self.assertEqual(b'SECTION', fentry.name)
2116 self.assertEqual(4, fentry.offset)
2117 self.assertEqual(0x20 + expect_size, fentry.size)
2119 fentry = next(fiter)
2120 self.assertEqual(b'INTEL_MRC', fentry.name)
2121 self.assertEqual(4, fentry.offset)
2122 self.assertEqual(3, fentry.size)
2124 fentry = next(fiter)
2125 self.assertEqual(b'FMAP', fentry.name)
2126 self.assertEqual(36, fentry.offset)
2127 self.assertEqual(expect_size, fentry.size)
2130 """Basic test of ELF entries"""
2133 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2134 TestFunctional._MakeInputFile('-boot', fd.read())
2135 data = self._DoReadFile('096_elf.dts')
2137 def testElfStrip(self):
2138 """Basic test of ELF entries"""
2140 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2141 TestFunctional._MakeInputFile('-boot', fd.read())
2142 data = self._DoReadFile('097_elf_strip.dts')
2144 def testPackOverlapMap(self):
2145 """Test that overlapping regions are detected"""
2146 with test_util.capture_sys_output() as (stdout, stderr):
2147 with self.assertRaises(ValueError) as e:
2148 self._DoTestFile('014_pack_overlap.dts', map=True)
2149 map_fname = tools.GetOutputFilename('image.map')
2150 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2153 # We should not get an inmage, but there should be a map file
2154 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2155 self.assertTrue(os.path.exists(map_fname))
2156 map_data = tools.ReadFile(map_fname, binary=False)
2157 self.assertEqual('''ImagePos Offset Size Name
2158 <none> 00000000 00000008 main-section
2159 <none> 00000000 00000004 u-boot
2160 <none> 00000003 00000004 u-boot-align
2163 def testPackRefCode(self):
2164 """Test that an image with an Intel Reference code binary works"""
2165 data = self._DoReadFile('100_intel_refcode.dts')
2166 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2168 def testSectionOffset(self):
2169 """Tests use of a section with an offset"""
2170 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2172 self.assertEqual('''ImagePos Offset Size Name
2173 00000000 00000000 00000038 main-section
2174 00000004 00000004 00000010 section@0
2175 00000004 00000000 00000004 u-boot
2176 00000018 00000018 00000010 section@1
2177 00000018 00000000 00000004 u-boot
2178 0000002c 0000002c 00000004 section@2
2179 0000002c 00000000 00000004 u-boot
2181 self.assertEqual(data,
2182 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2183 tools.GetBytes(0x21, 12) +
2184 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2185 tools.GetBytes(0x61, 12) +
2186 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2187 tools.GetBytes(0x26, 8))
2189 def testCbfsRaw(self):
2190 """Test base handling of a Coreboot Filesystem (CBFS)
2192 The exact contents of the CBFS is verified by similar tests in
2193 cbfs_util_test.py. The tests here merely check that the files added to
2194 the CBFS can be found in the final image.
2196 data = self._DoReadFile('102_cbfs_raw.dts')
2199 cbfs = cbfs_util.CbfsReader(data)
2200 self.assertEqual(size, cbfs.rom_size)
2202 self.assertIn('u-boot-dtb', cbfs.files)
2203 cfile = cbfs.files['u-boot-dtb']
2204 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2206 def testCbfsArch(self):
2207 """Test on non-x86 architecture"""
2208 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2211 cbfs = cbfs_util.CbfsReader(data)
2212 self.assertEqual(size, cbfs.rom_size)
2214 self.assertIn('u-boot-dtb', cbfs.files)
2215 cfile = cbfs.files['u-boot-dtb']
2216 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2218 def testCbfsStage(self):
2219 """Tests handling of a Coreboot Filesystem (CBFS)"""
2220 if not elf.ELF_TOOLS:
2221 self.skipTest('Python elftools not available')
2222 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2223 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2226 data = self._DoReadFile('104_cbfs_stage.dts')
2227 cbfs = cbfs_util.CbfsReader(data)
2228 self.assertEqual(size, cbfs.rom_size)
2230 self.assertIn('u-boot', cbfs.files)
2231 cfile = cbfs.files['u-boot']
2232 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2234 def testCbfsRawCompress(self):
2235 """Test handling of compressing raw files"""
2237 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2240 cbfs = cbfs_util.CbfsReader(data)
2241 self.assertIn('u-boot', cbfs.files)
2242 cfile = cbfs.files['u-boot']
2243 self.assertEqual(COMPRESS_DATA, cfile.data)
2245 def testCbfsBadArch(self):
2246 """Test handling of a bad architecture"""
2247 with self.assertRaises(ValueError) as e:
2248 self._DoReadFile('106_cbfs_bad_arch.dts')
2249 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2251 def testCbfsNoSize(self):
2252 """Test handling of a missing size property"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('107_cbfs_no_size.dts')
2255 self.assertIn('entry must have a size property', str(e.exception))
2257 def testCbfsNoCOntents(self):
2258 """Test handling of a CBFS entry which does not provide contentsy"""
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFile('108_cbfs_no_contents.dts')
2261 self.assertIn('Could not complete processing of contents',
2264 def testCbfsBadCompress(self):
2265 """Test handling of a bad architecture"""
2266 with self.assertRaises(ValueError) as e:
2267 self._DoReadFile('109_cbfs_bad_compress.dts')
2268 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2271 def testCbfsNamedEntries(self):
2272 """Test handling of named entries"""
2273 data = self._DoReadFile('110_cbfs_name.dts')
2275 cbfs = cbfs_util.CbfsReader(data)
2276 self.assertIn('FRED', cbfs.files)
2277 cfile1 = cbfs.files['FRED']
2278 self.assertEqual(U_BOOT_DATA, cfile1.data)
2280 self.assertIn('hello', cbfs.files)
2281 cfile2 = cbfs.files['hello']
2282 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2284 def _SetupIfwi(self, fname):
2285 """Set up to run an IFWI test
2288 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2293 # Intel Integrated Firmware Image (IFWI) file
2294 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2296 TestFunctional._MakeInputFile(fname,data)
2298 def _CheckIfwi(self, data):
2299 """Check that an image with an IFWI contains the correct output
2302 data: Conents of output file
2304 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2305 if data[:0x1000] != expected_desc:
2306 self.fail('Expected descriptor binary at start of image')
2308 # We expect to find the TPL wil in subpart IBBP entry IBBL
2309 image_fname = tools.GetOutputFilename('image.bin')
2310 tpl_fname = tools.GetOutputFilename('tpl.out')
2311 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2312 subpart='IBBP', entry_name='IBBL')
2314 tpl_data = tools.ReadFile(tpl_fname)
2315 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2317 def testPackX86RomIfwi(self):
2318 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2319 self._SetupIfwi('fitimage.bin')
2320 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2321 self._CheckIfwi(data)
2323 def testPackX86RomIfwiNoDesc(self):
2324 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2325 self._SetupIfwi('ifwi.bin')
2326 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2327 self._CheckIfwi(data)
2329 def testPackX86RomIfwiNoData(self):
2330 """Test that an x86 ROM with IFWI handles missing data"""
2331 self._SetupIfwi('ifwi.bin')
2332 with self.assertRaises(ValueError) as e:
2333 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2334 self.assertIn('Could not complete processing of contents',
2337 def testCbfsOffset(self):
2338 """Test a CBFS with files at particular offsets
2340 Like all CFBS tests, this is just checking the logic that calls
2341 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2343 data = self._DoReadFile('114_cbfs_offset.dts')
2346 cbfs = cbfs_util.CbfsReader(data)
2347 self.assertEqual(size, cbfs.rom_size)
2349 self.assertIn('u-boot', cbfs.files)
2350 cfile = cbfs.files['u-boot']
2351 self.assertEqual(U_BOOT_DATA, cfile.data)
2352 self.assertEqual(0x40, cfile.cbfs_offset)
2354 self.assertIn('u-boot-dtb', cbfs.files)
2355 cfile2 = cbfs.files['u-boot-dtb']
2356 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2357 self.assertEqual(0x140, cfile2.cbfs_offset)
2359 def testFdtmap(self):
2360 """Test an FDT map can be inserted in the image"""
2361 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2362 fdtmap_data = data[len(U_BOOT_DATA):]
2363 magic = fdtmap_data[:8]
2364 self.assertEqual(b'_FDTMAP_', magic)
2365 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2367 fdt_data = fdtmap_data[16:]
2368 dtb = fdt.Fdt.FromData(fdt_data)
2370 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2375 'u-boot:size': len(U_BOOT_DATA),
2376 'u-boot:image-pos': 0,
2377 'fdtmap:image-pos': 4,
2379 'fdtmap:size': len(fdtmap_data),
2383 def testFdtmapNoMatch(self):
2384 """Check handling of an FDT map when the section cannot be found"""
2385 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2387 # Mangle the section name, which should cause a mismatch between the
2388 # correct FDT path and the one expected by the section
2389 image = control.images['image']
2390 image._node.path += '-suffix'
2391 entries = image.GetEntries()
2392 fdtmap = entries['fdtmap']
2393 with self.assertRaises(ValueError) as e:
2395 self.assertIn("Cannot locate node for path '/binman-suffix'",
2398 def testFdtmapHeader(self):
2399 """Test an FDT map and image header can be inserted in the image"""
2400 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2401 fdtmap_pos = len(U_BOOT_DATA)
2402 fdtmap_data = data[fdtmap_pos:]
2403 fdt_data = fdtmap_data[16:]
2404 dtb = fdt.Fdt.FromData(fdt_data)
2405 fdt_size = dtb.GetFdtObj().totalsize()
2406 hdr_data = data[-8:]
2407 self.assertEqual(b'BinM', hdr_data[:4])
2408 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2409 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2411 def testFdtmapHeaderStart(self):
2412 """Test an image header can be inserted at the image start"""
2413 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2414 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2416 self.assertEqual(b'BinM', hdr_data[:4])
2417 offset = struct.unpack('<I', hdr_data[4:])[0]
2418 self.assertEqual(fdtmap_pos, offset)
2420 def testFdtmapHeaderPos(self):
2421 """Test an image header can be inserted at a chosen position"""
2422 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2423 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2424 hdr_data = data[0x80:0x88]
2425 self.assertEqual(b'BinM', hdr_data[:4])
2426 offset = struct.unpack('<I', hdr_data[4:])[0]
2427 self.assertEqual(fdtmap_pos, offset)
2429 def testHeaderMissingFdtmap(self):
2430 """Test an image header requires an fdtmap"""
2431 with self.assertRaises(ValueError) as e:
2432 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2433 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2436 def testHeaderNoLocation(self):
2437 """Test an image header with a no specified location is detected"""
2438 with self.assertRaises(ValueError) as e:
2439 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2440 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2443 def testEntryExpand(self):
2444 """Test expanding an entry after it is packed"""
2445 data = self._DoReadFile('121_entry_expand.dts')
2446 self.assertEqual(b'aaa', data[:3])
2447 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2448 self.assertEqual(b'aaa', data[-3:])
2450 def testEntryExpandBad(self):
2451 """Test expanding an entry after it is packed, twice"""
2452 with self.assertRaises(ValueError) as e:
2453 self._DoReadFile('122_entry_expand_twice.dts')
2454 self.assertIn("Image '/binman': Entries changed size after packing",
2457 def testEntryExpandSection(self):
2458 """Test expanding an entry within a section after it is packed"""
2459 data = self._DoReadFile('123_entry_expand_section.dts')
2460 self.assertEqual(b'aaa', data[:3])
2461 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2462 self.assertEqual(b'aaa', data[-3:])
2464 def testCompressDtb(self):
2465 """Test that compress of device-tree files is supported"""
2467 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2468 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2469 comp_data = data[len(U_BOOT_DATA):]
2470 orig = self._decompress(comp_data)
2471 dtb = fdt.Fdt.FromData(orig)
2473 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2475 'u-boot:size': len(U_BOOT_DATA),
2476 'u-boot-dtb:uncomp-size': len(orig),
2477 'u-boot-dtb:size': len(comp_data),
2480 self.assertEqual(expected, props)
2482 def testCbfsUpdateFdt(self):
2483 """Test that we can update the device tree with CBFS offset/size info"""
2485 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2487 dtb = fdt.Fdt(out_dtb_fname)
2489 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2490 del props['cbfs/u-boot:size']
2496 'cbfs:size': len(data),
2497 'cbfs:image-pos': 0,
2498 'cbfs/u-boot:offset': 0x38,
2499 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2500 'cbfs/u-boot:image-pos': 0x38,
2501 'cbfs/u-boot-dtb:offset': 0xb8,
2502 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2503 'cbfs/u-boot-dtb:image-pos': 0xb8,
2506 def testCbfsBadType(self):
2507 """Test an image header with a no specified location is detected"""
2508 with self.assertRaises(ValueError) as e:
2509 self._DoReadFile('126_cbfs_bad_type.dts')
2510 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2513 """Test listing the files in an image"""
2515 data = self._DoReadFile('127_list.dts')
2516 image = control.images['image']
2517 entries = image.BuildEntryList()
2518 self.assertEqual(7, len(entries))
2521 self.assertEqual(0, ent.indent)
2522 self.assertEqual('main-section', ent.name)
2523 self.assertEqual('section', ent.etype)
2524 self.assertEqual(len(data), ent.size)
2525 self.assertEqual(0, ent.image_pos)
2526 self.assertEqual(None, ent.uncomp_size)
2527 self.assertEqual(0, ent.offset)
2530 self.assertEqual(1, ent.indent)
2531 self.assertEqual('u-boot', ent.name)
2532 self.assertEqual('u-boot', ent.etype)
2533 self.assertEqual(len(U_BOOT_DATA), ent.size)
2534 self.assertEqual(0, ent.image_pos)
2535 self.assertEqual(None, ent.uncomp_size)
2536 self.assertEqual(0, ent.offset)
2539 self.assertEqual(1, ent.indent)
2540 self.assertEqual('section', ent.name)
2541 self.assertEqual('section', ent.etype)
2542 section_size = ent.size
2543 self.assertEqual(0x100, ent.image_pos)
2544 self.assertEqual(None, ent.uncomp_size)
2545 self.assertEqual(0x100, ent.offset)
2548 self.assertEqual(2, ent.indent)
2549 self.assertEqual('cbfs', ent.name)
2550 self.assertEqual('cbfs', ent.etype)
2551 self.assertEqual(0x400, ent.size)
2552 self.assertEqual(0x100, ent.image_pos)
2553 self.assertEqual(None, ent.uncomp_size)
2554 self.assertEqual(0, ent.offset)
2557 self.assertEqual(3, ent.indent)
2558 self.assertEqual('u-boot', ent.name)
2559 self.assertEqual('u-boot', ent.etype)
2560 self.assertEqual(len(U_BOOT_DATA), ent.size)
2561 self.assertEqual(0x138, ent.image_pos)
2562 self.assertEqual(None, ent.uncomp_size)
2563 self.assertEqual(0x38, ent.offset)
2566 self.assertEqual(3, ent.indent)
2567 self.assertEqual('u-boot-dtb', ent.name)
2568 self.assertEqual('text', ent.etype)
2569 self.assertGreater(len(COMPRESS_DATA), ent.size)
2570 self.assertEqual(0x178, ent.image_pos)
2571 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2572 self.assertEqual(0x78, ent.offset)
2575 self.assertEqual(2, ent.indent)
2576 self.assertEqual('u-boot-dtb', ent.name)
2577 self.assertEqual('u-boot-dtb', ent.etype)
2578 self.assertEqual(0x500, ent.image_pos)
2579 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2581 # Compressing this data expands it since headers are added
2582 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2583 self.assertEqual(0x400, ent.offset)
2585 self.assertEqual(len(data), 0x100 + section_size)
2586 self.assertEqual(section_size, 0x400 + dtb_size)
2588 def testFindFdtmap(self):
2589 """Test locating an FDT map in an image"""
2591 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2592 image = control.images['image']
2593 entries = image.GetEntries()
2594 entry = entries['fdtmap']
2595 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2597 def testFindFdtmapMissing(self):
2598 """Test failing to locate an FDP map"""
2599 data = self._DoReadFile('005_simple.dts')
2600 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2602 def testFindImageHeader(self):
2603 """Test locating a image header"""
2605 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2606 image = control.images['image']
2607 entries = image.GetEntries()
2608 entry = entries['fdtmap']
2609 # The header should point to the FDT map
2610 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2612 def testFindImageHeaderStart(self):
2613 """Test locating a image header located at the start of an image"""
2614 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2615 image = control.images['image']
2616 entries = image.GetEntries()
2617 entry = entries['fdtmap']
2618 # The header should point to the FDT map
2619 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2621 def testFindImageHeaderMissing(self):
2622 """Test failing to locate an image header"""
2623 data = self._DoReadFile('005_simple.dts')
2624 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2626 def testReadImage(self):
2627 """Test reading an image and accessing its FDT map"""
2629 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2630 image_fname = tools.GetOutputFilename('image.bin')
2631 orig_image = control.images['image']
2632 image = Image.FromFile(image_fname)
2633 self.assertEqual(orig_image.GetEntries().keys(),
2634 image.GetEntries().keys())
2636 orig_entry = orig_image.GetEntries()['fdtmap']
2637 entry = image.GetEntries()['fdtmap']
2638 self.assertEquals(orig_entry.offset, entry.offset)
2639 self.assertEquals(orig_entry.size, entry.size)
2640 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2642 def testReadImageNoHeader(self):
2643 """Test accessing an image's FDT map without an image header"""
2645 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2646 image_fname = tools.GetOutputFilename('image.bin')
2647 image = Image.FromFile(image_fname)
2648 self.assertTrue(isinstance(image, Image))
2649 self.assertEqual('image', image.image_name[-5:])
2651 def testReadImageFail(self):
2652 """Test failing to read an image image's FDT map"""
2653 self._DoReadFile('005_simple.dts')
2654 image_fname = tools.GetOutputFilename('image.bin')
2655 with self.assertRaises(ValueError) as e:
2656 image = Image.FromFile(image_fname)
2657 self.assertIn("Cannot find FDT map in image", str(e.exception))
2659 def testListCmd(self):
2660 """Test listing the files in an image using an Fdtmap"""
2662 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2664 # lz4 compression size differs depending on the version
2665 image = control.images['image']
2666 entries = image.GetEntries()
2667 section_size = entries['section'].size
2668 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2669 fdtmap_offset = entries['fdtmap'].offset
2672 tmpdir, updated_fname = self._SetupImageInTmpdir()
2673 with test_util.capture_sys_output() as (stdout, stderr):
2674 self._DoBinman('ls', '-i', updated_fname)
2676 shutil.rmtree(tmpdir)
2677 lines = stdout.getvalue().splitlines()
2679 'Name Image-pos Size Entry-type Offset Uncomp-size',
2680 '----------------------------------------------------------------------',
2681 'main-section 0 c00 section 0',
2682 ' u-boot 0 4 u-boot 0',
2683 ' section 100 %x section 100' % section_size,
2684 ' cbfs 100 400 cbfs 0',
2685 ' u-boot 138 4 u-boot 38',
2686 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2687 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2688 ' fdtmap %x 3bd fdtmap %x' %
2689 (fdtmap_offset, fdtmap_offset),
2690 ' image-header bf8 8 image-header bf8',
2692 self.assertEqual(expected, lines)
2694 def testListCmdFail(self):
2695 """Test failing to list an image"""
2696 self._DoReadFile('005_simple.dts')
2698 tmpdir, updated_fname = self._SetupImageInTmpdir()
2699 with self.assertRaises(ValueError) as e:
2700 self._DoBinman('ls', '-i', updated_fname)
2702 shutil.rmtree(tmpdir)
2703 self.assertIn("Cannot find FDT map in image", str(e.exception))
2705 def _RunListCmd(self, paths, expected):
2706 """List out entries and check the result
2709 paths: List of paths to pass to the list command
2710 expected: Expected list of filenames to be returned, in order
2713 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2714 image_fname = tools.GetOutputFilename('image.bin')
2715 image = Image.FromFile(image_fname)
2716 lines = image.GetListEntries(paths)[1]
2717 files = [line[0].strip() for line in lines[1:]]
2718 self.assertEqual(expected, files)
2720 def testListCmdSection(self):
2721 """Test listing the files in a section"""
2722 self._RunListCmd(['section'],
2723 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2725 def testListCmdFile(self):
2726 """Test listing a particular file"""
2727 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2729 def testListCmdWildcard(self):
2730 """Test listing a wildcarded file"""
2731 self._RunListCmd(['*boot*'],
2732 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2734 def testListCmdWildcardMulti(self):
2735 """Test listing a wildcarded file"""
2736 self._RunListCmd(['*cb*', '*head*'],
2737 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2739 def testListCmdEmpty(self):
2740 """Test listing a wildcarded file"""
2741 self._RunListCmd(['nothing'], [])
2743 def testListCmdPath(self):
2744 """Test listing the files in a sub-entry of a section"""
2745 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2747 def _RunExtractCmd(self, entry_name, decomp=True):
2748 """Extract an entry from an image
2751 entry_name: Entry name to extract
2752 decomp: True to decompress the data if compressed, False to leave
2753 it in its raw uncompressed format
2759 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2760 image_fname = tools.GetOutputFilename('image.bin')
2761 return control.ReadEntry(image_fname, entry_name, decomp)
2763 def testExtractSimple(self):
2764 """Test extracting a single file"""
2765 data = self._RunExtractCmd('u-boot')
2766 self.assertEqual(U_BOOT_DATA, data)
2768 def testExtractSection(self):
2769 """Test extracting the files in a section"""
2770 data = self._RunExtractCmd('section')
2771 cbfs_data = data[:0x400]
2772 cbfs = cbfs_util.CbfsReader(cbfs_data)
2773 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2774 dtb_data = data[0x400:]
2775 dtb = self._decompress(dtb_data)
2776 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2778 def testExtractCompressed(self):
2779 """Test extracting compressed data"""
2780 data = self._RunExtractCmd('section/u-boot-dtb')
2781 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2783 def testExtractRaw(self):
2784 """Test extracting compressed data without decompressing it"""
2785 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2786 dtb = self._decompress(data)
2787 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2789 def testExtractCbfs(self):
2790 """Test extracting CBFS data"""
2791 data = self._RunExtractCmd('section/cbfs/u-boot')
2792 self.assertEqual(U_BOOT_DATA, data)
2794 def testExtractCbfsCompressed(self):
2795 """Test extracting CBFS compressed data"""
2796 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2797 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2799 def testExtractCbfsRaw(self):
2800 """Test extracting CBFS compressed data without decompressing it"""
2801 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2802 dtb = tools.Decompress(data, 'lzma', with_header=False)
2803 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2805 def testExtractBadEntry(self):
2806 """Test extracting a bad section path"""
2807 with self.assertRaises(ValueError) as e:
2808 self._RunExtractCmd('section/does-not-exist')
2809 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2812 def testExtractMissingFile(self):
2813 """Test extracting file that does not exist"""
2814 with self.assertRaises(IOError) as e:
2815 control.ReadEntry('missing-file', 'name')
2817 def testExtractBadFile(self):
2818 """Test extracting an invalid file"""
2819 fname = os.path.join(self._indir, 'badfile')
2820 tools.WriteFile(fname, b'')
2821 with self.assertRaises(ValueError) as e:
2822 control.ReadEntry(fname, 'name')
2824 def testExtractCmd(self):
2825 """Test extracting a file fron an image on the command line"""
2827 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2828 fname = os.path.join(self._indir, 'output.extact')
2830 tmpdir, updated_fname = self._SetupImageInTmpdir()
2831 with test_util.capture_sys_output() as (stdout, stderr):
2832 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2835 shutil.rmtree(tmpdir)
2836 data = tools.ReadFile(fname)
2837 self.assertEqual(U_BOOT_DATA, data)
2839 def testExtractOneEntry(self):
2840 """Test extracting a single entry fron an image """
2842 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2843 image_fname = tools.GetOutputFilename('image.bin')
2844 fname = os.path.join(self._indir, 'output.extact')
2845 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2846 data = tools.ReadFile(fname)
2847 self.assertEqual(U_BOOT_DATA, data)
2849 def _CheckExtractOutput(self, decomp):
2850 """Helper to test file output with and without decompression
2853 decomp: True to decompress entry data, False to output it raw
2855 def _CheckPresent(entry_path, expect_data, expect_size=None):
2856 """Check and remove expected file
2858 This checks the data/size of a file and removes the file both from
2859 the outfiles set and from the output directory. Once all files are
2860 processed, both the set and directory should be empty.
2863 entry_path: Entry path
2864 expect_data: Data to expect in file, or None to skip check
2865 expect_size: Size of data to expect in file, or None to skip
2867 path = os.path.join(outdir, entry_path)
2868 data = tools.ReadFile(path)
2871 self.assertEqual(expect_data, data)
2873 self.assertEqual(expect_size, len(data))
2874 outfiles.remove(path)
2876 def _CheckDirPresent(name):
2877 """Remove expected directory
2879 This gives an error if the directory does not exist as expected
2882 name: Name of directory to remove
2884 path = os.path.join(outdir, name)
2887 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2888 image_fname = tools.GetOutputFilename('image.bin')
2889 outdir = os.path.join(self._indir, 'extract')
2890 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2892 # Create a set of all file that were output (should be 9)
2894 for root, dirs, files in os.walk(outdir):
2895 outfiles |= set([os.path.join(root, fname) for fname in files])
2896 self.assertEqual(9, len(outfiles))
2897 self.assertEqual(9, len(einfos))
2899 image = control.images['image']
2900 entries = image.GetEntries()
2902 # Check the 9 files in various ways
2903 section = entries['section']
2904 section_entries = section.GetEntries()
2905 cbfs_entries = section_entries['cbfs'].GetEntries()
2906 _CheckPresent('u-boot', U_BOOT_DATA)
2907 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2908 dtb_len = EXTRACT_DTB_SIZE
2910 dtb_len = cbfs_entries['u-boot-dtb'].size
2911 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2913 dtb_len = section_entries['u-boot-dtb'].size
2914 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2916 fdtmap = entries['fdtmap']
2917 _CheckPresent('fdtmap', fdtmap.data)
2918 hdr = entries['image-header']
2919 _CheckPresent('image-header', hdr.data)
2921 _CheckPresent('section/root', section.data)
2922 cbfs = section_entries['cbfs']
2923 _CheckPresent('section/cbfs/root', cbfs.data)
2924 data = tools.ReadFile(image_fname)
2925 _CheckPresent('root', data)
2927 # There should be no files left. Remove all the directories to check.
2928 # If there are any files/dirs remaining, one of these checks will fail.
2929 self.assertEqual(0, len(outfiles))
2930 _CheckDirPresent('section/cbfs')
2931 _CheckDirPresent('section')
2932 _CheckDirPresent('')
2933 self.assertFalse(os.path.exists(outdir))
2935 def testExtractAllEntries(self):
2936 """Test extracting all entries"""
2938 self._CheckExtractOutput(decomp=True)
2940 def testExtractAllEntriesRaw(self):
2941 """Test extracting all entries without decompressing them"""
2943 self._CheckExtractOutput(decomp=False)
2945 def testExtractSelectedEntries(self):
2946 """Test extracting some entries"""
2948 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2949 image_fname = tools.GetOutputFilename('image.bin')
2950 outdir = os.path.join(self._indir, 'extract')
2951 einfos = control.ExtractEntries(image_fname, None, outdir,
2954 # File output is tested by testExtractAllEntries(), so just check that
2955 # the expected entries are selected
2956 names = [einfo.name for einfo in einfos]
2957 self.assertEqual(names,
2958 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2960 def testExtractNoEntryPaths(self):
2961 """Test extracting some entries"""
2963 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2964 image_fname = tools.GetOutputFilename('image.bin')
2965 with self.assertRaises(ValueError) as e:
2966 control.ExtractEntries(image_fname, 'fname', None, [])
2967 self.assertIn('Must specify an entry path to write with -f',
2970 def testExtractTooManyEntryPaths(self):
2971 """Test extracting some entries"""
2973 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2974 image_fname = tools.GetOutputFilename('image.bin')
2975 with self.assertRaises(ValueError) as e:
2976 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2977 self.assertIn('Must specify exactly one entry path to write with -f',
2980 def testPackAlignSection(self):
2981 """Test that sections can have alignment"""
2982 self._DoReadFile('131_pack_align_section.dts')
2984 self.assertIn('image', control.images)
2985 image = control.images['image']
2986 entries = image.GetEntries()
2987 self.assertEqual(3, len(entries))
2990 self.assertIn('u-boot', entries)
2991 entry = entries['u-boot']
2992 self.assertEqual(0, entry.offset)
2993 self.assertEqual(0, entry.image_pos)
2994 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2995 self.assertEqual(len(U_BOOT_DATA), entry.size)
2998 self.assertIn('section0', entries)
2999 section0 = entries['section0']
3000 self.assertEqual(0x10, section0.offset)
3001 self.assertEqual(0x10, section0.image_pos)
3002 self.assertEqual(len(U_BOOT_DATA), section0.size)
3005 section_entries = section0.GetEntries()
3006 self.assertIn('u-boot', section_entries)
3007 entry = section_entries['u-boot']
3008 self.assertEqual(0, entry.offset)
3009 self.assertEqual(0x10, entry.image_pos)
3010 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3011 self.assertEqual(len(U_BOOT_DATA), entry.size)
3014 self.assertIn('section1', entries)
3015 section1 = entries['section1']
3016 self.assertEqual(0x14, section1.offset)
3017 self.assertEqual(0x14, section1.image_pos)
3018 self.assertEqual(0x20, section1.size)
3021 section_entries = section1.GetEntries()
3022 self.assertIn('u-boot', section_entries)
3023 entry = section_entries['u-boot']
3024 self.assertEqual(0, entry.offset)
3025 self.assertEqual(0x14, entry.image_pos)
3026 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3027 self.assertEqual(len(U_BOOT_DATA), entry.size)
3030 self.assertIn('section2', section_entries)
3031 section2 = section_entries['section2']
3032 self.assertEqual(0x4, section2.offset)
3033 self.assertEqual(0x18, section2.image_pos)
3034 self.assertEqual(4, section2.size)
3037 section_entries = section2.GetEntries()
3038 self.assertIn('u-boot', section_entries)
3039 entry = section_entries['u-boot']
3040 self.assertEqual(0, entry.offset)
3041 self.assertEqual(0x18, entry.image_pos)
3042 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3043 self.assertEqual(len(U_BOOT_DATA), entry.size)
3045 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3046 dts='132_replace.dts'):
3047 """Replace an entry in an image
3049 This writes the entry data to update it, then opens the updated file and
3050 returns the value that it now finds there.
3053 entry_name: Entry name to replace
3054 data: Data to replace it with
3055 decomp: True to compress the data if needed, False if data is
3056 already compressed so should be used as is
3057 allow_resize: True to allow entries to change size, False to raise
3063 data from fdtmap (excluding header)
3064 Image object that was modified
3066 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3069 self.assertIn('image', control.images)
3070 image = control.images['image']
3071 entries = image.GetEntries()
3072 orig_dtb_data = entries['u-boot-dtb'].data
3073 orig_fdtmap_data = entries['fdtmap'].data
3075 image_fname = tools.GetOutputFilename('image.bin')
3076 updated_fname = tools.GetOutputFilename('image-updated.bin')
3077 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3078 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3080 data = control.ReadEntry(updated_fname, entry_name, decomp)
3082 # The DT data should not change unless resized:
3083 if not allow_resize:
3084 new_dtb_data = entries['u-boot-dtb'].data
3085 self.assertEqual(new_dtb_data, orig_dtb_data)
3086 new_fdtmap_data = entries['fdtmap'].data
3087 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3089 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3091 def testReplaceSimple(self):
3092 """Test replacing a single file"""
3093 expected = b'x' * len(U_BOOT_DATA)
3094 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3096 self.assertEqual(expected, data)
3098 # Test that the state looks right. There should be an FDT for the fdtmap
3099 # that we jsut read back in, and it should match what we find in the
3100 # 'control' tables. Checking for an FDT that does not exist should
3102 path, fdtmap = state.GetFdtContents('fdtmap')
3103 self.assertIsNotNone(path)
3104 self.assertEqual(expected_fdtmap, fdtmap)
3106 dtb = state.GetFdtForEtype('fdtmap')
3107 self.assertEqual(dtb.GetContents(), fdtmap)
3109 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3110 self.assertIsNone(missing_path)
3111 self.assertIsNone(missing_fdtmap)
3113 missing_dtb = state.GetFdtForEtype('missing')
3114 self.assertIsNone(missing_dtb)
3116 self.assertEqual('/binman', state.fdt_path_prefix)
3118 def testReplaceResizeFail(self):
3119 """Test replacing a file by something larger"""
3120 expected = U_BOOT_DATA + b'x'
3121 with self.assertRaises(ValueError) as e:
3122 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3123 dts='139_replace_repack.dts')
3124 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3127 def testReplaceMulti(self):
3128 """Test replacing entry data where multiple images are generated"""
3129 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3131 expected = b'x' * len(U_BOOT_DATA)
3132 updated_fname = tools.GetOutputFilename('image-updated.bin')
3133 tools.WriteFile(updated_fname, data)
3134 entry_name = 'u-boot'
3135 control.WriteEntry(updated_fname, entry_name, expected,
3137 data = control.ReadEntry(updated_fname, entry_name)
3138 self.assertEqual(expected, data)
3140 # Check the state looks right.
3141 self.assertEqual('/binman/image', state.fdt_path_prefix)
3143 # Now check we can write the first image
3144 image_fname = tools.GetOutputFilename('first-image.bin')
3145 updated_fname = tools.GetOutputFilename('first-updated.bin')
3146 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3147 entry_name = 'u-boot'
3148 control.WriteEntry(updated_fname, entry_name, expected,
3150 data = control.ReadEntry(updated_fname, entry_name)
3151 self.assertEqual(expected, data)
3153 # Check the state looks right.
3154 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3156 def testUpdateFdtAllRepack(self):
3157 """Test that all device trees are updated with offset/size info"""
3158 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3159 SECTION_SIZE = 0x300
3164 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3166 'section:offset': 0,
3167 'section:size': SECTION_SIZE,
3168 'section:image-pos': 0,
3169 'section/u-boot-dtb:offset': 4,
3170 'section/u-boot-dtb:size': 636,
3171 'section/u-boot-dtb:image-pos': 4,
3172 'u-boot-spl-dtb:offset': SECTION_SIZE,
3173 'u-boot-spl-dtb:size': DTB_SIZE,
3174 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3175 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3176 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3177 'u-boot-tpl-dtb:size': DTB_SIZE,
3178 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3179 'fdtmap:size': FDTMAP_SIZE,
3180 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3183 'section:orig-size': SECTION_SIZE,
3184 'section/u-boot-dtb:orig-offset': 4,
3187 # We expect three device-tree files in the output, with the first one
3188 # within a fixed-size section.
3189 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3190 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3191 # main U-Boot tree. All three should have the same positions and offset
3192 # except that the main tree should include the main_expected properties
3194 for item in ['', 'spl', 'tpl', None]:
3196 start += 16 # Move past fdtmap header
3197 dtb = fdt.Fdt.FromData(data[start:])
3199 props = self._GetPropTree(dtb,
3200 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3201 prefix='/' if item is None else '/binman/')
3202 expected = dict(base_expected)
3206 # Main DTB and fdtdec should include the 'orig-' properties
3207 expected.update(main_expected)
3208 # Helpful for debugging:
3209 #for prop in sorted(props):
3210 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3211 self.assertEqual(expected, props)
3213 start = SECTION_SIZE
3215 start += dtb._fdt_obj.totalsize()
3217 def testFdtmapHeaderMiddle(self):
3218 """Test an FDT map in the middle of an image when it should be at end"""
3219 with self.assertRaises(ValueError) as e:
3220 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3221 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3224 def testFdtmapHeaderStartBad(self):
3225 """Test an FDT map in middle of an image when it should be at start"""
3226 with self.assertRaises(ValueError) as e:
3227 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3228 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3231 def testFdtmapHeaderEndBad(self):
3232 """Test an FDT map at the start of an image when it should be at end"""
3233 with self.assertRaises(ValueError) as e:
3234 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3235 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3238 def testFdtmapHeaderNoSize(self):
3239 """Test an image header at the end of an image with undefined size"""
3240 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3242 def testReplaceResize(self):
3243 """Test replacing a single file in an entry with a larger file"""
3244 expected = U_BOOT_DATA + b'x'
3245 data, _, image = self._RunReplaceCmd('u-boot', expected,
3246 dts='139_replace_repack.dts')
3247 self.assertEqual(expected, data)
3249 entries = image.GetEntries()
3250 dtb_data = entries['u-boot-dtb'].data
3251 dtb = fdt.Fdt.FromData(dtb_data)
3254 # The u-boot section should now be larger in the dtb
3255 node = dtb.GetNode('/binman/u-boot')
3256 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3258 # Same for the fdtmap
3259 fdata = entries['fdtmap'].data
3260 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3262 fnode = fdtb.GetNode('/u-boot')
3263 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3265 def testReplaceResizeNoRepack(self):
3266 """Test replacing an entry with a larger file when not allowed"""
3267 expected = U_BOOT_DATA + b'x'
3268 with self.assertRaises(ValueError) as e:
3269 self._RunReplaceCmd('u-boot', expected)
3270 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3273 def testEntryShrink(self):
3274 """Test contracting an entry after it is packed"""
3276 state.SetAllowEntryContraction(True)
3277 data = self._DoReadFileDtb('140_entry_shrink.dts',
3280 state.SetAllowEntryContraction(False)
3281 self.assertEqual(b'a', data[:1])
3282 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3283 self.assertEqual(b'a', data[-1:])
3285 def testEntryShrinkFail(self):
3286 """Test not being allowed to contract an entry after it is packed"""
3287 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3289 # In this case there is a spare byte at the end of the data. The size of
3290 # the contents is only 1 byte but we still have the size before it
3292 self.assertEqual(b'a\0', data[:2])
3293 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3294 self.assertEqual(b'a\0', data[-2:])
3296 def testDescriptorOffset(self):
3297 """Test that the Intel descriptor is always placed at at the start"""
3298 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3299 image = control.images['image']
3300 entries = image.GetEntries()
3301 desc = entries['intel-descriptor']
3302 self.assertEqual(0xff800000, desc.offset);
3303 self.assertEqual(0xff800000, desc.image_pos);
3305 def testReplaceCbfs(self):
3306 """Test replacing a single file in CBFS without changing the size"""
3308 expected = b'x' * len(U_BOOT_DATA)
3309 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3310 updated_fname = tools.GetOutputFilename('image-updated.bin')
3311 tools.WriteFile(updated_fname, data)
3312 entry_name = 'section/cbfs/u-boot'
3313 control.WriteEntry(updated_fname, entry_name, expected,
3315 data = control.ReadEntry(updated_fname, entry_name)
3316 self.assertEqual(expected, data)
3318 def testReplaceResizeCbfs(self):
3319 """Test replacing a single file in CBFS with one of a different size"""
3321 expected = U_BOOT_DATA + b'x'
3322 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3323 updated_fname = tools.GetOutputFilename('image-updated.bin')
3324 tools.WriteFile(updated_fname, data)
3325 entry_name = 'section/cbfs/u-boot'
3326 control.WriteEntry(updated_fname, entry_name, expected,
3328 data = control.ReadEntry(updated_fname, entry_name)
3329 self.assertEqual(expected, data)
3331 def _SetupForReplace(self):
3332 """Set up some files to use to replace entries
3334 This generates an image, copies it to a new file, extracts all the files
3335 in it and updates some of them
3341 Expected values for updated entries, each a string
3343 data = self._DoReadFileRealDtb('143_replace_all.dts')
3345 updated_fname = tools.GetOutputFilename('image-updated.bin')
3346 tools.WriteFile(updated_fname, data)
3348 outdir = os.path.join(self._indir, 'extract')
3349 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3351 expected1 = b'x' + U_BOOT_DATA + b'y'
3352 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3353 tools.WriteFile(u_boot_fname1, expected1)
3355 expected2 = b'a' + U_BOOT_DATA + b'b'
3356 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3357 tools.WriteFile(u_boot_fname2, expected2)
3359 expected_text = b'not the same text'
3360 text_fname = os.path.join(outdir, 'text')
3361 tools.WriteFile(text_fname, expected_text)
3363 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3364 dtb = fdt.FdtScan(dtb_fname)
3365 node = dtb.GetNode('/binman/text')
3366 node.AddString('my-property', 'the value')
3367 dtb.Sync(auto_resize=True)
3370 return updated_fname, outdir, expected1, expected2, expected_text
3372 def _CheckReplaceMultiple(self, entry_paths):
3373 """Handle replacing the contents of multiple entries
3376 entry_paths: List of entry paths to replace
3380 Dict of entries in the image:
3383 Expected values for updated entries, each a string
3385 updated_fname, outdir, expected1, expected2, expected_text = (
3386 self._SetupForReplace())
3387 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3389 image = Image.FromFile(updated_fname)
3391 return image.GetEntries(), expected1, expected2, expected_text
3393 def testReplaceAll(self):
3394 """Test replacing the contents of all entries"""
3395 entries, expected1, expected2, expected_text = (
3396 self._CheckReplaceMultiple([]))
3397 data = entries['u-boot'].data
3398 self.assertEqual(expected1, data)
3400 data = entries['u-boot2'].data
3401 self.assertEqual(expected2, data)
3403 data = entries['text'].data
3404 self.assertEqual(expected_text, data)
3406 # Check that the device tree is updated
3407 data = entries['u-boot-dtb'].data
3408 dtb = fdt.Fdt.FromData(data)
3410 node = dtb.GetNode('/binman/text')
3411 self.assertEqual('the value', node.props['my-property'].value)
3413 def testReplaceSome(self):
3414 """Test replacing the contents of a few entries"""
3415 entries, expected1, expected2, expected_text = (
3416 self._CheckReplaceMultiple(['u-boot2', 'text']))
3418 # This one should not change
3419 data = entries['u-boot'].data
3420 self.assertEqual(U_BOOT_DATA, data)
3422 data = entries['u-boot2'].data
3423 self.assertEqual(expected2, data)
3425 data = entries['text'].data
3426 self.assertEqual(expected_text, data)
3428 def testReplaceCmd(self):
3429 """Test replacing a file fron an image on the command line"""
3430 self._DoReadFileRealDtb('143_replace_all.dts')
3433 tmpdir, updated_fname = self._SetupImageInTmpdir()
3435 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3436 expected = b'x' * len(U_BOOT_DATA)
3437 tools.WriteFile(fname, expected)
3439 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3440 data = tools.ReadFile(updated_fname)
3441 self.assertEqual(expected, data[:len(expected)])
3442 map_fname = os.path.join(tmpdir, 'image-updated.map')
3443 self.assertFalse(os.path.exists(map_fname))
3445 shutil.rmtree(tmpdir)
3447 def testReplaceCmdSome(self):
3448 """Test replacing some files fron an image on the command line"""
3449 updated_fname, outdir, expected1, expected2, expected_text = (
3450 self._SetupForReplace())
3452 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3455 tools.PrepareOutputDir(None)
3456 image = Image.FromFile(updated_fname)
3458 entries = image.GetEntries()
3460 # This one should not change
3461 data = entries['u-boot'].data
3462 self.assertEqual(U_BOOT_DATA, data)
3464 data = entries['u-boot2'].data
3465 self.assertEqual(expected2, data)
3467 data = entries['text'].data
3468 self.assertEqual(expected_text, data)
3470 def testReplaceMissing(self):
3471 """Test replacing entries where the file is missing"""
3472 updated_fname, outdir, expected1, expected2, expected_text = (
3473 self._SetupForReplace())
3475 # Remove one of the files, to generate a warning
3476 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3477 os.remove(u_boot_fname1)
3479 with test_util.capture_sys_output() as (stdout, stderr):
3480 control.ReplaceEntries(updated_fname, None, outdir, [])
3481 self.assertIn("Skipping entry '/u-boot' from missing file",
3484 def testReplaceCmdMap(self):
3485 """Test replacing a file fron an image on the command line"""
3486 self._DoReadFileRealDtb('143_replace_all.dts')
3489 tmpdir, updated_fname = self._SetupImageInTmpdir()
3491 fname = os.path.join(self._indir, 'update-u-boot.bin')
3492 expected = b'x' * len(U_BOOT_DATA)
3493 tools.WriteFile(fname, expected)
3495 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3497 map_fname = os.path.join(tmpdir, 'image-updated.map')
3498 self.assertTrue(os.path.exists(map_fname))
3500 shutil.rmtree(tmpdir)
3502 def testReplaceNoEntryPaths(self):
3503 """Test replacing an entry without an entry path"""
3504 self._DoReadFileRealDtb('143_replace_all.dts')
3505 image_fname = tools.GetOutputFilename('image.bin')
3506 with self.assertRaises(ValueError) as e:
3507 control.ReplaceEntries(image_fname, 'fname', None, [])
3508 self.assertIn('Must specify an entry path to read with -f',
3511 def testReplaceTooManyEntryPaths(self):
3512 """Test extracting some entries"""
3513 self._DoReadFileRealDtb('143_replace_all.dts')
3514 image_fname = tools.GetOutputFilename('image.bin')
3515 with self.assertRaises(ValueError) as e:
3516 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3517 self.assertIn('Must specify exactly one entry path to write with -f',
3520 def testPackReset16(self):
3521 """Test that an image with an x86 reset16 region can be created"""
3522 data = self._DoReadFile('144_x86_reset16.dts')
3523 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3525 def testPackReset16Spl(self):
3526 """Test that an image with an x86 reset16-spl region can be created"""
3527 data = self._DoReadFile('145_x86_reset16_spl.dts')
3528 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3530 def testPackReset16Tpl(self):
3531 """Test that an image with an x86 reset16-tpl region can be created"""
3532 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3533 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3535 def testPackIntelFit(self):
3536 """Test that an image with an Intel FIT and pointer can be created"""
3537 data = self._DoReadFile('147_intel_fit.dts')
3538 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3540 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3541 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3543 image = control.images['image']
3544 entries = image.GetEntries()
3545 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3546 self.assertEqual(expected_ptr, ptr)
3548 def testPackIntelFitMissing(self):
3549 """Test detection of a FIT pointer with not FIT region"""
3550 with self.assertRaises(ValueError) as e:
3551 self._DoReadFile('148_intel_fit_missing.dts')
3552 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3555 def _CheckSymbolsTplSection(self, dts, expected_vals):
3556 data = self._DoReadFile(dts)
3557 sym_values = struct.pack('<LQLL', *expected_vals)
3558 upto1 = 4 + len(U_BOOT_SPL_DATA)
3559 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3560 self.assertEqual(expected1, data[:upto1])
3562 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3563 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3564 self.assertEqual(expected2, data[upto1:upto2])
3566 upto3 = 0x34 + len(U_BOOT_DATA)
3567 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3568 self.assertEqual(expected3, data[upto2:upto3])
3570 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3571 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3573 def testSymbolsTplSection(self):
3574 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3575 self._SetupSplElf('u_boot_binman_syms')
3576 self._SetupTplElf('u_boot_binman_syms')
3577 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3578 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3580 def testSymbolsTplSectionX86(self):
3581 """Test binman can assign symbols in a section with end-at-4gb"""
3582 self._SetupSplElf('u_boot_binman_syms_x86')
3583 self._SetupTplElf('u_boot_binman_syms_x86')
3584 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3585 [0xffffff04, 0xffffff1c, 0xffffff34,
3588 def testPackX86RomIfwiSectiom(self):
3589 """Test that a section can be placed in an IFWI region"""
3590 self._SetupIfwi('fitimage.bin')
3591 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3592 self._CheckIfwi(data)
3594 def testPackFspM(self):
3595 """Test that an image with a FSP memory-init binary can be created"""
3596 data = self._DoReadFile('152_intel_fsp_m.dts')
3597 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3599 def testPackFspS(self):
3600 """Test that an image with a FSP silicon-init binary can be created"""
3601 data = self._DoReadFile('153_intel_fsp_s.dts')
3602 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3604 def testPackFspT(self):
3605 """Test that an image with a FSP temp-ram-init binary can be created"""
3606 data = self._DoReadFile('154_intel_fsp_t.dts')
3607 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3609 def testMkimage(self):
3610 """Test using mkimage to build an image"""
3611 data = self._DoReadFile('156_mkimage.dts')
3613 # Just check that the data appears in the file somewhere
3614 self.assertIn(U_BOOT_SPL_DATA, data)
3616 def testExtblob(self):
3617 """Test an image with an external blob"""
3618 data = self._DoReadFile('157_blob_ext.dts')
3619 self.assertEqual(REFCODE_DATA, data)
3621 def testExtblobMissing(self):
3622 """Test an image with a missing external blob"""
3623 with self.assertRaises(ValueError) as e:
3624 self._DoReadFile('158_blob_ext_missing.dts')
3625 self.assertIn("Filename 'missing-file' not found in input path",
3628 def testExtblobMissingOk(self):
3629 """Test an image with an missing external blob that is allowed"""
3630 with test_util.capture_sys_output() as (stdout, stderr):
3631 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3632 err = stderr.getvalue()
3633 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3635 def testExtblobMissingOkSect(self):
3636 """Test an image with an missing external blob that is allowed"""
3637 with test_util.capture_sys_output() as (stdout, stderr):
3638 self._DoTestFile('159_blob_ext_missing_sect.dts',
3640 err = stderr.getvalue()
3641 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3642 "blob-ext blob-ext2")
3644 def testPackX86RomMeMissingDesc(self):
3645 """Test that an missing Intel descriptor entry is allowed"""
3646 with test_util.capture_sys_output() as (stdout, stderr):
3647 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3648 err = stderr.getvalue()
3649 self.assertRegex(err,
3650 "Image 'main-section'.*missing.*: intel-descriptor")
3652 def testPackX86RomMissingIfwi(self):
3653 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3654 self._SetupIfwi('fitimage.bin')
3655 pathname = os.path.join(self._indir, 'fitimage.bin')
3657 with test_util.capture_sys_output() as (stdout, stderr):
3658 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3659 err = stderr.getvalue()
3660 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3662 def testPackOverlap(self):
3663 """Test that zero-size overlapping regions are ignored"""
3664 self._DoTestFile('160_pack_overlap_zero.dts')
3666 def testSimpleFit(self):
3667 """Test an image with a FIT inside"""
3668 data = self._DoReadFile('161_fit.dts')
3669 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3670 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3671 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3673 # The data should be inside the FIT
3674 dtb = fdt.Fdt.FromData(fit_data)
3676 fnode = dtb.GetNode('/images/kernel')
3677 self.assertIn('data', fnode.props)
3679 fname = os.path.join(self._indir, 'fit_data.fit')
3680 tools.WriteFile(fname, fit_data)
3681 out = tools.Run('dumpimage', '-l', fname)
3683 # Check a few features to make sure the plumbing works. We don't need
3684 # to test the operation of mkimage or dumpimage here. First convert the
3685 # output into a dict where the keys are the fields printed by dumpimage
3686 # and the values are a list of values for each field
3687 lines = out.splitlines()
3689 # Converts "Compression: gzip compressed" into two groups:
3690 # 'Compression' and 'gzip compressed'
3691 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3692 vals = collections.defaultdict(list)
3694 mat = re_line.match(line)
3695 vals[mat.group(1)].append(mat.group(2))
3697 self.assertEquals('FIT description: test-desc', lines[0])
3698 self.assertIn('Created:', lines[1])
3699 self.assertIn('Image 0 (kernel)', vals)
3700 self.assertIn('Hash value', vals)
3701 data_sizes = vals.get('Data Size')
3702 self.assertIsNotNone(data_sizes)
3703 self.assertEqual(2, len(data_sizes))
3704 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3705 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3706 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3708 def testFitExternal(self):
3709 """Test an image with an FIT with external images"""
3710 data = self._DoReadFile('162_fit_external.dts')
3711 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3713 # The data should be outside the FIT
3714 dtb = fdt.Fdt.FromData(fit_data)
3716 fnode = dtb.GetNode('/images/kernel')
3717 self.assertNotIn('data', fnode.props)
3719 def testSectionIgnoreHashSignature(self):
3720 """Test that sections ignore hash, signature nodes for its data"""
3721 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3722 expected = (U_BOOT_DATA + U_BOOT_DATA)
3723 self.assertEqual(expected, data)
3725 def testPadInSections(self):
3726 """Test pad-before, pad-after for entries in sections"""
3727 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3728 '166_pad_in_sections.dts', update_dtb=True)
3729 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3730 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3732 self.assertEqual(expected, data)
3734 dtb = fdt.Fdt(out_dtb_fname)
3736 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3740 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3742 'section:image-pos': 0,
3743 'section:offset': 0,
3744 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3746 'section/before:image-pos': 0,
3747 'section/before:offset': 0,
3748 'section/before:size': len(U_BOOT_DATA),
3750 'section/u-boot:image-pos': 4,
3751 'section/u-boot:offset': 4,
3752 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3754 'section/after:image-pos': 26,
3755 'section/after:offset': 26,
3756 'section/after:size': len(U_BOOT_DATA),
3758 self.assertEqual(expected, props)
3760 def testFitImageSubentryAlignment(self):
3761 """Test relative alignability of FIT image subentries"""
3763 'test-id': TEXT_DATA,
3765 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3766 entry_args=entry_args)
3767 dtb = fdt.Fdt.FromData(data)
3770 node = dtb.GetNode('/images/kernel')
3771 data = dtb.GetProps(node)["data"].bytes
3772 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3773 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3774 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3775 self.assertEqual(expected, data)
3777 node = dtb.GetNode('/images/fdt-1')
3778 data = dtb.GetProps(node)["data"].bytes
3779 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3780 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3782 self.assertEqual(expected, data)
3784 def testFitExtblobMissingOk(self):
3785 """Test a FIT with a missing external blob that is allowed"""
3786 with test_util.capture_sys_output() as (stdout, stderr):
3787 self._DoTestFile('168_fit_missing_blob.dts',
3789 err = stderr.getvalue()
3790 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3792 def testBlobNamedByArgMissing(self):
3793 """Test handling of a missing entry arg"""
3794 with self.assertRaises(ValueError) as e:
3795 self._DoReadFile('068_blob_named_by_arg.dts')
3796 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3799 def testPackBl31(self):
3800 """Test that an image with an ATF BL31 binary can be created"""
3801 data = self._DoReadFile('169_atf_bl31.dts')
3802 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3804 def testPackScp(self):
3805 """Test that an image with an SCP binary can be created"""
3806 data = self._DoReadFile('172_scp.dts')
3807 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3809 def testFitFdt(self):
3810 """Test an image with an FIT with multiple FDT images"""
3811 def _CheckFdt(seq, expected_data):
3812 """Check the FDT nodes
3815 seq: Sequence number to check (0 or 1)
3816 expected_data: Expected contents of 'data' property
3818 name = 'fdt-%d' % seq
3819 fnode = dtb.GetNode('/images/%s' % name)
3820 self.assertIsNotNone(fnode)
3821 self.assertEqual({'description','type', 'compression', 'data'},
3822 set(fnode.props.keys()))
3823 self.assertEqual(expected_data, fnode.props['data'].bytes)
3824 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3825 fnode.props['description'].value)
3827 def _CheckConfig(seq, expected_data):
3828 """Check the configuration nodes
3831 seq: Sequence number to check (0 or 1)
3832 expected_data: Expected contents of 'data' property
3834 cnode = dtb.GetNode('/configurations')
3835 self.assertIn('default', cnode.props)
3836 self.assertEqual('config-2', cnode.props['default'].value)
3838 name = 'config-%d' % seq
3839 fnode = dtb.GetNode('/configurations/%s' % name)
3840 self.assertIsNotNone(fnode)
3841 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3842 set(fnode.props.keys()))
3843 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3844 fnode.props['description'].value)
3845 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3848 'of-list': 'test-fdt1 test-fdt2',
3849 'default-dt': 'test-fdt2',
3851 data = self._DoReadFileDtb(
3853 entry_args=entry_args,
3854 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3855 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3856 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3858 dtb = fdt.Fdt.FromData(fit_data)
3860 fnode = dtb.GetNode('/images/kernel')
3861 self.assertIn('data', fnode.props)
3863 # Check all the properties in fdt-1 and fdt-2
3864 _CheckFdt(1, TEST_FDT1_DATA)
3865 _CheckFdt(2, TEST_FDT2_DATA)
3867 # Check configurations
3868 _CheckConfig(1, TEST_FDT1_DATA)
3869 _CheckConfig(2, TEST_FDT2_DATA)
3871 def testFitFdtMissingList(self):
3872 """Test handling of a missing 'of-list' entry arg"""
3873 with self.assertRaises(ValueError) as e:
3874 self._DoReadFile('170_fit_fdt.dts')
3875 self.assertIn("Generator node requires 'of-list' entry argument",
3878 def testFitFdtEmptyList(self):
3879 """Test handling of an empty 'of-list' entry arg"""
3883 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3885 def testFitFdtMissingProp(self):
3886 """Test handling of a missing 'fit,fdt-list' property"""
3887 with self.assertRaises(ValueError) as e:
3888 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3889 self.assertIn("Generator node requires 'fit,fdt-list' property",
3892 def testFitFdtEmptyList(self):
3893 """Test handling of an empty 'of-list' entry arg"""
3897 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3899 def testFitFdtMissing(self):
3900 """Test handling of a missing 'default-dt' entry arg"""
3902 'of-list': 'test-fdt1 test-fdt2',
3904 with self.assertRaises(ValueError) as e:
3905 self._DoReadFileDtb(
3907 entry_args=entry_args,
3908 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3909 self.assertIn("Generated 'default' node requires default-dt entry argument",
3912 def testFitFdtNotInList(self):
3913 """Test handling of a default-dt that is not in the of-list"""
3915 'of-list': 'test-fdt1 test-fdt2',
3916 'default-dt': 'test-fdt3',
3918 with self.assertRaises(ValueError) as e:
3919 self._DoReadFileDtb(
3921 entry_args=entry_args,
3922 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3923 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3926 def testFitExtblobMissingHelp(self):
3927 """Test display of help messages when an external blob is missing"""
3928 control.missing_blob_help = control._ReadMissingBlobHelp()
3929 control.missing_blob_help['wibble'] = 'Wibble test'
3930 control.missing_blob_help['another'] = 'Another test'
3931 with test_util.capture_sys_output() as (stdout, stderr):
3932 self._DoTestFile('168_fit_missing_blob.dts',
3934 err = stderr.getvalue()
3936 # We can get the tag from the name, the type or the missing-msg
3937 # property. Check all three.
3938 self.assertIn('You may need to build ARM Trusted', err)
3939 self.assertIn('Wibble test', err)
3940 self.assertIn('Another test', err)
3942 def testMissingBlob(self):
3943 """Test handling of a blob containing a missing file"""
3944 with self.assertRaises(ValueError) as e:
3945 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3946 self.assertIn("Filename 'missing' not found in input path",
3949 def testEnvironment(self):
3950 """Test adding a U-Boot environment"""
3951 data = self._DoReadFile('174_env.dts')
3952 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3953 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3954 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3955 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3958 def testEnvironmentNoSize(self):
3959 """Test that a missing 'size' property is detected"""
3960 with self.assertRaises(ValueError) as e:
3961 self._DoTestFile('175_env_no_size.dts')
3962 self.assertIn("'u-boot-env' entry must have a size property",
3965 def testEnvironmentTooSmall(self):
3966 """Test handling of an environment that does not fit"""
3967 with self.assertRaises(ValueError) as e:
3968 self._DoTestFile('176_env_too_small.dts')
3970 # checksum, start byte, environment with \0 terminator, final \0
3971 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3973 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3976 def testSkipAtStart(self):
3977 """Test handling of skip-at-start section"""
3978 data = self._DoReadFile('177_skip_at_start.dts')
3979 self.assertEqual(U_BOOT_DATA, data)
3981 image = control.images['image']
3982 entries = image.GetEntries()
3983 section = entries['section']
3984 self.assertEqual(0, section.offset)
3985 self.assertEqual(len(U_BOOT_DATA), section.size)
3986 self.assertEqual(U_BOOT_DATA, section.GetData())
3988 entry = section.GetEntries()['u-boot']
3989 self.assertEqual(16, entry.offset)
3990 self.assertEqual(len(U_BOOT_DATA), entry.size)
3991 self.assertEqual(U_BOOT_DATA, entry.data)
3993 def testSkipAtStartPad(self):
3994 """Test handling of skip-at-start section with padded entry"""
3995 data = self._DoReadFile('178_skip_at_start_pad.dts')
3996 before = tools.GetBytes(0, 8)
3997 after = tools.GetBytes(0, 4)
3998 all = before + U_BOOT_DATA + after
3999 self.assertEqual(all, data)
4001 image = control.images['image']
4002 entries = image.GetEntries()
4003 section = entries['section']
4004 self.assertEqual(0, section.offset)
4005 self.assertEqual(len(all), section.size)
4006 self.assertEqual(all, section.GetData())
4008 entry = section.GetEntries()['u-boot']
4009 self.assertEqual(16, entry.offset)
4010 self.assertEqual(len(all), entry.size)
4011 self.assertEqual(U_BOOT_DATA, entry.data)
4013 def testSkipAtStartSectionPad(self):
4014 """Test handling of skip-at-start section with padding"""
4015 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4016 before = tools.GetBytes(0, 8)
4017 after = tools.GetBytes(0, 4)
4018 all = before + U_BOOT_DATA + after
4019 self.assertEqual(all, data)
4021 image = control.images['image']
4022 entries = image.GetEntries()
4023 section = entries['section']
4024 self.assertEqual(0, section.offset)
4025 self.assertEqual(len(all), section.size)
4026 self.assertEqual(U_BOOT_DATA, section.data)
4027 self.assertEqual(all, section.GetPaddedData())
4029 entry = section.GetEntries()['u-boot']
4030 self.assertEqual(16, entry.offset)
4031 self.assertEqual(len(U_BOOT_DATA), entry.size)
4032 self.assertEqual(U_BOOT_DATA, entry.data)
4034 def testSectionPad(self):
4035 """Testing padding with sections"""
4036 data = self._DoReadFile('180_section_pad.dts')
4037 expected = (tools.GetBytes(ord('&'), 3) +
4038 tools.GetBytes(ord('!'), 5) +
4040 tools.GetBytes(ord('!'), 1) +
4041 tools.GetBytes(ord('&'), 2))
4042 self.assertEqual(expected, data)
4044 def testSectionAlign(self):
4045 """Testing alignment with sections"""
4046 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4047 expected = (b'\0' + # fill section
4048 tools.GetBytes(ord('&'), 1) + # padding to section align
4049 b'\0' + # fill section
4050 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4052 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4053 tools.GetBytes(ord('!'), 4)) # padding to section size
4054 self.assertEqual(expected, data)
4056 def testCompressImage(self):
4057 """Test compression of the entire image"""
4059 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4060 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4061 dtb = fdt.Fdt(out_dtb_fname)
4063 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4065 orig = self._decompress(data)
4066 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4068 # Do a sanity check on various fields
4069 image = control.images['image']
4070 entries = image.GetEntries()
4071 self.assertEqual(2, len(entries))
4073 entry = entries['blob']
4074 self.assertEqual(COMPRESS_DATA, entry.data)
4075 self.assertEqual(len(COMPRESS_DATA), entry.size)
4077 entry = entries['u-boot']
4078 self.assertEqual(U_BOOT_DATA, entry.data)
4079 self.assertEqual(len(U_BOOT_DATA), entry.size)
4081 self.assertEqual(len(data), image.size)
4082 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4083 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4084 orig = self._decompress(image.data)
4085 self.assertEqual(orig, image.uncomp_data)
4089 'blob:size': len(COMPRESS_DATA),
4090 'u-boot:offset': len(COMPRESS_DATA),
4091 'u-boot:size': len(U_BOOT_DATA),
4092 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4097 self.assertEqual(expected, props)
4099 def testCompressImageLess(self):
4100 """Test compression where compression reduces the image size"""
4102 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4103 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4104 dtb = fdt.Fdt(out_dtb_fname)
4106 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4108 orig = self._decompress(data)
4110 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4112 # Do a sanity check on various fields
4113 image = control.images['image']
4114 entries = image.GetEntries()
4115 self.assertEqual(2, len(entries))
4117 entry = entries['blob']
4118 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4119 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4121 entry = entries['u-boot']
4122 self.assertEqual(U_BOOT_DATA, entry.data)
4123 self.assertEqual(len(U_BOOT_DATA), entry.size)
4125 self.assertEqual(len(data), image.size)
4126 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4127 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4129 orig = self._decompress(image.data)
4130 self.assertEqual(orig, image.uncomp_data)
4134 'blob:size': len(COMPRESS_DATA_BIG),
4135 'u-boot:offset': len(COMPRESS_DATA_BIG),
4136 'u-boot:size': len(U_BOOT_DATA),
4137 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4142 self.assertEqual(expected, props)
4144 def testCompressSectionSize(self):
4145 """Test compression of a section with a fixed size"""
4147 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4148 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4149 dtb = fdt.Fdt(out_dtb_fname)
4151 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4153 orig = self._decompress(data)
4154 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4156 'section/blob:offset': 0,
4157 'section/blob:size': len(COMPRESS_DATA),
4158 'section/u-boot:offset': len(COMPRESS_DATA),
4159 'section/u-boot:size': len(U_BOOT_DATA),
4160 'section:offset': 0,
4161 'section:image-pos': 0,
4162 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4163 'section:size': 0x30,
4168 self.assertEqual(expected, props)
4170 def testCompressSection(self):
4171 """Test compression of a section with no fixed size"""
4173 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4174 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4175 dtb = fdt.Fdt(out_dtb_fname)
4177 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4179 orig = self._decompress(data)
4180 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4182 'section/blob:offset': 0,
4183 'section/blob:size': len(COMPRESS_DATA),
4184 'section/u-boot:offset': len(COMPRESS_DATA),
4185 'section/u-boot:size': len(U_BOOT_DATA),
4186 'section:offset': 0,
4187 'section:image-pos': 0,
4188 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4189 'section:size': len(data),
4194 self.assertEqual(expected, props)
4196 def testCompressExtra(self):
4197 """Test compression of a section with no fixed size"""
4199 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4200 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4201 dtb = fdt.Fdt(out_dtb_fname)
4203 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4206 base = data[len(U_BOOT_DATA):]
4207 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4208 rest = base[len(U_BOOT_DATA):]
4210 # Check compressed data
4211 section1 = self._decompress(rest)
4212 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4213 self.assertEquals(expect1, rest[:len(expect1)])
4214 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4215 rest1 = rest[len(expect1):]
4217 section2 = self._decompress(rest1)
4218 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4219 self.assertEquals(expect2, rest1[:len(expect2)])
4220 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4221 rest2 = rest1[len(expect2):]
4223 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4224 len(expect2) + len(U_BOOT_DATA))
4225 #self.assertEquals(expect_size, len(data))
4227 #self.assertEquals(U_BOOT_DATA, rest2)
4232 'u-boot:image-pos': 0,
4233 'u-boot:size': len(U_BOOT_DATA),
4235 'base:offset': len(U_BOOT_DATA),
4236 'base:image-pos': len(U_BOOT_DATA),
4237 'base:size': len(data) - len(U_BOOT_DATA),
4238 'base/u-boot:offset': 0,
4239 'base/u-boot:image-pos': len(U_BOOT_DATA),
4240 'base/u-boot:size': len(U_BOOT_DATA),
4241 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4243 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4245 'base/u-boot2:size': len(U_BOOT_DATA),
4247 'base/section:offset': len(U_BOOT_DATA),
4248 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4249 'base/section:size': len(expect1),
4250 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4251 'base/section/blob:offset': 0,
4252 'base/section/blob:size': len(COMPRESS_DATA),
4253 'base/section/u-boot:offset': len(COMPRESS_DATA),
4254 'base/section/u-boot:size': len(U_BOOT_DATA),
4256 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4257 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4258 'base/section2:size': len(expect2),
4259 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4260 'base/section2/blob:offset': 0,
4261 'base/section2/blob:size': len(COMPRESS_DATA),
4262 'base/section2/blob2:offset': len(COMPRESS_DATA),
4263 'base/section2/blob2:size': len(COMPRESS_DATA),
4269 self.assertEqual(expected, props)
4271 def testSymbolsSubsection(self):
4272 """Test binman can assign symbols from a subsection"""
4273 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4275 def testReadImageEntryArg(self):
4276 """Test reading an image that would need an entry arg to generate"""
4278 'cros-ec-rw-path': 'ecrw.bin',
4280 data = self.data = self._DoReadFileDtb(
4281 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4282 entry_args=entry_args)
4284 image_fname = tools.GetOutputFilename('image.bin')
4285 orig_image = control.images['image']
4287 # This should not generate an error about the missing 'cros-ec-rw-path'
4288 # since we are reading the image from a file. Compare with
4289 # testEntryArgsRequired()
4290 image = Image.FromFile(image_fname)
4291 self.assertEqual(orig_image.GetEntries().keys(),
4292 image.GetEntries().keys())
4294 def testFilesAlign(self):
4295 """Test alignment with files"""
4296 data = self._DoReadFile('190_files_align.dts')
4298 # The first string is 15 bytes so will align to 16
4299 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4300 self.assertEqual(expect, data)
4302 def testReadImageSkip(self):
4303 """Test reading an image and accessing its FDT map"""
4304 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4305 image_fname = tools.GetOutputFilename('image.bin')
4306 orig_image = control.images['image']
4307 image = Image.FromFile(image_fname)
4308 self.assertEqual(orig_image.GetEntries().keys(),
4309 image.GetEntries().keys())
4311 orig_entry = orig_image.GetEntries()['fdtmap']
4312 entry = image.GetEntries()['fdtmap']
4313 self.assertEqual(orig_entry.offset, entry.offset)
4314 self.assertEqual(orig_entry.size, entry.size)
4315 self.assertEqual(16, entry.image_pos)
4317 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4319 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4321 def testTplNoDtb(self):
4322 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4324 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4325 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4326 data[:len(U_BOOT_TPL_NODTB_DATA)])
4328 def testTplBssPad(self):
4329 """Test that we can pad TPL's BSS with zeros"""
4330 # ELF file with a '__bss_size' symbol
4332 data = self._DoReadFile('193_tpl_bss_pad.dts')
4333 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4336 def testTplBssPadMissing(self):
4337 """Test that a missing symbol is detected"""
4338 self._SetupTplElf('u_boot_ucode_ptr')
4339 with self.assertRaises(ValueError) as e:
4340 self._DoReadFile('193_tpl_bss_pad.dts')
4341 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4344 def checkDtbSizes(self, data, pad_len, start):
4345 """Check the size arguments in a dtb embedded in an image
4348 data: The image data
4349 pad_len: Length of the pad section in the image, in bytes
4350 start: Start offset of the devicetree to examine, within the image
4353 Size of the devicetree in bytes
4355 dtb_data = data[start:]
4356 dtb = fdt.Fdt.FromData(dtb_data)
4357 fdt_size = dtb.GetFdtObj().totalsize()
4359 props = self._GetPropTree(dtb, 'size')
4362 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4363 'u-boot-spl/u-boot-spl-dtb:size': 801,
4364 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4365 'u-boot-spl:size': 860,
4366 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4367 'u-boot/u-boot-dtb:size': 781,
4368 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4373 def testExpanded(self):
4374 """Test that an expanded entry type is selected when needed"""
4378 # SPL has a devicetree, TPL does not
4384 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4385 entry_args=entry_args)
4386 image = control.images['image']
4387 entries = image.GetEntries()
4388 self.assertEqual(3, len(entries))
4390 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4391 self.assertIn('u-boot', entries)
4392 entry = entries['u-boot']
4393 self.assertEqual('u-boot-expanded', entry.etype)
4394 subent = entry.GetEntries()
4395 self.assertEqual(2, len(subent))
4396 self.assertIn('u-boot-nodtb', subent)
4397 self.assertIn('u-boot-dtb', subent)
4399 # Second, u-boot-spl, which should be expanded into three parts
4400 self.assertIn('u-boot-spl', entries)
4401 entry = entries['u-boot-spl']
4402 self.assertEqual('u-boot-spl-expanded', entry.etype)
4403 subent = entry.GetEntries()
4404 self.assertEqual(3, len(subent))
4405 self.assertIn('u-boot-spl-nodtb', subent)
4406 self.assertIn('u-boot-spl-bss-pad', subent)
4407 self.assertIn('u-boot-spl-dtb', subent)
4409 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4411 self.assertIn('u-boot-tpl', entries)
4412 entry = entries['u-boot-tpl']
4413 self.assertEqual('u-boot-tpl', entry.etype)
4414 self.assertEqual(None, entry.GetEntries())
4416 def testExpandedTpl(self):
4417 """Test that an expanded entry type is selected for TPL when needed"""
4424 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4425 entry_args=entry_args)
4426 image = control.images['image']
4427 entries = image.GetEntries()
4428 self.assertEqual(1, len(entries))
4430 # We only have u-boot-tpl, which be expanded
4431 self.assertIn('u-boot-tpl', entries)
4432 entry = entries['u-boot-tpl']
4433 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4434 subent = entry.GetEntries()
4435 self.assertEqual(3, len(subent))
4436 self.assertIn('u-boot-tpl-nodtb', subent)
4437 self.assertIn('u-boot-tpl-bss-pad', subent)
4438 self.assertIn('u-boot-tpl-dtb', subent)
4440 def testExpandedNoPad(self):
4441 """Test an expanded entry without BSS pad enabled"""
4445 # SPL has a devicetree, TPL does not
4447 'spl-dtb': 'something',
4451 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4452 entry_args=entry_args)
4453 image = control.images['image']
4454 entries = image.GetEntries()
4456 # Just check u-boot-spl, which should be expanded into two parts
4457 self.assertIn('u-boot-spl', entries)
4458 entry = entries['u-boot-spl']
4459 self.assertEqual('u-boot-spl-expanded', entry.etype)
4460 subent = entry.GetEntries()
4461 self.assertEqual(2, len(subent))
4462 self.assertIn('u-boot-spl-nodtb', subent)
4463 self.assertIn('u-boot-spl-dtb', subent)
4465 def testExpandedTplNoPad(self):
4466 """Test that an expanded entry type with padding disabled in TPL"""
4473 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4474 entry_args=entry_args)
4475 image = control.images['image']
4476 entries = image.GetEntries()
4477 self.assertEqual(1, len(entries))
4479 # We only have u-boot-tpl, which be expanded
4480 self.assertIn('u-boot-tpl', entries)
4481 entry = entries['u-boot-tpl']
4482 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4483 subent = entry.GetEntries()
4484 self.assertEqual(2, len(subent))
4485 self.assertIn('u-boot-tpl-nodtb', subent)
4486 self.assertIn('u-boot-tpl-dtb', subent)
4488 def testFdtInclude(self):
4489 """Test that an Fdt is update within all binaries"""
4493 # SPL has a devicetree, TPL does not
4500 # Build the image. It includes two separate devicetree binaries, each
4501 # with their own contents, but all contain the binman definition.
4502 data = self._DoReadFileDtb(
4503 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4504 update_dtb=True, entry_args=entry_args)[0]
4507 # Check the U-Boot dtb
4508 start = len(U_BOOT_NODTB_DATA)
4509 fdt_size = self.checkDtbSizes(data, pad_len, start)
4512 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4513 fdt_size = self.checkDtbSizes(data, pad_len, start)
4515 # TPL has no devicetree
4516 start += fdt_size + len(U_BOOT_TPL_DATA)
4517 self.assertEqual(len(data), start)
4519 def testSymbolsExpanded(self):
4520 """Test binman can assign symbols in expanded entries"""
4524 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4525 U_BOOT_SPL_DTB_DATA, 0x38,
4526 entry_args=entry_args, use_expanded=True)
4528 def testCollection(self):
4529 """Test a collection"""
4530 data = self._DoReadFile('198_collection.dts')
4531 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4532 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4533 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4536 def testCollectionSection(self):
4537 """Test a collection where a section must be built first"""
4538 # Sections never have their contents when GetData() is called, but when
4539 # _BuildSectionData() is called with required=True, a section will force
4540 # building the contents, producing an error is anything is still
4542 data = self._DoReadFile('199_collection_section.dts')
4543 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4544 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4545 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4548 def testAlignDefault(self):
4549 """Test that default alignment works on sections"""
4550 data = self._DoReadFile('200_align_default.dts')
4551 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4553 # Special alignment for section
4554 expected += tools.GetBytes(0, 32 - len(expected))
4555 # No alignment within the nested section
4556 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4557 # Now the final piece, which should be default-aligned
4558 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4559 self.assertEqual(expected, data)
4561 def testPackOpenSBI(self):
4562 """Test that an image with an OpenSBI binary can be created"""
4563 data = self._DoReadFile('201_opensbi.dts')
4564 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4566 def testSectionsSingleThread(self):
4567 """Test sections without multithreading"""
4568 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4569 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4570 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4571 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4572 self.assertEqual(expected, data)
4574 def testThreadTimeout(self):
4575 """Test handling a thread that takes too long"""
4576 with self.assertRaises(ValueError) as e:
4577 self._DoTestFile('202_section_timeout.dts',
4578 test_section_timeout=True)
4579 self.assertIn("Timed out obtaining contents", str(e.exception))
4581 def testTiming(self):
4582 """Test output of timing information"""
4583 data = self._DoReadFile('055_sections.dts')
4584 with test_util.capture_sys_output() as (stdout, stderr):
4586 self.assertIn('read:', stdout.getvalue())
4587 self.assertIn('compress:', stdout.getvalue())
4589 def testUpdateFdtInElf(self):
4590 """Test that we can update the devicetree in an ELF file"""
4591 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4592 outfile = os.path.join(self._indir, 'u-boot.out')
4593 begin_sym = 'dtb_embed_begin'
4594 end_sym = 'dtb_embed_end'
4595 retcode = self._DoTestFile(
4596 '060_fdt_update.dts', update_dtb=True,
4597 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4598 self.assertEqual(0, retcode)
4600 # Check that the output file does in fact contact a dtb with the binman
4601 # definition in the correct place
4602 syms = elf.GetSymbolFileOffset(infile,
4603 ['dtb_embed_begin', 'dtb_embed_end'])
4604 data = tools.ReadFile(outfile)
4605 dtb_data = data[syms['dtb_embed_begin'].offset:
4606 syms['dtb_embed_end'].offset]
4608 dtb = fdt.Fdt.FromData(dtb_data)
4610 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4614 '_testing:offset': 32,
4616 '_testing:image-pos': 32,
4617 'section@0/u-boot:offset': 0,
4618 'section@0/u-boot:size': len(U_BOOT_DATA),
4619 'section@0/u-boot:image-pos': 0,
4620 'section@0:offset': 0,
4621 'section@0:size': 16,
4622 'section@0:image-pos': 0,
4624 'section@1/u-boot:offset': 0,
4625 'section@1/u-boot:size': len(U_BOOT_DATA),
4626 'section@1/u-boot:image-pos': 16,
4627 'section@1:offset': 16,
4628 'section@1:size': 16,
4629 'section@1:image-pos': 16,
4633 def testUpdateFdtInElfInvalid(self):
4634 """Test that invalid args are detected with --update-fdt-in-elf"""
4635 with self.assertRaises(ValueError) as e:
4636 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4637 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4640 def testUpdateFdtInElfNoSyms(self):
4641 """Test that missing symbols are detected with --update-fdt-in-elf"""
4642 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4644 begin_sym = 'wrong_begin'
4645 end_sym = 'wrong_end'
4646 with self.assertRaises(ValueError) as e:
4648 '060_fdt_update.dts',
4649 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4650 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4653 def testUpdateFdtInElfTooSmall(self):
4654 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4655 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4656 outfile = os.path.join(self._indir, 'u-boot.out')
4657 begin_sym = 'dtb_embed_begin'
4658 end_sym = 'dtb_embed_end'
4659 with self.assertRaises(ValueError) as e:
4661 '060_fdt_update.dts', update_dtb=True,
4662 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4665 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4667 def testFakeBlob(self):
4668 """Test handling of faking an external blob"""
4669 with test_util.capture_sys_output() as (stdout, stderr):
4670 self._DoTestFile('203_fake_blob.dts', allow_missing=True,
4671 allow_fake_blobs=True)
4672 err = stderr.getvalue()
4673 self.assertRegex(err,
4674 "Image '.*' has faked external blobs and is non-functional: .*")
4675 os.remove('binman_faking_test_blob')
4678 if __name__ == "__main__":