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 extra_indirs=None, threads=None,
312 test_section_timeout=False):
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 extra_indirs: Extra input directories to add using -I
335 threads: Number of threads to use (None for default, 0 for
337 test_section_timeout: True to force the first time to timeout, as
338 used in testThreadTimeout()
341 int return code, 0 on success
346 if verbosity is not None:
347 args.append('-v%d' % verbosity)
349 args.append('-v%d' % self.verbosity)
351 for path in self.toolpath:
352 args += ['--toolpath', path]
353 if threads is not None:
354 args.append('-T%d' % threads)
355 if test_section_timeout:
356 args.append('--test-section-timeout')
357 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
363 args.append('--fake-dtb')
365 args.append('--no-expanded')
367 for arg, value in entry_args.items():
368 args.append('-a%s=%s' % (arg, value))
373 args += ['-i', image]
375 for indir in extra_indirs:
376 args += ['-I', indir]
377 return self._DoBinman(*args)
379 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
380 """Set up a new test device-tree file
382 The given file is compiled and set up as the device tree to be used
386 fname: Filename of .dts file to read
387 outfile: Output filename for compiled device-tree binary
390 Contents of device-tree binary
392 tmpdir = tempfile.mkdtemp(prefix='binmant.')
393 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
394 with open(dtb, 'rb') as fd:
396 TestFunctional._MakeInputFile(outfile, data)
397 shutil.rmtree(tmpdir)
400 def _GetDtbContentsForSplTpl(self, dtb_data, name):
401 """Create a version of the main DTB for SPL or SPL
403 For testing we don't actually have different versions of the DTB. With
404 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
405 we don't normally have any unwanted nodes.
407 We still want the DTBs for SPL and TPL to be different though, since
408 otherwise it is confusing to know which one we are looking at. So add
409 an 'spl' or 'tpl' property to the top-level node.
412 dtb_data: dtb data to modify (this should be a value devicetree)
413 name: Name of a new property to add
416 New dtb data with the property added
418 dtb = fdt.Fdt.FromData(dtb_data)
420 dtb.GetNode('/binman').AddZeroProp(name)
421 dtb.Sync(auto_resize=True)
423 return dtb.GetContents()
425 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
426 map=False, update_dtb=False, entry_args=None,
427 reset_dtbs=True, extra_indirs=None, threads=None):
428 """Run binman and return the resulting image
430 This runs binman with a given test file and then reads the resulting
431 output file. It is a shortcut function since most tests need to do
434 Raises an assertion failure if binman returns a non-zero exit code.
437 fname: Device-tree source filename to use (e.g. 005_simple.dts)
438 use_real_dtb: True to use the test file as the contents of
439 the u-boot-dtb entry. Normally this is not needed and the
440 test contents (the U_BOOT_DTB_DATA string) can be used.
441 But in some test we need the real contents.
442 use_expanded: True to use expanded entries where available, e.g.
443 'u-boot-expanded' instead of 'u-boot'
444 map: True to output map files for the images
445 update_dtb: Update the offset and size of each entry in the device
446 tree before packing it into the image
447 entry_args: Dict of entry args to supply to binman
449 value: value of that arg
450 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
451 function. If reset_dtbs is True, then the original test dtb
452 is written back before this function finishes
453 extra_indirs: Extra input directories to add using -I
454 threads: Number of threads to use (None for default, 0 for
459 Resulting image contents
461 Map data showing contents of image (or None if none)
462 Output device tree binary filename ('u-boot.dtb' path)
465 # Use the compiled test file as the u-boot-dtb input
467 dtb_data = self._SetupDtb(fname)
469 # For testing purposes, make a copy of the DT for SPL and TPL. Add
470 # a node indicating which it is, so aid verification.
471 for name in ['spl', 'tpl']:
472 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
473 outfile = os.path.join(self._indir, dtb_fname)
474 TestFunctional._MakeInputFile(dtb_fname,
475 self._GetDtbContentsForSplTpl(dtb_data, name))
478 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
479 entry_args=entry_args, use_real_dtb=use_real_dtb,
480 use_expanded=use_expanded, extra_indirs=extra_indirs,
482 self.assertEqual(0, retcode)
483 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
485 # Find the (only) image, read it and return its contents
486 image = control.images['image']
487 image_fname = tools.GetOutputFilename('image.bin')
488 self.assertTrue(os.path.exists(image_fname))
490 map_fname = tools.GetOutputFilename('image.map')
491 with open(map_fname) as fd:
495 with open(image_fname, 'rb') as fd:
496 return fd.read(), dtb_data, map_data, out_dtb_fname
498 # Put the test file back
499 if reset_dtbs and use_real_dtb:
502 def _DoReadFileRealDtb(self, fname):
503 """Run binman with a real .dtb file and return the resulting data
506 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
509 Resulting image contents
511 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
513 def _DoReadFile(self, fname, use_real_dtb=False):
514 """Helper function which discards the device-tree binary
517 fname: Device-tree source filename to use (e.g. 005_simple.dts)
518 use_real_dtb: True to use the test file as the contents of
519 the u-boot-dtb entry. Normally this is not needed and the
520 test contents (the U_BOOT_DTB_DATA string) can be used.
521 But in some test we need the real contents.
524 Resulting image contents
526 return self._DoReadFileDtb(fname, use_real_dtb)[0]
529 def _MakeInputFile(cls, fname, contents):
530 """Create a new test input file, creating directories as needed
533 fname: Filename to create
534 contents: File contents to write in to the file
536 Full pathname of file created
538 pathname = os.path.join(cls._indir, fname)
539 dirname = os.path.dirname(pathname)
540 if dirname and not os.path.exists(dirname):
542 with open(pathname, 'wb') as fd:
547 def _MakeInputDir(cls, dirname):
548 """Create a new test input directory, creating directories as needed
551 dirname: Directory name to create
554 Full pathname of directory created
556 pathname = os.path.join(cls._indir, dirname)
557 if not os.path.exists(pathname):
558 os.makedirs(pathname)
562 def _SetupSplElf(cls, src_fname='bss_data'):
563 """Set up an ELF file with a '_dt_ucode_base_size' symbol
566 Filename of ELF file to use as SPL
568 TestFunctional._MakeInputFile('spl/u-boot-spl',
569 tools.ReadFile(cls.ElfTestFile(src_fname)))
572 def _SetupTplElf(cls, src_fname='bss_data'):
573 """Set up an ELF file with a '_dt_ucode_base_size' symbol
576 Filename of ELF file to use as TPL
578 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
579 tools.ReadFile(cls.ElfTestFile(src_fname)))
582 def _SetupDescriptor(cls):
583 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
584 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
587 def TestFile(cls, fname):
588 return os.path.join(cls._binman_dir, 'test', fname)
591 def ElfTestFile(cls, fname):
592 return os.path.join(cls._elf_testdir, fname)
594 def AssertInList(self, grep_list, target):
595 """Assert that at least one of a list of things is in a target
598 grep_list: List of strings to check
599 target: Target string
601 for grep in grep_list:
604 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
606 def CheckNoGaps(self, entries):
607 """Check that all entries fit together without gaps
610 entries: List of entries to check
613 for entry in entries.values():
614 self.assertEqual(offset, entry.offset)
617 def GetFdtLen(self, dtb):
618 """Get the totalsize field from a device-tree binary
621 dtb: Device-tree binary contents
624 Total size of device-tree binary, from the header
626 return struct.unpack('>L', dtb[4:8])[0]
628 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
629 def AddNode(node, path):
631 path += '/' + node.name
632 for prop in node.props.values():
633 if prop.name in prop_names:
634 prop_path = path + ':' + prop.name
635 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
637 for subnode in node.subnodes:
638 AddNode(subnode, path)
641 AddNode(dtb.GetRoot(), '')
645 """Test a basic run with valid args"""
646 result = self._RunBinman('-h')
648 def testFullHelp(self):
649 """Test that the full help is displayed with -H"""
650 result = self._RunBinman('-H')
651 help_file = os.path.join(self._binman_dir, 'README.rst')
652 # Remove possible extraneous strings
653 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
654 gothelp = result.stdout.replace(extra, '')
655 self.assertEqual(len(gothelp), os.path.getsize(help_file))
656 self.assertEqual(0, len(result.stderr))
657 self.assertEqual(0, result.return_code)
659 def testFullHelpInternal(self):
660 """Test that the full help is displayed with -H"""
662 command.test_result = command.CommandResult()
663 result = self._DoBinman('-H')
664 help_file = os.path.join(self._binman_dir, 'README.rst')
666 command.test_result = None
669 """Test that the basic help is displayed with -h"""
670 result = self._RunBinman('-h')
671 self.assertTrue(len(result.stdout) > 200)
672 self.assertEqual(0, len(result.stderr))
673 self.assertEqual(0, result.return_code)
676 """Test that we can run it with a specific board"""
677 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
678 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
679 result = self._DoBinman('build', '-n', '-b', 'sandbox')
680 self.assertEqual(0, result)
682 def testNeedBoard(self):
683 """Test that we get an error when no board ius supplied"""
684 with self.assertRaises(ValueError) as e:
685 result = self._DoBinman('build')
686 self.assertIn("Must provide a board to process (use -b <board>)",
689 def testMissingDt(self):
690 """Test that an invalid device-tree file generates an error"""
691 with self.assertRaises(Exception) as e:
692 self._RunBinman('build', '-d', 'missing_file')
693 # We get one error from libfdt, and a different one from fdtget.
694 self.AssertInList(["Couldn't open blob from 'missing_file'",
695 'No such file or directory'], str(e.exception))
697 def testBrokenDt(self):
698 """Test that an invalid device-tree source file generates an error
700 Since this is a source file it should be compiled and the error
701 will come from the device-tree compiler (dtc).
703 with self.assertRaises(Exception) as e:
704 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
705 self.assertIn("FATAL ERROR: Unable to parse input tree",
708 def testMissingNode(self):
709 """Test that a device tree without a 'binman' node generates an error"""
710 with self.assertRaises(Exception) as e:
711 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
712 self.assertIn("does not have a 'binman' node", str(e.exception))
715 """Test that an empty binman node works OK (i.e. does nothing)"""
716 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
717 self.assertEqual(0, len(result.stderr))
718 self.assertEqual(0, result.return_code)
720 def testInvalidEntry(self):
721 """Test that an invalid entry is flagged"""
722 with self.assertRaises(Exception) as e:
723 result = self._RunBinman('build', '-d',
724 self.TestFile('004_invalid_entry.dts'))
725 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
726 "'/binman/not-a-valid-type'", str(e.exception))
728 def testSimple(self):
729 """Test a simple binman with a single file"""
730 data = self._DoReadFile('005_simple.dts')
731 self.assertEqual(U_BOOT_DATA, data)
733 def testSimpleDebug(self):
734 """Test a simple binman run with debugging enabled"""
735 self._DoTestFile('005_simple.dts', debug=True)
738 """Test that we can handle creating two images
740 This also tests image padding.
742 retcode = self._DoTestFile('006_dual_image.dts')
743 self.assertEqual(0, retcode)
745 image = control.images['image1']
746 self.assertEqual(len(U_BOOT_DATA), image.size)
747 fname = tools.GetOutputFilename('image1.bin')
748 self.assertTrue(os.path.exists(fname))
749 with open(fname, 'rb') as fd:
751 self.assertEqual(U_BOOT_DATA, data)
753 image = control.images['image2']
754 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
755 fname = tools.GetOutputFilename('image2.bin')
756 self.assertTrue(os.path.exists(fname))
757 with open(fname, 'rb') as fd:
759 self.assertEqual(U_BOOT_DATA, data[3:7])
760 self.assertEqual(tools.GetBytes(0, 3), data[:3])
761 self.assertEqual(tools.GetBytes(0, 5), data[7:])
763 def testBadAlign(self):
764 """Test that an invalid alignment value is detected"""
765 with self.assertRaises(ValueError) as e:
766 self._DoTestFile('007_bad_align.dts')
767 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
768 "of two", str(e.exception))
770 def testPackSimple(self):
771 """Test that packing works as expected"""
772 retcode = self._DoTestFile('008_pack.dts')
773 self.assertEqual(0, retcode)
774 self.assertIn('image', control.images)
775 image = control.images['image']
776 entries = image.GetEntries()
777 self.assertEqual(5, len(entries))
780 self.assertIn('u-boot', entries)
781 entry = entries['u-boot']
782 self.assertEqual(0, entry.offset)
783 self.assertEqual(len(U_BOOT_DATA), entry.size)
785 # Second u-boot, aligned to 16-byte boundary
786 self.assertIn('u-boot-align', entries)
787 entry = entries['u-boot-align']
788 self.assertEqual(16, entry.offset)
789 self.assertEqual(len(U_BOOT_DATA), entry.size)
791 # Third u-boot, size 23 bytes
792 self.assertIn('u-boot-size', entries)
793 entry = entries['u-boot-size']
794 self.assertEqual(20, entry.offset)
795 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
796 self.assertEqual(23, entry.size)
798 # Fourth u-boot, placed immediate after the above
799 self.assertIn('u-boot-next', entries)
800 entry = entries['u-boot-next']
801 self.assertEqual(43, entry.offset)
802 self.assertEqual(len(U_BOOT_DATA), entry.size)
804 # Fifth u-boot, placed at a fixed offset
805 self.assertIn('u-boot-fixed', entries)
806 entry = entries['u-boot-fixed']
807 self.assertEqual(61, entry.offset)
808 self.assertEqual(len(U_BOOT_DATA), entry.size)
810 self.assertEqual(65, image.size)
812 def testPackExtra(self):
813 """Test that extra packing feature works as expected"""
814 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
817 self.assertIn('image', control.images)
818 image = control.images['image']
819 entries = image.GetEntries()
820 self.assertEqual(5, len(entries))
822 # First u-boot with padding before and after
823 self.assertIn('u-boot', entries)
824 entry = entries['u-boot']
825 self.assertEqual(0, entry.offset)
826 self.assertEqual(3, entry.pad_before)
827 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
828 self.assertEqual(U_BOOT_DATA, entry.data)
829 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
830 tools.GetBytes(0, 5), data[:entry.size])
833 # Second u-boot has an aligned size, but it has no effect
834 self.assertIn('u-boot-align-size-nop', entries)
835 entry = entries['u-boot-align-size-nop']
836 self.assertEqual(pos, entry.offset)
837 self.assertEqual(len(U_BOOT_DATA), entry.size)
838 self.assertEqual(U_BOOT_DATA, entry.data)
839 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
842 # Third u-boot has an aligned size too
843 self.assertIn('u-boot-align-size', entries)
844 entry = entries['u-boot-align-size']
845 self.assertEqual(pos, entry.offset)
846 self.assertEqual(32, entry.size)
847 self.assertEqual(U_BOOT_DATA, entry.data)
848 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
849 data[pos:pos + entry.size])
852 # Fourth u-boot has an aligned end
853 self.assertIn('u-boot-align-end', entries)
854 entry = entries['u-boot-align-end']
855 self.assertEqual(48, entry.offset)
856 self.assertEqual(16, entry.size)
857 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
858 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
859 data[pos:pos + entry.size])
862 # Fifth u-boot immediately afterwards
863 self.assertIn('u-boot-align-both', entries)
864 entry = entries['u-boot-align-both']
865 self.assertEqual(64, entry.offset)
866 self.assertEqual(64, entry.size)
867 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
868 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
869 data[pos:pos + entry.size])
871 self.CheckNoGaps(entries)
872 self.assertEqual(128, image.size)
874 dtb = fdt.Fdt(out_dtb_fname)
876 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
882 'u-boot:image-pos': 0,
884 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
886 'u-boot-align-size-nop:image-pos': 12,
887 'u-boot-align-size-nop:offset': 12,
888 'u-boot-align-size-nop:size': 4,
890 'u-boot-align-size:image-pos': 16,
891 'u-boot-align-size:offset': 16,
892 'u-boot-align-size:size': 32,
894 'u-boot-align-end:image-pos': 48,
895 'u-boot-align-end:offset': 48,
896 'u-boot-align-end:size': 16,
898 'u-boot-align-both:image-pos': 64,
899 'u-boot-align-both:offset': 64,
900 'u-boot-align-both:size': 64,
902 self.assertEqual(expected, props)
904 def testPackAlignPowerOf2(self):
905 """Test that invalid entry alignment is detected"""
906 with self.assertRaises(ValueError) as e:
907 self._DoTestFile('010_pack_align_power2.dts')
908 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
909 "of two", str(e.exception))
911 def testPackAlignSizePowerOf2(self):
912 """Test that invalid entry size alignment is detected"""
913 with self.assertRaises(ValueError) as e:
914 self._DoTestFile('011_pack_align_size_power2.dts')
915 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
916 "power of two", str(e.exception))
918 def testPackInvalidAlign(self):
919 """Test detection of an offset that does not match its alignment"""
920 with self.assertRaises(ValueError) as e:
921 self._DoTestFile('012_pack_inv_align.dts')
922 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
923 "align 0x4 (4)", str(e.exception))
925 def testPackInvalidSizeAlign(self):
926 """Test that invalid entry size alignment is detected"""
927 with self.assertRaises(ValueError) as e:
928 self._DoTestFile('013_pack_inv_size_align.dts')
929 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
930 "align-size 0x4 (4)", str(e.exception))
932 def testPackOverlap(self):
933 """Test that overlapping regions are detected"""
934 with self.assertRaises(ValueError) as e:
935 self._DoTestFile('014_pack_overlap.dts')
936 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
937 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
940 def testPackEntryOverflow(self):
941 """Test that entries that overflow their size are detected"""
942 with self.assertRaises(ValueError) as e:
943 self._DoTestFile('015_pack_overflow.dts')
944 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
945 "but entry size is 0x3 (3)", str(e.exception))
947 def testPackImageOverflow(self):
948 """Test that entries which overflow the image size are detected"""
949 with self.assertRaises(ValueError) as e:
950 self._DoTestFile('016_pack_image_overflow.dts')
951 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
952 "size 0x3 (3)", str(e.exception))
954 def testPackImageSize(self):
955 """Test that the image size can be set"""
956 retcode = self._DoTestFile('017_pack_image_size.dts')
957 self.assertEqual(0, retcode)
958 self.assertIn('image', control.images)
959 image = control.images['image']
960 self.assertEqual(7, image.size)
962 def testPackImageSizeAlign(self):
963 """Test that image size alignemnt works as expected"""
964 retcode = self._DoTestFile('018_pack_image_align.dts')
965 self.assertEqual(0, retcode)
966 self.assertIn('image', control.images)
967 image = control.images['image']
968 self.assertEqual(16, image.size)
970 def testPackInvalidImageAlign(self):
971 """Test that invalid image alignment is detected"""
972 with self.assertRaises(ValueError) as e:
973 self._DoTestFile('019_pack_inv_image_align.dts')
974 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
975 "align-size 0x8 (8)", str(e.exception))
977 def testPackAlignPowerOf2(self):
978 """Test that invalid image alignment is detected"""
979 with self.assertRaises(ValueError) as e:
980 self._DoTestFile('020_pack_inv_image_align_power2.dts')
981 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
982 "two", str(e.exception))
984 def testImagePadByte(self):
985 """Test that the image pad byte can be specified"""
987 data = self._DoReadFile('021_image_pad.dts')
988 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
991 def testImageName(self):
992 """Test that image files can be named"""
993 retcode = self._DoTestFile('022_image_name.dts')
994 self.assertEqual(0, retcode)
995 image = control.images['image1']
996 fname = tools.GetOutputFilename('test-name')
997 self.assertTrue(os.path.exists(fname))
999 image = control.images['image2']
1000 fname = tools.GetOutputFilename('test-name.xx')
1001 self.assertTrue(os.path.exists(fname))
1003 def testBlobFilename(self):
1004 """Test that generic blobs can be provided by filename"""
1005 data = self._DoReadFile('023_blob.dts')
1006 self.assertEqual(BLOB_DATA, data)
1008 def testPackSorted(self):
1009 """Test that entries can be sorted"""
1011 data = self._DoReadFile('024_sorted.dts')
1012 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1013 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
1015 def testPackZeroOffset(self):
1016 """Test that an entry at offset 0 is not given a new offset"""
1017 with self.assertRaises(ValueError) as e:
1018 self._DoTestFile('025_pack_zero_size.dts')
1019 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1020 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1023 def testPackUbootDtb(self):
1024 """Test that a device tree can be added to U-Boot"""
1025 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1026 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1028 def testPackX86RomNoSize(self):
1029 """Test that the end-at-4gb property requires a size property"""
1030 with self.assertRaises(ValueError) as e:
1031 self._DoTestFile('027_pack_4gb_no_size.dts')
1032 self.assertIn("Image '/binman': Section size must be provided when "
1033 "using end-at-4gb", str(e.exception))
1035 def test4gbAndSkipAtStartTogether(self):
1036 """Test that the end-at-4gb and skip-at-size property can't be used
1038 with self.assertRaises(ValueError) as e:
1039 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1040 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1041 "'skip-at-start'", str(e.exception))
1043 def testPackX86RomOutside(self):
1044 """Test that the end-at-4gb property checks for offset boundaries"""
1045 with self.assertRaises(ValueError) as e:
1046 self._DoTestFile('028_pack_4gb_outside.dts')
1047 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1048 "is outside the section '/binman' starting at "
1049 '0xffffffe0 (4294967264) of size 0x20 (32)',
1052 def testPackX86Rom(self):
1053 """Test that a basic x86 ROM can be created"""
1055 data = self._DoReadFile('029_x86_rom.dts')
1056 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
1057 tools.GetBytes(0, 2), data)
1059 def testPackX86RomMeNoDesc(self):
1060 """Test that an invalid Intel descriptor entry is detected"""
1062 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1063 with self.assertRaises(ValueError) as e:
1064 self._DoTestFile('163_x86_rom_me_empty.dts')
1065 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1068 self._SetupDescriptor()
1070 def testPackX86RomBadDesc(self):
1071 """Test that the Intel requires a descriptor entry"""
1072 with self.assertRaises(ValueError) as e:
1073 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1074 self.assertIn("Node '/binman/intel-me': No offset set with "
1075 "offset-unset: should another entry provide this correct "
1076 "offset?", str(e.exception))
1078 def testPackX86RomMe(self):
1079 """Test that an x86 ROM with an ME region can be created"""
1080 data = self._DoReadFile('031_x86_rom_me.dts')
1081 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1082 if data[:0x1000] != expected_desc:
1083 self.fail('Expected descriptor binary at start of image')
1084 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1086 def testPackVga(self):
1087 """Test that an image with a VGA binary can be created"""
1088 data = self._DoReadFile('032_intel_vga.dts')
1089 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1091 def testPackStart16(self):
1092 """Test that an image with an x86 start16 region can be created"""
1093 data = self._DoReadFile('033_x86_start16.dts')
1094 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1096 def testPackPowerpcMpc85xxBootpgResetvec(self):
1097 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1099 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1100 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1102 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1103 """Handle running a test for insertion of microcode
1106 dts_fname: Name of test .dts file
1107 nodtb_data: Data that we expect in the first section
1108 ucode_second: True if the microsecond entry is second instead of
1113 Contents of first region (U-Boot or SPL)
1114 Offset and size components of microcode pointer, as inserted
1115 in the above (two 4-byte words)
1117 data = self._DoReadFile(dts_fname, True)
1119 # Now check the device tree has no microcode
1121 ucode_content = data[len(nodtb_data):]
1122 ucode_pos = len(nodtb_data)
1123 dtb_with_ucode = ucode_content[16:]
1124 fdt_len = self.GetFdtLen(dtb_with_ucode)
1126 dtb_with_ucode = data[len(nodtb_data):]
1127 fdt_len = self.GetFdtLen(dtb_with_ucode)
1128 ucode_content = dtb_with_ucode[fdt_len:]
1129 ucode_pos = len(nodtb_data) + fdt_len
1130 fname = tools.GetOutputFilename('test.dtb')
1131 with open(fname, 'wb') as fd:
1132 fd.write(dtb_with_ucode)
1133 dtb = fdt.FdtScan(fname)
1134 ucode = dtb.GetNode('/microcode')
1135 self.assertTrue(ucode)
1136 for node in ucode.subnodes:
1137 self.assertFalse(node.props.get('data'))
1139 # Check that the microcode appears immediately after the Fdt
1140 # This matches the concatenation of the data properties in
1141 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1142 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1144 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1146 # Check that the microcode pointer was inserted. It should match the
1147 # expected offset and size
1148 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1150 u_boot = data[:len(nodtb_data)]
1151 return u_boot, pos_and_size
1153 def testPackUbootMicrocode(self):
1154 """Test that x86 microcode can be handled correctly
1156 We expect to see the following in the image, in order:
1157 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1159 u-boot.dtb with the microcode removed
1162 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1164 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1165 b' somewhere in here', first)
1167 def _RunPackUbootSingleMicrocode(self):
1168 """Test that x86 microcode can be handled correctly
1170 We expect to see the following in the image, in order:
1171 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1173 u-boot.dtb with the microcode
1174 an empty microcode region
1176 # We need the libfdt library to run this test since only that allows
1177 # finding the offset of a property. This is required by
1178 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1179 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1181 second = data[len(U_BOOT_NODTB_DATA):]
1183 fdt_len = self.GetFdtLen(second)
1184 third = second[fdt_len:]
1185 second = second[:fdt_len]
1187 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1188 self.assertIn(ucode_data, second)
1189 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1191 # Check that the microcode pointer was inserted. It should match the
1192 # expected offset and size
1193 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1195 first = data[:len(U_BOOT_NODTB_DATA)]
1196 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1197 b' somewhere in here', first)
1199 def testPackUbootSingleMicrocode(self):
1200 """Test that x86 microcode can be handled correctly with fdt_normal.
1202 self._RunPackUbootSingleMicrocode()
1204 def testUBootImg(self):
1205 """Test that u-boot.img can be put in a file"""
1206 data = self._DoReadFile('036_u_boot_img.dts')
1207 self.assertEqual(U_BOOT_IMG_DATA, data)
1209 def testNoMicrocode(self):
1210 """Test that a missing microcode region is detected"""
1211 with self.assertRaises(ValueError) as e:
1212 self._DoReadFile('037_x86_no_ucode.dts', True)
1213 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1214 "node found in ", str(e.exception))
1216 def testMicrocodeWithoutNode(self):
1217 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1218 with self.assertRaises(ValueError) as e:
1219 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1220 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1221 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1223 def testMicrocodeWithoutNode2(self):
1224 """Test that a missing u-boot-ucode node is detected"""
1225 with self.assertRaises(ValueError) as e:
1226 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1227 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1228 "microcode region u-boot-ucode", str(e.exception))
1230 def testMicrocodeWithoutPtrInElf(self):
1231 """Test that a U-Boot binary without the microcode symbol is detected"""
1232 # ELF file without a '_dt_ucode_base_size' symbol
1234 TestFunctional._MakeInputFile('u-boot',
1235 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1237 with self.assertRaises(ValueError) as e:
1238 self._RunPackUbootSingleMicrocode()
1239 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1240 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1243 # Put the original file back
1244 TestFunctional._MakeInputFile('u-boot',
1245 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1247 def testMicrocodeNotInImage(self):
1248 """Test that microcode must be placed within the image"""
1249 with self.assertRaises(ValueError) as e:
1250 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1251 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1252 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1253 "section ranging from 00000000 to 0000002e", str(e.exception))
1255 def testWithoutMicrocode(self):
1256 """Test that we can cope with an image without microcode (e.g. qemu)"""
1257 TestFunctional._MakeInputFile('u-boot',
1258 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1259 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1261 # Now check the device tree has no microcode
1262 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1263 second = data[len(U_BOOT_NODTB_DATA):]
1265 fdt_len = self.GetFdtLen(second)
1266 self.assertEqual(dtb, second[:fdt_len])
1268 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1269 third = data[used_len:]
1270 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1272 def testUnknownPosSize(self):
1273 """Test that microcode must be placed within the image"""
1274 with self.assertRaises(ValueError) as e:
1275 self._DoReadFile('041_unknown_pos_size.dts', True)
1276 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1277 "entry 'invalid-entry'", str(e.exception))
1279 def testPackFsp(self):
1280 """Test that an image with a FSP binary can be created"""
1281 data = self._DoReadFile('042_intel_fsp.dts')
1282 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1284 def testPackCmc(self):
1285 """Test that an image with a CMC binary can be created"""
1286 data = self._DoReadFile('043_intel_cmc.dts')
1287 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1289 def testPackVbt(self):
1290 """Test that an image with a VBT binary can be created"""
1291 data = self._DoReadFile('046_intel_vbt.dts')
1292 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1294 def testSplBssPad(self):
1295 """Test that we can pad SPL's BSS with zeros"""
1296 # ELF file with a '__bss_size' symbol
1298 data = self._DoReadFile('047_spl_bss_pad.dts')
1299 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1302 def testSplBssPadMissing(self):
1303 """Test that a missing symbol is detected"""
1304 self._SetupSplElf('u_boot_ucode_ptr')
1305 with self.assertRaises(ValueError) as e:
1306 self._DoReadFile('047_spl_bss_pad.dts')
1307 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1310 def testPackStart16Spl(self):
1311 """Test that an image with an x86 start16 SPL region can be created"""
1312 data = self._DoReadFile('048_x86_start16_spl.dts')
1313 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1315 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1316 """Helper function for microcode tests
1318 We expect to see the following in the image, in order:
1319 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1321 u-boot.dtb with the microcode removed
1325 dts: Device tree file to use for test
1326 ucode_second: True if the microsecond entry is second instead of
1329 self._SetupSplElf('u_boot_ucode_ptr')
1330 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1331 ucode_second=ucode_second)
1332 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1333 b'ter somewhere in here', first)
1335 def testPackUbootSplMicrocode(self):
1336 """Test that x86 microcode can be handled correctly in SPL"""
1337 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1339 def testPackUbootSplMicrocodeReorder(self):
1340 """Test that order doesn't matter for microcode entries
1342 This is the same as testPackUbootSplMicrocode but when we process the
1343 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1344 entry, so we reply on binman to try later.
1346 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1349 def testPackMrc(self):
1350 """Test that an image with an MRC binary can be created"""
1351 data = self._DoReadFile('050_intel_mrc.dts')
1352 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1354 def testSplDtb(self):
1355 """Test that an image with spl/u-boot-spl.dtb can be created"""
1356 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1357 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1359 def testSplNoDtb(self):
1360 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1362 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1363 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1365 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1366 use_expanded=False):
1367 """Check the image contains the expected symbol values
1370 dts: Device tree file to use for test
1371 base_data: Data before and after 'u-boot' section
1372 u_boot_offset: Offset of 'u-boot' section in image
1373 entry_args: Dict of entry args to supply to binman
1375 value: value of that arg
1376 use_expanded: True to use expanded entries where available, e.g.
1377 'u-boot-expanded' instead of 'u-boot'
1379 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1380 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1381 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1382 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1385 self._SetupSplElf('u_boot_binman_syms')
1386 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1387 use_expanded=use_expanded)[0]
1388 # The image should contain the symbols from u_boot_binman_syms.c
1389 # Note that image_pos is adjusted by the base address of the image,
1390 # which is 0x10 in our test image
1391 sym_values = struct.pack('<LQLL', 0x00,
1392 u_boot_offset + len(U_BOOT_DATA),
1393 0x10 + u_boot_offset, 0x04)
1394 expected = (sym_values + base_data[20:] +
1395 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1397 self.assertEqual(expected, data)
1399 def testSymbols(self):
1400 """Test binman can assign symbols embedded in U-Boot"""
1401 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1403 def testSymbolsNoDtb(self):
1404 """Test binman can assign symbols embedded in U-Boot SPL"""
1405 self.checkSymbols('196_symbols_nodtb.dts',
1406 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1409 def testPackUnitAddress(self):
1410 """Test that we support multiple binaries with the same name"""
1411 data = self._DoReadFile('054_unit_address.dts')
1412 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1414 def testSections(self):
1415 """Basic test of sections"""
1416 data = self._DoReadFile('055_sections.dts')
1417 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1418 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1419 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1420 self.assertEqual(expected, data)
1423 """Tests outputting a map of the images"""
1424 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1425 self.assertEqual('''ImagePos Offset Size Name
1426 00000000 00000000 00000028 main-section
1427 00000000 00000000 00000010 section@0
1428 00000000 00000000 00000004 u-boot
1429 00000010 00000010 00000010 section@1
1430 00000010 00000000 00000004 u-boot
1431 00000020 00000020 00000004 section@2
1432 00000020 00000000 00000004 u-boot
1435 def testNamePrefix(self):
1436 """Tests that name prefixes are used"""
1437 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1438 self.assertEqual('''ImagePos Offset Size Name
1439 00000000 00000000 00000028 main-section
1440 00000000 00000000 00000010 section@0
1441 00000000 00000000 00000004 ro-u-boot
1442 00000010 00000010 00000010 section@1
1443 00000010 00000000 00000004 rw-u-boot
1446 def testUnknownContents(self):
1447 """Test that obtaining the contents works as expected"""
1448 with self.assertRaises(ValueError) as e:
1449 self._DoReadFile('057_unknown_contents.dts', True)
1450 self.assertIn("Image '/binman': Internal error: Could not complete "
1451 "processing of contents: remaining ["
1452 "<binman.etype._testing.Entry__testing ", str(e.exception))
1454 def testBadChangeSize(self):
1455 """Test that trying to change the size of an entry fails"""
1457 state.SetAllowEntryExpansion(False)
1458 with self.assertRaises(ValueError) as e:
1459 self._DoReadFile('059_change_size.dts', True)
1460 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1463 state.SetAllowEntryExpansion(True)
1465 def testUpdateFdt(self):
1466 """Test that we can update the device tree with offset/size info"""
1467 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1469 dtb = fdt.Fdt(out_dtb_fname)
1471 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1475 '_testing:offset': 32,
1477 '_testing:image-pos': 32,
1478 'section@0/u-boot:offset': 0,
1479 'section@0/u-boot:size': len(U_BOOT_DATA),
1480 'section@0/u-boot:image-pos': 0,
1481 'section@0:offset': 0,
1482 'section@0:size': 16,
1483 'section@0:image-pos': 0,
1485 'section@1/u-boot:offset': 0,
1486 'section@1/u-boot:size': len(U_BOOT_DATA),
1487 'section@1/u-boot:image-pos': 16,
1488 'section@1:offset': 16,
1489 'section@1:size': 16,
1490 'section@1:image-pos': 16,
1494 def testUpdateFdtBad(self):
1495 """Test that we detect when ProcessFdt never completes"""
1496 with self.assertRaises(ValueError) as e:
1497 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1498 self.assertIn('Could not complete processing of Fdt: remaining '
1499 '[<binman.etype._testing.Entry__testing',
1502 def testEntryArgs(self):
1503 """Test passing arguments to entries from the command line"""
1505 'test-str-arg': 'test1',
1506 'test-int-arg': '456',
1508 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1509 self.assertIn('image', control.images)
1510 entry = control.images['image'].GetEntries()['_testing']
1511 self.assertEqual('test0', entry.test_str_fdt)
1512 self.assertEqual('test1', entry.test_str_arg)
1513 self.assertEqual(123, entry.test_int_fdt)
1514 self.assertEqual(456, entry.test_int_arg)
1516 def testEntryArgsMissing(self):
1517 """Test missing arguments and properties"""
1519 'test-int-arg': '456',
1521 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1522 entry = control.images['image'].GetEntries()['_testing']
1523 self.assertEqual('test0', entry.test_str_fdt)
1524 self.assertEqual(None, entry.test_str_arg)
1525 self.assertEqual(None, entry.test_int_fdt)
1526 self.assertEqual(456, entry.test_int_arg)
1528 def testEntryArgsRequired(self):
1529 """Test missing arguments and properties"""
1531 'test-int-arg': '456',
1533 with self.assertRaises(ValueError) as e:
1534 self._DoReadFileDtb('064_entry_args_required.dts')
1535 self.assertIn("Node '/binman/_testing': "
1536 'Missing required properties/entry args: test-str-arg, '
1537 'test-int-fdt, test-int-arg',
1540 def testEntryArgsInvalidFormat(self):
1541 """Test that an invalid entry-argument format is detected"""
1542 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1544 with self.assertRaises(ValueError) as e:
1545 self._DoBinman(*args)
1546 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1548 def testEntryArgsInvalidInteger(self):
1549 """Test that an invalid entry-argument integer is detected"""
1551 'test-int-arg': 'abc',
1553 with self.assertRaises(ValueError) as e:
1554 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1555 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1556 "'test-int-arg' (value 'abc') to integer",
1559 def testEntryArgsInvalidDatatype(self):
1560 """Test that an invalid entry-argument datatype is detected
1562 This test could be written in entry_test.py except that it needs
1563 access to control.entry_args, which seems more than that module should
1567 'test-bad-datatype-arg': '12',
1569 with self.assertRaises(ValueError) as e:
1570 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1571 entry_args=entry_args)
1572 self.assertIn('GetArg() internal error: Unknown data type ',
1576 """Test for a text entry type"""
1578 'test-id': TEXT_DATA,
1579 'test-id2': TEXT_DATA2,
1580 'test-id3': TEXT_DATA3,
1582 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1583 entry_args=entry_args)
1584 expected = (tools.ToBytes(TEXT_DATA) +
1585 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1586 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1587 b'some text' + b'more text')
1588 self.assertEqual(expected, data)
1590 def testEntryDocs(self):
1591 """Test for creation of entry documentation"""
1592 with test_util.capture_sys_output() as (stdout, stderr):
1593 control.WriteEntryDocs(control.GetEntryModules())
1594 self.assertTrue(len(stdout.getvalue()) > 0)
1596 def testEntryDocsMissing(self):
1597 """Test handling of missing entry documentation"""
1598 with self.assertRaises(ValueError) as e:
1599 with test_util.capture_sys_output() as (stdout, stderr):
1600 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1601 self.assertIn('Documentation is missing for modules: u_boot',
1605 """Basic test of generation of a flashrom fmap"""
1606 data = self._DoReadFile('067_fmap.dts')
1607 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1608 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1609 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1610 self.assertEqual(expected, data[:32])
1611 self.assertEqual(b'__FMAP__', fhdr.signature)
1612 self.assertEqual(1, fhdr.ver_major)
1613 self.assertEqual(0, fhdr.ver_minor)
1614 self.assertEqual(0, fhdr.base)
1615 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1616 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1617 self.assertEqual(b'FMAP', fhdr.name)
1618 self.assertEqual(5, fhdr.nareas)
1619 fiter = iter(fentries)
1621 fentry = next(fiter)
1622 self.assertEqual(b'SECTION0', fentry.name)
1623 self.assertEqual(0, fentry.offset)
1624 self.assertEqual(16, fentry.size)
1625 self.assertEqual(0, fentry.flags)
1627 fentry = next(fiter)
1628 self.assertEqual(b'RO_U_BOOT', fentry.name)
1629 self.assertEqual(0, fentry.offset)
1630 self.assertEqual(4, fentry.size)
1631 self.assertEqual(0, fentry.flags)
1633 fentry = next(fiter)
1634 self.assertEqual(b'SECTION1', fentry.name)
1635 self.assertEqual(16, fentry.offset)
1636 self.assertEqual(16, fentry.size)
1637 self.assertEqual(0, fentry.flags)
1639 fentry = next(fiter)
1640 self.assertEqual(b'RW_U_BOOT', fentry.name)
1641 self.assertEqual(16, fentry.offset)
1642 self.assertEqual(4, fentry.size)
1643 self.assertEqual(0, fentry.flags)
1645 fentry = next(fiter)
1646 self.assertEqual(b'FMAP', fentry.name)
1647 self.assertEqual(32, fentry.offset)
1648 self.assertEqual(expect_size, fentry.size)
1649 self.assertEqual(0, fentry.flags)
1651 def testBlobNamedByArg(self):
1652 """Test we can add a blob with the filename coming from an entry arg"""
1654 'cros-ec-rw-path': 'ecrw.bin',
1656 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1659 """Test for an fill entry type"""
1660 data = self._DoReadFile('069_fill.dts')
1661 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1662 self.assertEqual(expected, data)
1664 def testFillNoSize(self):
1665 """Test for an fill entry type with no size"""
1666 with self.assertRaises(ValueError) as e:
1667 self._DoReadFile('070_fill_no_size.dts')
1668 self.assertIn("'fill' entry must have a size property",
1671 def _HandleGbbCommand(self, pipe_list):
1672 """Fake calls to the futility utility"""
1673 if pipe_list[0][0] == 'futility':
1674 fname = pipe_list[0][-1]
1675 # Append our GBB data to the file, which will happen every time the
1676 # futility command is called.
1677 with open(fname, 'ab') as fd:
1679 return command.CommandResult()
1682 """Test for the Chromium OS Google Binary Block"""
1683 command.test_result = self._HandleGbbCommand
1685 'keydir': 'devkeys',
1686 'bmpblk': 'bmpblk.bin',
1688 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1691 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1692 tools.GetBytes(0, 0x2180 - 16))
1693 self.assertEqual(expected, data)
1695 def testGbbTooSmall(self):
1696 """Test for the Chromium OS Google Binary Block being large enough"""
1697 with self.assertRaises(ValueError) as e:
1698 self._DoReadFileDtb('072_gbb_too_small.dts')
1699 self.assertIn("Node '/binman/gbb': GBB is too small",
1702 def testGbbNoSize(self):
1703 """Test for the Chromium OS Google Binary Block having a size"""
1704 with self.assertRaises(ValueError) as e:
1705 self._DoReadFileDtb('073_gbb_no_size.dts')
1706 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1709 def _HandleVblockCommand(self, pipe_list):
1710 """Fake calls to the futility utility
1712 The expected pipe is:
1714 [('futility', 'vbutil_firmware', '--vblock',
1715 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1716 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1717 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1718 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1720 This writes to the output file (here, 'vblock.vblock'). If
1721 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1722 of the input data (here, 'input.vblock').
1724 if pipe_list[0][0] == 'futility':
1725 fname = pipe_list[0][3]
1726 with open(fname, 'wb') as fd:
1728 infile = pipe_list[0][11]
1729 m = hashlib.sha256()
1730 data = tools.ReadFile(infile)
1732 fd.write(m.digest())
1734 fd.write(VBLOCK_DATA)
1736 return command.CommandResult()
1738 def testVblock(self):
1739 """Test for the Chromium OS Verified Boot Block"""
1740 self._hash_data = False
1741 command.test_result = self._HandleVblockCommand
1743 'keydir': 'devkeys',
1745 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1746 entry_args=entry_args)
1747 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1748 self.assertEqual(expected, data)
1750 def testVblockNoContent(self):
1751 """Test we detect a vblock which has no content to sign"""
1752 with self.assertRaises(ValueError) as e:
1753 self._DoReadFile('075_vblock_no_content.dts')
1754 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1755 'property', str(e.exception))
1757 def testVblockBadPhandle(self):
1758 """Test that we detect a vblock with an invalid phandle in contents"""
1759 with self.assertRaises(ValueError) as e:
1760 self._DoReadFile('076_vblock_bad_phandle.dts')
1761 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1762 '1000', str(e.exception))
1764 def testVblockBadEntry(self):
1765 """Test that we detect an entry that points to a non-entry"""
1766 with self.assertRaises(ValueError) as e:
1767 self._DoReadFile('077_vblock_bad_entry.dts')
1768 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1769 "'other'", str(e.exception))
1771 def testVblockContent(self):
1772 """Test that the vblock signs the right data"""
1773 self._hash_data = True
1774 command.test_result = self._HandleVblockCommand
1776 'keydir': 'devkeys',
1778 data = self._DoReadFileDtb(
1779 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1780 entry_args=entry_args)[0]
1781 hashlen = 32 # SHA256 hash is 32 bytes
1782 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1783 hashval = data[-hashlen:]
1784 dtb = data[len(U_BOOT_DATA):-hashlen]
1786 expected_data = U_BOOT_DATA + dtb
1788 # The hashval should be a hash of the dtb
1789 m = hashlib.sha256()
1790 m.update(expected_data)
1791 expected_hashval = m.digest()
1792 self.assertEqual(expected_hashval, hashval)
1795 """Test that an image with TPL and its device tree can be created"""
1796 # ELF file with a '__bss_size' symbol
1798 data = self._DoReadFile('078_u_boot_tpl.dts')
1799 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1801 def testUsesPos(self):
1802 """Test that the 'pos' property cannot be used anymore"""
1803 with self.assertRaises(ValueError) as e:
1804 data = self._DoReadFile('079_uses_pos.dts')
1805 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1806 "'pos'", str(e.exception))
1808 def testFillZero(self):
1809 """Test for an fill entry type with a size of 0"""
1810 data = self._DoReadFile('080_fill_empty.dts')
1811 self.assertEqual(tools.GetBytes(0, 16), data)
1813 def testTextMissing(self):
1814 """Test for a text entry type where there is no text"""
1815 with self.assertRaises(ValueError) as e:
1816 self._DoReadFileDtb('066_text.dts',)
1817 self.assertIn("Node '/binman/text': No value provided for text label "
1818 "'test-id'", str(e.exception))
1820 def testPackStart16Tpl(self):
1821 """Test that an image with an x86 start16 TPL region can be created"""
1822 data = self._DoReadFile('081_x86_start16_tpl.dts')
1823 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1825 def testSelectImage(self):
1826 """Test that we can select which images to build"""
1827 expected = 'Skipping images: image1'
1829 # We should only get the expected message in verbose mode
1830 for verbosity in (0, 2):
1831 with test_util.capture_sys_output() as (stdout, stderr):
1832 retcode = self._DoTestFile('006_dual_image.dts',
1833 verbosity=verbosity,
1835 self.assertEqual(0, retcode)
1837 self.assertIn(expected, stdout.getvalue())
1839 self.assertNotIn(expected, stdout.getvalue())
1841 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1842 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1843 self._CleanupOutputDir()
1845 def testUpdateFdtAll(self):
1846 """Test that all device trees are updated with offset/size info"""
1847 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1850 'section:image-pos': 0,
1851 'u-boot-tpl-dtb:size': 513,
1852 'u-boot-spl-dtb:size': 513,
1853 'u-boot-spl-dtb:offset': 493,
1855 'section/u-boot-dtb:image-pos': 0,
1856 'u-boot-spl-dtb:image-pos': 493,
1857 'section/u-boot-dtb:size': 493,
1858 'u-boot-tpl-dtb:image-pos': 1006,
1859 'section/u-boot-dtb:offset': 0,
1860 'section:size': 493,
1862 'section:offset': 0,
1863 'u-boot-tpl-dtb:offset': 1006,
1867 # We expect three device-tree files in the output, one after the other.
1868 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1869 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1870 # main U-Boot tree. All three should have the same postions and offset.
1872 for item in ['', 'spl', 'tpl']:
1873 dtb = fdt.Fdt.FromData(data[start:])
1875 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1877 expected = dict(base_expected)
1880 self.assertEqual(expected, props)
1881 start += dtb._fdt_obj.totalsize()
1883 def testUpdateFdtOutput(self):
1884 """Test that output DTB files are updated"""
1886 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1887 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1889 # Unfortunately, compiling a source file always results in a file
1890 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1891 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1892 # binman as a file called u-boot.dtb. To fix this, copy the file
1893 # over to the expected place.
1895 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1896 'tpl/u-boot-tpl.dtb.out']:
1897 dtb = fdt.Fdt.FromData(data[start:])
1898 size = dtb._fdt_obj.totalsize()
1899 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1900 outdata = tools.ReadFile(pathname)
1901 name = os.path.split(fname)[0]
1904 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1906 orig_indata = dtb_data
1907 self.assertNotEqual(outdata, orig_indata,
1908 "Expected output file '%s' be updated" % pathname)
1909 self.assertEqual(outdata, data[start:start + size],
1910 "Expected output file '%s' to match output image" %
1916 def _decompress(self, data):
1917 return tools.Decompress(data, 'lz4')
1919 def testCompress(self):
1920 """Test compression of blobs"""
1922 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1923 use_real_dtb=True, update_dtb=True)
1924 dtb = fdt.Fdt(out_dtb_fname)
1926 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1927 orig = self._decompress(data)
1928 self.assertEquals(COMPRESS_DATA, orig)
1930 # Do a sanity check on various fields
1931 image = control.images['image']
1932 entries = image.GetEntries()
1933 self.assertEqual(1, len(entries))
1935 entry = entries['blob']
1936 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1937 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1938 orig = self._decompress(entry.data)
1939 self.assertEqual(orig, entry.uncomp_data)
1941 self.assertEqual(image.data, entry.data)
1944 'blob:uncomp-size': len(COMPRESS_DATA),
1945 'blob:size': len(data),
1948 self.assertEqual(expected, props)
1950 def testFiles(self):
1951 """Test bringing in multiple files"""
1952 data = self._DoReadFile('084_files.dts')
1953 self.assertEqual(FILES_DATA, data)
1955 def testFilesCompress(self):
1956 """Test bringing in multiple files and compressing them"""
1958 data = self._DoReadFile('085_files_compress.dts')
1960 image = control.images['image']
1961 entries = image.GetEntries()
1962 files = entries['files']
1963 entries = files._entries
1966 for i in range(1, 3):
1968 start = entries[key].image_pos
1969 len = entries[key].size
1970 chunk = data[start:start + len]
1971 orig += self._decompress(chunk)
1973 self.assertEqual(FILES_DATA, orig)
1975 def testFilesMissing(self):
1976 """Test missing files"""
1977 with self.assertRaises(ValueError) as e:
1978 data = self._DoReadFile('086_files_none.dts')
1979 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1980 'no files', str(e.exception))
1982 def testFilesNoPattern(self):
1983 """Test missing files"""
1984 with self.assertRaises(ValueError) as e:
1985 data = self._DoReadFile('087_files_no_pattern.dts')
1986 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1989 def testExpandSize(self):
1990 """Test an expanding entry"""
1991 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1993 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1994 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1995 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1996 tools.GetBytes(ord('d'), 8))
1997 self.assertEqual(expect, data)
1998 self.assertEqual('''ImagePos Offset Size Name
1999 00000000 00000000 00000028 main-section
2000 00000000 00000000 00000008 fill
2001 00000008 00000008 00000004 u-boot
2002 0000000c 0000000c 00000004 section
2003 0000000c 00000000 00000003 intel-mrc
2004 00000010 00000010 00000004 u-boot2
2005 00000014 00000014 0000000c section2
2006 00000014 00000000 00000008 fill
2007 0000001c 00000008 00000004 u-boot
2008 00000020 00000020 00000008 fill2
2011 def testExpandSizeBad(self):
2012 """Test an expanding entry which fails to provide contents"""
2013 with test_util.capture_sys_output() as (stdout, stderr):
2014 with self.assertRaises(ValueError) as e:
2015 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
2016 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2017 'expanding entry', str(e.exception))
2020 """Test hashing of the contents of an entry"""
2021 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2022 use_real_dtb=True, update_dtb=True)
2023 dtb = fdt.Fdt(out_dtb_fname)
2025 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2026 m = hashlib.sha256()
2027 m.update(U_BOOT_DATA)
2028 self.assertEqual(m.digest(), b''.join(hash_node.value))
2030 def testHashNoAlgo(self):
2031 with self.assertRaises(ValueError) as e:
2032 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2033 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2034 'hash node', str(e.exception))
2036 def testHashBadAlgo(self):
2037 with self.assertRaises(ValueError) as e:
2038 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2039 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2042 def testHashSection(self):
2043 """Test hashing of the contents of an entry"""
2044 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2045 use_real_dtb=True, update_dtb=True)
2046 dtb = fdt.Fdt(out_dtb_fname)
2048 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2049 m = hashlib.sha256()
2050 m.update(U_BOOT_DATA)
2051 m.update(tools.GetBytes(ord('a'), 16))
2052 self.assertEqual(m.digest(), b''.join(hash_node.value))
2054 def testPackUBootTplMicrocode(self):
2055 """Test that x86 microcode can be handled correctly in TPL
2057 We expect to see the following in the image, in order:
2058 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2060 u-boot-tpl.dtb with the microcode removed
2063 self._SetupTplElf('u_boot_ucode_ptr')
2064 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2065 U_BOOT_TPL_NODTB_DATA)
2066 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2067 b'ter somewhere in here', first)
2069 def testFmapX86(self):
2070 """Basic test of generation of a flashrom fmap"""
2071 data = self._DoReadFile('094_fmap_x86.dts')
2072 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2073 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
2074 self.assertEqual(expected, data[:32])
2075 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2077 self.assertEqual(0x100, fhdr.image_size)
2079 self.assertEqual(0, fentries[0].offset)
2080 self.assertEqual(4, fentries[0].size)
2081 self.assertEqual(b'U_BOOT', fentries[0].name)
2083 self.assertEqual(4, fentries[1].offset)
2084 self.assertEqual(3, fentries[1].size)
2085 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2087 self.assertEqual(32, fentries[2].offset)
2088 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2089 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2090 self.assertEqual(b'FMAP', fentries[2].name)
2092 def testFmapX86Section(self):
2093 """Basic test of generation of a flashrom fmap"""
2094 data = self._DoReadFile('095_fmap_x86_section.dts')
2095 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
2096 self.assertEqual(expected, data[:32])
2097 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2099 self.assertEqual(0x180, fhdr.image_size)
2100 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2101 fiter = iter(fentries)
2103 fentry = next(fiter)
2104 self.assertEqual(b'U_BOOT', fentry.name)
2105 self.assertEqual(0, fentry.offset)
2106 self.assertEqual(4, fentry.size)
2108 fentry = next(fiter)
2109 self.assertEqual(b'SECTION', fentry.name)
2110 self.assertEqual(4, fentry.offset)
2111 self.assertEqual(0x20 + expect_size, fentry.size)
2113 fentry = next(fiter)
2114 self.assertEqual(b'INTEL_MRC', fentry.name)
2115 self.assertEqual(4, fentry.offset)
2116 self.assertEqual(3, fentry.size)
2118 fentry = next(fiter)
2119 self.assertEqual(b'FMAP', fentry.name)
2120 self.assertEqual(36, fentry.offset)
2121 self.assertEqual(expect_size, fentry.size)
2124 """Basic test of ELF entries"""
2127 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2128 TestFunctional._MakeInputFile('-boot', fd.read())
2129 data = self._DoReadFile('096_elf.dts')
2131 def testElfStrip(self):
2132 """Basic test of ELF entries"""
2134 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2135 TestFunctional._MakeInputFile('-boot', fd.read())
2136 data = self._DoReadFile('097_elf_strip.dts')
2138 def testPackOverlapMap(self):
2139 """Test that overlapping regions are detected"""
2140 with test_util.capture_sys_output() as (stdout, stderr):
2141 with self.assertRaises(ValueError) as e:
2142 self._DoTestFile('014_pack_overlap.dts', map=True)
2143 map_fname = tools.GetOutputFilename('image.map')
2144 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2147 # We should not get an inmage, but there should be a map file
2148 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2149 self.assertTrue(os.path.exists(map_fname))
2150 map_data = tools.ReadFile(map_fname, binary=False)
2151 self.assertEqual('''ImagePos Offset Size Name
2152 <none> 00000000 00000008 main-section
2153 <none> 00000000 00000004 u-boot
2154 <none> 00000003 00000004 u-boot-align
2157 def testPackRefCode(self):
2158 """Test that an image with an Intel Reference code binary works"""
2159 data = self._DoReadFile('100_intel_refcode.dts')
2160 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2162 def testSectionOffset(self):
2163 """Tests use of a section with an offset"""
2164 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2166 self.assertEqual('''ImagePos Offset Size Name
2167 00000000 00000000 00000038 main-section
2168 00000004 00000004 00000010 section@0
2169 00000004 00000000 00000004 u-boot
2170 00000018 00000018 00000010 section@1
2171 00000018 00000000 00000004 u-boot
2172 0000002c 0000002c 00000004 section@2
2173 0000002c 00000000 00000004 u-boot
2175 self.assertEqual(data,
2176 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2177 tools.GetBytes(0x21, 12) +
2178 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2179 tools.GetBytes(0x61, 12) +
2180 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2181 tools.GetBytes(0x26, 8))
2183 def testCbfsRaw(self):
2184 """Test base handling of a Coreboot Filesystem (CBFS)
2186 The exact contents of the CBFS is verified by similar tests in
2187 cbfs_util_test.py. The tests here merely check that the files added to
2188 the CBFS can be found in the final image.
2190 data = self._DoReadFile('102_cbfs_raw.dts')
2193 cbfs = cbfs_util.CbfsReader(data)
2194 self.assertEqual(size, cbfs.rom_size)
2196 self.assertIn('u-boot-dtb', cbfs.files)
2197 cfile = cbfs.files['u-boot-dtb']
2198 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2200 def testCbfsArch(self):
2201 """Test on non-x86 architecture"""
2202 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2205 cbfs = cbfs_util.CbfsReader(data)
2206 self.assertEqual(size, cbfs.rom_size)
2208 self.assertIn('u-boot-dtb', cbfs.files)
2209 cfile = cbfs.files['u-boot-dtb']
2210 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2212 def testCbfsStage(self):
2213 """Tests handling of a Coreboot Filesystem (CBFS)"""
2214 if not elf.ELF_TOOLS:
2215 self.skipTest('Python elftools not available')
2216 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2217 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2220 data = self._DoReadFile('104_cbfs_stage.dts')
2221 cbfs = cbfs_util.CbfsReader(data)
2222 self.assertEqual(size, cbfs.rom_size)
2224 self.assertIn('u-boot', cbfs.files)
2225 cfile = cbfs.files['u-boot']
2226 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2228 def testCbfsRawCompress(self):
2229 """Test handling of compressing raw files"""
2231 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2234 cbfs = cbfs_util.CbfsReader(data)
2235 self.assertIn('u-boot', cbfs.files)
2236 cfile = cbfs.files['u-boot']
2237 self.assertEqual(COMPRESS_DATA, cfile.data)
2239 def testCbfsBadArch(self):
2240 """Test handling of a bad architecture"""
2241 with self.assertRaises(ValueError) as e:
2242 self._DoReadFile('106_cbfs_bad_arch.dts')
2243 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2245 def testCbfsNoSize(self):
2246 """Test handling of a missing size property"""
2247 with self.assertRaises(ValueError) as e:
2248 self._DoReadFile('107_cbfs_no_size.dts')
2249 self.assertIn('entry must have a size property', str(e.exception))
2251 def testCbfsNoCOntents(self):
2252 """Test handling of a CBFS entry which does not provide contentsy"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('108_cbfs_no_contents.dts')
2255 self.assertIn('Could not complete processing of contents',
2258 def testCbfsBadCompress(self):
2259 """Test handling of a bad architecture"""
2260 with self.assertRaises(ValueError) as e:
2261 self._DoReadFile('109_cbfs_bad_compress.dts')
2262 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2265 def testCbfsNamedEntries(self):
2266 """Test handling of named entries"""
2267 data = self._DoReadFile('110_cbfs_name.dts')
2269 cbfs = cbfs_util.CbfsReader(data)
2270 self.assertIn('FRED', cbfs.files)
2271 cfile1 = cbfs.files['FRED']
2272 self.assertEqual(U_BOOT_DATA, cfile1.data)
2274 self.assertIn('hello', cbfs.files)
2275 cfile2 = cbfs.files['hello']
2276 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2278 def _SetupIfwi(self, fname):
2279 """Set up to run an IFWI test
2282 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2287 # Intel Integrated Firmware Image (IFWI) file
2288 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2290 TestFunctional._MakeInputFile(fname,data)
2292 def _CheckIfwi(self, data):
2293 """Check that an image with an IFWI contains the correct output
2296 data: Conents of output file
2298 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2299 if data[:0x1000] != expected_desc:
2300 self.fail('Expected descriptor binary at start of image')
2302 # We expect to find the TPL wil in subpart IBBP entry IBBL
2303 image_fname = tools.GetOutputFilename('image.bin')
2304 tpl_fname = tools.GetOutputFilename('tpl.out')
2305 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2306 subpart='IBBP', entry_name='IBBL')
2308 tpl_data = tools.ReadFile(tpl_fname)
2309 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2311 def testPackX86RomIfwi(self):
2312 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2313 self._SetupIfwi('fitimage.bin')
2314 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2315 self._CheckIfwi(data)
2317 def testPackX86RomIfwiNoDesc(self):
2318 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2319 self._SetupIfwi('ifwi.bin')
2320 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2321 self._CheckIfwi(data)
2323 def testPackX86RomIfwiNoData(self):
2324 """Test that an x86 ROM with IFWI handles missing data"""
2325 self._SetupIfwi('ifwi.bin')
2326 with self.assertRaises(ValueError) as e:
2327 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2328 self.assertIn('Could not complete processing of contents',
2331 def testCbfsOffset(self):
2332 """Test a CBFS with files at particular offsets
2334 Like all CFBS tests, this is just checking the logic that calls
2335 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2337 data = self._DoReadFile('114_cbfs_offset.dts')
2340 cbfs = cbfs_util.CbfsReader(data)
2341 self.assertEqual(size, cbfs.rom_size)
2343 self.assertIn('u-boot', cbfs.files)
2344 cfile = cbfs.files['u-boot']
2345 self.assertEqual(U_BOOT_DATA, cfile.data)
2346 self.assertEqual(0x40, cfile.cbfs_offset)
2348 self.assertIn('u-boot-dtb', cbfs.files)
2349 cfile2 = cbfs.files['u-boot-dtb']
2350 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2351 self.assertEqual(0x140, cfile2.cbfs_offset)
2353 def testFdtmap(self):
2354 """Test an FDT map can be inserted in the image"""
2355 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2356 fdtmap_data = data[len(U_BOOT_DATA):]
2357 magic = fdtmap_data[:8]
2358 self.assertEqual(b'_FDTMAP_', magic)
2359 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2361 fdt_data = fdtmap_data[16:]
2362 dtb = fdt.Fdt.FromData(fdt_data)
2364 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2369 'u-boot:size': len(U_BOOT_DATA),
2370 'u-boot:image-pos': 0,
2371 'fdtmap:image-pos': 4,
2373 'fdtmap:size': len(fdtmap_data),
2377 def testFdtmapNoMatch(self):
2378 """Check handling of an FDT map when the section cannot be found"""
2379 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2381 # Mangle the section name, which should cause a mismatch between the
2382 # correct FDT path and the one expected by the section
2383 image = control.images['image']
2384 image._node.path += '-suffix'
2385 entries = image.GetEntries()
2386 fdtmap = entries['fdtmap']
2387 with self.assertRaises(ValueError) as e:
2389 self.assertIn("Cannot locate node for path '/binman-suffix'",
2392 def testFdtmapHeader(self):
2393 """Test an FDT map and image header can be inserted in the image"""
2394 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2395 fdtmap_pos = len(U_BOOT_DATA)
2396 fdtmap_data = data[fdtmap_pos:]
2397 fdt_data = fdtmap_data[16:]
2398 dtb = fdt.Fdt.FromData(fdt_data)
2399 fdt_size = dtb.GetFdtObj().totalsize()
2400 hdr_data = data[-8:]
2401 self.assertEqual(b'BinM', hdr_data[:4])
2402 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2403 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2405 def testFdtmapHeaderStart(self):
2406 """Test an image header can be inserted at the image start"""
2407 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2408 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2410 self.assertEqual(b'BinM', hdr_data[:4])
2411 offset = struct.unpack('<I', hdr_data[4:])[0]
2412 self.assertEqual(fdtmap_pos, offset)
2414 def testFdtmapHeaderPos(self):
2415 """Test an image header can be inserted at a chosen position"""
2416 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2417 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2418 hdr_data = data[0x80:0x88]
2419 self.assertEqual(b'BinM', hdr_data[:4])
2420 offset = struct.unpack('<I', hdr_data[4:])[0]
2421 self.assertEqual(fdtmap_pos, offset)
2423 def testHeaderMissingFdtmap(self):
2424 """Test an image header requires an fdtmap"""
2425 with self.assertRaises(ValueError) as e:
2426 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2427 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2430 def testHeaderNoLocation(self):
2431 """Test an image header with a no specified location is detected"""
2432 with self.assertRaises(ValueError) as e:
2433 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2434 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2437 def testEntryExpand(self):
2438 """Test expanding an entry after it is packed"""
2439 data = self._DoReadFile('121_entry_expand.dts')
2440 self.assertEqual(b'aaa', data[:3])
2441 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2442 self.assertEqual(b'aaa', data[-3:])
2444 def testEntryExpandBad(self):
2445 """Test expanding an entry after it is packed, twice"""
2446 with self.assertRaises(ValueError) as e:
2447 self._DoReadFile('122_entry_expand_twice.dts')
2448 self.assertIn("Image '/binman': Entries changed size after packing",
2451 def testEntryExpandSection(self):
2452 """Test expanding an entry within a section after it is packed"""
2453 data = self._DoReadFile('123_entry_expand_section.dts')
2454 self.assertEqual(b'aaa', data[:3])
2455 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2456 self.assertEqual(b'aaa', data[-3:])
2458 def testCompressDtb(self):
2459 """Test that compress of device-tree files is supported"""
2461 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2462 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2463 comp_data = data[len(U_BOOT_DATA):]
2464 orig = self._decompress(comp_data)
2465 dtb = fdt.Fdt.FromData(orig)
2467 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2469 'u-boot:size': len(U_BOOT_DATA),
2470 'u-boot-dtb:uncomp-size': len(orig),
2471 'u-boot-dtb:size': len(comp_data),
2474 self.assertEqual(expected, props)
2476 def testCbfsUpdateFdt(self):
2477 """Test that we can update the device tree with CBFS offset/size info"""
2479 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2481 dtb = fdt.Fdt(out_dtb_fname)
2483 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2484 del props['cbfs/u-boot:size']
2490 'cbfs:size': len(data),
2491 'cbfs:image-pos': 0,
2492 'cbfs/u-boot:offset': 0x38,
2493 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2494 'cbfs/u-boot:image-pos': 0x38,
2495 'cbfs/u-boot-dtb:offset': 0xb8,
2496 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2497 'cbfs/u-boot-dtb:image-pos': 0xb8,
2500 def testCbfsBadType(self):
2501 """Test an image header with a no specified location is detected"""
2502 with self.assertRaises(ValueError) as e:
2503 self._DoReadFile('126_cbfs_bad_type.dts')
2504 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2507 """Test listing the files in an image"""
2509 data = self._DoReadFile('127_list.dts')
2510 image = control.images['image']
2511 entries = image.BuildEntryList()
2512 self.assertEqual(7, len(entries))
2515 self.assertEqual(0, ent.indent)
2516 self.assertEqual('main-section', ent.name)
2517 self.assertEqual('section', ent.etype)
2518 self.assertEqual(len(data), ent.size)
2519 self.assertEqual(0, ent.image_pos)
2520 self.assertEqual(None, ent.uncomp_size)
2521 self.assertEqual(0, ent.offset)
2524 self.assertEqual(1, ent.indent)
2525 self.assertEqual('u-boot', ent.name)
2526 self.assertEqual('u-boot', ent.etype)
2527 self.assertEqual(len(U_BOOT_DATA), ent.size)
2528 self.assertEqual(0, ent.image_pos)
2529 self.assertEqual(None, ent.uncomp_size)
2530 self.assertEqual(0, ent.offset)
2533 self.assertEqual(1, ent.indent)
2534 self.assertEqual('section', ent.name)
2535 self.assertEqual('section', ent.etype)
2536 section_size = ent.size
2537 self.assertEqual(0x100, ent.image_pos)
2538 self.assertEqual(None, ent.uncomp_size)
2539 self.assertEqual(0x100, ent.offset)
2542 self.assertEqual(2, ent.indent)
2543 self.assertEqual('cbfs', ent.name)
2544 self.assertEqual('cbfs', ent.etype)
2545 self.assertEqual(0x400, ent.size)
2546 self.assertEqual(0x100, ent.image_pos)
2547 self.assertEqual(None, ent.uncomp_size)
2548 self.assertEqual(0, ent.offset)
2551 self.assertEqual(3, ent.indent)
2552 self.assertEqual('u-boot', ent.name)
2553 self.assertEqual('u-boot', ent.etype)
2554 self.assertEqual(len(U_BOOT_DATA), ent.size)
2555 self.assertEqual(0x138, ent.image_pos)
2556 self.assertEqual(None, ent.uncomp_size)
2557 self.assertEqual(0x38, ent.offset)
2560 self.assertEqual(3, ent.indent)
2561 self.assertEqual('u-boot-dtb', ent.name)
2562 self.assertEqual('text', ent.etype)
2563 self.assertGreater(len(COMPRESS_DATA), ent.size)
2564 self.assertEqual(0x178, ent.image_pos)
2565 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2566 self.assertEqual(0x78, ent.offset)
2569 self.assertEqual(2, ent.indent)
2570 self.assertEqual('u-boot-dtb', ent.name)
2571 self.assertEqual('u-boot-dtb', ent.etype)
2572 self.assertEqual(0x500, ent.image_pos)
2573 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2575 # Compressing this data expands it since headers are added
2576 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2577 self.assertEqual(0x400, ent.offset)
2579 self.assertEqual(len(data), 0x100 + section_size)
2580 self.assertEqual(section_size, 0x400 + dtb_size)
2582 def testFindFdtmap(self):
2583 """Test locating an FDT map in an image"""
2585 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2586 image = control.images['image']
2587 entries = image.GetEntries()
2588 entry = entries['fdtmap']
2589 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2591 def testFindFdtmapMissing(self):
2592 """Test failing to locate an FDP map"""
2593 data = self._DoReadFile('005_simple.dts')
2594 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2596 def testFindImageHeader(self):
2597 """Test locating a image header"""
2599 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2600 image = control.images['image']
2601 entries = image.GetEntries()
2602 entry = entries['fdtmap']
2603 # The header should point to the FDT map
2604 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2606 def testFindImageHeaderStart(self):
2607 """Test locating a image header located at the start of an image"""
2608 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2609 image = control.images['image']
2610 entries = image.GetEntries()
2611 entry = entries['fdtmap']
2612 # The header should point to the FDT map
2613 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2615 def testFindImageHeaderMissing(self):
2616 """Test failing to locate an image header"""
2617 data = self._DoReadFile('005_simple.dts')
2618 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2620 def testReadImage(self):
2621 """Test reading an image and accessing its FDT map"""
2623 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2624 image_fname = tools.GetOutputFilename('image.bin')
2625 orig_image = control.images['image']
2626 image = Image.FromFile(image_fname)
2627 self.assertEqual(orig_image.GetEntries().keys(),
2628 image.GetEntries().keys())
2630 orig_entry = orig_image.GetEntries()['fdtmap']
2631 entry = image.GetEntries()['fdtmap']
2632 self.assertEquals(orig_entry.offset, entry.offset)
2633 self.assertEquals(orig_entry.size, entry.size)
2634 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2636 def testReadImageNoHeader(self):
2637 """Test accessing an image's FDT map without an image header"""
2639 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2640 image_fname = tools.GetOutputFilename('image.bin')
2641 image = Image.FromFile(image_fname)
2642 self.assertTrue(isinstance(image, Image))
2643 self.assertEqual('image', image.image_name[-5:])
2645 def testReadImageFail(self):
2646 """Test failing to read an image image's FDT map"""
2647 self._DoReadFile('005_simple.dts')
2648 image_fname = tools.GetOutputFilename('image.bin')
2649 with self.assertRaises(ValueError) as e:
2650 image = Image.FromFile(image_fname)
2651 self.assertIn("Cannot find FDT map in image", str(e.exception))
2653 def testListCmd(self):
2654 """Test listing the files in an image using an Fdtmap"""
2656 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2658 # lz4 compression size differs depending on the version
2659 image = control.images['image']
2660 entries = image.GetEntries()
2661 section_size = entries['section'].size
2662 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2663 fdtmap_offset = entries['fdtmap'].offset
2666 tmpdir, updated_fname = self._SetupImageInTmpdir()
2667 with test_util.capture_sys_output() as (stdout, stderr):
2668 self._DoBinman('ls', '-i', updated_fname)
2670 shutil.rmtree(tmpdir)
2671 lines = stdout.getvalue().splitlines()
2673 'Name Image-pos Size Entry-type Offset Uncomp-size',
2674 '----------------------------------------------------------------------',
2675 'main-section 0 c00 section 0',
2676 ' u-boot 0 4 u-boot 0',
2677 ' section 100 %x section 100' % section_size,
2678 ' cbfs 100 400 cbfs 0',
2679 ' u-boot 138 4 u-boot 38',
2680 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2681 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2682 ' fdtmap %x 3bd fdtmap %x' %
2683 (fdtmap_offset, fdtmap_offset),
2684 ' image-header bf8 8 image-header bf8',
2686 self.assertEqual(expected, lines)
2688 def testListCmdFail(self):
2689 """Test failing to list an image"""
2690 self._DoReadFile('005_simple.dts')
2692 tmpdir, updated_fname = self._SetupImageInTmpdir()
2693 with self.assertRaises(ValueError) as e:
2694 self._DoBinman('ls', '-i', updated_fname)
2696 shutil.rmtree(tmpdir)
2697 self.assertIn("Cannot find FDT map in image", str(e.exception))
2699 def _RunListCmd(self, paths, expected):
2700 """List out entries and check the result
2703 paths: List of paths to pass to the list command
2704 expected: Expected list of filenames to be returned, in order
2707 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2708 image_fname = tools.GetOutputFilename('image.bin')
2709 image = Image.FromFile(image_fname)
2710 lines = image.GetListEntries(paths)[1]
2711 files = [line[0].strip() for line in lines[1:]]
2712 self.assertEqual(expected, files)
2714 def testListCmdSection(self):
2715 """Test listing the files in a section"""
2716 self._RunListCmd(['section'],
2717 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2719 def testListCmdFile(self):
2720 """Test listing a particular file"""
2721 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2723 def testListCmdWildcard(self):
2724 """Test listing a wildcarded file"""
2725 self._RunListCmd(['*boot*'],
2726 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2728 def testListCmdWildcardMulti(self):
2729 """Test listing a wildcarded file"""
2730 self._RunListCmd(['*cb*', '*head*'],
2731 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2733 def testListCmdEmpty(self):
2734 """Test listing a wildcarded file"""
2735 self._RunListCmd(['nothing'], [])
2737 def testListCmdPath(self):
2738 """Test listing the files in a sub-entry of a section"""
2739 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2741 def _RunExtractCmd(self, entry_name, decomp=True):
2742 """Extract an entry from an image
2745 entry_name: Entry name to extract
2746 decomp: True to decompress the data if compressed, False to leave
2747 it in its raw uncompressed format
2753 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2754 image_fname = tools.GetOutputFilename('image.bin')
2755 return control.ReadEntry(image_fname, entry_name, decomp)
2757 def testExtractSimple(self):
2758 """Test extracting a single file"""
2759 data = self._RunExtractCmd('u-boot')
2760 self.assertEqual(U_BOOT_DATA, data)
2762 def testExtractSection(self):
2763 """Test extracting the files in a section"""
2764 data = self._RunExtractCmd('section')
2765 cbfs_data = data[:0x400]
2766 cbfs = cbfs_util.CbfsReader(cbfs_data)
2767 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2768 dtb_data = data[0x400:]
2769 dtb = self._decompress(dtb_data)
2770 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2772 def testExtractCompressed(self):
2773 """Test extracting compressed data"""
2774 data = self._RunExtractCmd('section/u-boot-dtb')
2775 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2777 def testExtractRaw(self):
2778 """Test extracting compressed data without decompressing it"""
2779 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2780 dtb = self._decompress(data)
2781 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2783 def testExtractCbfs(self):
2784 """Test extracting CBFS data"""
2785 data = self._RunExtractCmd('section/cbfs/u-boot')
2786 self.assertEqual(U_BOOT_DATA, data)
2788 def testExtractCbfsCompressed(self):
2789 """Test extracting CBFS compressed data"""
2790 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2791 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2793 def testExtractCbfsRaw(self):
2794 """Test extracting CBFS compressed data without decompressing it"""
2795 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2796 dtb = tools.Decompress(data, 'lzma', with_header=False)
2797 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2799 def testExtractBadEntry(self):
2800 """Test extracting a bad section path"""
2801 with self.assertRaises(ValueError) as e:
2802 self._RunExtractCmd('section/does-not-exist')
2803 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2806 def testExtractMissingFile(self):
2807 """Test extracting file that does not exist"""
2808 with self.assertRaises(IOError) as e:
2809 control.ReadEntry('missing-file', 'name')
2811 def testExtractBadFile(self):
2812 """Test extracting an invalid file"""
2813 fname = os.path.join(self._indir, 'badfile')
2814 tools.WriteFile(fname, b'')
2815 with self.assertRaises(ValueError) as e:
2816 control.ReadEntry(fname, 'name')
2818 def testExtractCmd(self):
2819 """Test extracting a file fron an image on the command line"""
2821 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2822 fname = os.path.join(self._indir, 'output.extact')
2824 tmpdir, updated_fname = self._SetupImageInTmpdir()
2825 with test_util.capture_sys_output() as (stdout, stderr):
2826 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2829 shutil.rmtree(tmpdir)
2830 data = tools.ReadFile(fname)
2831 self.assertEqual(U_BOOT_DATA, data)
2833 def testExtractOneEntry(self):
2834 """Test extracting a single entry fron an image """
2836 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2837 image_fname = tools.GetOutputFilename('image.bin')
2838 fname = os.path.join(self._indir, 'output.extact')
2839 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2840 data = tools.ReadFile(fname)
2841 self.assertEqual(U_BOOT_DATA, data)
2843 def _CheckExtractOutput(self, decomp):
2844 """Helper to test file output with and without decompression
2847 decomp: True to decompress entry data, False to output it raw
2849 def _CheckPresent(entry_path, expect_data, expect_size=None):
2850 """Check and remove expected file
2852 This checks the data/size of a file and removes the file both from
2853 the outfiles set and from the output directory. Once all files are
2854 processed, both the set and directory should be empty.
2857 entry_path: Entry path
2858 expect_data: Data to expect in file, or None to skip check
2859 expect_size: Size of data to expect in file, or None to skip
2861 path = os.path.join(outdir, entry_path)
2862 data = tools.ReadFile(path)
2865 self.assertEqual(expect_data, data)
2867 self.assertEqual(expect_size, len(data))
2868 outfiles.remove(path)
2870 def _CheckDirPresent(name):
2871 """Remove expected directory
2873 This gives an error if the directory does not exist as expected
2876 name: Name of directory to remove
2878 path = os.path.join(outdir, name)
2881 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2882 image_fname = tools.GetOutputFilename('image.bin')
2883 outdir = os.path.join(self._indir, 'extract')
2884 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2886 # Create a set of all file that were output (should be 9)
2888 for root, dirs, files in os.walk(outdir):
2889 outfiles |= set([os.path.join(root, fname) for fname in files])
2890 self.assertEqual(9, len(outfiles))
2891 self.assertEqual(9, len(einfos))
2893 image = control.images['image']
2894 entries = image.GetEntries()
2896 # Check the 9 files in various ways
2897 section = entries['section']
2898 section_entries = section.GetEntries()
2899 cbfs_entries = section_entries['cbfs'].GetEntries()
2900 _CheckPresent('u-boot', U_BOOT_DATA)
2901 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2902 dtb_len = EXTRACT_DTB_SIZE
2904 dtb_len = cbfs_entries['u-boot-dtb'].size
2905 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2907 dtb_len = section_entries['u-boot-dtb'].size
2908 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2910 fdtmap = entries['fdtmap']
2911 _CheckPresent('fdtmap', fdtmap.data)
2912 hdr = entries['image-header']
2913 _CheckPresent('image-header', hdr.data)
2915 _CheckPresent('section/root', section.data)
2916 cbfs = section_entries['cbfs']
2917 _CheckPresent('section/cbfs/root', cbfs.data)
2918 data = tools.ReadFile(image_fname)
2919 _CheckPresent('root', data)
2921 # There should be no files left. Remove all the directories to check.
2922 # If there are any files/dirs remaining, one of these checks will fail.
2923 self.assertEqual(0, len(outfiles))
2924 _CheckDirPresent('section/cbfs')
2925 _CheckDirPresent('section')
2926 _CheckDirPresent('')
2927 self.assertFalse(os.path.exists(outdir))
2929 def testExtractAllEntries(self):
2930 """Test extracting all entries"""
2932 self._CheckExtractOutput(decomp=True)
2934 def testExtractAllEntriesRaw(self):
2935 """Test extracting all entries without decompressing them"""
2937 self._CheckExtractOutput(decomp=False)
2939 def testExtractSelectedEntries(self):
2940 """Test extracting some entries"""
2942 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2943 image_fname = tools.GetOutputFilename('image.bin')
2944 outdir = os.path.join(self._indir, 'extract')
2945 einfos = control.ExtractEntries(image_fname, None, outdir,
2948 # File output is tested by testExtractAllEntries(), so just check that
2949 # the expected entries are selected
2950 names = [einfo.name for einfo in einfos]
2951 self.assertEqual(names,
2952 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2954 def testExtractNoEntryPaths(self):
2955 """Test extracting some entries"""
2957 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2958 image_fname = tools.GetOutputFilename('image.bin')
2959 with self.assertRaises(ValueError) as e:
2960 control.ExtractEntries(image_fname, 'fname', None, [])
2961 self.assertIn('Must specify an entry path to write with -f',
2964 def testExtractTooManyEntryPaths(self):
2965 """Test extracting some entries"""
2967 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2968 image_fname = tools.GetOutputFilename('image.bin')
2969 with self.assertRaises(ValueError) as e:
2970 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2971 self.assertIn('Must specify exactly one entry path to write with -f',
2974 def testPackAlignSection(self):
2975 """Test that sections can have alignment"""
2976 self._DoReadFile('131_pack_align_section.dts')
2978 self.assertIn('image', control.images)
2979 image = control.images['image']
2980 entries = image.GetEntries()
2981 self.assertEqual(3, len(entries))
2984 self.assertIn('u-boot', entries)
2985 entry = entries['u-boot']
2986 self.assertEqual(0, entry.offset)
2987 self.assertEqual(0, entry.image_pos)
2988 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2989 self.assertEqual(len(U_BOOT_DATA), entry.size)
2992 self.assertIn('section0', entries)
2993 section0 = entries['section0']
2994 self.assertEqual(0x10, section0.offset)
2995 self.assertEqual(0x10, section0.image_pos)
2996 self.assertEqual(len(U_BOOT_DATA), section0.size)
2999 section_entries = section0.GetEntries()
3000 self.assertIn('u-boot', section_entries)
3001 entry = section_entries['u-boot']
3002 self.assertEqual(0, entry.offset)
3003 self.assertEqual(0x10, entry.image_pos)
3004 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3005 self.assertEqual(len(U_BOOT_DATA), entry.size)
3008 self.assertIn('section1', entries)
3009 section1 = entries['section1']
3010 self.assertEqual(0x14, section1.offset)
3011 self.assertEqual(0x14, section1.image_pos)
3012 self.assertEqual(0x20, section1.size)
3015 section_entries = section1.GetEntries()
3016 self.assertIn('u-boot', section_entries)
3017 entry = section_entries['u-boot']
3018 self.assertEqual(0, entry.offset)
3019 self.assertEqual(0x14, entry.image_pos)
3020 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3021 self.assertEqual(len(U_BOOT_DATA), entry.size)
3024 self.assertIn('section2', section_entries)
3025 section2 = section_entries['section2']
3026 self.assertEqual(0x4, section2.offset)
3027 self.assertEqual(0x18, section2.image_pos)
3028 self.assertEqual(4, section2.size)
3031 section_entries = section2.GetEntries()
3032 self.assertIn('u-boot', section_entries)
3033 entry = section_entries['u-boot']
3034 self.assertEqual(0, entry.offset)
3035 self.assertEqual(0x18, entry.image_pos)
3036 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3037 self.assertEqual(len(U_BOOT_DATA), entry.size)
3039 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3040 dts='132_replace.dts'):
3041 """Replace an entry in an image
3043 This writes the entry data to update it, then opens the updated file and
3044 returns the value that it now finds there.
3047 entry_name: Entry name to replace
3048 data: Data to replace it with
3049 decomp: True to compress the data if needed, False if data is
3050 already compressed so should be used as is
3051 allow_resize: True to allow entries to change size, False to raise
3057 data from fdtmap (excluding header)
3058 Image object that was modified
3060 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3063 self.assertIn('image', control.images)
3064 image = control.images['image']
3065 entries = image.GetEntries()
3066 orig_dtb_data = entries['u-boot-dtb'].data
3067 orig_fdtmap_data = entries['fdtmap'].data
3069 image_fname = tools.GetOutputFilename('image.bin')
3070 updated_fname = tools.GetOutputFilename('image-updated.bin')
3071 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3072 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3074 data = control.ReadEntry(updated_fname, entry_name, decomp)
3076 # The DT data should not change unless resized:
3077 if not allow_resize:
3078 new_dtb_data = entries['u-boot-dtb'].data
3079 self.assertEqual(new_dtb_data, orig_dtb_data)
3080 new_fdtmap_data = entries['fdtmap'].data
3081 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3083 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3085 def testReplaceSimple(self):
3086 """Test replacing a single file"""
3087 expected = b'x' * len(U_BOOT_DATA)
3088 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3090 self.assertEqual(expected, data)
3092 # Test that the state looks right. There should be an FDT for the fdtmap
3093 # that we jsut read back in, and it should match what we find in the
3094 # 'control' tables. Checking for an FDT that does not exist should
3096 path, fdtmap = state.GetFdtContents('fdtmap')
3097 self.assertIsNotNone(path)
3098 self.assertEqual(expected_fdtmap, fdtmap)
3100 dtb = state.GetFdtForEtype('fdtmap')
3101 self.assertEqual(dtb.GetContents(), fdtmap)
3103 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3104 self.assertIsNone(missing_path)
3105 self.assertIsNone(missing_fdtmap)
3107 missing_dtb = state.GetFdtForEtype('missing')
3108 self.assertIsNone(missing_dtb)
3110 self.assertEqual('/binman', state.fdt_path_prefix)
3112 def testReplaceResizeFail(self):
3113 """Test replacing a file by something larger"""
3114 expected = U_BOOT_DATA + b'x'
3115 with self.assertRaises(ValueError) as e:
3116 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3117 dts='139_replace_repack.dts')
3118 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3121 def testReplaceMulti(self):
3122 """Test replacing entry data where multiple images are generated"""
3123 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3125 expected = b'x' * len(U_BOOT_DATA)
3126 updated_fname = tools.GetOutputFilename('image-updated.bin')
3127 tools.WriteFile(updated_fname, data)
3128 entry_name = 'u-boot'
3129 control.WriteEntry(updated_fname, entry_name, expected,
3131 data = control.ReadEntry(updated_fname, entry_name)
3132 self.assertEqual(expected, data)
3134 # Check the state looks right.
3135 self.assertEqual('/binman/image', state.fdt_path_prefix)
3137 # Now check we can write the first image
3138 image_fname = tools.GetOutputFilename('first-image.bin')
3139 updated_fname = tools.GetOutputFilename('first-updated.bin')
3140 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3141 entry_name = 'u-boot'
3142 control.WriteEntry(updated_fname, entry_name, expected,
3144 data = control.ReadEntry(updated_fname, entry_name)
3145 self.assertEqual(expected, data)
3147 # Check the state looks right.
3148 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3150 def testUpdateFdtAllRepack(self):
3151 """Test that all device trees are updated with offset/size info"""
3152 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3153 SECTION_SIZE = 0x300
3158 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3160 'section:offset': 0,
3161 'section:size': SECTION_SIZE,
3162 'section:image-pos': 0,
3163 'section/u-boot-dtb:offset': 4,
3164 'section/u-boot-dtb:size': 636,
3165 'section/u-boot-dtb:image-pos': 4,
3166 'u-boot-spl-dtb:offset': SECTION_SIZE,
3167 'u-boot-spl-dtb:size': DTB_SIZE,
3168 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3169 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3170 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3171 'u-boot-tpl-dtb:size': DTB_SIZE,
3172 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3173 'fdtmap:size': FDTMAP_SIZE,
3174 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3177 'section:orig-size': SECTION_SIZE,
3178 'section/u-boot-dtb:orig-offset': 4,
3181 # We expect three device-tree files in the output, with the first one
3182 # within a fixed-size section.
3183 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3184 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3185 # main U-Boot tree. All three should have the same positions and offset
3186 # except that the main tree should include the main_expected properties
3188 for item in ['', 'spl', 'tpl', None]:
3190 start += 16 # Move past fdtmap header
3191 dtb = fdt.Fdt.FromData(data[start:])
3193 props = self._GetPropTree(dtb,
3194 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3195 prefix='/' if item is None else '/binman/')
3196 expected = dict(base_expected)
3200 # Main DTB and fdtdec should include the 'orig-' properties
3201 expected.update(main_expected)
3202 # Helpful for debugging:
3203 #for prop in sorted(props):
3204 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3205 self.assertEqual(expected, props)
3207 start = SECTION_SIZE
3209 start += dtb._fdt_obj.totalsize()
3211 def testFdtmapHeaderMiddle(self):
3212 """Test an FDT map in the middle of an image when it should be at end"""
3213 with self.assertRaises(ValueError) as e:
3214 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3215 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3218 def testFdtmapHeaderStartBad(self):
3219 """Test an FDT map in middle of an image when it should be at start"""
3220 with self.assertRaises(ValueError) as e:
3221 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3222 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3225 def testFdtmapHeaderEndBad(self):
3226 """Test an FDT map at the start of an image when it should be at end"""
3227 with self.assertRaises(ValueError) as e:
3228 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3229 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3232 def testFdtmapHeaderNoSize(self):
3233 """Test an image header at the end of an image with undefined size"""
3234 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3236 def testReplaceResize(self):
3237 """Test replacing a single file in an entry with a larger file"""
3238 expected = U_BOOT_DATA + b'x'
3239 data, _, image = self._RunReplaceCmd('u-boot', expected,
3240 dts='139_replace_repack.dts')
3241 self.assertEqual(expected, data)
3243 entries = image.GetEntries()
3244 dtb_data = entries['u-boot-dtb'].data
3245 dtb = fdt.Fdt.FromData(dtb_data)
3248 # The u-boot section should now be larger in the dtb
3249 node = dtb.GetNode('/binman/u-boot')
3250 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3252 # Same for the fdtmap
3253 fdata = entries['fdtmap'].data
3254 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3256 fnode = fdtb.GetNode('/u-boot')
3257 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3259 def testReplaceResizeNoRepack(self):
3260 """Test replacing an entry with a larger file when not allowed"""
3261 expected = U_BOOT_DATA + b'x'
3262 with self.assertRaises(ValueError) as e:
3263 self._RunReplaceCmd('u-boot', expected)
3264 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3267 def testEntryShrink(self):
3268 """Test contracting an entry after it is packed"""
3270 state.SetAllowEntryContraction(True)
3271 data = self._DoReadFileDtb('140_entry_shrink.dts',
3274 state.SetAllowEntryContraction(False)
3275 self.assertEqual(b'a', data[:1])
3276 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3277 self.assertEqual(b'a', data[-1:])
3279 def testEntryShrinkFail(self):
3280 """Test not being allowed to contract an entry after it is packed"""
3281 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3283 # In this case there is a spare byte at the end of the data. The size of
3284 # the contents is only 1 byte but we still have the size before it
3286 self.assertEqual(b'a\0', data[:2])
3287 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3288 self.assertEqual(b'a\0', data[-2:])
3290 def testDescriptorOffset(self):
3291 """Test that the Intel descriptor is always placed at at the start"""
3292 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3293 image = control.images['image']
3294 entries = image.GetEntries()
3295 desc = entries['intel-descriptor']
3296 self.assertEqual(0xff800000, desc.offset);
3297 self.assertEqual(0xff800000, desc.image_pos);
3299 def testReplaceCbfs(self):
3300 """Test replacing a single file in CBFS without changing the size"""
3302 expected = b'x' * len(U_BOOT_DATA)
3303 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3304 updated_fname = tools.GetOutputFilename('image-updated.bin')
3305 tools.WriteFile(updated_fname, data)
3306 entry_name = 'section/cbfs/u-boot'
3307 control.WriteEntry(updated_fname, entry_name, expected,
3309 data = control.ReadEntry(updated_fname, entry_name)
3310 self.assertEqual(expected, data)
3312 def testReplaceResizeCbfs(self):
3313 """Test replacing a single file in CBFS with one of a different size"""
3315 expected = U_BOOT_DATA + b'x'
3316 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3317 updated_fname = tools.GetOutputFilename('image-updated.bin')
3318 tools.WriteFile(updated_fname, data)
3319 entry_name = 'section/cbfs/u-boot'
3320 control.WriteEntry(updated_fname, entry_name, expected,
3322 data = control.ReadEntry(updated_fname, entry_name)
3323 self.assertEqual(expected, data)
3325 def _SetupForReplace(self):
3326 """Set up some files to use to replace entries
3328 This generates an image, copies it to a new file, extracts all the files
3329 in it and updates some of them
3335 Expected values for updated entries, each a string
3337 data = self._DoReadFileRealDtb('143_replace_all.dts')
3339 updated_fname = tools.GetOutputFilename('image-updated.bin')
3340 tools.WriteFile(updated_fname, data)
3342 outdir = os.path.join(self._indir, 'extract')
3343 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3345 expected1 = b'x' + U_BOOT_DATA + b'y'
3346 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3347 tools.WriteFile(u_boot_fname1, expected1)
3349 expected2 = b'a' + U_BOOT_DATA + b'b'
3350 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3351 tools.WriteFile(u_boot_fname2, expected2)
3353 expected_text = b'not the same text'
3354 text_fname = os.path.join(outdir, 'text')
3355 tools.WriteFile(text_fname, expected_text)
3357 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3358 dtb = fdt.FdtScan(dtb_fname)
3359 node = dtb.GetNode('/binman/text')
3360 node.AddString('my-property', 'the value')
3361 dtb.Sync(auto_resize=True)
3364 return updated_fname, outdir, expected1, expected2, expected_text
3366 def _CheckReplaceMultiple(self, entry_paths):
3367 """Handle replacing the contents of multiple entries
3370 entry_paths: List of entry paths to replace
3374 Dict of entries in the image:
3377 Expected values for updated entries, each a string
3379 updated_fname, outdir, expected1, expected2, expected_text = (
3380 self._SetupForReplace())
3381 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3383 image = Image.FromFile(updated_fname)
3385 return image.GetEntries(), expected1, expected2, expected_text
3387 def testReplaceAll(self):
3388 """Test replacing the contents of all entries"""
3389 entries, expected1, expected2, expected_text = (
3390 self._CheckReplaceMultiple([]))
3391 data = entries['u-boot'].data
3392 self.assertEqual(expected1, data)
3394 data = entries['u-boot2'].data
3395 self.assertEqual(expected2, data)
3397 data = entries['text'].data
3398 self.assertEqual(expected_text, data)
3400 # Check that the device tree is updated
3401 data = entries['u-boot-dtb'].data
3402 dtb = fdt.Fdt.FromData(data)
3404 node = dtb.GetNode('/binman/text')
3405 self.assertEqual('the value', node.props['my-property'].value)
3407 def testReplaceSome(self):
3408 """Test replacing the contents of a few entries"""
3409 entries, expected1, expected2, expected_text = (
3410 self._CheckReplaceMultiple(['u-boot2', 'text']))
3412 # This one should not change
3413 data = entries['u-boot'].data
3414 self.assertEqual(U_BOOT_DATA, data)
3416 data = entries['u-boot2'].data
3417 self.assertEqual(expected2, data)
3419 data = entries['text'].data
3420 self.assertEqual(expected_text, data)
3422 def testReplaceCmd(self):
3423 """Test replacing a file fron an image on the command line"""
3424 self._DoReadFileRealDtb('143_replace_all.dts')
3427 tmpdir, updated_fname = self._SetupImageInTmpdir()
3429 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3430 expected = b'x' * len(U_BOOT_DATA)
3431 tools.WriteFile(fname, expected)
3433 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3434 data = tools.ReadFile(updated_fname)
3435 self.assertEqual(expected, data[:len(expected)])
3436 map_fname = os.path.join(tmpdir, 'image-updated.map')
3437 self.assertFalse(os.path.exists(map_fname))
3439 shutil.rmtree(tmpdir)
3441 def testReplaceCmdSome(self):
3442 """Test replacing some files fron an image on the command line"""
3443 updated_fname, outdir, expected1, expected2, expected_text = (
3444 self._SetupForReplace())
3446 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3449 tools.PrepareOutputDir(None)
3450 image = Image.FromFile(updated_fname)
3452 entries = image.GetEntries()
3454 # This one should not change
3455 data = entries['u-boot'].data
3456 self.assertEqual(U_BOOT_DATA, data)
3458 data = entries['u-boot2'].data
3459 self.assertEqual(expected2, data)
3461 data = entries['text'].data
3462 self.assertEqual(expected_text, data)
3464 def testReplaceMissing(self):
3465 """Test replacing entries where the file is missing"""
3466 updated_fname, outdir, expected1, expected2, expected_text = (
3467 self._SetupForReplace())
3469 # Remove one of the files, to generate a warning
3470 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3471 os.remove(u_boot_fname1)
3473 with test_util.capture_sys_output() as (stdout, stderr):
3474 control.ReplaceEntries(updated_fname, None, outdir, [])
3475 self.assertIn("Skipping entry '/u-boot' from missing file",
3478 def testReplaceCmdMap(self):
3479 """Test replacing a file fron an image on the command line"""
3480 self._DoReadFileRealDtb('143_replace_all.dts')
3483 tmpdir, updated_fname = self._SetupImageInTmpdir()
3485 fname = os.path.join(self._indir, 'update-u-boot.bin')
3486 expected = b'x' * len(U_BOOT_DATA)
3487 tools.WriteFile(fname, expected)
3489 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3491 map_fname = os.path.join(tmpdir, 'image-updated.map')
3492 self.assertTrue(os.path.exists(map_fname))
3494 shutil.rmtree(tmpdir)
3496 def testReplaceNoEntryPaths(self):
3497 """Test replacing an entry without an entry path"""
3498 self._DoReadFileRealDtb('143_replace_all.dts')
3499 image_fname = tools.GetOutputFilename('image.bin')
3500 with self.assertRaises(ValueError) as e:
3501 control.ReplaceEntries(image_fname, 'fname', None, [])
3502 self.assertIn('Must specify an entry path to read with -f',
3505 def testReplaceTooManyEntryPaths(self):
3506 """Test extracting some entries"""
3507 self._DoReadFileRealDtb('143_replace_all.dts')
3508 image_fname = tools.GetOutputFilename('image.bin')
3509 with self.assertRaises(ValueError) as e:
3510 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3511 self.assertIn('Must specify exactly one entry path to write with -f',
3514 def testPackReset16(self):
3515 """Test that an image with an x86 reset16 region can be created"""
3516 data = self._DoReadFile('144_x86_reset16.dts')
3517 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3519 def testPackReset16Spl(self):
3520 """Test that an image with an x86 reset16-spl region can be created"""
3521 data = self._DoReadFile('145_x86_reset16_spl.dts')
3522 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3524 def testPackReset16Tpl(self):
3525 """Test that an image with an x86 reset16-tpl region can be created"""
3526 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3527 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3529 def testPackIntelFit(self):
3530 """Test that an image with an Intel FIT and pointer can be created"""
3531 data = self._DoReadFile('147_intel_fit.dts')
3532 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3534 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3535 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3537 image = control.images['image']
3538 entries = image.GetEntries()
3539 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3540 self.assertEqual(expected_ptr, ptr)
3542 def testPackIntelFitMissing(self):
3543 """Test detection of a FIT pointer with not FIT region"""
3544 with self.assertRaises(ValueError) as e:
3545 self._DoReadFile('148_intel_fit_missing.dts')
3546 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3549 def _CheckSymbolsTplSection(self, dts, expected_vals):
3550 data = self._DoReadFile(dts)
3551 sym_values = struct.pack('<LQLL', *expected_vals)
3552 upto1 = 4 + len(U_BOOT_SPL_DATA)
3553 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3554 self.assertEqual(expected1, data[:upto1])
3556 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3557 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3558 self.assertEqual(expected2, data[upto1:upto2])
3560 upto3 = 0x34 + len(U_BOOT_DATA)
3561 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3562 self.assertEqual(expected3, data[upto2:upto3])
3564 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3565 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3567 def testSymbolsTplSection(self):
3568 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3569 self._SetupSplElf('u_boot_binman_syms')
3570 self._SetupTplElf('u_boot_binman_syms')
3571 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3572 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3574 def testSymbolsTplSectionX86(self):
3575 """Test binman can assign symbols in a section with end-at-4gb"""
3576 self._SetupSplElf('u_boot_binman_syms_x86')
3577 self._SetupTplElf('u_boot_binman_syms_x86')
3578 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3579 [0xffffff04, 0xffffff1c, 0xffffff34,
3582 def testPackX86RomIfwiSectiom(self):
3583 """Test that a section can be placed in an IFWI region"""
3584 self._SetupIfwi('fitimage.bin')
3585 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3586 self._CheckIfwi(data)
3588 def testPackFspM(self):
3589 """Test that an image with a FSP memory-init binary can be created"""
3590 data = self._DoReadFile('152_intel_fsp_m.dts')
3591 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3593 def testPackFspS(self):
3594 """Test that an image with a FSP silicon-init binary can be created"""
3595 data = self._DoReadFile('153_intel_fsp_s.dts')
3596 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3598 def testPackFspT(self):
3599 """Test that an image with a FSP temp-ram-init binary can be created"""
3600 data = self._DoReadFile('154_intel_fsp_t.dts')
3601 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3603 def testMkimage(self):
3604 """Test using mkimage to build an image"""
3605 data = self._DoReadFile('156_mkimage.dts')
3607 # Just check that the data appears in the file somewhere
3608 self.assertIn(U_BOOT_SPL_DATA, data)
3610 def testExtblob(self):
3611 """Test an image with an external blob"""
3612 data = self._DoReadFile('157_blob_ext.dts')
3613 self.assertEqual(REFCODE_DATA, data)
3615 def testExtblobMissing(self):
3616 """Test an image with a missing external blob"""
3617 with self.assertRaises(ValueError) as e:
3618 self._DoReadFile('158_blob_ext_missing.dts')
3619 self.assertIn("Filename 'missing-file' not found in input path",
3622 def testExtblobMissingOk(self):
3623 """Test an image with an missing external blob that is allowed"""
3624 with test_util.capture_sys_output() as (stdout, stderr):
3625 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3626 err = stderr.getvalue()
3627 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3629 def testExtblobMissingOkSect(self):
3630 """Test an image with an missing external blob that is allowed"""
3631 with test_util.capture_sys_output() as (stdout, stderr):
3632 self._DoTestFile('159_blob_ext_missing_sect.dts',
3634 err = stderr.getvalue()
3635 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3636 "blob-ext blob-ext2")
3638 def testPackX86RomMeMissingDesc(self):
3639 """Test that an missing Intel descriptor entry is allowed"""
3640 with test_util.capture_sys_output() as (stdout, stderr):
3641 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3642 err = stderr.getvalue()
3643 self.assertRegex(err,
3644 "Image 'main-section'.*missing.*: intel-descriptor")
3646 def testPackX86RomMissingIfwi(self):
3647 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3648 self._SetupIfwi('fitimage.bin')
3649 pathname = os.path.join(self._indir, 'fitimage.bin')
3651 with test_util.capture_sys_output() as (stdout, stderr):
3652 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3653 err = stderr.getvalue()
3654 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3656 def testPackOverlap(self):
3657 """Test that zero-size overlapping regions are ignored"""
3658 self._DoTestFile('160_pack_overlap_zero.dts')
3660 def testSimpleFit(self):
3661 """Test an image with a FIT inside"""
3662 data = self._DoReadFile('161_fit.dts')
3663 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3664 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3665 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3667 # The data should be inside the FIT
3668 dtb = fdt.Fdt.FromData(fit_data)
3670 fnode = dtb.GetNode('/images/kernel')
3671 self.assertIn('data', fnode.props)
3673 fname = os.path.join(self._indir, 'fit_data.fit')
3674 tools.WriteFile(fname, fit_data)
3675 out = tools.Run('dumpimage', '-l', fname)
3677 # Check a few features to make sure the plumbing works. We don't need
3678 # to test the operation of mkimage or dumpimage here. First convert the
3679 # output into a dict where the keys are the fields printed by dumpimage
3680 # and the values are a list of values for each field
3681 lines = out.splitlines()
3683 # Converts "Compression: gzip compressed" into two groups:
3684 # 'Compression' and 'gzip compressed'
3685 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3686 vals = collections.defaultdict(list)
3688 mat = re_line.match(line)
3689 vals[mat.group(1)].append(mat.group(2))
3691 self.assertEquals('FIT description: test-desc', lines[0])
3692 self.assertIn('Created:', lines[1])
3693 self.assertIn('Image 0 (kernel)', vals)
3694 self.assertIn('Hash value', vals)
3695 data_sizes = vals.get('Data Size')
3696 self.assertIsNotNone(data_sizes)
3697 self.assertEqual(2, len(data_sizes))
3698 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3699 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3700 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3702 def testFitExternal(self):
3703 """Test an image with an FIT with external images"""
3704 data = self._DoReadFile('162_fit_external.dts')
3705 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3707 # The data should be outside the FIT
3708 dtb = fdt.Fdt.FromData(fit_data)
3710 fnode = dtb.GetNode('/images/kernel')
3711 self.assertNotIn('data', fnode.props)
3713 def testSectionIgnoreHashSignature(self):
3714 """Test that sections ignore hash, signature nodes for its data"""
3715 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3716 expected = (U_BOOT_DATA + U_BOOT_DATA)
3717 self.assertEqual(expected, data)
3719 def testPadInSections(self):
3720 """Test pad-before, pad-after for entries in sections"""
3721 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3722 '166_pad_in_sections.dts', update_dtb=True)
3723 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3724 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3726 self.assertEqual(expected, data)
3728 dtb = fdt.Fdt(out_dtb_fname)
3730 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3734 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3736 'section:image-pos': 0,
3737 'section:offset': 0,
3738 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3740 'section/before:image-pos': 0,
3741 'section/before:offset': 0,
3742 'section/before:size': len(U_BOOT_DATA),
3744 'section/u-boot:image-pos': 4,
3745 'section/u-boot:offset': 4,
3746 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3748 'section/after:image-pos': 26,
3749 'section/after:offset': 26,
3750 'section/after:size': len(U_BOOT_DATA),
3752 self.assertEqual(expected, props)
3754 def testFitImageSubentryAlignment(self):
3755 """Test relative alignability of FIT image subentries"""
3757 'test-id': TEXT_DATA,
3759 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3760 entry_args=entry_args)
3761 dtb = fdt.Fdt.FromData(data)
3764 node = dtb.GetNode('/images/kernel')
3765 data = dtb.GetProps(node)["data"].bytes
3766 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3767 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3768 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3769 self.assertEqual(expected, data)
3771 node = dtb.GetNode('/images/fdt-1')
3772 data = dtb.GetProps(node)["data"].bytes
3773 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3774 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3776 self.assertEqual(expected, data)
3778 def testFitExtblobMissingOk(self):
3779 """Test a FIT with a missing external blob that is allowed"""
3780 with test_util.capture_sys_output() as (stdout, stderr):
3781 self._DoTestFile('168_fit_missing_blob.dts',
3783 err = stderr.getvalue()
3784 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3786 def testBlobNamedByArgMissing(self):
3787 """Test handling of a missing entry arg"""
3788 with self.assertRaises(ValueError) as e:
3789 self._DoReadFile('068_blob_named_by_arg.dts')
3790 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3793 def testPackBl31(self):
3794 """Test that an image with an ATF BL31 binary can be created"""
3795 data = self._DoReadFile('169_atf_bl31.dts')
3796 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3798 def testPackScp(self):
3799 """Test that an image with an SCP binary can be created"""
3800 data = self._DoReadFile('172_scp.dts')
3801 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3803 def testFitFdt(self):
3804 """Test an image with an FIT with multiple FDT images"""
3805 def _CheckFdt(seq, expected_data):
3806 """Check the FDT nodes
3809 seq: Sequence number to check (0 or 1)
3810 expected_data: Expected contents of 'data' property
3812 name = 'fdt-%d' % seq
3813 fnode = dtb.GetNode('/images/%s' % name)
3814 self.assertIsNotNone(fnode)
3815 self.assertEqual({'description','type', 'compression', 'data'},
3816 set(fnode.props.keys()))
3817 self.assertEqual(expected_data, fnode.props['data'].bytes)
3818 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3819 fnode.props['description'].value)
3821 def _CheckConfig(seq, expected_data):
3822 """Check the configuration nodes
3825 seq: Sequence number to check (0 or 1)
3826 expected_data: Expected contents of 'data' property
3828 cnode = dtb.GetNode('/configurations')
3829 self.assertIn('default', cnode.props)
3830 self.assertEqual('config-2', cnode.props['default'].value)
3832 name = 'config-%d' % seq
3833 fnode = dtb.GetNode('/configurations/%s' % name)
3834 self.assertIsNotNone(fnode)
3835 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3836 set(fnode.props.keys()))
3837 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3838 fnode.props['description'].value)
3839 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3842 'of-list': 'test-fdt1 test-fdt2',
3843 'default-dt': 'test-fdt2',
3845 data = self._DoReadFileDtb(
3847 entry_args=entry_args,
3848 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3849 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3850 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3852 dtb = fdt.Fdt.FromData(fit_data)
3854 fnode = dtb.GetNode('/images/kernel')
3855 self.assertIn('data', fnode.props)
3857 # Check all the properties in fdt-1 and fdt-2
3858 _CheckFdt(1, TEST_FDT1_DATA)
3859 _CheckFdt(2, TEST_FDT2_DATA)
3861 # Check configurations
3862 _CheckConfig(1, TEST_FDT1_DATA)
3863 _CheckConfig(2, TEST_FDT2_DATA)
3865 def testFitFdtMissingList(self):
3866 """Test handling of a missing 'of-list' entry arg"""
3867 with self.assertRaises(ValueError) as e:
3868 self._DoReadFile('170_fit_fdt.dts')
3869 self.assertIn("Generator node requires 'of-list' entry argument",
3872 def testFitFdtEmptyList(self):
3873 """Test handling of an empty 'of-list' entry arg"""
3877 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3879 def testFitFdtMissingProp(self):
3880 """Test handling of a missing 'fit,fdt-list' property"""
3881 with self.assertRaises(ValueError) as e:
3882 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3883 self.assertIn("Generator node requires 'fit,fdt-list' property",
3886 def testFitFdtEmptyList(self):
3887 """Test handling of an empty 'of-list' entry arg"""
3891 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3893 def testFitFdtMissing(self):
3894 """Test handling of a missing 'default-dt' entry arg"""
3896 'of-list': 'test-fdt1 test-fdt2',
3898 with self.assertRaises(ValueError) as e:
3899 self._DoReadFileDtb(
3901 entry_args=entry_args,
3902 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3903 self.assertIn("Generated 'default' node requires default-dt entry argument",
3906 def testFitFdtNotInList(self):
3907 """Test handling of a default-dt that is not in the of-list"""
3909 'of-list': 'test-fdt1 test-fdt2',
3910 'default-dt': 'test-fdt3',
3912 with self.assertRaises(ValueError) as e:
3913 self._DoReadFileDtb(
3915 entry_args=entry_args,
3916 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3917 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3920 def testFitExtblobMissingHelp(self):
3921 """Test display of help messages when an external blob is missing"""
3922 control.missing_blob_help = control._ReadMissingBlobHelp()
3923 control.missing_blob_help['wibble'] = 'Wibble test'
3924 control.missing_blob_help['another'] = 'Another test'
3925 with test_util.capture_sys_output() as (stdout, stderr):
3926 self._DoTestFile('168_fit_missing_blob.dts',
3928 err = stderr.getvalue()
3930 # We can get the tag from the name, the type or the missing-msg
3931 # property. Check all three.
3932 self.assertIn('You may need to build ARM Trusted', err)
3933 self.assertIn('Wibble test', err)
3934 self.assertIn('Another test', err)
3936 def testMissingBlob(self):
3937 """Test handling of a blob containing a missing file"""
3938 with self.assertRaises(ValueError) as e:
3939 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3940 self.assertIn("Filename 'missing' not found in input path",
3943 def testEnvironment(self):
3944 """Test adding a U-Boot environment"""
3945 data = self._DoReadFile('174_env.dts')
3946 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3947 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3948 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3949 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3952 def testEnvironmentNoSize(self):
3953 """Test that a missing 'size' property is detected"""
3954 with self.assertRaises(ValueError) as e:
3955 self._DoTestFile('175_env_no_size.dts')
3956 self.assertIn("'u-boot-env' entry must have a size property",
3959 def testEnvironmentTooSmall(self):
3960 """Test handling of an environment that does not fit"""
3961 with self.assertRaises(ValueError) as e:
3962 self._DoTestFile('176_env_too_small.dts')
3964 # checksum, start byte, environment with \0 terminator, final \0
3965 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3967 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3970 def testSkipAtStart(self):
3971 """Test handling of skip-at-start section"""
3972 data = self._DoReadFile('177_skip_at_start.dts')
3973 self.assertEqual(U_BOOT_DATA, data)
3975 image = control.images['image']
3976 entries = image.GetEntries()
3977 section = entries['section']
3978 self.assertEqual(0, section.offset)
3979 self.assertEqual(len(U_BOOT_DATA), section.size)
3980 self.assertEqual(U_BOOT_DATA, section.GetData())
3982 entry = section.GetEntries()['u-boot']
3983 self.assertEqual(16, entry.offset)
3984 self.assertEqual(len(U_BOOT_DATA), entry.size)
3985 self.assertEqual(U_BOOT_DATA, entry.data)
3987 def testSkipAtStartPad(self):
3988 """Test handling of skip-at-start section with padded entry"""
3989 data = self._DoReadFile('178_skip_at_start_pad.dts')
3990 before = tools.GetBytes(0, 8)
3991 after = tools.GetBytes(0, 4)
3992 all = before + U_BOOT_DATA + after
3993 self.assertEqual(all, data)
3995 image = control.images['image']
3996 entries = image.GetEntries()
3997 section = entries['section']
3998 self.assertEqual(0, section.offset)
3999 self.assertEqual(len(all), section.size)
4000 self.assertEqual(all, section.GetData())
4002 entry = section.GetEntries()['u-boot']
4003 self.assertEqual(16, entry.offset)
4004 self.assertEqual(len(all), entry.size)
4005 self.assertEqual(U_BOOT_DATA, entry.data)
4007 def testSkipAtStartSectionPad(self):
4008 """Test handling of skip-at-start section with padding"""
4009 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4010 before = tools.GetBytes(0, 8)
4011 after = tools.GetBytes(0, 4)
4012 all = before + U_BOOT_DATA + after
4013 self.assertEqual(all, data)
4015 image = control.images['image']
4016 entries = image.GetEntries()
4017 section = entries['section']
4018 self.assertEqual(0, section.offset)
4019 self.assertEqual(len(all), section.size)
4020 self.assertEqual(U_BOOT_DATA, section.data)
4021 self.assertEqual(all, section.GetPaddedData())
4023 entry = section.GetEntries()['u-boot']
4024 self.assertEqual(16, entry.offset)
4025 self.assertEqual(len(U_BOOT_DATA), entry.size)
4026 self.assertEqual(U_BOOT_DATA, entry.data)
4028 def testSectionPad(self):
4029 """Testing padding with sections"""
4030 data = self._DoReadFile('180_section_pad.dts')
4031 expected = (tools.GetBytes(ord('&'), 3) +
4032 tools.GetBytes(ord('!'), 5) +
4034 tools.GetBytes(ord('!'), 1) +
4035 tools.GetBytes(ord('&'), 2))
4036 self.assertEqual(expected, data)
4038 def testSectionAlign(self):
4039 """Testing alignment with sections"""
4040 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4041 expected = (b'\0' + # fill section
4042 tools.GetBytes(ord('&'), 1) + # padding to section align
4043 b'\0' + # fill section
4044 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4046 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4047 tools.GetBytes(ord('!'), 4)) # padding to section size
4048 self.assertEqual(expected, data)
4050 def testCompressImage(self):
4051 """Test compression of the entire image"""
4053 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4054 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4055 dtb = fdt.Fdt(out_dtb_fname)
4057 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4059 orig = self._decompress(data)
4060 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4062 # Do a sanity check on various fields
4063 image = control.images['image']
4064 entries = image.GetEntries()
4065 self.assertEqual(2, len(entries))
4067 entry = entries['blob']
4068 self.assertEqual(COMPRESS_DATA, entry.data)
4069 self.assertEqual(len(COMPRESS_DATA), entry.size)
4071 entry = entries['u-boot']
4072 self.assertEqual(U_BOOT_DATA, entry.data)
4073 self.assertEqual(len(U_BOOT_DATA), entry.size)
4075 self.assertEqual(len(data), image.size)
4076 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4077 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4078 orig = self._decompress(image.data)
4079 self.assertEqual(orig, image.uncomp_data)
4083 'blob:size': len(COMPRESS_DATA),
4084 'u-boot:offset': len(COMPRESS_DATA),
4085 'u-boot:size': len(U_BOOT_DATA),
4086 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4091 self.assertEqual(expected, props)
4093 def testCompressImageLess(self):
4094 """Test compression where compression reduces the image size"""
4096 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4097 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4098 dtb = fdt.Fdt(out_dtb_fname)
4100 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4102 orig = self._decompress(data)
4104 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4106 # Do a sanity check on various fields
4107 image = control.images['image']
4108 entries = image.GetEntries()
4109 self.assertEqual(2, len(entries))
4111 entry = entries['blob']
4112 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4113 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4115 entry = entries['u-boot']
4116 self.assertEqual(U_BOOT_DATA, entry.data)
4117 self.assertEqual(len(U_BOOT_DATA), entry.size)
4119 self.assertEqual(len(data), image.size)
4120 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4121 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4123 orig = self._decompress(image.data)
4124 self.assertEqual(orig, image.uncomp_data)
4128 'blob:size': len(COMPRESS_DATA_BIG),
4129 'u-boot:offset': len(COMPRESS_DATA_BIG),
4130 'u-boot:size': len(U_BOOT_DATA),
4131 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4136 self.assertEqual(expected, props)
4138 def testCompressSectionSize(self):
4139 """Test compression of a section with a fixed size"""
4141 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4142 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4143 dtb = fdt.Fdt(out_dtb_fname)
4145 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4147 orig = self._decompress(data)
4148 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4150 'section/blob:offset': 0,
4151 'section/blob:size': len(COMPRESS_DATA),
4152 'section/u-boot:offset': len(COMPRESS_DATA),
4153 'section/u-boot:size': len(U_BOOT_DATA),
4154 'section:offset': 0,
4155 'section:image-pos': 0,
4156 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4157 'section:size': 0x30,
4162 self.assertEqual(expected, props)
4164 def testCompressSection(self):
4165 """Test compression of a section with no fixed size"""
4167 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4168 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4169 dtb = fdt.Fdt(out_dtb_fname)
4171 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4173 orig = self._decompress(data)
4174 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4176 'section/blob:offset': 0,
4177 'section/blob:size': len(COMPRESS_DATA),
4178 'section/u-boot:offset': len(COMPRESS_DATA),
4179 'section/u-boot:size': len(U_BOOT_DATA),
4180 'section:offset': 0,
4181 'section:image-pos': 0,
4182 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4183 'section:size': len(data),
4188 self.assertEqual(expected, props)
4190 def testCompressExtra(self):
4191 """Test compression of a section with no fixed size"""
4193 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4194 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4195 dtb = fdt.Fdt(out_dtb_fname)
4197 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4200 base = data[len(U_BOOT_DATA):]
4201 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4202 rest = base[len(U_BOOT_DATA):]
4204 # Check compressed data
4205 section1 = self._decompress(rest)
4206 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4207 self.assertEquals(expect1, rest[:len(expect1)])
4208 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4209 rest1 = rest[len(expect1):]
4211 section2 = self._decompress(rest1)
4212 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4213 self.assertEquals(expect2, rest1[:len(expect2)])
4214 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4215 rest2 = rest1[len(expect2):]
4217 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4218 len(expect2) + len(U_BOOT_DATA))
4219 #self.assertEquals(expect_size, len(data))
4221 #self.assertEquals(U_BOOT_DATA, rest2)
4226 'u-boot:image-pos': 0,
4227 'u-boot:size': len(U_BOOT_DATA),
4229 'base:offset': len(U_BOOT_DATA),
4230 'base:image-pos': len(U_BOOT_DATA),
4231 'base:size': len(data) - len(U_BOOT_DATA),
4232 'base/u-boot:offset': 0,
4233 'base/u-boot:image-pos': len(U_BOOT_DATA),
4234 'base/u-boot:size': len(U_BOOT_DATA),
4235 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4237 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4239 'base/u-boot2:size': len(U_BOOT_DATA),
4241 'base/section:offset': len(U_BOOT_DATA),
4242 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4243 'base/section:size': len(expect1),
4244 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4245 'base/section/blob:offset': 0,
4246 'base/section/blob:size': len(COMPRESS_DATA),
4247 'base/section/u-boot:offset': len(COMPRESS_DATA),
4248 'base/section/u-boot:size': len(U_BOOT_DATA),
4250 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4251 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4252 'base/section2:size': len(expect2),
4253 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4254 'base/section2/blob:offset': 0,
4255 'base/section2/blob:size': len(COMPRESS_DATA),
4256 'base/section2/blob2:offset': len(COMPRESS_DATA),
4257 'base/section2/blob2:size': len(COMPRESS_DATA),
4263 self.assertEqual(expected, props)
4265 def testSymbolsSubsection(self):
4266 """Test binman can assign symbols from a subsection"""
4267 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4269 def testReadImageEntryArg(self):
4270 """Test reading an image that would need an entry arg to generate"""
4272 'cros-ec-rw-path': 'ecrw.bin',
4274 data = self.data = self._DoReadFileDtb(
4275 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4276 entry_args=entry_args)
4278 image_fname = tools.GetOutputFilename('image.bin')
4279 orig_image = control.images['image']
4281 # This should not generate an error about the missing 'cros-ec-rw-path'
4282 # since we are reading the image from a file. Compare with
4283 # testEntryArgsRequired()
4284 image = Image.FromFile(image_fname)
4285 self.assertEqual(orig_image.GetEntries().keys(),
4286 image.GetEntries().keys())
4288 def testFilesAlign(self):
4289 """Test alignment with files"""
4290 data = self._DoReadFile('190_files_align.dts')
4292 # The first string is 15 bytes so will align to 16
4293 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4294 self.assertEqual(expect, data)
4296 def testReadImageSkip(self):
4297 """Test reading an image and accessing its FDT map"""
4298 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4299 image_fname = tools.GetOutputFilename('image.bin')
4300 orig_image = control.images['image']
4301 image = Image.FromFile(image_fname)
4302 self.assertEqual(orig_image.GetEntries().keys(),
4303 image.GetEntries().keys())
4305 orig_entry = orig_image.GetEntries()['fdtmap']
4306 entry = image.GetEntries()['fdtmap']
4307 self.assertEqual(orig_entry.offset, entry.offset)
4308 self.assertEqual(orig_entry.size, entry.size)
4309 self.assertEqual(16, entry.image_pos)
4311 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4313 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4315 def testTplNoDtb(self):
4316 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4318 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4319 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4320 data[:len(U_BOOT_TPL_NODTB_DATA)])
4322 def testTplBssPad(self):
4323 """Test that we can pad TPL's BSS with zeros"""
4324 # ELF file with a '__bss_size' symbol
4326 data = self._DoReadFile('193_tpl_bss_pad.dts')
4327 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4330 def testTplBssPadMissing(self):
4331 """Test that a missing symbol is detected"""
4332 self._SetupTplElf('u_boot_ucode_ptr')
4333 with self.assertRaises(ValueError) as e:
4334 self._DoReadFile('193_tpl_bss_pad.dts')
4335 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4338 def checkDtbSizes(self, data, pad_len, start):
4339 """Check the size arguments in a dtb embedded in an image
4342 data: The image data
4343 pad_len: Length of the pad section in the image, in bytes
4344 start: Start offset of the devicetree to examine, within the image
4347 Size of the devicetree in bytes
4349 dtb_data = data[start:]
4350 dtb = fdt.Fdt.FromData(dtb_data)
4351 fdt_size = dtb.GetFdtObj().totalsize()
4353 props = self._GetPropTree(dtb, 'size')
4356 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4357 'u-boot-spl/u-boot-spl-dtb:size': 801,
4358 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4359 'u-boot-spl:size': 860,
4360 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4361 'u-boot/u-boot-dtb:size': 781,
4362 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4367 def testExpanded(self):
4368 """Test that an expanded entry type is selected when needed"""
4372 # SPL has a devicetree, TPL does not
4378 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4379 entry_args=entry_args)
4380 image = control.images['image']
4381 entries = image.GetEntries()
4382 self.assertEqual(3, len(entries))
4384 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4385 self.assertIn('u-boot', entries)
4386 entry = entries['u-boot']
4387 self.assertEqual('u-boot-expanded', entry.etype)
4388 subent = entry.GetEntries()
4389 self.assertEqual(2, len(subent))
4390 self.assertIn('u-boot-nodtb', subent)
4391 self.assertIn('u-boot-dtb', subent)
4393 # Second, u-boot-spl, which should be expanded into three parts
4394 self.assertIn('u-boot-spl', entries)
4395 entry = entries['u-boot-spl']
4396 self.assertEqual('u-boot-spl-expanded', entry.etype)
4397 subent = entry.GetEntries()
4398 self.assertEqual(3, len(subent))
4399 self.assertIn('u-boot-spl-nodtb', subent)
4400 self.assertIn('u-boot-spl-bss-pad', subent)
4401 self.assertIn('u-boot-spl-dtb', subent)
4403 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4405 self.assertIn('u-boot-tpl', entries)
4406 entry = entries['u-boot-tpl']
4407 self.assertEqual('u-boot-tpl', entry.etype)
4408 self.assertEqual(None, entry.GetEntries())
4410 def testExpandedTpl(self):
4411 """Test that an expanded entry type is selected for TPL when needed"""
4418 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4419 entry_args=entry_args)
4420 image = control.images['image']
4421 entries = image.GetEntries()
4422 self.assertEqual(1, len(entries))
4424 # We only have u-boot-tpl, which be expanded
4425 self.assertIn('u-boot-tpl', entries)
4426 entry = entries['u-boot-tpl']
4427 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4428 subent = entry.GetEntries()
4429 self.assertEqual(3, len(subent))
4430 self.assertIn('u-boot-tpl-nodtb', subent)
4431 self.assertIn('u-boot-tpl-bss-pad', subent)
4432 self.assertIn('u-boot-tpl-dtb', subent)
4434 def testExpandedNoPad(self):
4435 """Test an expanded entry without BSS pad enabled"""
4439 # SPL has a devicetree, TPL does not
4441 'spl-dtb': 'something',
4445 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4446 entry_args=entry_args)
4447 image = control.images['image']
4448 entries = image.GetEntries()
4450 # Just check u-boot-spl, which should be expanded into two parts
4451 self.assertIn('u-boot-spl', entries)
4452 entry = entries['u-boot-spl']
4453 self.assertEqual('u-boot-spl-expanded', entry.etype)
4454 subent = entry.GetEntries()
4455 self.assertEqual(2, len(subent))
4456 self.assertIn('u-boot-spl-nodtb', subent)
4457 self.assertIn('u-boot-spl-dtb', subent)
4459 def testExpandedTplNoPad(self):
4460 """Test that an expanded entry type with padding disabled in TPL"""
4467 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4468 entry_args=entry_args)
4469 image = control.images['image']
4470 entries = image.GetEntries()
4471 self.assertEqual(1, len(entries))
4473 # We only have u-boot-tpl, which be expanded
4474 self.assertIn('u-boot-tpl', entries)
4475 entry = entries['u-boot-tpl']
4476 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4477 subent = entry.GetEntries()
4478 self.assertEqual(2, len(subent))
4479 self.assertIn('u-boot-tpl-nodtb', subent)
4480 self.assertIn('u-boot-tpl-dtb', subent)
4482 def testFdtInclude(self):
4483 """Test that an Fdt is update within all binaries"""
4487 # SPL has a devicetree, TPL does not
4494 # Build the image. It includes two separate devicetree binaries, each
4495 # with their own contents, but all contain the binman definition.
4496 data = self._DoReadFileDtb(
4497 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4498 update_dtb=True, entry_args=entry_args)[0]
4501 # Check the U-Boot dtb
4502 start = len(U_BOOT_NODTB_DATA)
4503 fdt_size = self.checkDtbSizes(data, pad_len, start)
4506 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4507 fdt_size = self.checkDtbSizes(data, pad_len, start)
4509 # TPL has no devicetree
4510 start += fdt_size + len(U_BOOT_TPL_DATA)
4511 self.assertEqual(len(data), start)
4513 def testSymbolsExpanded(self):
4514 """Test binman can assign symbols in expanded entries"""
4518 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4519 U_BOOT_SPL_DTB_DATA, 0x38,
4520 entry_args=entry_args, use_expanded=True)
4522 def testCollection(self):
4523 """Test a collection"""
4524 data = self._DoReadFile('198_collection.dts')
4525 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4526 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4527 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4530 def testCollectionSection(self):
4531 """Test a collection where a section must be built first"""
4532 # Sections never have their contents when GetData() is called, but when
4533 # _BuildSectionData() is called with required=True, a section will force
4534 # building the contents, producing an error is anything is still
4536 data = self._DoReadFile('199_collection_section.dts')
4537 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4538 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4539 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4542 def testAlignDefault(self):
4543 """Test that default alignment works on sections"""
4544 data = self._DoReadFile('200_align_default.dts')
4545 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4547 # Special alignment for section
4548 expected += tools.GetBytes(0, 32 - len(expected))
4549 # No alignment within the nested section
4550 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4551 # Now the final piece, which should be default-aligned
4552 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4553 self.assertEqual(expected, data)
4555 def testPackOpenSBI(self):
4556 """Test that an image with an OpenSBI binary can be created"""
4557 data = self._DoReadFile('201_opensbi.dts')
4558 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4560 def testSectionsSingleThread(self):
4561 """Test sections without multithreading"""
4562 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4563 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4564 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4565 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4566 self.assertEqual(expected, data)
4568 def testThreadTimeout(self):
4569 """Test handling a thread that takes too long"""
4570 with self.assertRaises(ValueError) as e:
4571 self._DoTestFile('202_section_timeout.dts',
4572 test_section_timeout=True)
4573 self.assertIn("Timed out obtaining contents", str(e.exception))
4575 def testTiming(self):
4576 """Test output of timing information"""
4577 data = self._DoReadFile('055_sections.dts')
4578 with test_util.capture_sys_output() as (stdout, stderr):
4580 self.assertIn('read:', stdout.getvalue())
4581 self.assertIn('compress:', stdout.getvalue())
4584 if __name__ == "__main__":