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'
80 TEST_FDT1_DATA = b'fdt1'
81 TEST_FDT2_DATA = b'test-fdt2'
82 ENV_DATA = b'var1=1\nvar2="2"'
84 # Subdirectory of the input dir to use to put test FDTs
85 TEST_FDT_SUBDIR = 'fdts'
87 # The expected size for the device tree in some tests
88 EXTRACT_DTB_SIZE = 0x3c9
90 # Properties expected to be in the device tree when update_dtb is used
91 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
93 # Extra properties expected to be in the device tree when allow-repack is used
94 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
97 class TestFunctional(unittest.TestCase):
98 """Functional tests for binman
100 Most of these use a sample .dts file to build an image and then check
101 that it looks correct. The sample files are in the test/ subdirectory
104 For each entry type a very small test file is created using fixed
105 string contents. This makes it easy to test that things look right, and
108 In some cases a 'real' file must be used - these are also supplied in
109 the test/ diurectory.
114 from binman import entry
116 # Handle the case where argv[0] is 'python'
117 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
118 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
120 # Create a temporary directory for input files
121 cls._indir = tempfile.mkdtemp(prefix='binmant.')
123 # Create some test files
124 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
125 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
126 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
127 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
128 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
129 TestFunctional._MakeInputFile('me.bin', ME_DATA)
130 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
133 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
135 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
136 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
137 X86_START16_SPL_DATA)
138 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
139 X86_START16_TPL_DATA)
141 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
143 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
144 X86_RESET16_SPL_DATA)
145 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
146 X86_RESET16_TPL_DATA)
148 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
149 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
150 U_BOOT_SPL_NODTB_DATA)
151 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
152 U_BOOT_TPL_NODTB_DATA)
153 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
154 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
155 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
156 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
157 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
158 TestFunctional._MakeInputDir('devkeys')
159 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
160 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
161 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
162 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
163 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
165 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
166 elf_test.BuildElfTestFiles(cls._elf_testdir)
168 # ELF file with a '_dt_ucode_base_size' symbol
169 TestFunctional._MakeInputFile('u-boot',
170 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
172 # Intel flash descriptor file
173 cls._SetupDescriptor()
175 shutil.copytree(cls.TestFile('files'),
176 os.path.join(cls._indir, 'files'))
178 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
179 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
180 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
181 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
183 # Add a few .dtb files for testing
184 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
186 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
189 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
191 # Travis-CI may have an old lz4
194 tools.Run('lz4', '--no-frame-crc', '-c',
195 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
200 def tearDownClass(cls):
201 """Remove the temporary input directory and its contents"""
202 if cls.preserve_indir:
203 print('Preserving input dir: %s' % cls._indir)
206 shutil.rmtree(cls._indir)
210 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
211 toolpath=None, verbosity=None):
212 """Accept arguments controlling test execution
215 preserve_indir: Preserve the shared input directory used by all
217 preserve_outdir: Preserve the output directories used by tests. Each
218 test has its own, so this is normally only useful when running a
220 toolpath: ist of paths to use for tools
222 cls.preserve_indir = preserve_indir
223 cls.preserve_outdirs = preserve_outdirs
224 cls.toolpath = toolpath
225 cls.verbosity = verbosity
228 if not self.have_lz4:
229 self.skipTest('lz4 --no-frame-crc not available')
231 def _CleanupOutputDir(self):
232 """Remove the temporary output directory"""
233 if self.preserve_outdirs:
234 print('Preserving output dir: %s' % tools.outdir)
236 tools._FinaliseForTest()
239 # Enable this to turn on debugging output
240 # tout.Init(tout.DEBUG)
241 command.test_result = None
244 """Remove the temporary output directory"""
245 self._CleanupOutputDir()
247 def _SetupImageInTmpdir(self):
248 """Set up the output image in a new temporary directory
250 This is used when an image has been generated in the output directory,
251 but we want to run binman again. This will create a new output
252 directory and fail to delete the original one.
254 This creates a new temporary directory, copies the image to it (with a
255 new name) and removes the old output directory.
259 Temporary directory to use
262 image_fname = tools.GetOutputFilename('image.bin')
263 tmpdir = tempfile.mkdtemp(prefix='binman.')
264 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
265 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
266 self._CleanupOutputDir()
267 return tmpdir, updated_fname
271 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
272 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
273 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
275 def _RunBinman(self, *args, **kwargs):
276 """Run binman using the command line
279 Arguments to pass, as a list of strings
280 kwargs: Arguments to pass to Command.RunPipe()
282 result = command.RunPipe([[self._binman_pathname] + list(args)],
283 capture=True, capture_stderr=True, raise_on_error=False)
284 if result.return_code and kwargs.get('raise_on_error', True):
285 raise Exception("Error running '%s': %s" % (' '.join(args),
286 result.stdout + result.stderr))
289 def _DoBinman(self, *argv):
290 """Run binman using directly (in the same process)
293 Arguments to pass, as a list of strings
295 Return value (0 for success)
298 args = cmdline.ParseArgs(argv)
299 args.pager = 'binman-invalid-pager'
300 args.build_dir = self._indir
302 # For testing, you can force an increase in verbosity here
303 # args.verbosity = tout.DEBUG
304 return control.Binman(args)
306 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
307 entry_args=None, images=None, use_real_dtb=False,
308 use_expanded=False, verbosity=None, allow_missing=False,
310 """Run binman with a given test file
313 fname: Device-tree source filename to use (e.g. 005_simple.dts)
314 debug: True to enable debugging output
315 map: True to output map files for the images
316 update_dtb: Update the offset and size of each entry in the device
317 tree before packing it into the image
318 entry_args: Dict of entry args to supply to binman
320 value: value of that arg
321 images: List of image names to build
322 use_real_dtb: True to use the test file as the contents of
323 the u-boot-dtb entry. Normally this is not needed and the
324 test contents (the U_BOOT_DTB_DATA string) can be used.
325 But in some test we need the real contents.
326 use_expanded: True to use expanded entries where available, e.g.
327 'u-boot-expanded' instead of 'u-boot'
328 verbosity: Verbosity level to use (0-3, None=don't set it)
329 allow_missing: Set the '--allow-missing' flag so that missing
330 external binaries just produce a warning instead of an error
331 extra_indirs: Extra input directories to add using -I
336 if verbosity is not None:
337 args.append('-v%d' % verbosity)
339 args.append('-v%d' % self.verbosity)
341 for path in self.toolpath:
342 args += ['--toolpath', path]
343 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
349 args.append('--fake-dtb')
351 args.append('--no-expanded')
353 for arg, value in entry_args.items():
354 args.append('-a%s=%s' % (arg, value))
359 args += ['-i', image]
361 for indir in extra_indirs:
362 args += ['-I', indir]
363 return self._DoBinman(*args)
365 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
366 """Set up a new test device-tree file
368 The given file is compiled and set up as the device tree to be used
372 fname: Filename of .dts file to read
373 outfile: Output filename for compiled device-tree binary
376 Contents of device-tree binary
378 tmpdir = tempfile.mkdtemp(prefix='binmant.')
379 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
380 with open(dtb, 'rb') as fd:
382 TestFunctional._MakeInputFile(outfile, data)
383 shutil.rmtree(tmpdir)
386 def _GetDtbContentsForSplTpl(self, dtb_data, name):
387 """Create a version of the main DTB for SPL or SPL
389 For testing we don't actually have different versions of the DTB. With
390 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
391 we don't normally have any unwanted nodes.
393 We still want the DTBs for SPL and TPL to be different though, since
394 otherwise it is confusing to know which one we are looking at. So add
395 an 'spl' or 'tpl' property to the top-level node.
398 dtb_data: dtb data to modify (this should be a value devicetree)
399 name: Name of a new property to add
402 New dtb data with the property added
404 dtb = fdt.Fdt.FromData(dtb_data)
406 dtb.GetNode('/binman').AddZeroProp(name)
407 dtb.Sync(auto_resize=True)
409 return dtb.GetContents()
411 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
412 map=False, update_dtb=False, entry_args=None,
413 reset_dtbs=True, extra_indirs=None):
414 """Run binman and return the resulting image
416 This runs binman with a given test file and then reads the resulting
417 output file. It is a shortcut function since most tests need to do
420 Raises an assertion failure if binman returns a non-zero exit code.
423 fname: Device-tree source filename to use (e.g. 005_simple.dts)
424 use_real_dtb: True to use the test file as the contents of
425 the u-boot-dtb entry. Normally this is not needed and the
426 test contents (the U_BOOT_DTB_DATA string) can be used.
427 But in some test we need the real contents.
428 use_expanded: True to use expanded entries where available, e.g.
429 'u-boot-expanded' instead of 'u-boot'
430 map: True to output map files for the images
431 update_dtb: Update the offset and size of each entry in the device
432 tree before packing it into the image
433 entry_args: Dict of entry args to supply to binman
435 value: value of that arg
436 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
437 function. If reset_dtbs is True, then the original test dtb
438 is written back before this function finishes
439 extra_indirs: Extra input directories to add using -I
443 Resulting image contents
445 Map data showing contents of image (or None if none)
446 Output device tree binary filename ('u-boot.dtb' path)
449 # Use the compiled test file as the u-boot-dtb input
451 dtb_data = self._SetupDtb(fname)
453 # For testing purposes, make a copy of the DT for SPL and TPL. Add
454 # a node indicating which it is, so aid verification.
455 for name in ['spl', 'tpl']:
456 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
457 outfile = os.path.join(self._indir, dtb_fname)
458 TestFunctional._MakeInputFile(dtb_fname,
459 self._GetDtbContentsForSplTpl(dtb_data, name))
462 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
463 entry_args=entry_args, use_real_dtb=use_real_dtb,
464 use_expanded=use_expanded, extra_indirs=extra_indirs)
465 self.assertEqual(0, retcode)
466 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
468 # Find the (only) image, read it and return its contents
469 image = control.images['image']
470 image_fname = tools.GetOutputFilename('image.bin')
471 self.assertTrue(os.path.exists(image_fname))
473 map_fname = tools.GetOutputFilename('image.map')
474 with open(map_fname) as fd:
478 with open(image_fname, 'rb') as fd:
479 return fd.read(), dtb_data, map_data, out_dtb_fname
481 # Put the test file back
482 if reset_dtbs and use_real_dtb:
485 def _DoReadFileRealDtb(self, fname):
486 """Run binman with a real .dtb file and return the resulting data
489 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
492 Resulting image contents
494 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
496 def _DoReadFile(self, fname, use_real_dtb=False):
497 """Helper function which discards the device-tree binary
500 fname: Device-tree source filename to use (e.g. 005_simple.dts)
501 use_real_dtb: True to use the test file as the contents of
502 the u-boot-dtb entry. Normally this is not needed and the
503 test contents (the U_BOOT_DTB_DATA string) can be used.
504 But in some test we need the real contents.
507 Resulting image contents
509 return self._DoReadFileDtb(fname, use_real_dtb)[0]
512 def _MakeInputFile(cls, fname, contents):
513 """Create a new test input file, creating directories as needed
516 fname: Filename to create
517 contents: File contents to write in to the file
519 Full pathname of file created
521 pathname = os.path.join(cls._indir, fname)
522 dirname = os.path.dirname(pathname)
523 if dirname and not os.path.exists(dirname):
525 with open(pathname, 'wb') as fd:
530 def _MakeInputDir(cls, dirname):
531 """Create a new test input directory, creating directories as needed
534 dirname: Directory name to create
537 Full pathname of directory created
539 pathname = os.path.join(cls._indir, dirname)
540 if not os.path.exists(pathname):
541 os.makedirs(pathname)
545 def _SetupSplElf(cls, src_fname='bss_data'):
546 """Set up an ELF file with a '_dt_ucode_base_size' symbol
549 Filename of ELF file to use as SPL
551 TestFunctional._MakeInputFile('spl/u-boot-spl',
552 tools.ReadFile(cls.ElfTestFile(src_fname)))
555 def _SetupTplElf(cls, src_fname='bss_data'):
556 """Set up an ELF file with a '_dt_ucode_base_size' symbol
559 Filename of ELF file to use as TPL
561 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
562 tools.ReadFile(cls.ElfTestFile(src_fname)))
565 def _SetupDescriptor(cls):
566 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
567 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
570 def TestFile(cls, fname):
571 return os.path.join(cls._binman_dir, 'test', fname)
574 def ElfTestFile(cls, fname):
575 return os.path.join(cls._elf_testdir, fname)
577 def AssertInList(self, grep_list, target):
578 """Assert that at least one of a list of things is in a target
581 grep_list: List of strings to check
582 target: Target string
584 for grep in grep_list:
587 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
589 def CheckNoGaps(self, entries):
590 """Check that all entries fit together without gaps
593 entries: List of entries to check
596 for entry in entries.values():
597 self.assertEqual(offset, entry.offset)
600 def GetFdtLen(self, dtb):
601 """Get the totalsize field from a device-tree binary
604 dtb: Device-tree binary contents
607 Total size of device-tree binary, from the header
609 return struct.unpack('>L', dtb[4:8])[0]
611 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
612 def AddNode(node, path):
614 path += '/' + node.name
615 for prop in node.props.values():
616 if prop.name in prop_names:
617 prop_path = path + ':' + prop.name
618 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
620 for subnode in node.subnodes:
621 AddNode(subnode, path)
624 AddNode(dtb.GetRoot(), '')
628 """Test a basic run with valid args"""
629 result = self._RunBinman('-h')
631 def testFullHelp(self):
632 """Test that the full help is displayed with -H"""
633 result = self._RunBinman('-H')
634 help_file = os.path.join(self._binman_dir, 'README.rst')
635 # Remove possible extraneous strings
636 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
637 gothelp = result.stdout.replace(extra, '')
638 self.assertEqual(len(gothelp), os.path.getsize(help_file))
639 self.assertEqual(0, len(result.stderr))
640 self.assertEqual(0, result.return_code)
642 def testFullHelpInternal(self):
643 """Test that the full help is displayed with -H"""
645 command.test_result = command.CommandResult()
646 result = self._DoBinman('-H')
647 help_file = os.path.join(self._binman_dir, 'README.rst')
649 command.test_result = None
652 """Test that the basic help is displayed with -h"""
653 result = self._RunBinman('-h')
654 self.assertTrue(len(result.stdout) > 200)
655 self.assertEqual(0, len(result.stderr))
656 self.assertEqual(0, result.return_code)
659 """Test that we can run it with a specific board"""
660 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
661 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
662 result = self._DoBinman('build', '-n', '-b', 'sandbox')
663 self.assertEqual(0, result)
665 def testNeedBoard(self):
666 """Test that we get an error when no board ius supplied"""
667 with self.assertRaises(ValueError) as e:
668 result = self._DoBinman('build')
669 self.assertIn("Must provide a board to process (use -b <board>)",
672 def testMissingDt(self):
673 """Test that an invalid device-tree file generates an error"""
674 with self.assertRaises(Exception) as e:
675 self._RunBinman('build', '-d', 'missing_file')
676 # We get one error from libfdt, and a different one from fdtget.
677 self.AssertInList(["Couldn't open blob from 'missing_file'",
678 'No such file or directory'], str(e.exception))
680 def testBrokenDt(self):
681 """Test that an invalid device-tree source file generates an error
683 Since this is a source file it should be compiled and the error
684 will come from the device-tree compiler (dtc).
686 with self.assertRaises(Exception) as e:
687 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
688 self.assertIn("FATAL ERROR: Unable to parse input tree",
691 def testMissingNode(self):
692 """Test that a device tree without a 'binman' node generates an error"""
693 with self.assertRaises(Exception) as e:
694 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
695 self.assertIn("does not have a 'binman' node", str(e.exception))
698 """Test that an empty binman node works OK (i.e. does nothing)"""
699 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
700 self.assertEqual(0, len(result.stderr))
701 self.assertEqual(0, result.return_code)
703 def testInvalidEntry(self):
704 """Test that an invalid entry is flagged"""
705 with self.assertRaises(Exception) as e:
706 result = self._RunBinman('build', '-d',
707 self.TestFile('004_invalid_entry.dts'))
708 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
709 "'/binman/not-a-valid-type'", str(e.exception))
711 def testSimple(self):
712 """Test a simple binman with a single file"""
713 data = self._DoReadFile('005_simple.dts')
714 self.assertEqual(U_BOOT_DATA, data)
716 def testSimpleDebug(self):
717 """Test a simple binman run with debugging enabled"""
718 self._DoTestFile('005_simple.dts', debug=True)
721 """Test that we can handle creating two images
723 This also tests image padding.
725 retcode = self._DoTestFile('006_dual_image.dts')
726 self.assertEqual(0, retcode)
728 image = control.images['image1']
729 self.assertEqual(len(U_BOOT_DATA), image.size)
730 fname = tools.GetOutputFilename('image1.bin')
731 self.assertTrue(os.path.exists(fname))
732 with open(fname, 'rb') as fd:
734 self.assertEqual(U_BOOT_DATA, data)
736 image = control.images['image2']
737 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
738 fname = tools.GetOutputFilename('image2.bin')
739 self.assertTrue(os.path.exists(fname))
740 with open(fname, 'rb') as fd:
742 self.assertEqual(U_BOOT_DATA, data[3:7])
743 self.assertEqual(tools.GetBytes(0, 3), data[:3])
744 self.assertEqual(tools.GetBytes(0, 5), data[7:])
746 def testBadAlign(self):
747 """Test that an invalid alignment value is detected"""
748 with self.assertRaises(ValueError) as e:
749 self._DoTestFile('007_bad_align.dts')
750 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
751 "of two", str(e.exception))
753 def testPackSimple(self):
754 """Test that packing works as expected"""
755 retcode = self._DoTestFile('008_pack.dts')
756 self.assertEqual(0, retcode)
757 self.assertIn('image', control.images)
758 image = control.images['image']
759 entries = image.GetEntries()
760 self.assertEqual(5, len(entries))
763 self.assertIn('u-boot', entries)
764 entry = entries['u-boot']
765 self.assertEqual(0, entry.offset)
766 self.assertEqual(len(U_BOOT_DATA), entry.size)
768 # Second u-boot, aligned to 16-byte boundary
769 self.assertIn('u-boot-align', entries)
770 entry = entries['u-boot-align']
771 self.assertEqual(16, entry.offset)
772 self.assertEqual(len(U_BOOT_DATA), entry.size)
774 # Third u-boot, size 23 bytes
775 self.assertIn('u-boot-size', entries)
776 entry = entries['u-boot-size']
777 self.assertEqual(20, entry.offset)
778 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
779 self.assertEqual(23, entry.size)
781 # Fourth u-boot, placed immediate after the above
782 self.assertIn('u-boot-next', entries)
783 entry = entries['u-boot-next']
784 self.assertEqual(43, entry.offset)
785 self.assertEqual(len(U_BOOT_DATA), entry.size)
787 # Fifth u-boot, placed at a fixed offset
788 self.assertIn('u-boot-fixed', entries)
789 entry = entries['u-boot-fixed']
790 self.assertEqual(61, entry.offset)
791 self.assertEqual(len(U_BOOT_DATA), entry.size)
793 self.assertEqual(65, image.size)
795 def testPackExtra(self):
796 """Test that extra packing feature works as expected"""
797 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
800 self.assertIn('image', control.images)
801 image = control.images['image']
802 entries = image.GetEntries()
803 self.assertEqual(5, len(entries))
805 # First u-boot with padding before and after
806 self.assertIn('u-boot', entries)
807 entry = entries['u-boot']
808 self.assertEqual(0, entry.offset)
809 self.assertEqual(3, entry.pad_before)
810 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
811 self.assertEqual(U_BOOT_DATA, entry.data)
812 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
813 tools.GetBytes(0, 5), data[:entry.size])
816 # Second u-boot has an aligned size, but it has no effect
817 self.assertIn('u-boot-align-size-nop', entries)
818 entry = entries['u-boot-align-size-nop']
819 self.assertEqual(pos, entry.offset)
820 self.assertEqual(len(U_BOOT_DATA), entry.size)
821 self.assertEqual(U_BOOT_DATA, entry.data)
822 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
825 # Third u-boot has an aligned size too
826 self.assertIn('u-boot-align-size', entries)
827 entry = entries['u-boot-align-size']
828 self.assertEqual(pos, entry.offset)
829 self.assertEqual(32, entry.size)
830 self.assertEqual(U_BOOT_DATA, entry.data)
831 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
832 data[pos:pos + entry.size])
835 # Fourth u-boot has an aligned end
836 self.assertIn('u-boot-align-end', entries)
837 entry = entries['u-boot-align-end']
838 self.assertEqual(48, entry.offset)
839 self.assertEqual(16, entry.size)
840 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
841 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
842 data[pos:pos + entry.size])
845 # Fifth u-boot immediately afterwards
846 self.assertIn('u-boot-align-both', entries)
847 entry = entries['u-boot-align-both']
848 self.assertEqual(64, entry.offset)
849 self.assertEqual(64, entry.size)
850 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
851 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
852 data[pos:pos + entry.size])
854 self.CheckNoGaps(entries)
855 self.assertEqual(128, image.size)
857 dtb = fdt.Fdt(out_dtb_fname)
859 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
865 'u-boot:image-pos': 0,
867 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
869 'u-boot-align-size-nop:image-pos': 12,
870 'u-boot-align-size-nop:offset': 12,
871 'u-boot-align-size-nop:size': 4,
873 'u-boot-align-size:image-pos': 16,
874 'u-boot-align-size:offset': 16,
875 'u-boot-align-size:size': 32,
877 'u-boot-align-end:image-pos': 48,
878 'u-boot-align-end:offset': 48,
879 'u-boot-align-end:size': 16,
881 'u-boot-align-both:image-pos': 64,
882 'u-boot-align-both:offset': 64,
883 'u-boot-align-both:size': 64,
885 self.assertEqual(expected, props)
887 def testPackAlignPowerOf2(self):
888 """Test that invalid entry alignment is detected"""
889 with self.assertRaises(ValueError) as e:
890 self._DoTestFile('010_pack_align_power2.dts')
891 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
892 "of two", str(e.exception))
894 def testPackAlignSizePowerOf2(self):
895 """Test that invalid entry size alignment is detected"""
896 with self.assertRaises(ValueError) as e:
897 self._DoTestFile('011_pack_align_size_power2.dts')
898 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
899 "power of two", str(e.exception))
901 def testPackInvalidAlign(self):
902 """Test detection of an offset that does not match its alignment"""
903 with self.assertRaises(ValueError) as e:
904 self._DoTestFile('012_pack_inv_align.dts')
905 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
906 "align 0x4 (4)", str(e.exception))
908 def testPackInvalidSizeAlign(self):
909 """Test that invalid entry size alignment is detected"""
910 with self.assertRaises(ValueError) as e:
911 self._DoTestFile('013_pack_inv_size_align.dts')
912 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
913 "align-size 0x4 (4)", str(e.exception))
915 def testPackOverlap(self):
916 """Test that overlapping regions are detected"""
917 with self.assertRaises(ValueError) as e:
918 self._DoTestFile('014_pack_overlap.dts')
919 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
920 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
923 def testPackEntryOverflow(self):
924 """Test that entries that overflow their size are detected"""
925 with self.assertRaises(ValueError) as e:
926 self._DoTestFile('015_pack_overflow.dts')
927 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
928 "but entry size is 0x3 (3)", str(e.exception))
930 def testPackImageOverflow(self):
931 """Test that entries which overflow the image size are detected"""
932 with self.assertRaises(ValueError) as e:
933 self._DoTestFile('016_pack_image_overflow.dts')
934 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
935 "size 0x3 (3)", str(e.exception))
937 def testPackImageSize(self):
938 """Test that the image size can be set"""
939 retcode = self._DoTestFile('017_pack_image_size.dts')
940 self.assertEqual(0, retcode)
941 self.assertIn('image', control.images)
942 image = control.images['image']
943 self.assertEqual(7, image.size)
945 def testPackImageSizeAlign(self):
946 """Test that image size alignemnt works as expected"""
947 retcode = self._DoTestFile('018_pack_image_align.dts')
948 self.assertEqual(0, retcode)
949 self.assertIn('image', control.images)
950 image = control.images['image']
951 self.assertEqual(16, image.size)
953 def testPackInvalidImageAlign(self):
954 """Test that invalid image alignment is detected"""
955 with self.assertRaises(ValueError) as e:
956 self._DoTestFile('019_pack_inv_image_align.dts')
957 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
958 "align-size 0x8 (8)", str(e.exception))
960 def testPackAlignPowerOf2(self):
961 """Test that invalid image alignment is detected"""
962 with self.assertRaises(ValueError) as e:
963 self._DoTestFile('020_pack_inv_image_align_power2.dts')
964 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
965 "two", str(e.exception))
967 def testImagePadByte(self):
968 """Test that the image pad byte can be specified"""
970 data = self._DoReadFile('021_image_pad.dts')
971 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
974 def testImageName(self):
975 """Test that image files can be named"""
976 retcode = self._DoTestFile('022_image_name.dts')
977 self.assertEqual(0, retcode)
978 image = control.images['image1']
979 fname = tools.GetOutputFilename('test-name')
980 self.assertTrue(os.path.exists(fname))
982 image = control.images['image2']
983 fname = tools.GetOutputFilename('test-name.xx')
984 self.assertTrue(os.path.exists(fname))
986 def testBlobFilename(self):
987 """Test that generic blobs can be provided by filename"""
988 data = self._DoReadFile('023_blob.dts')
989 self.assertEqual(BLOB_DATA, data)
991 def testPackSorted(self):
992 """Test that entries can be sorted"""
994 data = self._DoReadFile('024_sorted.dts')
995 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
996 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
998 def testPackZeroOffset(self):
999 """Test that an entry at offset 0 is not given a new offset"""
1000 with self.assertRaises(ValueError) as e:
1001 self._DoTestFile('025_pack_zero_size.dts')
1002 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
1003 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1006 def testPackUbootDtb(self):
1007 """Test that a device tree can be added to U-Boot"""
1008 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
1009 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
1011 def testPackX86RomNoSize(self):
1012 """Test that the end-at-4gb property requires a size property"""
1013 with self.assertRaises(ValueError) as e:
1014 self._DoTestFile('027_pack_4gb_no_size.dts')
1015 self.assertIn("Image '/binman': Section size must be provided when "
1016 "using end-at-4gb", str(e.exception))
1018 def test4gbAndSkipAtStartTogether(self):
1019 """Test that the end-at-4gb and skip-at-size property can't be used
1021 with self.assertRaises(ValueError) as e:
1022 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
1023 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
1024 "'skip-at-start'", str(e.exception))
1026 def testPackX86RomOutside(self):
1027 """Test that the end-at-4gb property checks for offset boundaries"""
1028 with self.assertRaises(ValueError) as e:
1029 self._DoTestFile('028_pack_4gb_outside.dts')
1030 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1031 "is outside the section '/binman' starting at "
1032 '0xffffffe0 (4294967264) of size 0x20 (32)',
1035 def testPackX86Rom(self):
1036 """Test that a basic x86 ROM can be created"""
1038 data = self._DoReadFile('029_x86_rom.dts')
1039 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
1040 tools.GetBytes(0, 2), data)
1042 def testPackX86RomMeNoDesc(self):
1043 """Test that an invalid Intel descriptor entry is detected"""
1045 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1046 with self.assertRaises(ValueError) as e:
1047 self._DoTestFile('163_x86_rom_me_empty.dts')
1048 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1051 self._SetupDescriptor()
1053 def testPackX86RomBadDesc(self):
1054 """Test that the Intel requires a descriptor entry"""
1055 with self.assertRaises(ValueError) as e:
1056 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1057 self.assertIn("Node '/binman/intel-me': No offset set with "
1058 "offset-unset: should another entry provide this correct "
1059 "offset?", str(e.exception))
1061 def testPackX86RomMe(self):
1062 """Test that an x86 ROM with an ME region can be created"""
1063 data = self._DoReadFile('031_x86_rom_me.dts')
1064 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1065 if data[:0x1000] != expected_desc:
1066 self.fail('Expected descriptor binary at start of image')
1067 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1069 def testPackVga(self):
1070 """Test that an image with a VGA binary can be created"""
1071 data = self._DoReadFile('032_intel_vga.dts')
1072 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1074 def testPackStart16(self):
1075 """Test that an image with an x86 start16 region can be created"""
1076 data = self._DoReadFile('033_x86_start16.dts')
1077 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1079 def testPackPowerpcMpc85xxBootpgResetvec(self):
1080 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1082 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1083 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1085 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1086 """Handle running a test for insertion of microcode
1089 dts_fname: Name of test .dts file
1090 nodtb_data: Data that we expect in the first section
1091 ucode_second: True if the microsecond entry is second instead of
1096 Contents of first region (U-Boot or SPL)
1097 Offset and size components of microcode pointer, as inserted
1098 in the above (two 4-byte words)
1100 data = self._DoReadFile(dts_fname, True)
1102 # Now check the device tree has no microcode
1104 ucode_content = data[len(nodtb_data):]
1105 ucode_pos = len(nodtb_data)
1106 dtb_with_ucode = ucode_content[16:]
1107 fdt_len = self.GetFdtLen(dtb_with_ucode)
1109 dtb_with_ucode = data[len(nodtb_data):]
1110 fdt_len = self.GetFdtLen(dtb_with_ucode)
1111 ucode_content = dtb_with_ucode[fdt_len:]
1112 ucode_pos = len(nodtb_data) + fdt_len
1113 fname = tools.GetOutputFilename('test.dtb')
1114 with open(fname, 'wb') as fd:
1115 fd.write(dtb_with_ucode)
1116 dtb = fdt.FdtScan(fname)
1117 ucode = dtb.GetNode('/microcode')
1118 self.assertTrue(ucode)
1119 for node in ucode.subnodes:
1120 self.assertFalse(node.props.get('data'))
1122 # Check that the microcode appears immediately after the Fdt
1123 # This matches the concatenation of the data properties in
1124 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1125 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1127 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1129 # Check that the microcode pointer was inserted. It should match the
1130 # expected offset and size
1131 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1133 u_boot = data[:len(nodtb_data)]
1134 return u_boot, pos_and_size
1136 def testPackUbootMicrocode(self):
1137 """Test that x86 microcode can be handled correctly
1139 We expect to see the following in the image, in order:
1140 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1142 u-boot.dtb with the microcode removed
1145 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1147 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1148 b' somewhere in here', first)
1150 def _RunPackUbootSingleMicrocode(self):
1151 """Test that x86 microcode can be handled correctly
1153 We expect to see the following in the image, in order:
1154 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1156 u-boot.dtb with the microcode
1157 an empty microcode region
1159 # We need the libfdt library to run this test since only that allows
1160 # finding the offset of a property. This is required by
1161 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1162 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1164 second = data[len(U_BOOT_NODTB_DATA):]
1166 fdt_len = self.GetFdtLen(second)
1167 third = second[fdt_len:]
1168 second = second[:fdt_len]
1170 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1171 self.assertIn(ucode_data, second)
1172 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1174 # Check that the microcode pointer was inserted. It should match the
1175 # expected offset and size
1176 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1178 first = data[:len(U_BOOT_NODTB_DATA)]
1179 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1180 b' somewhere in here', first)
1182 def testPackUbootSingleMicrocode(self):
1183 """Test that x86 microcode can be handled correctly with fdt_normal.
1185 self._RunPackUbootSingleMicrocode()
1187 def testUBootImg(self):
1188 """Test that u-boot.img can be put in a file"""
1189 data = self._DoReadFile('036_u_boot_img.dts')
1190 self.assertEqual(U_BOOT_IMG_DATA, data)
1192 def testNoMicrocode(self):
1193 """Test that a missing microcode region is detected"""
1194 with self.assertRaises(ValueError) as e:
1195 self._DoReadFile('037_x86_no_ucode.dts', True)
1196 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1197 "node found in ", str(e.exception))
1199 def testMicrocodeWithoutNode(self):
1200 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1201 with self.assertRaises(ValueError) as e:
1202 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1203 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1204 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1206 def testMicrocodeWithoutNode2(self):
1207 """Test that a missing u-boot-ucode node is detected"""
1208 with self.assertRaises(ValueError) as e:
1209 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1210 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1211 "microcode region u-boot-ucode", str(e.exception))
1213 def testMicrocodeWithoutPtrInElf(self):
1214 """Test that a U-Boot binary without the microcode symbol is detected"""
1215 # ELF file without a '_dt_ucode_base_size' symbol
1217 TestFunctional._MakeInputFile('u-boot',
1218 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1220 with self.assertRaises(ValueError) as e:
1221 self._RunPackUbootSingleMicrocode()
1222 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1223 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1226 # Put the original file back
1227 TestFunctional._MakeInputFile('u-boot',
1228 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1230 def testMicrocodeNotInImage(self):
1231 """Test that microcode must be placed within the image"""
1232 with self.assertRaises(ValueError) as e:
1233 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1234 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1235 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1236 "section ranging from 00000000 to 0000002e", str(e.exception))
1238 def testWithoutMicrocode(self):
1239 """Test that we can cope with an image without microcode (e.g. qemu)"""
1240 TestFunctional._MakeInputFile('u-boot',
1241 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1242 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1244 # Now check the device tree has no microcode
1245 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1246 second = data[len(U_BOOT_NODTB_DATA):]
1248 fdt_len = self.GetFdtLen(second)
1249 self.assertEqual(dtb, second[:fdt_len])
1251 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1252 third = data[used_len:]
1253 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1255 def testUnknownPosSize(self):
1256 """Test that microcode must be placed within the image"""
1257 with self.assertRaises(ValueError) as e:
1258 self._DoReadFile('041_unknown_pos_size.dts', True)
1259 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1260 "entry 'invalid-entry'", str(e.exception))
1262 def testPackFsp(self):
1263 """Test that an image with a FSP binary can be created"""
1264 data = self._DoReadFile('042_intel_fsp.dts')
1265 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1267 def testPackCmc(self):
1268 """Test that an image with a CMC binary can be created"""
1269 data = self._DoReadFile('043_intel_cmc.dts')
1270 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1272 def testPackVbt(self):
1273 """Test that an image with a VBT binary can be created"""
1274 data = self._DoReadFile('046_intel_vbt.dts')
1275 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1277 def testSplBssPad(self):
1278 """Test that we can pad SPL's BSS with zeros"""
1279 # ELF file with a '__bss_size' symbol
1281 data = self._DoReadFile('047_spl_bss_pad.dts')
1282 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1285 def testSplBssPadMissing(self):
1286 """Test that a missing symbol is detected"""
1287 self._SetupSplElf('u_boot_ucode_ptr')
1288 with self.assertRaises(ValueError) as e:
1289 self._DoReadFile('047_spl_bss_pad.dts')
1290 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1293 def testPackStart16Spl(self):
1294 """Test that an image with an x86 start16 SPL region can be created"""
1295 data = self._DoReadFile('048_x86_start16_spl.dts')
1296 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1298 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1299 """Helper function for microcode tests
1301 We expect to see the following in the image, in order:
1302 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1304 u-boot.dtb with the microcode removed
1308 dts: Device tree file to use for test
1309 ucode_second: True if the microsecond entry is second instead of
1312 self._SetupSplElf('u_boot_ucode_ptr')
1313 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1314 ucode_second=ucode_second)
1315 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1316 b'ter somewhere in here', first)
1318 def testPackUbootSplMicrocode(self):
1319 """Test that x86 microcode can be handled correctly in SPL"""
1320 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1322 def testPackUbootSplMicrocodeReorder(self):
1323 """Test that order doesn't matter for microcode entries
1325 This is the same as testPackUbootSplMicrocode but when we process the
1326 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1327 entry, so we reply on binman to try later.
1329 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1332 def testPackMrc(self):
1333 """Test that an image with an MRC binary can be created"""
1334 data = self._DoReadFile('050_intel_mrc.dts')
1335 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1337 def testSplDtb(self):
1338 """Test that an image with spl/u-boot-spl.dtb can be created"""
1339 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1340 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1342 def testSplNoDtb(self):
1343 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1345 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1346 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1348 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1349 use_expanded=False):
1350 """Check the image contains the expected symbol values
1353 dts: Device tree file to use for test
1354 base_data: Data before and after 'u-boot' section
1355 u_boot_offset: Offset of 'u-boot' section in image
1356 entry_args: Dict of entry args to supply to binman
1358 value: value of that arg
1359 use_expanded: True to use expanded entries where available, e.g.
1360 'u-boot-expanded' instead of 'u-boot'
1362 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1363 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1364 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1365 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1368 self._SetupSplElf('u_boot_binman_syms')
1369 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1370 use_expanded=use_expanded)[0]
1371 # The image should contain the symbols from u_boot_binman_syms.c
1372 # Note that image_pos is adjusted by the base address of the image,
1373 # which is 0x10 in our test image
1374 sym_values = struct.pack('<LQLL', 0x00,
1375 u_boot_offset + len(U_BOOT_DATA),
1376 0x10 + u_boot_offset, 0x04)
1377 expected = (sym_values + base_data[20:] +
1378 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1380 self.assertEqual(expected, data)
1382 def testSymbols(self):
1383 """Test binman can assign symbols embedded in U-Boot"""
1384 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1386 def testSymbolsNoDtb(self):
1387 """Test binman can assign symbols embedded in U-Boot SPL"""
1388 self.checkSymbols('196_symbols_nodtb.dts',
1389 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1392 def testPackUnitAddress(self):
1393 """Test that we support multiple binaries with the same name"""
1394 data = self._DoReadFile('054_unit_address.dts')
1395 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1397 def testSections(self):
1398 """Basic test of sections"""
1399 data = self._DoReadFile('055_sections.dts')
1400 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1401 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1402 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1403 self.assertEqual(expected, data)
1406 """Tests outputting a map of the images"""
1407 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1408 self.assertEqual('''ImagePos Offset Size Name
1409 00000000 00000000 00000028 main-section
1410 00000000 00000000 00000010 section@0
1411 00000000 00000000 00000004 u-boot
1412 00000010 00000010 00000010 section@1
1413 00000010 00000000 00000004 u-boot
1414 00000020 00000020 00000004 section@2
1415 00000020 00000000 00000004 u-boot
1418 def testNamePrefix(self):
1419 """Tests that name prefixes are used"""
1420 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1421 self.assertEqual('''ImagePos Offset Size Name
1422 00000000 00000000 00000028 main-section
1423 00000000 00000000 00000010 section@0
1424 00000000 00000000 00000004 ro-u-boot
1425 00000010 00000010 00000010 section@1
1426 00000010 00000000 00000004 rw-u-boot
1429 def testUnknownContents(self):
1430 """Test that obtaining the contents works as expected"""
1431 with self.assertRaises(ValueError) as e:
1432 self._DoReadFile('057_unknown_contents.dts', True)
1433 self.assertIn("Image '/binman': Internal error: Could not complete "
1434 "processing of contents: remaining ["
1435 "<binman.etype._testing.Entry__testing ", str(e.exception))
1437 def testBadChangeSize(self):
1438 """Test that trying to change the size of an entry fails"""
1440 state.SetAllowEntryExpansion(False)
1441 with self.assertRaises(ValueError) as e:
1442 self._DoReadFile('059_change_size.dts', True)
1443 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1446 state.SetAllowEntryExpansion(True)
1448 def testUpdateFdt(self):
1449 """Test that we can update the device tree with offset/size info"""
1450 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1452 dtb = fdt.Fdt(out_dtb_fname)
1454 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1458 '_testing:offset': 32,
1460 '_testing:image-pos': 32,
1461 'section@0/u-boot:offset': 0,
1462 'section@0/u-boot:size': len(U_BOOT_DATA),
1463 'section@0/u-boot:image-pos': 0,
1464 'section@0:offset': 0,
1465 'section@0:size': 16,
1466 'section@0:image-pos': 0,
1468 'section@1/u-boot:offset': 0,
1469 'section@1/u-boot:size': len(U_BOOT_DATA),
1470 'section@1/u-boot:image-pos': 16,
1471 'section@1:offset': 16,
1472 'section@1:size': 16,
1473 'section@1:image-pos': 16,
1477 def testUpdateFdtBad(self):
1478 """Test that we detect when ProcessFdt never completes"""
1479 with self.assertRaises(ValueError) as e:
1480 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1481 self.assertIn('Could not complete processing of Fdt: remaining '
1482 '[<binman.etype._testing.Entry__testing',
1485 def testEntryArgs(self):
1486 """Test passing arguments to entries from the command line"""
1488 'test-str-arg': 'test1',
1489 'test-int-arg': '456',
1491 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1492 self.assertIn('image', control.images)
1493 entry = control.images['image'].GetEntries()['_testing']
1494 self.assertEqual('test0', entry.test_str_fdt)
1495 self.assertEqual('test1', entry.test_str_arg)
1496 self.assertEqual(123, entry.test_int_fdt)
1497 self.assertEqual(456, entry.test_int_arg)
1499 def testEntryArgsMissing(self):
1500 """Test missing arguments and properties"""
1502 'test-int-arg': '456',
1504 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1505 entry = control.images['image'].GetEntries()['_testing']
1506 self.assertEqual('test0', entry.test_str_fdt)
1507 self.assertEqual(None, entry.test_str_arg)
1508 self.assertEqual(None, entry.test_int_fdt)
1509 self.assertEqual(456, entry.test_int_arg)
1511 def testEntryArgsRequired(self):
1512 """Test missing arguments and properties"""
1514 'test-int-arg': '456',
1516 with self.assertRaises(ValueError) as e:
1517 self._DoReadFileDtb('064_entry_args_required.dts')
1518 self.assertIn("Node '/binman/_testing': "
1519 'Missing required properties/entry args: test-str-arg, '
1520 'test-int-fdt, test-int-arg',
1523 def testEntryArgsInvalidFormat(self):
1524 """Test that an invalid entry-argument format is detected"""
1525 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1527 with self.assertRaises(ValueError) as e:
1528 self._DoBinman(*args)
1529 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1531 def testEntryArgsInvalidInteger(self):
1532 """Test that an invalid entry-argument integer is detected"""
1534 'test-int-arg': 'abc',
1536 with self.assertRaises(ValueError) as e:
1537 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1538 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1539 "'test-int-arg' (value 'abc') to integer",
1542 def testEntryArgsInvalidDatatype(self):
1543 """Test that an invalid entry-argument datatype is detected
1545 This test could be written in entry_test.py except that it needs
1546 access to control.entry_args, which seems more than that module should
1550 'test-bad-datatype-arg': '12',
1552 with self.assertRaises(ValueError) as e:
1553 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1554 entry_args=entry_args)
1555 self.assertIn('GetArg() internal error: Unknown data type ',
1559 """Test for a text entry type"""
1561 'test-id': TEXT_DATA,
1562 'test-id2': TEXT_DATA2,
1563 'test-id3': TEXT_DATA3,
1565 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1566 entry_args=entry_args)
1567 expected = (tools.ToBytes(TEXT_DATA) +
1568 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1569 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1570 b'some text' + b'more text')
1571 self.assertEqual(expected, data)
1573 def testEntryDocs(self):
1574 """Test for creation of entry documentation"""
1575 with test_util.capture_sys_output() as (stdout, stderr):
1576 control.WriteEntryDocs(control.GetEntryModules())
1577 self.assertTrue(len(stdout.getvalue()) > 0)
1579 def testEntryDocsMissing(self):
1580 """Test handling of missing entry documentation"""
1581 with self.assertRaises(ValueError) as e:
1582 with test_util.capture_sys_output() as (stdout, stderr):
1583 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1584 self.assertIn('Documentation is missing for modules: u_boot',
1588 """Basic test of generation of a flashrom fmap"""
1589 data = self._DoReadFile('067_fmap.dts')
1590 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1591 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1592 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1593 self.assertEqual(expected, data[:32])
1594 self.assertEqual(b'__FMAP__', fhdr.signature)
1595 self.assertEqual(1, fhdr.ver_major)
1596 self.assertEqual(0, fhdr.ver_minor)
1597 self.assertEqual(0, fhdr.base)
1598 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
1599 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
1600 self.assertEqual(b'FMAP', fhdr.name)
1601 self.assertEqual(5, fhdr.nareas)
1602 fiter = iter(fentries)
1604 fentry = next(fiter)
1605 self.assertEqual(b'SECTION0', fentry.name)
1606 self.assertEqual(0, fentry.offset)
1607 self.assertEqual(16, fentry.size)
1608 self.assertEqual(0, fentry.flags)
1610 fentry = next(fiter)
1611 self.assertEqual(b'RO_U_BOOT', fentry.name)
1612 self.assertEqual(0, fentry.offset)
1613 self.assertEqual(4, fentry.size)
1614 self.assertEqual(0, fentry.flags)
1616 fentry = next(fiter)
1617 self.assertEqual(b'SECTION1', fentry.name)
1618 self.assertEqual(16, fentry.offset)
1619 self.assertEqual(16, fentry.size)
1620 self.assertEqual(0, fentry.flags)
1622 fentry = next(fiter)
1623 self.assertEqual(b'RW_U_BOOT', fentry.name)
1624 self.assertEqual(16, fentry.offset)
1625 self.assertEqual(4, fentry.size)
1626 self.assertEqual(0, fentry.flags)
1628 fentry = next(fiter)
1629 self.assertEqual(b'FMAP', fentry.name)
1630 self.assertEqual(32, fentry.offset)
1631 self.assertEqual(expect_size, fentry.size)
1632 self.assertEqual(0, fentry.flags)
1634 def testBlobNamedByArg(self):
1635 """Test we can add a blob with the filename coming from an entry arg"""
1637 'cros-ec-rw-path': 'ecrw.bin',
1639 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1642 """Test for an fill entry type"""
1643 data = self._DoReadFile('069_fill.dts')
1644 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1645 self.assertEqual(expected, data)
1647 def testFillNoSize(self):
1648 """Test for an fill entry type with no size"""
1649 with self.assertRaises(ValueError) as e:
1650 self._DoReadFile('070_fill_no_size.dts')
1651 self.assertIn("'fill' entry must have a size property",
1654 def _HandleGbbCommand(self, pipe_list):
1655 """Fake calls to the futility utility"""
1656 if pipe_list[0][0] == 'futility':
1657 fname = pipe_list[0][-1]
1658 # Append our GBB data to the file, which will happen every time the
1659 # futility command is called.
1660 with open(fname, 'ab') as fd:
1662 return command.CommandResult()
1665 """Test for the Chromium OS Google Binary Block"""
1666 command.test_result = self._HandleGbbCommand
1668 'keydir': 'devkeys',
1669 'bmpblk': 'bmpblk.bin',
1671 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1674 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1675 tools.GetBytes(0, 0x2180 - 16))
1676 self.assertEqual(expected, data)
1678 def testGbbTooSmall(self):
1679 """Test for the Chromium OS Google Binary Block being large enough"""
1680 with self.assertRaises(ValueError) as e:
1681 self._DoReadFileDtb('072_gbb_too_small.dts')
1682 self.assertIn("Node '/binman/gbb': GBB is too small",
1685 def testGbbNoSize(self):
1686 """Test for the Chromium OS Google Binary Block having a size"""
1687 with self.assertRaises(ValueError) as e:
1688 self._DoReadFileDtb('073_gbb_no_size.dts')
1689 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1692 def _HandleVblockCommand(self, pipe_list):
1693 """Fake calls to the futility utility
1695 The expected pipe is:
1697 [('futility', 'vbutil_firmware', '--vblock',
1698 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1699 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1700 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1701 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1703 This writes to the output file (here, 'vblock.vblock'). If
1704 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1705 of the input data (here, 'input.vblock').
1707 if pipe_list[0][0] == 'futility':
1708 fname = pipe_list[0][3]
1709 with open(fname, 'wb') as fd:
1711 infile = pipe_list[0][11]
1712 m = hashlib.sha256()
1713 data = tools.ReadFile(infile)
1715 fd.write(m.digest())
1717 fd.write(VBLOCK_DATA)
1719 return command.CommandResult()
1721 def testVblock(self):
1722 """Test for the Chromium OS Verified Boot Block"""
1723 self._hash_data = False
1724 command.test_result = self._HandleVblockCommand
1726 'keydir': 'devkeys',
1728 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1729 entry_args=entry_args)
1730 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1731 self.assertEqual(expected, data)
1733 def testVblockNoContent(self):
1734 """Test we detect a vblock which has no content to sign"""
1735 with self.assertRaises(ValueError) as e:
1736 self._DoReadFile('075_vblock_no_content.dts')
1737 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1738 'property', str(e.exception))
1740 def testVblockBadPhandle(self):
1741 """Test that we detect a vblock with an invalid phandle in contents"""
1742 with self.assertRaises(ValueError) as e:
1743 self._DoReadFile('076_vblock_bad_phandle.dts')
1744 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1745 '1000', str(e.exception))
1747 def testVblockBadEntry(self):
1748 """Test that we detect an entry that points to a non-entry"""
1749 with self.assertRaises(ValueError) as e:
1750 self._DoReadFile('077_vblock_bad_entry.dts')
1751 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1752 "'other'", str(e.exception))
1754 def testVblockContent(self):
1755 """Test that the vblock signs the right data"""
1756 self._hash_data = True
1757 command.test_result = self._HandleVblockCommand
1759 'keydir': 'devkeys',
1761 data = self._DoReadFileDtb(
1762 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1763 entry_args=entry_args)[0]
1764 hashlen = 32 # SHA256 hash is 32 bytes
1765 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1766 hashval = data[-hashlen:]
1767 dtb = data[len(U_BOOT_DATA):-hashlen]
1769 expected_data = U_BOOT_DATA + dtb
1771 # The hashval should be a hash of the dtb
1772 m = hashlib.sha256()
1773 m.update(expected_data)
1774 expected_hashval = m.digest()
1775 self.assertEqual(expected_hashval, hashval)
1778 """Test that an image with TPL and its device tree can be created"""
1779 # ELF file with a '__bss_size' symbol
1781 data = self._DoReadFile('078_u_boot_tpl.dts')
1782 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1784 def testUsesPos(self):
1785 """Test that the 'pos' property cannot be used anymore"""
1786 with self.assertRaises(ValueError) as e:
1787 data = self._DoReadFile('079_uses_pos.dts')
1788 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1789 "'pos'", str(e.exception))
1791 def testFillZero(self):
1792 """Test for an fill entry type with a size of 0"""
1793 data = self._DoReadFile('080_fill_empty.dts')
1794 self.assertEqual(tools.GetBytes(0, 16), data)
1796 def testTextMissing(self):
1797 """Test for a text entry type where there is no text"""
1798 with self.assertRaises(ValueError) as e:
1799 self._DoReadFileDtb('066_text.dts',)
1800 self.assertIn("Node '/binman/text': No value provided for text label "
1801 "'test-id'", str(e.exception))
1803 def testPackStart16Tpl(self):
1804 """Test that an image with an x86 start16 TPL region can be created"""
1805 data = self._DoReadFile('081_x86_start16_tpl.dts')
1806 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1808 def testSelectImage(self):
1809 """Test that we can select which images to build"""
1810 expected = 'Skipping images: image1'
1812 # We should only get the expected message in verbose mode
1813 for verbosity in (0, 2):
1814 with test_util.capture_sys_output() as (stdout, stderr):
1815 retcode = self._DoTestFile('006_dual_image.dts',
1816 verbosity=verbosity,
1818 self.assertEqual(0, retcode)
1820 self.assertIn(expected, stdout.getvalue())
1822 self.assertNotIn(expected, stdout.getvalue())
1824 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1825 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1826 self._CleanupOutputDir()
1828 def testUpdateFdtAll(self):
1829 """Test that all device trees are updated with offset/size info"""
1830 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1833 'section:image-pos': 0,
1834 'u-boot-tpl-dtb:size': 513,
1835 'u-boot-spl-dtb:size': 513,
1836 'u-boot-spl-dtb:offset': 493,
1838 'section/u-boot-dtb:image-pos': 0,
1839 'u-boot-spl-dtb:image-pos': 493,
1840 'section/u-boot-dtb:size': 493,
1841 'u-boot-tpl-dtb:image-pos': 1006,
1842 'section/u-boot-dtb:offset': 0,
1843 'section:size': 493,
1845 'section:offset': 0,
1846 'u-boot-tpl-dtb:offset': 1006,
1850 # We expect three device-tree files in the output, one after the other.
1851 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1852 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1853 # main U-Boot tree. All three should have the same postions and offset.
1855 for item in ['', 'spl', 'tpl']:
1856 dtb = fdt.Fdt.FromData(data[start:])
1858 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1860 expected = dict(base_expected)
1863 self.assertEqual(expected, props)
1864 start += dtb._fdt_obj.totalsize()
1866 def testUpdateFdtOutput(self):
1867 """Test that output DTB files are updated"""
1869 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1870 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1872 # Unfortunately, compiling a source file always results in a file
1873 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1874 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1875 # binman as a file called u-boot.dtb. To fix this, copy the file
1876 # over to the expected place.
1878 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1879 'tpl/u-boot-tpl.dtb.out']:
1880 dtb = fdt.Fdt.FromData(data[start:])
1881 size = dtb._fdt_obj.totalsize()
1882 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1883 outdata = tools.ReadFile(pathname)
1884 name = os.path.split(fname)[0]
1887 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1889 orig_indata = dtb_data
1890 self.assertNotEqual(outdata, orig_indata,
1891 "Expected output file '%s' be updated" % pathname)
1892 self.assertEqual(outdata, data[start:start + size],
1893 "Expected output file '%s' to match output image" %
1899 def _decompress(self, data):
1900 return tools.Decompress(data, 'lz4')
1902 def testCompress(self):
1903 """Test compression of blobs"""
1905 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1906 use_real_dtb=True, update_dtb=True)
1907 dtb = fdt.Fdt(out_dtb_fname)
1909 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1910 orig = self._decompress(data)
1911 self.assertEquals(COMPRESS_DATA, orig)
1913 # Do a sanity check on various fields
1914 image = control.images['image']
1915 entries = image.GetEntries()
1916 self.assertEqual(1, len(entries))
1918 entry = entries['blob']
1919 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1920 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1921 orig = self._decompress(entry.data)
1922 self.assertEqual(orig, entry.uncomp_data)
1924 self.assertEqual(image.data, entry.data)
1927 'blob:uncomp-size': len(COMPRESS_DATA),
1928 'blob:size': len(data),
1931 self.assertEqual(expected, props)
1933 def testFiles(self):
1934 """Test bringing in multiple files"""
1935 data = self._DoReadFile('084_files.dts')
1936 self.assertEqual(FILES_DATA, data)
1938 def testFilesCompress(self):
1939 """Test bringing in multiple files and compressing them"""
1941 data = self._DoReadFile('085_files_compress.dts')
1943 image = control.images['image']
1944 entries = image.GetEntries()
1945 files = entries['files']
1946 entries = files._entries
1949 for i in range(1, 3):
1951 start = entries[key].image_pos
1952 len = entries[key].size
1953 chunk = data[start:start + len]
1954 orig += self._decompress(chunk)
1956 self.assertEqual(FILES_DATA, orig)
1958 def testFilesMissing(self):
1959 """Test missing files"""
1960 with self.assertRaises(ValueError) as e:
1961 data = self._DoReadFile('086_files_none.dts')
1962 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1963 'no files', str(e.exception))
1965 def testFilesNoPattern(self):
1966 """Test missing files"""
1967 with self.assertRaises(ValueError) as e:
1968 data = self._DoReadFile('087_files_no_pattern.dts')
1969 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1972 def testExpandSize(self):
1973 """Test an expanding entry"""
1974 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1976 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1977 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1978 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1979 tools.GetBytes(ord('d'), 8))
1980 self.assertEqual(expect, data)
1981 self.assertEqual('''ImagePos Offset Size Name
1982 00000000 00000000 00000028 main-section
1983 00000000 00000000 00000008 fill
1984 00000008 00000008 00000004 u-boot
1985 0000000c 0000000c 00000004 section
1986 0000000c 00000000 00000003 intel-mrc
1987 00000010 00000010 00000004 u-boot2
1988 00000014 00000014 0000000c section2
1989 00000014 00000000 00000008 fill
1990 0000001c 00000008 00000004 u-boot
1991 00000020 00000020 00000008 fill2
1994 def testExpandSizeBad(self):
1995 """Test an expanding entry which fails to provide contents"""
1996 with test_util.capture_sys_output() as (stdout, stderr):
1997 with self.assertRaises(ValueError) as e:
1998 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1999 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2000 'expanding entry', str(e.exception))
2003 """Test hashing of the contents of an entry"""
2004 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
2005 use_real_dtb=True, update_dtb=True)
2006 dtb = fdt.Fdt(out_dtb_fname)
2008 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2009 m = hashlib.sha256()
2010 m.update(U_BOOT_DATA)
2011 self.assertEqual(m.digest(), b''.join(hash_node.value))
2013 def testHashNoAlgo(self):
2014 with self.assertRaises(ValueError) as e:
2015 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2016 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2017 'hash node', str(e.exception))
2019 def testHashBadAlgo(self):
2020 with self.assertRaises(ValueError) as e:
2021 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2022 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2025 def testHashSection(self):
2026 """Test hashing of the contents of an entry"""
2027 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2028 use_real_dtb=True, update_dtb=True)
2029 dtb = fdt.Fdt(out_dtb_fname)
2031 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2032 m = hashlib.sha256()
2033 m.update(U_BOOT_DATA)
2034 m.update(tools.GetBytes(ord('a'), 16))
2035 self.assertEqual(m.digest(), b''.join(hash_node.value))
2037 def testPackUBootTplMicrocode(self):
2038 """Test that x86 microcode can be handled correctly in TPL
2040 We expect to see the following in the image, in order:
2041 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2043 u-boot-tpl.dtb with the microcode removed
2046 self._SetupTplElf('u_boot_ucode_ptr')
2047 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2048 U_BOOT_TPL_NODTB_DATA)
2049 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2050 b'ter somewhere in here', first)
2052 def testFmapX86(self):
2053 """Basic test of generation of a flashrom fmap"""
2054 data = self._DoReadFile('094_fmap_x86.dts')
2055 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2056 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
2057 self.assertEqual(expected, data[:32])
2058 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2060 self.assertEqual(0x100, fhdr.image_size)
2062 self.assertEqual(0, fentries[0].offset)
2063 self.assertEqual(4, fentries[0].size)
2064 self.assertEqual(b'U_BOOT', fentries[0].name)
2066 self.assertEqual(4, fentries[1].offset)
2067 self.assertEqual(3, fentries[1].size)
2068 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2070 self.assertEqual(32, fentries[2].offset)
2071 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2072 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2073 self.assertEqual(b'FMAP', fentries[2].name)
2075 def testFmapX86Section(self):
2076 """Basic test of generation of a flashrom fmap"""
2077 data = self._DoReadFile('095_fmap_x86_section.dts')
2078 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
2079 self.assertEqual(expected, data[:32])
2080 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2082 self.assertEqual(0x180, fhdr.image_size)
2083 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
2084 fiter = iter(fentries)
2086 fentry = next(fiter)
2087 self.assertEqual(b'U_BOOT', fentry.name)
2088 self.assertEqual(0, fentry.offset)
2089 self.assertEqual(4, fentry.size)
2091 fentry = next(fiter)
2092 self.assertEqual(b'SECTION', fentry.name)
2093 self.assertEqual(4, fentry.offset)
2094 self.assertEqual(0x20 + expect_size, fentry.size)
2096 fentry = next(fiter)
2097 self.assertEqual(b'INTEL_MRC', fentry.name)
2098 self.assertEqual(4, fentry.offset)
2099 self.assertEqual(3, fentry.size)
2101 fentry = next(fiter)
2102 self.assertEqual(b'FMAP', fentry.name)
2103 self.assertEqual(36, fentry.offset)
2104 self.assertEqual(expect_size, fentry.size)
2107 """Basic test of ELF entries"""
2110 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2111 TestFunctional._MakeInputFile('-boot', fd.read())
2112 data = self._DoReadFile('096_elf.dts')
2114 def testElfStrip(self):
2115 """Basic test of ELF entries"""
2117 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2118 TestFunctional._MakeInputFile('-boot', fd.read())
2119 data = self._DoReadFile('097_elf_strip.dts')
2121 def testPackOverlapMap(self):
2122 """Test that overlapping regions are detected"""
2123 with test_util.capture_sys_output() as (stdout, stderr):
2124 with self.assertRaises(ValueError) as e:
2125 self._DoTestFile('014_pack_overlap.dts', map=True)
2126 map_fname = tools.GetOutputFilename('image.map')
2127 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2130 # We should not get an inmage, but there should be a map file
2131 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2132 self.assertTrue(os.path.exists(map_fname))
2133 map_data = tools.ReadFile(map_fname, binary=False)
2134 self.assertEqual('''ImagePos Offset Size Name
2135 <none> 00000000 00000008 main-section
2136 <none> 00000000 00000004 u-boot
2137 <none> 00000003 00000004 u-boot-align
2140 def testPackRefCode(self):
2141 """Test that an image with an Intel Reference code binary works"""
2142 data = self._DoReadFile('100_intel_refcode.dts')
2143 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2145 def testSectionOffset(self):
2146 """Tests use of a section with an offset"""
2147 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2149 self.assertEqual('''ImagePos Offset Size Name
2150 00000000 00000000 00000038 main-section
2151 00000004 00000004 00000010 section@0
2152 00000004 00000000 00000004 u-boot
2153 00000018 00000018 00000010 section@1
2154 00000018 00000000 00000004 u-boot
2155 0000002c 0000002c 00000004 section@2
2156 0000002c 00000000 00000004 u-boot
2158 self.assertEqual(data,
2159 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2160 tools.GetBytes(0x21, 12) +
2161 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2162 tools.GetBytes(0x61, 12) +
2163 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2164 tools.GetBytes(0x26, 8))
2166 def testCbfsRaw(self):
2167 """Test base handling of a Coreboot Filesystem (CBFS)
2169 The exact contents of the CBFS is verified by similar tests in
2170 cbfs_util_test.py. The tests here merely check that the files added to
2171 the CBFS can be found in the final image.
2173 data = self._DoReadFile('102_cbfs_raw.dts')
2176 cbfs = cbfs_util.CbfsReader(data)
2177 self.assertEqual(size, cbfs.rom_size)
2179 self.assertIn('u-boot-dtb', cbfs.files)
2180 cfile = cbfs.files['u-boot-dtb']
2181 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2183 def testCbfsArch(self):
2184 """Test on non-x86 architecture"""
2185 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2188 cbfs = cbfs_util.CbfsReader(data)
2189 self.assertEqual(size, cbfs.rom_size)
2191 self.assertIn('u-boot-dtb', cbfs.files)
2192 cfile = cbfs.files['u-boot-dtb']
2193 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2195 def testCbfsStage(self):
2196 """Tests handling of a Coreboot Filesystem (CBFS)"""
2197 if not elf.ELF_TOOLS:
2198 self.skipTest('Python elftools not available')
2199 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2200 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2203 data = self._DoReadFile('104_cbfs_stage.dts')
2204 cbfs = cbfs_util.CbfsReader(data)
2205 self.assertEqual(size, cbfs.rom_size)
2207 self.assertIn('u-boot', cbfs.files)
2208 cfile = cbfs.files['u-boot']
2209 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2211 def testCbfsRawCompress(self):
2212 """Test handling of compressing raw files"""
2214 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2217 cbfs = cbfs_util.CbfsReader(data)
2218 self.assertIn('u-boot', cbfs.files)
2219 cfile = cbfs.files['u-boot']
2220 self.assertEqual(COMPRESS_DATA, cfile.data)
2222 def testCbfsBadArch(self):
2223 """Test handling of a bad architecture"""
2224 with self.assertRaises(ValueError) as e:
2225 self._DoReadFile('106_cbfs_bad_arch.dts')
2226 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2228 def testCbfsNoSize(self):
2229 """Test handling of a missing size property"""
2230 with self.assertRaises(ValueError) as e:
2231 self._DoReadFile('107_cbfs_no_size.dts')
2232 self.assertIn('entry must have a size property', str(e.exception))
2234 def testCbfsNoCOntents(self):
2235 """Test handling of a CBFS entry which does not provide contentsy"""
2236 with self.assertRaises(ValueError) as e:
2237 self._DoReadFile('108_cbfs_no_contents.dts')
2238 self.assertIn('Could not complete processing of contents',
2241 def testCbfsBadCompress(self):
2242 """Test handling of a bad architecture"""
2243 with self.assertRaises(ValueError) as e:
2244 self._DoReadFile('109_cbfs_bad_compress.dts')
2245 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2248 def testCbfsNamedEntries(self):
2249 """Test handling of named entries"""
2250 data = self._DoReadFile('110_cbfs_name.dts')
2252 cbfs = cbfs_util.CbfsReader(data)
2253 self.assertIn('FRED', cbfs.files)
2254 cfile1 = cbfs.files['FRED']
2255 self.assertEqual(U_BOOT_DATA, cfile1.data)
2257 self.assertIn('hello', cbfs.files)
2258 cfile2 = cbfs.files['hello']
2259 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2261 def _SetupIfwi(self, fname):
2262 """Set up to run an IFWI test
2265 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2270 # Intel Integrated Firmware Image (IFWI) file
2271 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2273 TestFunctional._MakeInputFile(fname,data)
2275 def _CheckIfwi(self, data):
2276 """Check that an image with an IFWI contains the correct output
2279 data: Conents of output file
2281 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2282 if data[:0x1000] != expected_desc:
2283 self.fail('Expected descriptor binary at start of image')
2285 # We expect to find the TPL wil in subpart IBBP entry IBBL
2286 image_fname = tools.GetOutputFilename('image.bin')
2287 tpl_fname = tools.GetOutputFilename('tpl.out')
2288 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2289 subpart='IBBP', entry_name='IBBL')
2291 tpl_data = tools.ReadFile(tpl_fname)
2292 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2294 def testPackX86RomIfwi(self):
2295 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2296 self._SetupIfwi('fitimage.bin')
2297 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2298 self._CheckIfwi(data)
2300 def testPackX86RomIfwiNoDesc(self):
2301 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2302 self._SetupIfwi('ifwi.bin')
2303 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2304 self._CheckIfwi(data)
2306 def testPackX86RomIfwiNoData(self):
2307 """Test that an x86 ROM with IFWI handles missing data"""
2308 self._SetupIfwi('ifwi.bin')
2309 with self.assertRaises(ValueError) as e:
2310 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2311 self.assertIn('Could not complete processing of contents',
2314 def testCbfsOffset(self):
2315 """Test a CBFS with files at particular offsets
2317 Like all CFBS tests, this is just checking the logic that calls
2318 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2320 data = self._DoReadFile('114_cbfs_offset.dts')
2323 cbfs = cbfs_util.CbfsReader(data)
2324 self.assertEqual(size, cbfs.rom_size)
2326 self.assertIn('u-boot', cbfs.files)
2327 cfile = cbfs.files['u-boot']
2328 self.assertEqual(U_BOOT_DATA, cfile.data)
2329 self.assertEqual(0x40, cfile.cbfs_offset)
2331 self.assertIn('u-boot-dtb', cbfs.files)
2332 cfile2 = cbfs.files['u-boot-dtb']
2333 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2334 self.assertEqual(0x140, cfile2.cbfs_offset)
2336 def testFdtmap(self):
2337 """Test an FDT map can be inserted in the image"""
2338 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2339 fdtmap_data = data[len(U_BOOT_DATA):]
2340 magic = fdtmap_data[:8]
2341 self.assertEqual(b'_FDTMAP_', magic)
2342 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2344 fdt_data = fdtmap_data[16:]
2345 dtb = fdt.Fdt.FromData(fdt_data)
2347 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2352 'u-boot:size': len(U_BOOT_DATA),
2353 'u-boot:image-pos': 0,
2354 'fdtmap:image-pos': 4,
2356 'fdtmap:size': len(fdtmap_data),
2360 def testFdtmapNoMatch(self):
2361 """Check handling of an FDT map when the section cannot be found"""
2362 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2364 # Mangle the section name, which should cause a mismatch between the
2365 # correct FDT path and the one expected by the section
2366 image = control.images['image']
2367 image._node.path += '-suffix'
2368 entries = image.GetEntries()
2369 fdtmap = entries['fdtmap']
2370 with self.assertRaises(ValueError) as e:
2372 self.assertIn("Cannot locate node for path '/binman-suffix'",
2375 def testFdtmapHeader(self):
2376 """Test an FDT map and image header can be inserted in the image"""
2377 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2378 fdtmap_pos = len(U_BOOT_DATA)
2379 fdtmap_data = data[fdtmap_pos:]
2380 fdt_data = fdtmap_data[16:]
2381 dtb = fdt.Fdt.FromData(fdt_data)
2382 fdt_size = dtb.GetFdtObj().totalsize()
2383 hdr_data = data[-8:]
2384 self.assertEqual(b'BinM', hdr_data[:4])
2385 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2386 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2388 def testFdtmapHeaderStart(self):
2389 """Test an image header can be inserted at the image start"""
2390 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2391 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2393 self.assertEqual(b'BinM', hdr_data[:4])
2394 offset = struct.unpack('<I', hdr_data[4:])[0]
2395 self.assertEqual(fdtmap_pos, offset)
2397 def testFdtmapHeaderPos(self):
2398 """Test an image header can be inserted at a chosen position"""
2399 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2400 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2401 hdr_data = data[0x80:0x88]
2402 self.assertEqual(b'BinM', hdr_data[:4])
2403 offset = struct.unpack('<I', hdr_data[4:])[0]
2404 self.assertEqual(fdtmap_pos, offset)
2406 def testHeaderMissingFdtmap(self):
2407 """Test an image header requires an fdtmap"""
2408 with self.assertRaises(ValueError) as e:
2409 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2410 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2413 def testHeaderNoLocation(self):
2414 """Test an image header with a no specified location is detected"""
2415 with self.assertRaises(ValueError) as e:
2416 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2417 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2420 def testEntryExpand(self):
2421 """Test expanding an entry after it is packed"""
2422 data = self._DoReadFile('121_entry_expand.dts')
2423 self.assertEqual(b'aaa', data[:3])
2424 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2425 self.assertEqual(b'aaa', data[-3:])
2427 def testEntryExpandBad(self):
2428 """Test expanding an entry after it is packed, twice"""
2429 with self.assertRaises(ValueError) as e:
2430 self._DoReadFile('122_entry_expand_twice.dts')
2431 self.assertIn("Image '/binman': Entries changed size after packing",
2434 def testEntryExpandSection(self):
2435 """Test expanding an entry within a section after it is packed"""
2436 data = self._DoReadFile('123_entry_expand_section.dts')
2437 self.assertEqual(b'aaa', data[:3])
2438 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2439 self.assertEqual(b'aaa', data[-3:])
2441 def testCompressDtb(self):
2442 """Test that compress of device-tree files is supported"""
2444 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2445 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2446 comp_data = data[len(U_BOOT_DATA):]
2447 orig = self._decompress(comp_data)
2448 dtb = fdt.Fdt.FromData(orig)
2450 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2452 'u-boot:size': len(U_BOOT_DATA),
2453 'u-boot-dtb:uncomp-size': len(orig),
2454 'u-boot-dtb:size': len(comp_data),
2457 self.assertEqual(expected, props)
2459 def testCbfsUpdateFdt(self):
2460 """Test that we can update the device tree with CBFS offset/size info"""
2462 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2464 dtb = fdt.Fdt(out_dtb_fname)
2466 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2467 del props['cbfs/u-boot:size']
2473 'cbfs:size': len(data),
2474 'cbfs:image-pos': 0,
2475 'cbfs/u-boot:offset': 0x38,
2476 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2477 'cbfs/u-boot:image-pos': 0x38,
2478 'cbfs/u-boot-dtb:offset': 0xb8,
2479 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2480 'cbfs/u-boot-dtb:image-pos': 0xb8,
2483 def testCbfsBadType(self):
2484 """Test an image header with a no specified location is detected"""
2485 with self.assertRaises(ValueError) as e:
2486 self._DoReadFile('126_cbfs_bad_type.dts')
2487 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2490 """Test listing the files in an image"""
2492 data = self._DoReadFile('127_list.dts')
2493 image = control.images['image']
2494 entries = image.BuildEntryList()
2495 self.assertEqual(7, len(entries))
2498 self.assertEqual(0, ent.indent)
2499 self.assertEqual('main-section', ent.name)
2500 self.assertEqual('section', ent.etype)
2501 self.assertEqual(len(data), ent.size)
2502 self.assertEqual(0, ent.image_pos)
2503 self.assertEqual(None, ent.uncomp_size)
2504 self.assertEqual(0, ent.offset)
2507 self.assertEqual(1, ent.indent)
2508 self.assertEqual('u-boot', ent.name)
2509 self.assertEqual('u-boot', ent.etype)
2510 self.assertEqual(len(U_BOOT_DATA), ent.size)
2511 self.assertEqual(0, ent.image_pos)
2512 self.assertEqual(None, ent.uncomp_size)
2513 self.assertEqual(0, ent.offset)
2516 self.assertEqual(1, ent.indent)
2517 self.assertEqual('section', ent.name)
2518 self.assertEqual('section', ent.etype)
2519 section_size = ent.size
2520 self.assertEqual(0x100, ent.image_pos)
2521 self.assertEqual(None, ent.uncomp_size)
2522 self.assertEqual(0x100, ent.offset)
2525 self.assertEqual(2, ent.indent)
2526 self.assertEqual('cbfs', ent.name)
2527 self.assertEqual('cbfs', ent.etype)
2528 self.assertEqual(0x400, ent.size)
2529 self.assertEqual(0x100, ent.image_pos)
2530 self.assertEqual(None, ent.uncomp_size)
2531 self.assertEqual(0, ent.offset)
2534 self.assertEqual(3, ent.indent)
2535 self.assertEqual('u-boot', ent.name)
2536 self.assertEqual('u-boot', ent.etype)
2537 self.assertEqual(len(U_BOOT_DATA), ent.size)
2538 self.assertEqual(0x138, ent.image_pos)
2539 self.assertEqual(None, ent.uncomp_size)
2540 self.assertEqual(0x38, ent.offset)
2543 self.assertEqual(3, ent.indent)
2544 self.assertEqual('u-boot-dtb', ent.name)
2545 self.assertEqual('text', ent.etype)
2546 self.assertGreater(len(COMPRESS_DATA), ent.size)
2547 self.assertEqual(0x178, ent.image_pos)
2548 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2549 self.assertEqual(0x78, ent.offset)
2552 self.assertEqual(2, ent.indent)
2553 self.assertEqual('u-boot-dtb', ent.name)
2554 self.assertEqual('u-boot-dtb', ent.etype)
2555 self.assertEqual(0x500, ent.image_pos)
2556 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2558 # Compressing this data expands it since headers are added
2559 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2560 self.assertEqual(0x400, ent.offset)
2562 self.assertEqual(len(data), 0x100 + section_size)
2563 self.assertEqual(section_size, 0x400 + dtb_size)
2565 def testFindFdtmap(self):
2566 """Test locating an FDT map in an image"""
2568 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2569 image = control.images['image']
2570 entries = image.GetEntries()
2571 entry = entries['fdtmap']
2572 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2574 def testFindFdtmapMissing(self):
2575 """Test failing to locate an FDP map"""
2576 data = self._DoReadFile('005_simple.dts')
2577 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2579 def testFindImageHeader(self):
2580 """Test locating a image header"""
2582 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2583 image = control.images['image']
2584 entries = image.GetEntries()
2585 entry = entries['fdtmap']
2586 # The header should point to the FDT map
2587 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2589 def testFindImageHeaderStart(self):
2590 """Test locating a image header located at the start of an image"""
2591 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2592 image = control.images['image']
2593 entries = image.GetEntries()
2594 entry = entries['fdtmap']
2595 # The header should point to the FDT map
2596 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2598 def testFindImageHeaderMissing(self):
2599 """Test failing to locate an image header"""
2600 data = self._DoReadFile('005_simple.dts')
2601 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2603 def testReadImage(self):
2604 """Test reading an image and accessing its FDT map"""
2606 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2607 image_fname = tools.GetOutputFilename('image.bin')
2608 orig_image = control.images['image']
2609 image = Image.FromFile(image_fname)
2610 self.assertEqual(orig_image.GetEntries().keys(),
2611 image.GetEntries().keys())
2613 orig_entry = orig_image.GetEntries()['fdtmap']
2614 entry = image.GetEntries()['fdtmap']
2615 self.assertEquals(orig_entry.offset, entry.offset)
2616 self.assertEquals(orig_entry.size, entry.size)
2617 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2619 def testReadImageNoHeader(self):
2620 """Test accessing an image's FDT map without an image header"""
2622 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2623 image_fname = tools.GetOutputFilename('image.bin')
2624 image = Image.FromFile(image_fname)
2625 self.assertTrue(isinstance(image, Image))
2626 self.assertEqual('image', image.image_name[-5:])
2628 def testReadImageFail(self):
2629 """Test failing to read an image image's FDT map"""
2630 self._DoReadFile('005_simple.dts')
2631 image_fname = tools.GetOutputFilename('image.bin')
2632 with self.assertRaises(ValueError) as e:
2633 image = Image.FromFile(image_fname)
2634 self.assertIn("Cannot find FDT map in image", str(e.exception))
2636 def testListCmd(self):
2637 """Test listing the files in an image using an Fdtmap"""
2639 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2641 # lz4 compression size differs depending on the version
2642 image = control.images['image']
2643 entries = image.GetEntries()
2644 section_size = entries['section'].size
2645 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2646 fdtmap_offset = entries['fdtmap'].offset
2649 tmpdir, updated_fname = self._SetupImageInTmpdir()
2650 with test_util.capture_sys_output() as (stdout, stderr):
2651 self._DoBinman('ls', '-i', updated_fname)
2653 shutil.rmtree(tmpdir)
2654 lines = stdout.getvalue().splitlines()
2656 'Name Image-pos Size Entry-type Offset Uncomp-size',
2657 '----------------------------------------------------------------------',
2658 'main-section 0 c00 section 0',
2659 ' u-boot 0 4 u-boot 0',
2660 ' section 100 %x section 100' % section_size,
2661 ' cbfs 100 400 cbfs 0',
2662 ' u-boot 138 4 u-boot 38',
2663 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2664 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2665 ' fdtmap %x 3bd fdtmap %x' %
2666 (fdtmap_offset, fdtmap_offset),
2667 ' image-header bf8 8 image-header bf8',
2669 self.assertEqual(expected, lines)
2671 def testListCmdFail(self):
2672 """Test failing to list an image"""
2673 self._DoReadFile('005_simple.dts')
2675 tmpdir, updated_fname = self._SetupImageInTmpdir()
2676 with self.assertRaises(ValueError) as e:
2677 self._DoBinman('ls', '-i', updated_fname)
2679 shutil.rmtree(tmpdir)
2680 self.assertIn("Cannot find FDT map in image", str(e.exception))
2682 def _RunListCmd(self, paths, expected):
2683 """List out entries and check the result
2686 paths: List of paths to pass to the list command
2687 expected: Expected list of filenames to be returned, in order
2690 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2691 image_fname = tools.GetOutputFilename('image.bin')
2692 image = Image.FromFile(image_fname)
2693 lines = image.GetListEntries(paths)[1]
2694 files = [line[0].strip() for line in lines[1:]]
2695 self.assertEqual(expected, files)
2697 def testListCmdSection(self):
2698 """Test listing the files in a section"""
2699 self._RunListCmd(['section'],
2700 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2702 def testListCmdFile(self):
2703 """Test listing a particular file"""
2704 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2706 def testListCmdWildcard(self):
2707 """Test listing a wildcarded file"""
2708 self._RunListCmd(['*boot*'],
2709 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2711 def testListCmdWildcardMulti(self):
2712 """Test listing a wildcarded file"""
2713 self._RunListCmd(['*cb*', '*head*'],
2714 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2716 def testListCmdEmpty(self):
2717 """Test listing a wildcarded file"""
2718 self._RunListCmd(['nothing'], [])
2720 def testListCmdPath(self):
2721 """Test listing the files in a sub-entry of a section"""
2722 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2724 def _RunExtractCmd(self, entry_name, decomp=True):
2725 """Extract an entry from an image
2728 entry_name: Entry name to extract
2729 decomp: True to decompress the data if compressed, False to leave
2730 it in its raw uncompressed format
2736 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2737 image_fname = tools.GetOutputFilename('image.bin')
2738 return control.ReadEntry(image_fname, entry_name, decomp)
2740 def testExtractSimple(self):
2741 """Test extracting a single file"""
2742 data = self._RunExtractCmd('u-boot')
2743 self.assertEqual(U_BOOT_DATA, data)
2745 def testExtractSection(self):
2746 """Test extracting the files in a section"""
2747 data = self._RunExtractCmd('section')
2748 cbfs_data = data[:0x400]
2749 cbfs = cbfs_util.CbfsReader(cbfs_data)
2750 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2751 dtb_data = data[0x400:]
2752 dtb = self._decompress(dtb_data)
2753 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2755 def testExtractCompressed(self):
2756 """Test extracting compressed data"""
2757 data = self._RunExtractCmd('section/u-boot-dtb')
2758 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2760 def testExtractRaw(self):
2761 """Test extracting compressed data without decompressing it"""
2762 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2763 dtb = self._decompress(data)
2764 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2766 def testExtractCbfs(self):
2767 """Test extracting CBFS data"""
2768 data = self._RunExtractCmd('section/cbfs/u-boot')
2769 self.assertEqual(U_BOOT_DATA, data)
2771 def testExtractCbfsCompressed(self):
2772 """Test extracting CBFS compressed data"""
2773 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2774 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2776 def testExtractCbfsRaw(self):
2777 """Test extracting CBFS compressed data without decompressing it"""
2778 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2779 dtb = tools.Decompress(data, 'lzma', with_header=False)
2780 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2782 def testExtractBadEntry(self):
2783 """Test extracting a bad section path"""
2784 with self.assertRaises(ValueError) as e:
2785 self._RunExtractCmd('section/does-not-exist')
2786 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2789 def testExtractMissingFile(self):
2790 """Test extracting file that does not exist"""
2791 with self.assertRaises(IOError) as e:
2792 control.ReadEntry('missing-file', 'name')
2794 def testExtractBadFile(self):
2795 """Test extracting an invalid file"""
2796 fname = os.path.join(self._indir, 'badfile')
2797 tools.WriteFile(fname, b'')
2798 with self.assertRaises(ValueError) as e:
2799 control.ReadEntry(fname, 'name')
2801 def testExtractCmd(self):
2802 """Test extracting a file fron an image on the command line"""
2804 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2805 fname = os.path.join(self._indir, 'output.extact')
2807 tmpdir, updated_fname = self._SetupImageInTmpdir()
2808 with test_util.capture_sys_output() as (stdout, stderr):
2809 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2812 shutil.rmtree(tmpdir)
2813 data = tools.ReadFile(fname)
2814 self.assertEqual(U_BOOT_DATA, data)
2816 def testExtractOneEntry(self):
2817 """Test extracting a single entry fron an image """
2819 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2820 image_fname = tools.GetOutputFilename('image.bin')
2821 fname = os.path.join(self._indir, 'output.extact')
2822 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2823 data = tools.ReadFile(fname)
2824 self.assertEqual(U_BOOT_DATA, data)
2826 def _CheckExtractOutput(self, decomp):
2827 """Helper to test file output with and without decompression
2830 decomp: True to decompress entry data, False to output it raw
2832 def _CheckPresent(entry_path, expect_data, expect_size=None):
2833 """Check and remove expected file
2835 This checks the data/size of a file and removes the file both from
2836 the outfiles set and from the output directory. Once all files are
2837 processed, both the set and directory should be empty.
2840 entry_path: Entry path
2841 expect_data: Data to expect in file, or None to skip check
2842 expect_size: Size of data to expect in file, or None to skip
2844 path = os.path.join(outdir, entry_path)
2845 data = tools.ReadFile(path)
2848 self.assertEqual(expect_data, data)
2850 self.assertEqual(expect_size, len(data))
2851 outfiles.remove(path)
2853 def _CheckDirPresent(name):
2854 """Remove expected directory
2856 This gives an error if the directory does not exist as expected
2859 name: Name of directory to remove
2861 path = os.path.join(outdir, name)
2864 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2865 image_fname = tools.GetOutputFilename('image.bin')
2866 outdir = os.path.join(self._indir, 'extract')
2867 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2869 # Create a set of all file that were output (should be 9)
2871 for root, dirs, files in os.walk(outdir):
2872 outfiles |= set([os.path.join(root, fname) for fname in files])
2873 self.assertEqual(9, len(outfiles))
2874 self.assertEqual(9, len(einfos))
2876 image = control.images['image']
2877 entries = image.GetEntries()
2879 # Check the 9 files in various ways
2880 section = entries['section']
2881 section_entries = section.GetEntries()
2882 cbfs_entries = section_entries['cbfs'].GetEntries()
2883 _CheckPresent('u-boot', U_BOOT_DATA)
2884 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2885 dtb_len = EXTRACT_DTB_SIZE
2887 dtb_len = cbfs_entries['u-boot-dtb'].size
2888 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2890 dtb_len = section_entries['u-boot-dtb'].size
2891 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2893 fdtmap = entries['fdtmap']
2894 _CheckPresent('fdtmap', fdtmap.data)
2895 hdr = entries['image-header']
2896 _CheckPresent('image-header', hdr.data)
2898 _CheckPresent('section/root', section.data)
2899 cbfs = section_entries['cbfs']
2900 _CheckPresent('section/cbfs/root', cbfs.data)
2901 data = tools.ReadFile(image_fname)
2902 _CheckPresent('root', data)
2904 # There should be no files left. Remove all the directories to check.
2905 # If there are any files/dirs remaining, one of these checks will fail.
2906 self.assertEqual(0, len(outfiles))
2907 _CheckDirPresent('section/cbfs')
2908 _CheckDirPresent('section')
2909 _CheckDirPresent('')
2910 self.assertFalse(os.path.exists(outdir))
2912 def testExtractAllEntries(self):
2913 """Test extracting all entries"""
2915 self._CheckExtractOutput(decomp=True)
2917 def testExtractAllEntriesRaw(self):
2918 """Test extracting all entries without decompressing them"""
2920 self._CheckExtractOutput(decomp=False)
2922 def testExtractSelectedEntries(self):
2923 """Test extracting some entries"""
2925 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2926 image_fname = tools.GetOutputFilename('image.bin')
2927 outdir = os.path.join(self._indir, 'extract')
2928 einfos = control.ExtractEntries(image_fname, None, outdir,
2931 # File output is tested by testExtractAllEntries(), so just check that
2932 # the expected entries are selected
2933 names = [einfo.name for einfo in einfos]
2934 self.assertEqual(names,
2935 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2937 def testExtractNoEntryPaths(self):
2938 """Test extracting some entries"""
2940 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2941 image_fname = tools.GetOutputFilename('image.bin')
2942 with self.assertRaises(ValueError) as e:
2943 control.ExtractEntries(image_fname, 'fname', None, [])
2944 self.assertIn('Must specify an entry path to write with -f',
2947 def testExtractTooManyEntryPaths(self):
2948 """Test extracting some entries"""
2950 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2951 image_fname = tools.GetOutputFilename('image.bin')
2952 with self.assertRaises(ValueError) as e:
2953 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2954 self.assertIn('Must specify exactly one entry path to write with -f',
2957 def testPackAlignSection(self):
2958 """Test that sections can have alignment"""
2959 self._DoReadFile('131_pack_align_section.dts')
2961 self.assertIn('image', control.images)
2962 image = control.images['image']
2963 entries = image.GetEntries()
2964 self.assertEqual(3, len(entries))
2967 self.assertIn('u-boot', entries)
2968 entry = entries['u-boot']
2969 self.assertEqual(0, entry.offset)
2970 self.assertEqual(0, entry.image_pos)
2971 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2972 self.assertEqual(len(U_BOOT_DATA), entry.size)
2975 self.assertIn('section0', entries)
2976 section0 = entries['section0']
2977 self.assertEqual(0x10, section0.offset)
2978 self.assertEqual(0x10, section0.image_pos)
2979 self.assertEqual(len(U_BOOT_DATA), section0.size)
2982 section_entries = section0.GetEntries()
2983 self.assertIn('u-boot', section_entries)
2984 entry = section_entries['u-boot']
2985 self.assertEqual(0, entry.offset)
2986 self.assertEqual(0x10, entry.image_pos)
2987 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2988 self.assertEqual(len(U_BOOT_DATA), entry.size)
2991 self.assertIn('section1', entries)
2992 section1 = entries['section1']
2993 self.assertEqual(0x14, section1.offset)
2994 self.assertEqual(0x14, section1.image_pos)
2995 self.assertEqual(0x20, section1.size)
2998 section_entries = section1.GetEntries()
2999 self.assertIn('u-boot', section_entries)
3000 entry = section_entries['u-boot']
3001 self.assertEqual(0, entry.offset)
3002 self.assertEqual(0x14, entry.image_pos)
3003 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3004 self.assertEqual(len(U_BOOT_DATA), entry.size)
3007 self.assertIn('section2', section_entries)
3008 section2 = section_entries['section2']
3009 self.assertEqual(0x4, section2.offset)
3010 self.assertEqual(0x18, section2.image_pos)
3011 self.assertEqual(4, section2.size)
3014 section_entries = section2.GetEntries()
3015 self.assertIn('u-boot', section_entries)
3016 entry = section_entries['u-boot']
3017 self.assertEqual(0, entry.offset)
3018 self.assertEqual(0x18, entry.image_pos)
3019 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3020 self.assertEqual(len(U_BOOT_DATA), entry.size)
3022 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3023 dts='132_replace.dts'):
3024 """Replace an entry in an image
3026 This writes the entry data to update it, then opens the updated file and
3027 returns the value that it now finds there.
3030 entry_name: Entry name to replace
3031 data: Data to replace it with
3032 decomp: True to compress the data if needed, False if data is
3033 already compressed so should be used as is
3034 allow_resize: True to allow entries to change size, False to raise
3040 data from fdtmap (excluding header)
3041 Image object that was modified
3043 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3046 self.assertIn('image', control.images)
3047 image = control.images['image']
3048 entries = image.GetEntries()
3049 orig_dtb_data = entries['u-boot-dtb'].data
3050 orig_fdtmap_data = entries['fdtmap'].data
3052 image_fname = tools.GetOutputFilename('image.bin')
3053 updated_fname = tools.GetOutputFilename('image-updated.bin')
3054 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3055 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3057 data = control.ReadEntry(updated_fname, entry_name, decomp)
3059 # The DT data should not change unless resized:
3060 if not allow_resize:
3061 new_dtb_data = entries['u-boot-dtb'].data
3062 self.assertEqual(new_dtb_data, orig_dtb_data)
3063 new_fdtmap_data = entries['fdtmap'].data
3064 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3066 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3068 def testReplaceSimple(self):
3069 """Test replacing a single file"""
3070 expected = b'x' * len(U_BOOT_DATA)
3071 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3073 self.assertEqual(expected, data)
3075 # Test that the state looks right. There should be an FDT for the fdtmap
3076 # that we jsut read back in, and it should match what we find in the
3077 # 'control' tables. Checking for an FDT that does not exist should
3079 path, fdtmap = state.GetFdtContents('fdtmap')
3080 self.assertIsNotNone(path)
3081 self.assertEqual(expected_fdtmap, fdtmap)
3083 dtb = state.GetFdtForEtype('fdtmap')
3084 self.assertEqual(dtb.GetContents(), fdtmap)
3086 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3087 self.assertIsNone(missing_path)
3088 self.assertIsNone(missing_fdtmap)
3090 missing_dtb = state.GetFdtForEtype('missing')
3091 self.assertIsNone(missing_dtb)
3093 self.assertEqual('/binman', state.fdt_path_prefix)
3095 def testReplaceResizeFail(self):
3096 """Test replacing a file by something larger"""
3097 expected = U_BOOT_DATA + b'x'
3098 with self.assertRaises(ValueError) as e:
3099 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3100 dts='139_replace_repack.dts')
3101 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3104 def testReplaceMulti(self):
3105 """Test replacing entry data where multiple images are generated"""
3106 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3108 expected = b'x' * len(U_BOOT_DATA)
3109 updated_fname = tools.GetOutputFilename('image-updated.bin')
3110 tools.WriteFile(updated_fname, data)
3111 entry_name = 'u-boot'
3112 control.WriteEntry(updated_fname, entry_name, expected,
3114 data = control.ReadEntry(updated_fname, entry_name)
3115 self.assertEqual(expected, data)
3117 # Check the state looks right.
3118 self.assertEqual('/binman/image', state.fdt_path_prefix)
3120 # Now check we can write the first image
3121 image_fname = tools.GetOutputFilename('first-image.bin')
3122 updated_fname = tools.GetOutputFilename('first-updated.bin')
3123 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3124 entry_name = 'u-boot'
3125 control.WriteEntry(updated_fname, entry_name, expected,
3127 data = control.ReadEntry(updated_fname, entry_name)
3128 self.assertEqual(expected, data)
3130 # Check the state looks right.
3131 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3133 def testUpdateFdtAllRepack(self):
3134 """Test that all device trees are updated with offset/size info"""
3135 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3136 SECTION_SIZE = 0x300
3141 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3143 'section:offset': 0,
3144 'section:size': SECTION_SIZE,
3145 'section:image-pos': 0,
3146 'section/u-boot-dtb:offset': 4,
3147 'section/u-boot-dtb:size': 636,
3148 'section/u-boot-dtb:image-pos': 4,
3149 'u-boot-spl-dtb:offset': SECTION_SIZE,
3150 'u-boot-spl-dtb:size': DTB_SIZE,
3151 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3152 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3153 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3154 'u-boot-tpl-dtb:size': DTB_SIZE,
3155 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3156 'fdtmap:size': FDTMAP_SIZE,
3157 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3160 'section:orig-size': SECTION_SIZE,
3161 'section/u-boot-dtb:orig-offset': 4,
3164 # We expect three device-tree files in the output, with the first one
3165 # within a fixed-size section.
3166 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3167 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3168 # main U-Boot tree. All three should have the same positions and offset
3169 # except that the main tree should include the main_expected properties
3171 for item in ['', 'spl', 'tpl', None]:
3173 start += 16 # Move past fdtmap header
3174 dtb = fdt.Fdt.FromData(data[start:])
3176 props = self._GetPropTree(dtb,
3177 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3178 prefix='/' if item is None else '/binman/')
3179 expected = dict(base_expected)
3183 # Main DTB and fdtdec should include the 'orig-' properties
3184 expected.update(main_expected)
3185 # Helpful for debugging:
3186 #for prop in sorted(props):
3187 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3188 self.assertEqual(expected, props)
3190 start = SECTION_SIZE
3192 start += dtb._fdt_obj.totalsize()
3194 def testFdtmapHeaderMiddle(self):
3195 """Test an FDT map in the middle of an image when it should be at end"""
3196 with self.assertRaises(ValueError) as e:
3197 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3198 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3201 def testFdtmapHeaderStartBad(self):
3202 """Test an FDT map in middle of an image when it should be at start"""
3203 with self.assertRaises(ValueError) as e:
3204 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3205 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3208 def testFdtmapHeaderEndBad(self):
3209 """Test an FDT map at the start of an image when it should be at end"""
3210 with self.assertRaises(ValueError) as e:
3211 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3212 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3215 def testFdtmapHeaderNoSize(self):
3216 """Test an image header at the end of an image with undefined size"""
3217 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3219 def testReplaceResize(self):
3220 """Test replacing a single file in an entry with a larger file"""
3221 expected = U_BOOT_DATA + b'x'
3222 data, _, image = self._RunReplaceCmd('u-boot', expected,
3223 dts='139_replace_repack.dts')
3224 self.assertEqual(expected, data)
3226 entries = image.GetEntries()
3227 dtb_data = entries['u-boot-dtb'].data
3228 dtb = fdt.Fdt.FromData(dtb_data)
3231 # The u-boot section should now be larger in the dtb
3232 node = dtb.GetNode('/binman/u-boot')
3233 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3235 # Same for the fdtmap
3236 fdata = entries['fdtmap'].data
3237 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3239 fnode = fdtb.GetNode('/u-boot')
3240 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3242 def testReplaceResizeNoRepack(self):
3243 """Test replacing an entry with a larger file when not allowed"""
3244 expected = U_BOOT_DATA + b'x'
3245 with self.assertRaises(ValueError) as e:
3246 self._RunReplaceCmd('u-boot', expected)
3247 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3250 def testEntryShrink(self):
3251 """Test contracting an entry after it is packed"""
3253 state.SetAllowEntryContraction(True)
3254 data = self._DoReadFileDtb('140_entry_shrink.dts',
3257 state.SetAllowEntryContraction(False)
3258 self.assertEqual(b'a', data[:1])
3259 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3260 self.assertEqual(b'a', data[-1:])
3262 def testEntryShrinkFail(self):
3263 """Test not being allowed to contract an entry after it is packed"""
3264 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3266 # In this case there is a spare byte at the end of the data. The size of
3267 # the contents is only 1 byte but we still have the size before it
3269 self.assertEqual(b'a\0', data[:2])
3270 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3271 self.assertEqual(b'a\0', data[-2:])
3273 def testDescriptorOffset(self):
3274 """Test that the Intel descriptor is always placed at at the start"""
3275 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3276 image = control.images['image']
3277 entries = image.GetEntries()
3278 desc = entries['intel-descriptor']
3279 self.assertEqual(0xff800000, desc.offset);
3280 self.assertEqual(0xff800000, desc.image_pos);
3282 def testReplaceCbfs(self):
3283 """Test replacing a single file in CBFS without changing the size"""
3285 expected = b'x' * len(U_BOOT_DATA)
3286 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3287 updated_fname = tools.GetOutputFilename('image-updated.bin')
3288 tools.WriteFile(updated_fname, data)
3289 entry_name = 'section/cbfs/u-boot'
3290 control.WriteEntry(updated_fname, entry_name, expected,
3292 data = control.ReadEntry(updated_fname, entry_name)
3293 self.assertEqual(expected, data)
3295 def testReplaceResizeCbfs(self):
3296 """Test replacing a single file in CBFS with one of a different size"""
3298 expected = U_BOOT_DATA + b'x'
3299 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3300 updated_fname = tools.GetOutputFilename('image-updated.bin')
3301 tools.WriteFile(updated_fname, data)
3302 entry_name = 'section/cbfs/u-boot'
3303 control.WriteEntry(updated_fname, entry_name, expected,
3305 data = control.ReadEntry(updated_fname, entry_name)
3306 self.assertEqual(expected, data)
3308 def _SetupForReplace(self):
3309 """Set up some files to use to replace entries
3311 This generates an image, copies it to a new file, extracts all the files
3312 in it and updates some of them
3318 Expected values for updated entries, each a string
3320 data = self._DoReadFileRealDtb('143_replace_all.dts')
3322 updated_fname = tools.GetOutputFilename('image-updated.bin')
3323 tools.WriteFile(updated_fname, data)
3325 outdir = os.path.join(self._indir, 'extract')
3326 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3328 expected1 = b'x' + U_BOOT_DATA + b'y'
3329 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3330 tools.WriteFile(u_boot_fname1, expected1)
3332 expected2 = b'a' + U_BOOT_DATA + b'b'
3333 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3334 tools.WriteFile(u_boot_fname2, expected2)
3336 expected_text = b'not the same text'
3337 text_fname = os.path.join(outdir, 'text')
3338 tools.WriteFile(text_fname, expected_text)
3340 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3341 dtb = fdt.FdtScan(dtb_fname)
3342 node = dtb.GetNode('/binman/text')
3343 node.AddString('my-property', 'the value')
3344 dtb.Sync(auto_resize=True)
3347 return updated_fname, outdir, expected1, expected2, expected_text
3349 def _CheckReplaceMultiple(self, entry_paths):
3350 """Handle replacing the contents of multiple entries
3353 entry_paths: List of entry paths to replace
3357 Dict of entries in the image:
3360 Expected values for updated entries, each a string
3362 updated_fname, outdir, expected1, expected2, expected_text = (
3363 self._SetupForReplace())
3364 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3366 image = Image.FromFile(updated_fname)
3368 return image.GetEntries(), expected1, expected2, expected_text
3370 def testReplaceAll(self):
3371 """Test replacing the contents of all entries"""
3372 entries, expected1, expected2, expected_text = (
3373 self._CheckReplaceMultiple([]))
3374 data = entries['u-boot'].data
3375 self.assertEqual(expected1, data)
3377 data = entries['u-boot2'].data
3378 self.assertEqual(expected2, data)
3380 data = entries['text'].data
3381 self.assertEqual(expected_text, data)
3383 # Check that the device tree is updated
3384 data = entries['u-boot-dtb'].data
3385 dtb = fdt.Fdt.FromData(data)
3387 node = dtb.GetNode('/binman/text')
3388 self.assertEqual('the value', node.props['my-property'].value)
3390 def testReplaceSome(self):
3391 """Test replacing the contents of a few entries"""
3392 entries, expected1, expected2, expected_text = (
3393 self._CheckReplaceMultiple(['u-boot2', 'text']))
3395 # This one should not change
3396 data = entries['u-boot'].data
3397 self.assertEqual(U_BOOT_DATA, data)
3399 data = entries['u-boot2'].data
3400 self.assertEqual(expected2, data)
3402 data = entries['text'].data
3403 self.assertEqual(expected_text, data)
3405 def testReplaceCmd(self):
3406 """Test replacing a file fron an image on the command line"""
3407 self._DoReadFileRealDtb('143_replace_all.dts')
3410 tmpdir, updated_fname = self._SetupImageInTmpdir()
3412 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3413 expected = b'x' * len(U_BOOT_DATA)
3414 tools.WriteFile(fname, expected)
3416 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3417 data = tools.ReadFile(updated_fname)
3418 self.assertEqual(expected, data[:len(expected)])
3419 map_fname = os.path.join(tmpdir, 'image-updated.map')
3420 self.assertFalse(os.path.exists(map_fname))
3422 shutil.rmtree(tmpdir)
3424 def testReplaceCmdSome(self):
3425 """Test replacing some files fron an image on the command line"""
3426 updated_fname, outdir, expected1, expected2, expected_text = (
3427 self._SetupForReplace())
3429 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3432 tools.PrepareOutputDir(None)
3433 image = Image.FromFile(updated_fname)
3435 entries = image.GetEntries()
3437 # This one should not change
3438 data = entries['u-boot'].data
3439 self.assertEqual(U_BOOT_DATA, data)
3441 data = entries['u-boot2'].data
3442 self.assertEqual(expected2, data)
3444 data = entries['text'].data
3445 self.assertEqual(expected_text, data)
3447 def testReplaceMissing(self):
3448 """Test replacing entries where the file is missing"""
3449 updated_fname, outdir, expected1, expected2, expected_text = (
3450 self._SetupForReplace())
3452 # Remove one of the files, to generate a warning
3453 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3454 os.remove(u_boot_fname1)
3456 with test_util.capture_sys_output() as (stdout, stderr):
3457 control.ReplaceEntries(updated_fname, None, outdir, [])
3458 self.assertIn("Skipping entry '/u-boot' from missing file",
3461 def testReplaceCmdMap(self):
3462 """Test replacing a file fron an image on the command line"""
3463 self._DoReadFileRealDtb('143_replace_all.dts')
3466 tmpdir, updated_fname = self._SetupImageInTmpdir()
3468 fname = os.path.join(self._indir, 'update-u-boot.bin')
3469 expected = b'x' * len(U_BOOT_DATA)
3470 tools.WriteFile(fname, expected)
3472 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3474 map_fname = os.path.join(tmpdir, 'image-updated.map')
3475 self.assertTrue(os.path.exists(map_fname))
3477 shutil.rmtree(tmpdir)
3479 def testReplaceNoEntryPaths(self):
3480 """Test replacing an entry without an entry path"""
3481 self._DoReadFileRealDtb('143_replace_all.dts')
3482 image_fname = tools.GetOutputFilename('image.bin')
3483 with self.assertRaises(ValueError) as e:
3484 control.ReplaceEntries(image_fname, 'fname', None, [])
3485 self.assertIn('Must specify an entry path to read with -f',
3488 def testReplaceTooManyEntryPaths(self):
3489 """Test extracting some entries"""
3490 self._DoReadFileRealDtb('143_replace_all.dts')
3491 image_fname = tools.GetOutputFilename('image.bin')
3492 with self.assertRaises(ValueError) as e:
3493 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3494 self.assertIn('Must specify exactly one entry path to write with -f',
3497 def testPackReset16(self):
3498 """Test that an image with an x86 reset16 region can be created"""
3499 data = self._DoReadFile('144_x86_reset16.dts')
3500 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3502 def testPackReset16Spl(self):
3503 """Test that an image with an x86 reset16-spl region can be created"""
3504 data = self._DoReadFile('145_x86_reset16_spl.dts')
3505 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3507 def testPackReset16Tpl(self):
3508 """Test that an image with an x86 reset16-tpl region can be created"""
3509 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3510 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3512 def testPackIntelFit(self):
3513 """Test that an image with an Intel FIT and pointer can be created"""
3514 data = self._DoReadFile('147_intel_fit.dts')
3515 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3517 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3518 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3520 image = control.images['image']
3521 entries = image.GetEntries()
3522 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3523 self.assertEqual(expected_ptr, ptr)
3525 def testPackIntelFitMissing(self):
3526 """Test detection of a FIT pointer with not FIT region"""
3527 with self.assertRaises(ValueError) as e:
3528 self._DoReadFile('148_intel_fit_missing.dts')
3529 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3532 def _CheckSymbolsTplSection(self, dts, expected_vals):
3533 data = self._DoReadFile(dts)
3534 sym_values = struct.pack('<LQLL', *expected_vals)
3535 upto1 = 4 + len(U_BOOT_SPL_DATA)
3536 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3537 self.assertEqual(expected1, data[:upto1])
3539 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3540 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3541 self.assertEqual(expected2, data[upto1:upto2])
3543 upto3 = 0x34 + len(U_BOOT_DATA)
3544 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3545 self.assertEqual(expected3, data[upto2:upto3])
3547 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3548 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3550 def testSymbolsTplSection(self):
3551 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3552 self._SetupSplElf('u_boot_binman_syms')
3553 self._SetupTplElf('u_boot_binman_syms')
3554 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3555 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3557 def testSymbolsTplSectionX86(self):
3558 """Test binman can assign symbols in a section with end-at-4gb"""
3559 self._SetupSplElf('u_boot_binman_syms_x86')
3560 self._SetupTplElf('u_boot_binman_syms_x86')
3561 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3562 [0xffffff04, 0xffffff1c, 0xffffff34,
3565 def testPackX86RomIfwiSectiom(self):
3566 """Test that a section can be placed in an IFWI region"""
3567 self._SetupIfwi('fitimage.bin')
3568 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3569 self._CheckIfwi(data)
3571 def testPackFspM(self):
3572 """Test that an image with a FSP memory-init binary can be created"""
3573 data = self._DoReadFile('152_intel_fsp_m.dts')
3574 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3576 def testPackFspS(self):
3577 """Test that an image with a FSP silicon-init binary can be created"""
3578 data = self._DoReadFile('153_intel_fsp_s.dts')
3579 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3581 def testPackFspT(self):
3582 """Test that an image with a FSP temp-ram-init binary can be created"""
3583 data = self._DoReadFile('154_intel_fsp_t.dts')
3584 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3586 def testMkimage(self):
3587 """Test using mkimage to build an image"""
3588 data = self._DoReadFile('156_mkimage.dts')
3590 # Just check that the data appears in the file somewhere
3591 self.assertIn(U_BOOT_SPL_DATA, data)
3593 def testExtblob(self):
3594 """Test an image with an external blob"""
3595 data = self._DoReadFile('157_blob_ext.dts')
3596 self.assertEqual(REFCODE_DATA, data)
3598 def testExtblobMissing(self):
3599 """Test an image with a missing external blob"""
3600 with self.assertRaises(ValueError) as e:
3601 self._DoReadFile('158_blob_ext_missing.dts')
3602 self.assertIn("Filename 'missing-file' not found in input path",
3605 def testExtblobMissingOk(self):
3606 """Test an image with an missing external blob that is allowed"""
3607 with test_util.capture_sys_output() as (stdout, stderr):
3608 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3609 err = stderr.getvalue()
3610 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3612 def testExtblobMissingOkSect(self):
3613 """Test an image with an missing external blob that is allowed"""
3614 with test_util.capture_sys_output() as (stdout, stderr):
3615 self._DoTestFile('159_blob_ext_missing_sect.dts',
3617 err = stderr.getvalue()
3618 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3619 "blob-ext blob-ext2")
3621 def testPackX86RomMeMissingDesc(self):
3622 """Test that an missing Intel descriptor entry is allowed"""
3623 with test_util.capture_sys_output() as (stdout, stderr):
3624 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3625 err = stderr.getvalue()
3626 self.assertRegex(err,
3627 "Image 'main-section'.*missing.*: intel-descriptor")
3629 def testPackX86RomMissingIfwi(self):
3630 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3631 self._SetupIfwi('fitimage.bin')
3632 pathname = os.path.join(self._indir, 'fitimage.bin')
3634 with test_util.capture_sys_output() as (stdout, stderr):
3635 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3636 err = stderr.getvalue()
3637 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3639 def testPackOverlap(self):
3640 """Test that zero-size overlapping regions are ignored"""
3641 self._DoTestFile('160_pack_overlap_zero.dts')
3643 def testSimpleFit(self):
3644 """Test an image with a FIT inside"""
3645 data = self._DoReadFile('161_fit.dts')
3646 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3647 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3648 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3650 # The data should be inside the FIT
3651 dtb = fdt.Fdt.FromData(fit_data)
3653 fnode = dtb.GetNode('/images/kernel')
3654 self.assertIn('data', fnode.props)
3656 fname = os.path.join(self._indir, 'fit_data.fit')
3657 tools.WriteFile(fname, fit_data)
3658 out = tools.Run('dumpimage', '-l', fname)
3660 # Check a few features to make sure the plumbing works. We don't need
3661 # to test the operation of mkimage or dumpimage here. First convert the
3662 # output into a dict where the keys are the fields printed by dumpimage
3663 # and the values are a list of values for each field
3664 lines = out.splitlines()
3666 # Converts "Compression: gzip compressed" into two groups:
3667 # 'Compression' and 'gzip compressed'
3668 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3669 vals = collections.defaultdict(list)
3671 mat = re_line.match(line)
3672 vals[mat.group(1)].append(mat.group(2))
3674 self.assertEquals('FIT description: test-desc', lines[0])
3675 self.assertIn('Created:', lines[1])
3676 self.assertIn('Image 0 (kernel)', vals)
3677 self.assertIn('Hash value', vals)
3678 data_sizes = vals.get('Data Size')
3679 self.assertIsNotNone(data_sizes)
3680 self.assertEqual(2, len(data_sizes))
3681 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3682 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3683 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3685 def testFitExternal(self):
3686 """Test an image with an FIT with external images"""
3687 data = self._DoReadFile('162_fit_external.dts')
3688 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3690 # The data should be outside the FIT
3691 dtb = fdt.Fdt.FromData(fit_data)
3693 fnode = dtb.GetNode('/images/kernel')
3694 self.assertNotIn('data', fnode.props)
3696 def testSectionIgnoreHashSignature(self):
3697 """Test that sections ignore hash, signature nodes for its data"""
3698 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3699 expected = (U_BOOT_DATA + U_BOOT_DATA)
3700 self.assertEqual(expected, data)
3702 def testPadInSections(self):
3703 """Test pad-before, pad-after for entries in sections"""
3704 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3705 '166_pad_in_sections.dts', update_dtb=True)
3706 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3707 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3709 self.assertEqual(expected, data)
3711 dtb = fdt.Fdt(out_dtb_fname)
3713 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3717 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3719 'section:image-pos': 0,
3720 'section:offset': 0,
3721 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3723 'section/before:image-pos': 0,
3724 'section/before:offset': 0,
3725 'section/before:size': len(U_BOOT_DATA),
3727 'section/u-boot:image-pos': 4,
3728 'section/u-boot:offset': 4,
3729 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3731 'section/after:image-pos': 26,
3732 'section/after:offset': 26,
3733 'section/after:size': len(U_BOOT_DATA),
3735 self.assertEqual(expected, props)
3737 def testFitImageSubentryAlignment(self):
3738 """Test relative alignability of FIT image subentries"""
3740 'test-id': TEXT_DATA,
3742 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3743 entry_args=entry_args)
3744 dtb = fdt.Fdt.FromData(data)
3747 node = dtb.GetNode('/images/kernel')
3748 data = dtb.GetProps(node)["data"].bytes
3749 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3750 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3751 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3752 self.assertEqual(expected, data)
3754 node = dtb.GetNode('/images/fdt-1')
3755 data = dtb.GetProps(node)["data"].bytes
3756 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3757 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3759 self.assertEqual(expected, data)
3761 def testFitExtblobMissingOk(self):
3762 """Test a FIT with a missing external blob that is allowed"""
3763 with test_util.capture_sys_output() as (stdout, stderr):
3764 self._DoTestFile('168_fit_missing_blob.dts',
3766 err = stderr.getvalue()
3767 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3769 def testBlobNamedByArgMissing(self):
3770 """Test handling of a missing entry arg"""
3771 with self.assertRaises(ValueError) as e:
3772 self._DoReadFile('068_blob_named_by_arg.dts')
3773 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3776 def testPackBl31(self):
3777 """Test that an image with an ATF BL31 binary can be created"""
3778 data = self._DoReadFile('169_atf_bl31.dts')
3779 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3781 def testPackScp(self):
3782 """Test that an image with an SCP binary can be created"""
3783 data = self._DoReadFile('172_scp.dts')
3784 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3786 def testFitFdt(self):
3787 """Test an image with an FIT with multiple FDT images"""
3788 def _CheckFdt(seq, expected_data):
3789 """Check the FDT nodes
3792 seq: Sequence number to check (0 or 1)
3793 expected_data: Expected contents of 'data' property
3795 name = 'fdt-%d' % seq
3796 fnode = dtb.GetNode('/images/%s' % name)
3797 self.assertIsNotNone(fnode)
3798 self.assertEqual({'description','type', 'compression', 'data'},
3799 set(fnode.props.keys()))
3800 self.assertEqual(expected_data, fnode.props['data'].bytes)
3801 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3802 fnode.props['description'].value)
3804 def _CheckConfig(seq, expected_data):
3805 """Check the configuration nodes
3808 seq: Sequence number to check (0 or 1)
3809 expected_data: Expected contents of 'data' property
3811 cnode = dtb.GetNode('/configurations')
3812 self.assertIn('default', cnode.props)
3813 self.assertEqual('config-2', cnode.props['default'].value)
3815 name = 'config-%d' % seq
3816 fnode = dtb.GetNode('/configurations/%s' % name)
3817 self.assertIsNotNone(fnode)
3818 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3819 set(fnode.props.keys()))
3820 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3821 fnode.props['description'].value)
3822 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3825 'of-list': 'test-fdt1 test-fdt2',
3826 'default-dt': 'test-fdt2',
3828 data = self._DoReadFileDtb(
3830 entry_args=entry_args,
3831 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3832 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3833 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3835 dtb = fdt.Fdt.FromData(fit_data)
3837 fnode = dtb.GetNode('/images/kernel')
3838 self.assertIn('data', fnode.props)
3840 # Check all the properties in fdt-1 and fdt-2
3841 _CheckFdt(1, TEST_FDT1_DATA)
3842 _CheckFdt(2, TEST_FDT2_DATA)
3844 # Check configurations
3845 _CheckConfig(1, TEST_FDT1_DATA)
3846 _CheckConfig(2, TEST_FDT2_DATA)
3848 def testFitFdtMissingList(self):
3849 """Test handling of a missing 'of-list' entry arg"""
3850 with self.assertRaises(ValueError) as e:
3851 self._DoReadFile('172_fit_fdt.dts')
3852 self.assertIn("Generator node requires 'of-list' entry argument",
3855 def testFitFdtEmptyList(self):
3856 """Test handling of an empty 'of-list' entry arg"""
3860 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3862 def testFitFdtMissingProp(self):
3863 """Test handling of a missing 'fit,fdt-list' property"""
3864 with self.assertRaises(ValueError) as e:
3865 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3866 self.assertIn("Generator node requires 'fit,fdt-list' property",
3869 def testFitFdtEmptyList(self):
3870 """Test handling of an empty 'of-list' entry arg"""
3874 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3876 def testFitFdtMissing(self):
3877 """Test handling of a missing 'default-dt' entry arg"""
3879 'of-list': 'test-fdt1 test-fdt2',
3881 with self.assertRaises(ValueError) as e:
3882 self._DoReadFileDtb(
3884 entry_args=entry_args,
3885 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3886 self.assertIn("Generated 'default' node requires default-dt entry argument",
3889 def testFitFdtNotInList(self):
3890 """Test handling of a default-dt that is not in the of-list"""
3892 'of-list': 'test-fdt1 test-fdt2',
3893 'default-dt': 'test-fdt3',
3895 with self.assertRaises(ValueError) as e:
3896 self._DoReadFileDtb(
3898 entry_args=entry_args,
3899 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3900 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3903 def testFitExtblobMissingHelp(self):
3904 """Test display of help messages when an external blob is missing"""
3905 control.missing_blob_help = control._ReadMissingBlobHelp()
3906 control.missing_blob_help['wibble'] = 'Wibble test'
3907 control.missing_blob_help['another'] = 'Another test'
3908 with test_util.capture_sys_output() as (stdout, stderr):
3909 self._DoTestFile('168_fit_missing_blob.dts',
3911 err = stderr.getvalue()
3913 # We can get the tag from the name, the type or the missing-msg
3914 # property. Check all three.
3915 self.assertIn('You may need to build ARM Trusted', err)
3916 self.assertIn('Wibble test', err)
3917 self.assertIn('Another test', err)
3919 def testMissingBlob(self):
3920 """Test handling of a blob containing a missing file"""
3921 with self.assertRaises(ValueError) as e:
3922 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3923 self.assertIn("Filename 'missing' not found in input path",
3926 def testEnvironment(self):
3927 """Test adding a U-Boot environment"""
3928 data = self._DoReadFile('174_env.dts')
3929 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3930 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3931 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3932 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3935 def testEnvironmentNoSize(self):
3936 """Test that a missing 'size' property is detected"""
3937 with self.assertRaises(ValueError) as e:
3938 self._DoTestFile('175_env_no_size.dts')
3939 self.assertIn("'u-boot-env' entry must have a size property",
3942 def testEnvironmentTooSmall(self):
3943 """Test handling of an environment that does not fit"""
3944 with self.assertRaises(ValueError) as e:
3945 self._DoTestFile('176_env_too_small.dts')
3947 # checksum, start byte, environment with \0 terminator, final \0
3948 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3950 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3953 def testSkipAtStart(self):
3954 """Test handling of skip-at-start section"""
3955 data = self._DoReadFile('177_skip_at_start.dts')
3956 self.assertEqual(U_BOOT_DATA, data)
3958 image = control.images['image']
3959 entries = image.GetEntries()
3960 section = entries['section']
3961 self.assertEqual(0, section.offset)
3962 self.assertEqual(len(U_BOOT_DATA), section.size)
3963 self.assertEqual(U_BOOT_DATA, section.GetData())
3965 entry = section.GetEntries()['u-boot']
3966 self.assertEqual(16, entry.offset)
3967 self.assertEqual(len(U_BOOT_DATA), entry.size)
3968 self.assertEqual(U_BOOT_DATA, entry.data)
3970 def testSkipAtStartPad(self):
3971 """Test handling of skip-at-start section with padded entry"""
3972 data = self._DoReadFile('178_skip_at_start_pad.dts')
3973 before = tools.GetBytes(0, 8)
3974 after = tools.GetBytes(0, 4)
3975 all = before + U_BOOT_DATA + after
3976 self.assertEqual(all, data)
3978 image = control.images['image']
3979 entries = image.GetEntries()
3980 section = entries['section']
3981 self.assertEqual(0, section.offset)
3982 self.assertEqual(len(all), section.size)
3983 self.assertEqual(all, section.GetData())
3985 entry = section.GetEntries()['u-boot']
3986 self.assertEqual(16, entry.offset)
3987 self.assertEqual(len(all), entry.size)
3988 self.assertEqual(U_BOOT_DATA, entry.data)
3990 def testSkipAtStartSectionPad(self):
3991 """Test handling of skip-at-start section with padding"""
3992 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3993 before = tools.GetBytes(0, 8)
3994 after = tools.GetBytes(0, 4)
3995 all = before + U_BOOT_DATA + after
3996 self.assertEqual(all, data)
3998 image = control.images['image']
3999 entries = image.GetEntries()
4000 section = entries['section']
4001 self.assertEqual(0, section.offset)
4002 self.assertEqual(len(all), section.size)
4003 self.assertEqual(U_BOOT_DATA, section.data)
4004 self.assertEqual(all, section.GetPaddedData())
4006 entry = section.GetEntries()['u-boot']
4007 self.assertEqual(16, entry.offset)
4008 self.assertEqual(len(U_BOOT_DATA), entry.size)
4009 self.assertEqual(U_BOOT_DATA, entry.data)
4011 def testSectionPad(self):
4012 """Testing padding with sections"""
4013 data = self._DoReadFile('180_section_pad.dts')
4014 expected = (tools.GetBytes(ord('&'), 3) +
4015 tools.GetBytes(ord('!'), 5) +
4017 tools.GetBytes(ord('!'), 1) +
4018 tools.GetBytes(ord('&'), 2))
4019 self.assertEqual(expected, data)
4021 def testSectionAlign(self):
4022 """Testing alignment with sections"""
4023 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4024 expected = (b'\0' + # fill section
4025 tools.GetBytes(ord('&'), 1) + # padding to section align
4026 b'\0' + # fill section
4027 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4029 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4030 tools.GetBytes(ord('!'), 4)) # padding to section size
4031 self.assertEqual(expected, data)
4033 def testCompressImage(self):
4034 """Test compression of the entire image"""
4036 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4037 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4038 dtb = fdt.Fdt(out_dtb_fname)
4040 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4042 orig = self._decompress(data)
4043 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4045 # Do a sanity check on various fields
4046 image = control.images['image']
4047 entries = image.GetEntries()
4048 self.assertEqual(2, len(entries))
4050 entry = entries['blob']
4051 self.assertEqual(COMPRESS_DATA, entry.data)
4052 self.assertEqual(len(COMPRESS_DATA), entry.size)
4054 entry = entries['u-boot']
4055 self.assertEqual(U_BOOT_DATA, entry.data)
4056 self.assertEqual(len(U_BOOT_DATA), entry.size)
4058 self.assertEqual(len(data), image.size)
4059 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4060 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4061 orig = self._decompress(image.data)
4062 self.assertEqual(orig, image.uncomp_data)
4066 'blob:size': len(COMPRESS_DATA),
4067 'u-boot:offset': len(COMPRESS_DATA),
4068 'u-boot:size': len(U_BOOT_DATA),
4069 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4074 self.assertEqual(expected, props)
4076 def testCompressImageLess(self):
4077 """Test compression where compression reduces the image size"""
4079 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4080 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4081 dtb = fdt.Fdt(out_dtb_fname)
4083 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4085 orig = self._decompress(data)
4087 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4089 # Do a sanity check on various fields
4090 image = control.images['image']
4091 entries = image.GetEntries()
4092 self.assertEqual(2, len(entries))
4094 entry = entries['blob']
4095 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4096 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4098 entry = entries['u-boot']
4099 self.assertEqual(U_BOOT_DATA, entry.data)
4100 self.assertEqual(len(U_BOOT_DATA), entry.size)
4102 self.assertEqual(len(data), image.size)
4103 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4104 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4106 orig = self._decompress(image.data)
4107 self.assertEqual(orig, image.uncomp_data)
4111 'blob:size': len(COMPRESS_DATA_BIG),
4112 'u-boot:offset': len(COMPRESS_DATA_BIG),
4113 'u-boot:size': len(U_BOOT_DATA),
4114 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4119 self.assertEqual(expected, props)
4121 def testCompressSectionSize(self):
4122 """Test compression of a section with a fixed size"""
4124 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4125 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4126 dtb = fdt.Fdt(out_dtb_fname)
4128 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4130 orig = self._decompress(data)
4131 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4133 'section/blob:offset': 0,
4134 'section/blob:size': len(COMPRESS_DATA),
4135 'section/u-boot:offset': len(COMPRESS_DATA),
4136 'section/u-boot:size': len(U_BOOT_DATA),
4137 'section:offset': 0,
4138 'section:image-pos': 0,
4139 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4140 'section:size': 0x30,
4145 self.assertEqual(expected, props)
4147 def testCompressSection(self):
4148 """Test compression of a section with no fixed size"""
4150 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4151 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4152 dtb = fdt.Fdt(out_dtb_fname)
4154 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4156 orig = self._decompress(data)
4157 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4159 'section/blob:offset': 0,
4160 'section/blob:size': len(COMPRESS_DATA),
4161 'section/u-boot:offset': len(COMPRESS_DATA),
4162 'section/u-boot:size': len(U_BOOT_DATA),
4163 'section:offset': 0,
4164 'section:image-pos': 0,
4165 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4166 'section:size': len(data),
4171 self.assertEqual(expected, props)
4173 def testCompressExtra(self):
4174 """Test compression of a section with no fixed size"""
4176 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4177 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4178 dtb = fdt.Fdt(out_dtb_fname)
4180 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4183 base = data[len(U_BOOT_DATA):]
4184 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4185 rest = base[len(U_BOOT_DATA):]
4187 # Check compressed data
4188 section1 = self._decompress(rest)
4189 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4190 self.assertEquals(expect1, rest[:len(expect1)])
4191 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4192 rest1 = rest[len(expect1):]
4194 section2 = self._decompress(rest1)
4195 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4196 self.assertEquals(expect2, rest1[:len(expect2)])
4197 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4198 rest2 = rest1[len(expect2):]
4200 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4201 len(expect2) + len(U_BOOT_DATA))
4202 #self.assertEquals(expect_size, len(data))
4204 #self.assertEquals(U_BOOT_DATA, rest2)
4209 'u-boot:image-pos': 0,
4210 'u-boot:size': len(U_BOOT_DATA),
4212 'base:offset': len(U_BOOT_DATA),
4213 'base:image-pos': len(U_BOOT_DATA),
4214 'base:size': len(data) - len(U_BOOT_DATA),
4215 'base/u-boot:offset': 0,
4216 'base/u-boot:image-pos': len(U_BOOT_DATA),
4217 'base/u-boot:size': len(U_BOOT_DATA),
4218 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4220 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4222 'base/u-boot2:size': len(U_BOOT_DATA),
4224 'base/section:offset': len(U_BOOT_DATA),
4225 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4226 'base/section:size': len(expect1),
4227 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4228 'base/section/blob:offset': 0,
4229 'base/section/blob:size': len(COMPRESS_DATA),
4230 'base/section/u-boot:offset': len(COMPRESS_DATA),
4231 'base/section/u-boot:size': len(U_BOOT_DATA),
4233 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4234 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4235 'base/section2:size': len(expect2),
4236 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4237 'base/section2/blob:offset': 0,
4238 'base/section2/blob:size': len(COMPRESS_DATA),
4239 'base/section2/blob2:offset': len(COMPRESS_DATA),
4240 'base/section2/blob2:size': len(COMPRESS_DATA),
4246 self.assertEqual(expected, props)
4248 def testSymbolsSubsection(self):
4249 """Test binman can assign symbols from a subsection"""
4250 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4252 def testReadImageEntryArg(self):
4253 """Test reading an image that would need an entry arg to generate"""
4255 'cros-ec-rw-path': 'ecrw.bin',
4257 data = self.data = self._DoReadFileDtb(
4258 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4259 entry_args=entry_args)
4261 image_fname = tools.GetOutputFilename('image.bin')
4262 orig_image = control.images['image']
4264 # This should not generate an error about the missing 'cros-ec-rw-path'
4265 # since we are reading the image from a file. Compare with
4266 # testEntryArgsRequired()
4267 image = Image.FromFile(image_fname)
4268 self.assertEqual(orig_image.GetEntries().keys(),
4269 image.GetEntries().keys())
4271 def testFilesAlign(self):
4272 """Test alignment with files"""
4273 data = self._DoReadFile('190_files_align.dts')
4275 # The first string is 15 bytes so will align to 16
4276 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4277 self.assertEqual(expect, data)
4279 def testReadImageSkip(self):
4280 """Test reading an image and accessing its FDT map"""
4281 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4282 image_fname = tools.GetOutputFilename('image.bin')
4283 orig_image = control.images['image']
4284 image = Image.FromFile(image_fname)
4285 self.assertEqual(orig_image.GetEntries().keys(),
4286 image.GetEntries().keys())
4288 orig_entry = orig_image.GetEntries()['fdtmap']
4289 entry = image.GetEntries()['fdtmap']
4290 self.assertEqual(orig_entry.offset, entry.offset)
4291 self.assertEqual(orig_entry.size, entry.size)
4292 self.assertEqual(16, entry.image_pos)
4294 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4296 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4298 def testTplNoDtb(self):
4299 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4301 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4302 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4303 data[:len(U_BOOT_TPL_NODTB_DATA)])
4305 def testTplBssPad(self):
4306 """Test that we can pad TPL's BSS with zeros"""
4307 # ELF file with a '__bss_size' symbol
4309 data = self._DoReadFile('193_tpl_bss_pad.dts')
4310 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4313 def testTplBssPadMissing(self):
4314 """Test that a missing symbol is detected"""
4315 self._SetupTplElf('u_boot_ucode_ptr')
4316 with self.assertRaises(ValueError) as e:
4317 self._DoReadFile('193_tpl_bss_pad.dts')
4318 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4321 def checkDtbSizes(self, data, pad_len, start):
4322 """Check the size arguments in a dtb embedded in an image
4325 data: The image data
4326 pad_len: Length of the pad section in the image, in bytes
4327 start: Start offset of the devicetree to examine, within the image
4330 Size of the devicetree in bytes
4332 dtb_data = data[start:]
4333 dtb = fdt.Fdt.FromData(dtb_data)
4334 fdt_size = dtb.GetFdtObj().totalsize()
4336 props = self._GetPropTree(dtb, 'size')
4339 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4340 'u-boot-spl/u-boot-spl-dtb:size': 801,
4341 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4342 'u-boot-spl:size': 860,
4343 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4344 'u-boot/u-boot-dtb:size': 781,
4345 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4350 def testExpanded(self):
4351 """Test that an expanded entry type is selected when needed"""
4355 # SPL has a devicetree, TPL does not
4361 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4362 entry_args=entry_args)
4363 image = control.images['image']
4364 entries = image.GetEntries()
4365 self.assertEqual(3, len(entries))
4367 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4368 self.assertIn('u-boot', entries)
4369 entry = entries['u-boot']
4370 self.assertEqual('u-boot-expanded', entry.etype)
4371 subent = entry.GetEntries()
4372 self.assertEqual(2, len(subent))
4373 self.assertIn('u-boot-nodtb', subent)
4374 self.assertIn('u-boot-dtb', subent)
4376 # Second, u-boot-spl, which should be expanded into three parts
4377 self.assertIn('u-boot-spl', entries)
4378 entry = entries['u-boot-spl']
4379 self.assertEqual('u-boot-spl-expanded', entry.etype)
4380 subent = entry.GetEntries()
4381 self.assertEqual(3, len(subent))
4382 self.assertIn('u-boot-spl-nodtb', subent)
4383 self.assertIn('u-boot-spl-bss-pad', subent)
4384 self.assertIn('u-boot-spl-dtb', subent)
4386 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4388 self.assertIn('u-boot-tpl', entries)
4389 entry = entries['u-boot-tpl']
4390 self.assertEqual('u-boot-tpl', entry.etype)
4391 self.assertEqual(None, entry.GetEntries())
4393 def testExpandedTpl(self):
4394 """Test that an expanded entry type is selected for TPL when needed"""
4401 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4402 entry_args=entry_args)
4403 image = control.images['image']
4404 entries = image.GetEntries()
4405 self.assertEqual(1, len(entries))
4407 # We only have u-boot-tpl, which be expanded
4408 self.assertIn('u-boot-tpl', entries)
4409 entry = entries['u-boot-tpl']
4410 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4411 subent = entry.GetEntries()
4412 self.assertEqual(3, len(subent))
4413 self.assertIn('u-boot-tpl-nodtb', subent)
4414 self.assertIn('u-boot-tpl-bss-pad', subent)
4415 self.assertIn('u-boot-tpl-dtb', subent)
4417 def testExpandedNoPad(self):
4418 """Test an expanded entry without BSS pad enabled"""
4422 # SPL has a devicetree, TPL does not
4424 'spl-dtb': 'something',
4428 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4429 entry_args=entry_args)
4430 image = control.images['image']
4431 entries = image.GetEntries()
4433 # Just check u-boot-spl, which should be expanded into two parts
4434 self.assertIn('u-boot-spl', entries)
4435 entry = entries['u-boot-spl']
4436 self.assertEqual('u-boot-spl-expanded', entry.etype)
4437 subent = entry.GetEntries()
4438 self.assertEqual(2, len(subent))
4439 self.assertIn('u-boot-spl-nodtb', subent)
4440 self.assertIn('u-boot-spl-dtb', subent)
4442 def testExpandedTplNoPad(self):
4443 """Test that an expanded entry type with padding disabled in TPL"""
4450 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4451 entry_args=entry_args)
4452 image = control.images['image']
4453 entries = image.GetEntries()
4454 self.assertEqual(1, len(entries))
4456 # We only have u-boot-tpl, which be expanded
4457 self.assertIn('u-boot-tpl', entries)
4458 entry = entries['u-boot-tpl']
4459 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4460 subent = entry.GetEntries()
4461 self.assertEqual(2, len(subent))
4462 self.assertIn('u-boot-tpl-nodtb', subent)
4463 self.assertIn('u-boot-tpl-dtb', subent)
4465 def testFdtInclude(self):
4466 """Test that an Fdt is update within all binaries"""
4470 # SPL has a devicetree, TPL does not
4477 # Build the image. It includes two separate devicetree binaries, each
4478 # with their own contents, but all contain the binman definition.
4479 data = self._DoReadFileDtb(
4480 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4481 update_dtb=True, entry_args=entry_args)[0]
4484 # Check the U-Boot dtb
4485 start = len(U_BOOT_NODTB_DATA)
4486 fdt_size = self.checkDtbSizes(data, pad_len, start)
4489 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4490 fdt_size = self.checkDtbSizes(data, pad_len, start)
4492 # TPL has no devicetree
4493 start += fdt_size + len(U_BOOT_TPL_DATA)
4494 self.assertEqual(len(data), start)
4496 def testSymbolsExpanded(self):
4497 """Test binman can assign symbols in expanded entries"""
4501 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4502 U_BOOT_SPL_DTB_DATA, 0x38,
4503 entry_args=entry_args, use_expanded=True)
4505 def testCollection(self):
4506 """Test a collection"""
4507 data = self._DoReadFile('198_collection.dts')
4508 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4509 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4510 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4513 def testCollectionSection(self):
4514 """Test a collection where a section must be built first"""
4515 # Sections never have their contents when GetData() is called, but when
4516 # _BuildSectionData() is called with required=True, a section will force
4517 # building the contents, producing an error is anything is still
4519 data = self._DoReadFile('199_collection_section.dts')
4520 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4521 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4522 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4525 def testAlignDefault(self):
4526 """Test that default alignment works on sections"""
4527 data = self._DoReadFile('200_align_default.dts')
4528 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4530 # Special alignment for section
4531 expected += tools.GetBytes(0, 32 - len(expected))
4532 # No alignment within the nested section
4533 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4534 # Now the final piece, which should be default-aligned
4535 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4536 self.assertEqual(expected, data)
4538 if __name__ == "__main__":