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"""
1344 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1345 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1347 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1348 use_expanded=False):
1349 """Check the image contains the expected symbol values
1352 dts: Device tree file to use for test
1353 base_data: Data before and after 'u-boot' section
1354 u_boot_offset: Offset of 'u-boot' section in image
1355 entry_args: Dict of entry args to supply to binman
1357 value: value of that arg
1358 use_expanded: True to use expanded entries where available, e.g.
1359 'u-boot-expanded' instead of 'u-boot'
1361 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1362 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1363 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1364 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1367 self._SetupSplElf('u_boot_binman_syms')
1368 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1369 use_expanded=use_expanded)[0]
1370 # The image should contain the symbols from u_boot_binman_syms.c
1371 # Note that image_pos is adjusted by the base address of the image,
1372 # which is 0x10 in our test image
1373 sym_values = struct.pack('<LQLL', 0x00,
1374 u_boot_offset + len(U_BOOT_DATA),
1375 0x10 + u_boot_offset, 0x04)
1376 expected = (sym_values + base_data[20:] +
1377 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1379 self.assertEqual(expected, data)
1381 def testSymbols(self):
1382 """Test binman can assign symbols embedded in U-Boot"""
1383 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1385 def testSymbolsNoDtb(self):
1386 """Test binman can assign symbols embedded in U-Boot SPL"""
1387 self.checkSymbols('196_symbols_nodtb.dts',
1388 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1391 def testPackUnitAddress(self):
1392 """Test that we support multiple binaries with the same name"""
1393 data = self._DoReadFile('054_unit_address.dts')
1394 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1396 def testSections(self):
1397 """Basic test of sections"""
1398 data = self._DoReadFile('055_sections.dts')
1399 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1400 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1401 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1402 self.assertEqual(expected, data)
1405 """Tests outputting a map of the images"""
1406 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1407 self.assertEqual('''ImagePos Offset Size Name
1408 00000000 00000000 00000028 main-section
1409 00000000 00000000 00000010 section@0
1410 00000000 00000000 00000004 u-boot
1411 00000010 00000010 00000010 section@1
1412 00000010 00000000 00000004 u-boot
1413 00000020 00000020 00000004 section@2
1414 00000020 00000000 00000004 u-boot
1417 def testNamePrefix(self):
1418 """Tests that name prefixes are used"""
1419 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1420 self.assertEqual('''ImagePos Offset Size Name
1421 00000000 00000000 00000028 main-section
1422 00000000 00000000 00000010 section@0
1423 00000000 00000000 00000004 ro-u-boot
1424 00000010 00000010 00000010 section@1
1425 00000010 00000000 00000004 rw-u-boot
1428 def testUnknownContents(self):
1429 """Test that obtaining the contents works as expected"""
1430 with self.assertRaises(ValueError) as e:
1431 self._DoReadFile('057_unknown_contents.dts', True)
1432 self.assertIn("Image '/binman': Internal error: Could not complete "
1433 "processing of contents: remaining ["
1434 "<binman.etype._testing.Entry__testing ", str(e.exception))
1436 def testBadChangeSize(self):
1437 """Test that trying to change the size of an entry fails"""
1439 state.SetAllowEntryExpansion(False)
1440 with self.assertRaises(ValueError) as e:
1441 self._DoReadFile('059_change_size.dts', True)
1442 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1445 state.SetAllowEntryExpansion(True)
1447 def testUpdateFdt(self):
1448 """Test that we can update the device tree with offset/size info"""
1449 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1451 dtb = fdt.Fdt(out_dtb_fname)
1453 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1457 '_testing:offset': 32,
1459 '_testing:image-pos': 32,
1460 'section@0/u-boot:offset': 0,
1461 'section@0/u-boot:size': len(U_BOOT_DATA),
1462 'section@0/u-boot:image-pos': 0,
1463 'section@0:offset': 0,
1464 'section@0:size': 16,
1465 'section@0:image-pos': 0,
1467 'section@1/u-boot:offset': 0,
1468 'section@1/u-boot:size': len(U_BOOT_DATA),
1469 'section@1/u-boot:image-pos': 16,
1470 'section@1:offset': 16,
1471 'section@1:size': 16,
1472 'section@1:image-pos': 16,
1476 def testUpdateFdtBad(self):
1477 """Test that we detect when ProcessFdt never completes"""
1478 with self.assertRaises(ValueError) as e:
1479 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1480 self.assertIn('Could not complete processing of Fdt: remaining '
1481 '[<binman.etype._testing.Entry__testing',
1484 def testEntryArgs(self):
1485 """Test passing arguments to entries from the command line"""
1487 'test-str-arg': 'test1',
1488 'test-int-arg': '456',
1490 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1491 self.assertIn('image', control.images)
1492 entry = control.images['image'].GetEntries()['_testing']
1493 self.assertEqual('test0', entry.test_str_fdt)
1494 self.assertEqual('test1', entry.test_str_arg)
1495 self.assertEqual(123, entry.test_int_fdt)
1496 self.assertEqual(456, entry.test_int_arg)
1498 def testEntryArgsMissing(self):
1499 """Test missing arguments and properties"""
1501 'test-int-arg': '456',
1503 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1504 entry = control.images['image'].GetEntries()['_testing']
1505 self.assertEqual('test0', entry.test_str_fdt)
1506 self.assertEqual(None, entry.test_str_arg)
1507 self.assertEqual(None, entry.test_int_fdt)
1508 self.assertEqual(456, entry.test_int_arg)
1510 def testEntryArgsRequired(self):
1511 """Test missing arguments and properties"""
1513 'test-int-arg': '456',
1515 with self.assertRaises(ValueError) as e:
1516 self._DoReadFileDtb('064_entry_args_required.dts')
1517 self.assertIn("Node '/binman/_testing': "
1518 'Missing required properties/entry args: test-str-arg, '
1519 'test-int-fdt, test-int-arg',
1522 def testEntryArgsInvalidFormat(self):
1523 """Test that an invalid entry-argument format is detected"""
1524 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1526 with self.assertRaises(ValueError) as e:
1527 self._DoBinman(*args)
1528 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1530 def testEntryArgsInvalidInteger(self):
1531 """Test that an invalid entry-argument integer is detected"""
1533 'test-int-arg': 'abc',
1535 with self.assertRaises(ValueError) as e:
1536 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1537 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1538 "'test-int-arg' (value 'abc') to integer",
1541 def testEntryArgsInvalidDatatype(self):
1542 """Test that an invalid entry-argument datatype is detected
1544 This test could be written in entry_test.py except that it needs
1545 access to control.entry_args, which seems more than that module should
1549 'test-bad-datatype-arg': '12',
1551 with self.assertRaises(ValueError) as e:
1552 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1553 entry_args=entry_args)
1554 self.assertIn('GetArg() internal error: Unknown data type ',
1558 """Test for a text entry type"""
1560 'test-id': TEXT_DATA,
1561 'test-id2': TEXT_DATA2,
1562 'test-id3': TEXT_DATA3,
1564 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1565 entry_args=entry_args)
1566 expected = (tools.ToBytes(TEXT_DATA) +
1567 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1568 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1569 b'some text' + b'more text')
1570 self.assertEqual(expected, data)
1572 def testEntryDocs(self):
1573 """Test for creation of entry documentation"""
1574 with test_util.capture_sys_output() as (stdout, stderr):
1575 control.WriteEntryDocs(control.GetEntryModules())
1576 self.assertTrue(len(stdout.getvalue()) > 0)
1578 def testEntryDocsMissing(self):
1579 """Test handling of missing entry documentation"""
1580 with self.assertRaises(ValueError) as e:
1581 with test_util.capture_sys_output() as (stdout, stderr):
1582 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1583 self.assertIn('Documentation is missing for modules: u_boot',
1587 """Basic test of generation of a flashrom fmap"""
1588 data = self._DoReadFile('067_fmap.dts')
1589 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1590 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1591 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1592 self.assertEqual(expected, data[:32])
1593 self.assertEqual(b'__FMAP__', fhdr.signature)
1594 self.assertEqual(1, fhdr.ver_major)
1595 self.assertEqual(0, fhdr.ver_minor)
1596 self.assertEqual(0, fhdr.base)
1597 self.assertEqual(16 + 16 +
1598 fmap_util.FMAP_HEADER_LEN +
1599 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1600 self.assertEqual(b'FMAP', fhdr.name)
1601 self.assertEqual(3, fhdr.nareas)
1602 for fentry in fentries:
1603 self.assertEqual(0, fentry.flags)
1605 self.assertEqual(0, fentries[0].offset)
1606 self.assertEqual(4, fentries[0].size)
1607 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1609 self.assertEqual(16, fentries[1].offset)
1610 self.assertEqual(4, fentries[1].size)
1611 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1613 self.assertEqual(32, fentries[2].offset)
1614 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1615 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1616 self.assertEqual(b'FMAP', fentries[2].name)
1618 def testBlobNamedByArg(self):
1619 """Test we can add a blob with the filename coming from an entry arg"""
1621 'cros-ec-rw-path': 'ecrw.bin',
1623 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1626 """Test for an fill entry type"""
1627 data = self._DoReadFile('069_fill.dts')
1628 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1629 self.assertEqual(expected, data)
1631 def testFillNoSize(self):
1632 """Test for an fill entry type with no size"""
1633 with self.assertRaises(ValueError) as e:
1634 self._DoReadFile('070_fill_no_size.dts')
1635 self.assertIn("'fill' entry must have a size property",
1638 def _HandleGbbCommand(self, pipe_list):
1639 """Fake calls to the futility utility"""
1640 if pipe_list[0][0] == 'futility':
1641 fname = pipe_list[0][-1]
1642 # Append our GBB data to the file, which will happen every time the
1643 # futility command is called.
1644 with open(fname, 'ab') as fd:
1646 return command.CommandResult()
1649 """Test for the Chromium OS Google Binary Block"""
1650 command.test_result = self._HandleGbbCommand
1652 'keydir': 'devkeys',
1653 'bmpblk': 'bmpblk.bin',
1655 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1658 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1659 tools.GetBytes(0, 0x2180 - 16))
1660 self.assertEqual(expected, data)
1662 def testGbbTooSmall(self):
1663 """Test for the Chromium OS Google Binary Block being large enough"""
1664 with self.assertRaises(ValueError) as e:
1665 self._DoReadFileDtb('072_gbb_too_small.dts')
1666 self.assertIn("Node '/binman/gbb': GBB is too small",
1669 def testGbbNoSize(self):
1670 """Test for the Chromium OS Google Binary Block having a size"""
1671 with self.assertRaises(ValueError) as e:
1672 self._DoReadFileDtb('073_gbb_no_size.dts')
1673 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1676 def _HandleVblockCommand(self, pipe_list):
1677 """Fake calls to the futility utility
1679 The expected pipe is:
1681 [('futility', 'vbutil_firmware', '--vblock',
1682 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1683 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1684 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1685 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1687 This writes to the output file (here, 'vblock.vblock'). If
1688 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1689 of the input data (here, 'input.vblock').
1691 if pipe_list[0][0] == 'futility':
1692 fname = pipe_list[0][3]
1693 with open(fname, 'wb') as fd:
1695 infile = pipe_list[0][11]
1696 m = hashlib.sha256()
1697 data = tools.ReadFile(infile)
1699 fd.write(m.digest())
1701 fd.write(VBLOCK_DATA)
1703 return command.CommandResult()
1705 def testVblock(self):
1706 """Test for the Chromium OS Verified Boot Block"""
1707 self._hash_data = False
1708 command.test_result = self._HandleVblockCommand
1710 'keydir': 'devkeys',
1712 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1713 entry_args=entry_args)
1714 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1715 self.assertEqual(expected, data)
1717 def testVblockNoContent(self):
1718 """Test we detect a vblock which has no content to sign"""
1719 with self.assertRaises(ValueError) as e:
1720 self._DoReadFile('075_vblock_no_content.dts')
1721 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
1722 'property', str(e.exception))
1724 def testVblockBadPhandle(self):
1725 """Test that we detect a vblock with an invalid phandle in contents"""
1726 with self.assertRaises(ValueError) as e:
1727 self._DoReadFile('076_vblock_bad_phandle.dts')
1728 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1729 '1000', str(e.exception))
1731 def testVblockBadEntry(self):
1732 """Test that we detect an entry that points to a non-entry"""
1733 with self.assertRaises(ValueError) as e:
1734 self._DoReadFile('077_vblock_bad_entry.dts')
1735 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1736 "'other'", str(e.exception))
1738 def testVblockContent(self):
1739 """Test that the vblock signs the right data"""
1740 self._hash_data = True
1741 command.test_result = self._HandleVblockCommand
1743 'keydir': 'devkeys',
1745 data = self._DoReadFileDtb(
1746 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1747 entry_args=entry_args)[0]
1748 hashlen = 32 # SHA256 hash is 32 bytes
1749 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1750 hashval = data[-hashlen:]
1751 dtb = data[len(U_BOOT_DATA):-hashlen]
1753 expected_data = U_BOOT_DATA + dtb
1755 # The hashval should be a hash of the dtb
1756 m = hashlib.sha256()
1757 m.update(expected_data)
1758 expected_hashval = m.digest()
1759 self.assertEqual(expected_hashval, hashval)
1762 """Test that an image with TPL and its device tree can be created"""
1763 # ELF file with a '__bss_size' symbol
1765 data = self._DoReadFile('078_u_boot_tpl.dts')
1766 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1768 def testUsesPos(self):
1769 """Test that the 'pos' property cannot be used anymore"""
1770 with self.assertRaises(ValueError) as e:
1771 data = self._DoReadFile('079_uses_pos.dts')
1772 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1773 "'pos'", str(e.exception))
1775 def testFillZero(self):
1776 """Test for an fill entry type with a size of 0"""
1777 data = self._DoReadFile('080_fill_empty.dts')
1778 self.assertEqual(tools.GetBytes(0, 16), data)
1780 def testTextMissing(self):
1781 """Test for a text entry type where there is no text"""
1782 with self.assertRaises(ValueError) as e:
1783 self._DoReadFileDtb('066_text.dts',)
1784 self.assertIn("Node '/binman/text': No value provided for text label "
1785 "'test-id'", str(e.exception))
1787 def testPackStart16Tpl(self):
1788 """Test that an image with an x86 start16 TPL region can be created"""
1789 data = self._DoReadFile('081_x86_start16_tpl.dts')
1790 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1792 def testSelectImage(self):
1793 """Test that we can select which images to build"""
1794 expected = 'Skipping images: image1'
1796 # We should only get the expected message in verbose mode
1797 for verbosity in (0, 2):
1798 with test_util.capture_sys_output() as (stdout, stderr):
1799 retcode = self._DoTestFile('006_dual_image.dts',
1800 verbosity=verbosity,
1802 self.assertEqual(0, retcode)
1804 self.assertIn(expected, stdout.getvalue())
1806 self.assertNotIn(expected, stdout.getvalue())
1808 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1809 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1810 self._CleanupOutputDir()
1812 def testUpdateFdtAll(self):
1813 """Test that all device trees are updated with offset/size info"""
1814 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1817 'section:image-pos': 0,
1818 'u-boot-tpl-dtb:size': 513,
1819 'u-boot-spl-dtb:size': 513,
1820 'u-boot-spl-dtb:offset': 493,
1822 'section/u-boot-dtb:image-pos': 0,
1823 'u-boot-spl-dtb:image-pos': 493,
1824 'section/u-boot-dtb:size': 493,
1825 'u-boot-tpl-dtb:image-pos': 1006,
1826 'section/u-boot-dtb:offset': 0,
1827 'section:size': 493,
1829 'section:offset': 0,
1830 'u-boot-tpl-dtb:offset': 1006,
1834 # We expect three device-tree files in the output, one after the other.
1835 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1836 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1837 # main U-Boot tree. All three should have the same postions and offset.
1839 for item in ['', 'spl', 'tpl']:
1840 dtb = fdt.Fdt.FromData(data[start:])
1842 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1844 expected = dict(base_expected)
1847 self.assertEqual(expected, props)
1848 start += dtb._fdt_obj.totalsize()
1850 def testUpdateFdtOutput(self):
1851 """Test that output DTB files are updated"""
1853 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1854 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1856 # Unfortunately, compiling a source file always results in a file
1857 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1858 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1859 # binman as a file called u-boot.dtb. To fix this, copy the file
1860 # over to the expected place.
1862 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1863 'tpl/u-boot-tpl.dtb.out']:
1864 dtb = fdt.Fdt.FromData(data[start:])
1865 size = dtb._fdt_obj.totalsize()
1866 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1867 outdata = tools.ReadFile(pathname)
1868 name = os.path.split(fname)[0]
1871 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1873 orig_indata = dtb_data
1874 self.assertNotEqual(outdata, orig_indata,
1875 "Expected output file '%s' be updated" % pathname)
1876 self.assertEqual(outdata, data[start:start + size],
1877 "Expected output file '%s' to match output image" %
1883 def _decompress(self, data):
1884 return tools.Decompress(data, 'lz4')
1886 def testCompress(self):
1887 """Test compression of blobs"""
1889 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1890 use_real_dtb=True, update_dtb=True)
1891 dtb = fdt.Fdt(out_dtb_fname)
1893 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1894 orig = self._decompress(data)
1895 self.assertEquals(COMPRESS_DATA, orig)
1897 # Do a sanity check on various fields
1898 image = control.images['image']
1899 entries = image.GetEntries()
1900 self.assertEqual(1, len(entries))
1902 entry = entries['blob']
1903 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1904 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1905 orig = self._decompress(entry.data)
1906 self.assertEqual(orig, entry.uncomp_data)
1908 self.assertEqual(image.data, entry.data)
1911 'blob:uncomp-size': len(COMPRESS_DATA),
1912 'blob:size': len(data),
1915 self.assertEqual(expected, props)
1917 def testFiles(self):
1918 """Test bringing in multiple files"""
1919 data = self._DoReadFile('084_files.dts')
1920 self.assertEqual(FILES_DATA, data)
1922 def testFilesCompress(self):
1923 """Test bringing in multiple files and compressing them"""
1925 data = self._DoReadFile('085_files_compress.dts')
1927 image = control.images['image']
1928 entries = image.GetEntries()
1929 files = entries['files']
1930 entries = files._entries
1933 for i in range(1, 3):
1935 start = entries[key].image_pos
1936 len = entries[key].size
1937 chunk = data[start:start + len]
1938 orig += self._decompress(chunk)
1940 self.assertEqual(FILES_DATA, orig)
1942 def testFilesMissing(self):
1943 """Test missing files"""
1944 with self.assertRaises(ValueError) as e:
1945 data = self._DoReadFile('086_files_none.dts')
1946 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1947 'no files', str(e.exception))
1949 def testFilesNoPattern(self):
1950 """Test missing files"""
1951 with self.assertRaises(ValueError) as e:
1952 data = self._DoReadFile('087_files_no_pattern.dts')
1953 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1956 def testExpandSize(self):
1957 """Test an expanding entry"""
1958 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1960 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1961 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1962 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1963 tools.GetBytes(ord('d'), 8))
1964 self.assertEqual(expect, data)
1965 self.assertEqual('''ImagePos Offset Size Name
1966 00000000 00000000 00000028 main-section
1967 00000000 00000000 00000008 fill
1968 00000008 00000008 00000004 u-boot
1969 0000000c 0000000c 00000004 section
1970 0000000c 00000000 00000003 intel-mrc
1971 00000010 00000010 00000004 u-boot2
1972 00000014 00000014 0000000c section2
1973 00000014 00000000 00000008 fill
1974 0000001c 00000008 00000004 u-boot
1975 00000020 00000020 00000008 fill2
1978 def testExpandSizeBad(self):
1979 """Test an expanding entry which fails to provide contents"""
1980 with test_util.capture_sys_output() as (stdout, stderr):
1981 with self.assertRaises(ValueError) as e:
1982 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1983 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1984 'expanding entry', str(e.exception))
1987 """Test hashing of the contents of an entry"""
1988 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1989 use_real_dtb=True, update_dtb=True)
1990 dtb = fdt.Fdt(out_dtb_fname)
1992 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1993 m = hashlib.sha256()
1994 m.update(U_BOOT_DATA)
1995 self.assertEqual(m.digest(), b''.join(hash_node.value))
1997 def testHashNoAlgo(self):
1998 with self.assertRaises(ValueError) as e:
1999 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
2000 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2001 'hash node', str(e.exception))
2003 def testHashBadAlgo(self):
2004 with self.assertRaises(ValueError) as e:
2005 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
2006 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2009 def testHashSection(self):
2010 """Test hashing of the contents of an entry"""
2011 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
2012 use_real_dtb=True, update_dtb=True)
2013 dtb = fdt.Fdt(out_dtb_fname)
2015 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2016 m = hashlib.sha256()
2017 m.update(U_BOOT_DATA)
2018 m.update(tools.GetBytes(ord('a'), 16))
2019 self.assertEqual(m.digest(), b''.join(hash_node.value))
2021 def testPackUBootTplMicrocode(self):
2022 """Test that x86 microcode can be handled correctly in TPL
2024 We expect to see the following in the image, in order:
2025 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2027 u-boot-tpl.dtb with the microcode removed
2030 self._SetupTplElf('u_boot_ucode_ptr')
2031 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
2032 U_BOOT_TPL_NODTB_DATA)
2033 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2034 b'ter somewhere in here', first)
2036 def testFmapX86(self):
2037 """Basic test of generation of a flashrom fmap"""
2038 data = self._DoReadFile('094_fmap_x86.dts')
2039 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2040 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
2041 self.assertEqual(expected, data[:32])
2042 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2044 self.assertEqual(0x100, fhdr.image_size)
2046 self.assertEqual(0, fentries[0].offset)
2047 self.assertEqual(4, fentries[0].size)
2048 self.assertEqual(b'U_BOOT', fentries[0].name)
2050 self.assertEqual(4, fentries[1].offset)
2051 self.assertEqual(3, fentries[1].size)
2052 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2054 self.assertEqual(32, fentries[2].offset)
2055 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2056 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2057 self.assertEqual(b'FMAP', fentries[2].name)
2059 def testFmapX86Section(self):
2060 """Basic test of generation of a flashrom fmap"""
2061 data = self._DoReadFile('095_fmap_x86_section.dts')
2062 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
2063 self.assertEqual(expected, data[:32])
2064 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2066 self.assertEqual(0x100, fhdr.image_size)
2068 self.assertEqual(0, fentries[0].offset)
2069 self.assertEqual(4, fentries[0].size)
2070 self.assertEqual(b'U_BOOT', fentries[0].name)
2072 self.assertEqual(4, fentries[1].offset)
2073 self.assertEqual(3, fentries[1].size)
2074 self.assertEqual(b'INTEL_MRC', fentries[1].name)
2076 self.assertEqual(36, fentries[2].offset)
2077 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2078 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
2079 self.assertEqual(b'FMAP', fentries[2].name)
2082 """Basic test of ELF entries"""
2085 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2086 TestFunctional._MakeInputFile('-boot', fd.read())
2087 data = self._DoReadFile('096_elf.dts')
2089 def testElfStrip(self):
2090 """Basic test of ELF entries"""
2092 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
2093 TestFunctional._MakeInputFile('-boot', fd.read())
2094 data = self._DoReadFile('097_elf_strip.dts')
2096 def testPackOverlapMap(self):
2097 """Test that overlapping regions are detected"""
2098 with test_util.capture_sys_output() as (stdout, stderr):
2099 with self.assertRaises(ValueError) as e:
2100 self._DoTestFile('014_pack_overlap.dts', map=True)
2101 map_fname = tools.GetOutputFilename('image.map')
2102 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2105 # We should not get an inmage, but there should be a map file
2106 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2107 self.assertTrue(os.path.exists(map_fname))
2108 map_data = tools.ReadFile(map_fname, binary=False)
2109 self.assertEqual('''ImagePos Offset Size Name
2110 <none> 00000000 00000008 main-section
2111 <none> 00000000 00000004 u-boot
2112 <none> 00000003 00000004 u-boot-align
2115 def testPackRefCode(self):
2116 """Test that an image with an Intel Reference code binary works"""
2117 data = self._DoReadFile('100_intel_refcode.dts')
2118 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2120 def testSectionOffset(self):
2121 """Tests use of a section with an offset"""
2122 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2124 self.assertEqual('''ImagePos Offset Size Name
2125 00000000 00000000 00000038 main-section
2126 00000004 00000004 00000010 section@0
2127 00000004 00000000 00000004 u-boot
2128 00000018 00000018 00000010 section@1
2129 00000018 00000000 00000004 u-boot
2130 0000002c 0000002c 00000004 section@2
2131 0000002c 00000000 00000004 u-boot
2133 self.assertEqual(data,
2134 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2135 tools.GetBytes(0x21, 12) +
2136 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2137 tools.GetBytes(0x61, 12) +
2138 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2139 tools.GetBytes(0x26, 8))
2141 def testCbfsRaw(self):
2142 """Test base handling of a Coreboot Filesystem (CBFS)
2144 The exact contents of the CBFS is verified by similar tests in
2145 cbfs_util_test.py. The tests here merely check that the files added to
2146 the CBFS can be found in the final image.
2148 data = self._DoReadFile('102_cbfs_raw.dts')
2151 cbfs = cbfs_util.CbfsReader(data)
2152 self.assertEqual(size, cbfs.rom_size)
2154 self.assertIn('u-boot-dtb', cbfs.files)
2155 cfile = cbfs.files['u-boot-dtb']
2156 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2158 def testCbfsArch(self):
2159 """Test on non-x86 architecture"""
2160 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2163 cbfs = cbfs_util.CbfsReader(data)
2164 self.assertEqual(size, cbfs.rom_size)
2166 self.assertIn('u-boot-dtb', cbfs.files)
2167 cfile = cbfs.files['u-boot-dtb']
2168 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2170 def testCbfsStage(self):
2171 """Tests handling of a Coreboot Filesystem (CBFS)"""
2172 if not elf.ELF_TOOLS:
2173 self.skipTest('Python elftools not available')
2174 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2175 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2178 data = self._DoReadFile('104_cbfs_stage.dts')
2179 cbfs = cbfs_util.CbfsReader(data)
2180 self.assertEqual(size, cbfs.rom_size)
2182 self.assertIn('u-boot', cbfs.files)
2183 cfile = cbfs.files['u-boot']
2184 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2186 def testCbfsRawCompress(self):
2187 """Test handling of compressing raw files"""
2189 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2192 cbfs = cbfs_util.CbfsReader(data)
2193 self.assertIn('u-boot', cbfs.files)
2194 cfile = cbfs.files['u-boot']
2195 self.assertEqual(COMPRESS_DATA, cfile.data)
2197 def testCbfsBadArch(self):
2198 """Test handling of a bad architecture"""
2199 with self.assertRaises(ValueError) as e:
2200 self._DoReadFile('106_cbfs_bad_arch.dts')
2201 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2203 def testCbfsNoSize(self):
2204 """Test handling of a missing size property"""
2205 with self.assertRaises(ValueError) as e:
2206 self._DoReadFile('107_cbfs_no_size.dts')
2207 self.assertIn('entry must have a size property', str(e.exception))
2209 def testCbfsNoCOntents(self):
2210 """Test handling of a CBFS entry which does not provide contentsy"""
2211 with self.assertRaises(ValueError) as e:
2212 self._DoReadFile('108_cbfs_no_contents.dts')
2213 self.assertIn('Could not complete processing of contents',
2216 def testCbfsBadCompress(self):
2217 """Test handling of a bad architecture"""
2218 with self.assertRaises(ValueError) as e:
2219 self._DoReadFile('109_cbfs_bad_compress.dts')
2220 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2223 def testCbfsNamedEntries(self):
2224 """Test handling of named entries"""
2225 data = self._DoReadFile('110_cbfs_name.dts')
2227 cbfs = cbfs_util.CbfsReader(data)
2228 self.assertIn('FRED', cbfs.files)
2229 cfile1 = cbfs.files['FRED']
2230 self.assertEqual(U_BOOT_DATA, cfile1.data)
2232 self.assertIn('hello', cbfs.files)
2233 cfile2 = cbfs.files['hello']
2234 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2236 def _SetupIfwi(self, fname):
2237 """Set up to run an IFWI test
2240 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2245 # Intel Integrated Firmware Image (IFWI) file
2246 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2248 TestFunctional._MakeInputFile(fname,data)
2250 def _CheckIfwi(self, data):
2251 """Check that an image with an IFWI contains the correct output
2254 data: Conents of output file
2256 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2257 if data[:0x1000] != expected_desc:
2258 self.fail('Expected descriptor binary at start of image')
2260 # We expect to find the TPL wil in subpart IBBP entry IBBL
2261 image_fname = tools.GetOutputFilename('image.bin')
2262 tpl_fname = tools.GetOutputFilename('tpl.out')
2263 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2264 subpart='IBBP', entry_name='IBBL')
2266 tpl_data = tools.ReadFile(tpl_fname)
2267 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2269 def testPackX86RomIfwi(self):
2270 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2271 self._SetupIfwi('fitimage.bin')
2272 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2273 self._CheckIfwi(data)
2275 def testPackX86RomIfwiNoDesc(self):
2276 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2277 self._SetupIfwi('ifwi.bin')
2278 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2279 self._CheckIfwi(data)
2281 def testPackX86RomIfwiNoData(self):
2282 """Test that an x86 ROM with IFWI handles missing data"""
2283 self._SetupIfwi('ifwi.bin')
2284 with self.assertRaises(ValueError) as e:
2285 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2286 self.assertIn('Could not complete processing of contents',
2289 def testCbfsOffset(self):
2290 """Test a CBFS with files at particular offsets
2292 Like all CFBS tests, this is just checking the logic that calls
2293 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2295 data = self._DoReadFile('114_cbfs_offset.dts')
2298 cbfs = cbfs_util.CbfsReader(data)
2299 self.assertEqual(size, cbfs.rom_size)
2301 self.assertIn('u-boot', cbfs.files)
2302 cfile = cbfs.files['u-boot']
2303 self.assertEqual(U_BOOT_DATA, cfile.data)
2304 self.assertEqual(0x40, cfile.cbfs_offset)
2306 self.assertIn('u-boot-dtb', cbfs.files)
2307 cfile2 = cbfs.files['u-boot-dtb']
2308 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2309 self.assertEqual(0x140, cfile2.cbfs_offset)
2311 def testFdtmap(self):
2312 """Test an FDT map can be inserted in the image"""
2313 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2314 fdtmap_data = data[len(U_BOOT_DATA):]
2315 magic = fdtmap_data[:8]
2316 self.assertEqual(b'_FDTMAP_', magic)
2317 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2319 fdt_data = fdtmap_data[16:]
2320 dtb = fdt.Fdt.FromData(fdt_data)
2322 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2327 'u-boot:size': len(U_BOOT_DATA),
2328 'u-boot:image-pos': 0,
2329 'fdtmap:image-pos': 4,
2331 'fdtmap:size': len(fdtmap_data),
2335 def testFdtmapNoMatch(self):
2336 """Check handling of an FDT map when the section cannot be found"""
2337 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2339 # Mangle the section name, which should cause a mismatch between the
2340 # correct FDT path and the one expected by the section
2341 image = control.images['image']
2342 image._node.path += '-suffix'
2343 entries = image.GetEntries()
2344 fdtmap = entries['fdtmap']
2345 with self.assertRaises(ValueError) as e:
2347 self.assertIn("Cannot locate node for path '/binman-suffix'",
2350 def testFdtmapHeader(self):
2351 """Test an FDT map and image header can be inserted in the image"""
2352 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2353 fdtmap_pos = len(U_BOOT_DATA)
2354 fdtmap_data = data[fdtmap_pos:]
2355 fdt_data = fdtmap_data[16:]
2356 dtb = fdt.Fdt.FromData(fdt_data)
2357 fdt_size = dtb.GetFdtObj().totalsize()
2358 hdr_data = data[-8:]
2359 self.assertEqual(b'BinM', hdr_data[:4])
2360 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2361 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2363 def testFdtmapHeaderStart(self):
2364 """Test an image header can be inserted at the image start"""
2365 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2366 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2368 self.assertEqual(b'BinM', hdr_data[:4])
2369 offset = struct.unpack('<I', hdr_data[4:])[0]
2370 self.assertEqual(fdtmap_pos, offset)
2372 def testFdtmapHeaderPos(self):
2373 """Test an image header can be inserted at a chosen position"""
2374 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2375 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2376 hdr_data = data[0x80:0x88]
2377 self.assertEqual(b'BinM', hdr_data[:4])
2378 offset = struct.unpack('<I', hdr_data[4:])[0]
2379 self.assertEqual(fdtmap_pos, offset)
2381 def testHeaderMissingFdtmap(self):
2382 """Test an image header requires an fdtmap"""
2383 with self.assertRaises(ValueError) as e:
2384 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2385 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2388 def testHeaderNoLocation(self):
2389 """Test an image header with a no specified location is detected"""
2390 with self.assertRaises(ValueError) as e:
2391 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2392 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2395 def testEntryExpand(self):
2396 """Test expanding an entry after it is packed"""
2397 data = self._DoReadFile('121_entry_expand.dts')
2398 self.assertEqual(b'aaa', data[:3])
2399 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2400 self.assertEqual(b'aaa', data[-3:])
2402 def testEntryExpandBad(self):
2403 """Test expanding an entry after it is packed, twice"""
2404 with self.assertRaises(ValueError) as e:
2405 self._DoReadFile('122_entry_expand_twice.dts')
2406 self.assertIn("Image '/binman': Entries changed size after packing",
2409 def testEntryExpandSection(self):
2410 """Test expanding an entry within a section after it is packed"""
2411 data = self._DoReadFile('123_entry_expand_section.dts')
2412 self.assertEqual(b'aaa', data[:3])
2413 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2414 self.assertEqual(b'aaa', data[-3:])
2416 def testCompressDtb(self):
2417 """Test that compress of device-tree files is supported"""
2419 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2420 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2421 comp_data = data[len(U_BOOT_DATA):]
2422 orig = self._decompress(comp_data)
2423 dtb = fdt.Fdt.FromData(orig)
2425 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2427 'u-boot:size': len(U_BOOT_DATA),
2428 'u-boot-dtb:uncomp-size': len(orig),
2429 'u-boot-dtb:size': len(comp_data),
2432 self.assertEqual(expected, props)
2434 def testCbfsUpdateFdt(self):
2435 """Test that we can update the device tree with CBFS offset/size info"""
2437 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2439 dtb = fdt.Fdt(out_dtb_fname)
2441 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2442 del props['cbfs/u-boot:size']
2448 'cbfs:size': len(data),
2449 'cbfs:image-pos': 0,
2450 'cbfs/u-boot:offset': 0x38,
2451 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2452 'cbfs/u-boot:image-pos': 0x38,
2453 'cbfs/u-boot-dtb:offset': 0xb8,
2454 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2455 'cbfs/u-boot-dtb:image-pos': 0xb8,
2458 def testCbfsBadType(self):
2459 """Test an image header with a no specified location is detected"""
2460 with self.assertRaises(ValueError) as e:
2461 self._DoReadFile('126_cbfs_bad_type.dts')
2462 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2465 """Test listing the files in an image"""
2467 data = self._DoReadFile('127_list.dts')
2468 image = control.images['image']
2469 entries = image.BuildEntryList()
2470 self.assertEqual(7, len(entries))
2473 self.assertEqual(0, ent.indent)
2474 self.assertEqual('main-section', ent.name)
2475 self.assertEqual('section', ent.etype)
2476 self.assertEqual(len(data), ent.size)
2477 self.assertEqual(0, ent.image_pos)
2478 self.assertEqual(None, ent.uncomp_size)
2479 self.assertEqual(0, ent.offset)
2482 self.assertEqual(1, ent.indent)
2483 self.assertEqual('u-boot', ent.name)
2484 self.assertEqual('u-boot', ent.etype)
2485 self.assertEqual(len(U_BOOT_DATA), ent.size)
2486 self.assertEqual(0, ent.image_pos)
2487 self.assertEqual(None, ent.uncomp_size)
2488 self.assertEqual(0, ent.offset)
2491 self.assertEqual(1, ent.indent)
2492 self.assertEqual('section', ent.name)
2493 self.assertEqual('section', ent.etype)
2494 section_size = ent.size
2495 self.assertEqual(0x100, ent.image_pos)
2496 self.assertEqual(None, ent.uncomp_size)
2497 self.assertEqual(0x100, ent.offset)
2500 self.assertEqual(2, ent.indent)
2501 self.assertEqual('cbfs', ent.name)
2502 self.assertEqual('cbfs', ent.etype)
2503 self.assertEqual(0x400, ent.size)
2504 self.assertEqual(0x100, ent.image_pos)
2505 self.assertEqual(None, ent.uncomp_size)
2506 self.assertEqual(0, ent.offset)
2509 self.assertEqual(3, ent.indent)
2510 self.assertEqual('u-boot', ent.name)
2511 self.assertEqual('u-boot', ent.etype)
2512 self.assertEqual(len(U_BOOT_DATA), ent.size)
2513 self.assertEqual(0x138, ent.image_pos)
2514 self.assertEqual(None, ent.uncomp_size)
2515 self.assertEqual(0x38, ent.offset)
2518 self.assertEqual(3, ent.indent)
2519 self.assertEqual('u-boot-dtb', ent.name)
2520 self.assertEqual('text', ent.etype)
2521 self.assertGreater(len(COMPRESS_DATA), ent.size)
2522 self.assertEqual(0x178, ent.image_pos)
2523 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2524 self.assertEqual(0x78, ent.offset)
2527 self.assertEqual(2, ent.indent)
2528 self.assertEqual('u-boot-dtb', ent.name)
2529 self.assertEqual('u-boot-dtb', ent.etype)
2530 self.assertEqual(0x500, ent.image_pos)
2531 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2533 # Compressing this data expands it since headers are added
2534 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2535 self.assertEqual(0x400, ent.offset)
2537 self.assertEqual(len(data), 0x100 + section_size)
2538 self.assertEqual(section_size, 0x400 + dtb_size)
2540 def testFindFdtmap(self):
2541 """Test locating an FDT map in an image"""
2543 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2544 image = control.images['image']
2545 entries = image.GetEntries()
2546 entry = entries['fdtmap']
2547 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2549 def testFindFdtmapMissing(self):
2550 """Test failing to locate an FDP map"""
2551 data = self._DoReadFile('005_simple.dts')
2552 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2554 def testFindImageHeader(self):
2555 """Test locating a image header"""
2557 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2558 image = control.images['image']
2559 entries = image.GetEntries()
2560 entry = entries['fdtmap']
2561 # The header should point to the FDT map
2562 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2564 def testFindImageHeaderStart(self):
2565 """Test locating a image header located at the start of an image"""
2566 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2567 image = control.images['image']
2568 entries = image.GetEntries()
2569 entry = entries['fdtmap']
2570 # The header should point to the FDT map
2571 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2573 def testFindImageHeaderMissing(self):
2574 """Test failing to locate an image header"""
2575 data = self._DoReadFile('005_simple.dts')
2576 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2578 def testReadImage(self):
2579 """Test reading an image and accessing its FDT map"""
2581 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2582 image_fname = tools.GetOutputFilename('image.bin')
2583 orig_image = control.images['image']
2584 image = Image.FromFile(image_fname)
2585 self.assertEqual(orig_image.GetEntries().keys(),
2586 image.GetEntries().keys())
2588 orig_entry = orig_image.GetEntries()['fdtmap']
2589 entry = image.GetEntries()['fdtmap']
2590 self.assertEquals(orig_entry.offset, entry.offset)
2591 self.assertEquals(orig_entry.size, entry.size)
2592 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2594 def testReadImageNoHeader(self):
2595 """Test accessing an image's FDT map without an image header"""
2597 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2598 image_fname = tools.GetOutputFilename('image.bin')
2599 image = Image.FromFile(image_fname)
2600 self.assertTrue(isinstance(image, Image))
2601 self.assertEqual('image', image.image_name[-5:])
2603 def testReadImageFail(self):
2604 """Test failing to read an image image's FDT map"""
2605 self._DoReadFile('005_simple.dts')
2606 image_fname = tools.GetOutputFilename('image.bin')
2607 with self.assertRaises(ValueError) as e:
2608 image = Image.FromFile(image_fname)
2609 self.assertIn("Cannot find FDT map in image", str(e.exception))
2611 def testListCmd(self):
2612 """Test listing the files in an image using an Fdtmap"""
2614 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2616 # lz4 compression size differs depending on the version
2617 image = control.images['image']
2618 entries = image.GetEntries()
2619 section_size = entries['section'].size
2620 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2621 fdtmap_offset = entries['fdtmap'].offset
2624 tmpdir, updated_fname = self._SetupImageInTmpdir()
2625 with test_util.capture_sys_output() as (stdout, stderr):
2626 self._DoBinman('ls', '-i', updated_fname)
2628 shutil.rmtree(tmpdir)
2629 lines = stdout.getvalue().splitlines()
2631 'Name Image-pos Size Entry-type Offset Uncomp-size',
2632 '----------------------------------------------------------------------',
2633 'main-section 0 c00 section 0',
2634 ' u-boot 0 4 u-boot 0',
2635 ' section 100 %x section 100' % section_size,
2636 ' cbfs 100 400 cbfs 0',
2637 ' u-boot 138 4 u-boot 38',
2638 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2639 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2640 ' fdtmap %x 3bd fdtmap %x' %
2641 (fdtmap_offset, fdtmap_offset),
2642 ' image-header bf8 8 image-header bf8',
2644 self.assertEqual(expected, lines)
2646 def testListCmdFail(self):
2647 """Test failing to list an image"""
2648 self._DoReadFile('005_simple.dts')
2650 tmpdir, updated_fname = self._SetupImageInTmpdir()
2651 with self.assertRaises(ValueError) as e:
2652 self._DoBinman('ls', '-i', updated_fname)
2654 shutil.rmtree(tmpdir)
2655 self.assertIn("Cannot find FDT map in image", str(e.exception))
2657 def _RunListCmd(self, paths, expected):
2658 """List out entries and check the result
2661 paths: List of paths to pass to the list command
2662 expected: Expected list of filenames to be returned, in order
2665 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2666 image_fname = tools.GetOutputFilename('image.bin')
2667 image = Image.FromFile(image_fname)
2668 lines = image.GetListEntries(paths)[1]
2669 files = [line[0].strip() for line in lines[1:]]
2670 self.assertEqual(expected, files)
2672 def testListCmdSection(self):
2673 """Test listing the files in a section"""
2674 self._RunListCmd(['section'],
2675 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2677 def testListCmdFile(self):
2678 """Test listing a particular file"""
2679 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2681 def testListCmdWildcard(self):
2682 """Test listing a wildcarded file"""
2683 self._RunListCmd(['*boot*'],
2684 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2686 def testListCmdWildcardMulti(self):
2687 """Test listing a wildcarded file"""
2688 self._RunListCmd(['*cb*', '*head*'],
2689 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2691 def testListCmdEmpty(self):
2692 """Test listing a wildcarded file"""
2693 self._RunListCmd(['nothing'], [])
2695 def testListCmdPath(self):
2696 """Test listing the files in a sub-entry of a section"""
2697 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2699 def _RunExtractCmd(self, entry_name, decomp=True):
2700 """Extract an entry from an image
2703 entry_name: Entry name to extract
2704 decomp: True to decompress the data if compressed, False to leave
2705 it in its raw uncompressed format
2711 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2712 image_fname = tools.GetOutputFilename('image.bin')
2713 return control.ReadEntry(image_fname, entry_name, decomp)
2715 def testExtractSimple(self):
2716 """Test extracting a single file"""
2717 data = self._RunExtractCmd('u-boot')
2718 self.assertEqual(U_BOOT_DATA, data)
2720 def testExtractSection(self):
2721 """Test extracting the files in a section"""
2722 data = self._RunExtractCmd('section')
2723 cbfs_data = data[:0x400]
2724 cbfs = cbfs_util.CbfsReader(cbfs_data)
2725 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2726 dtb_data = data[0x400:]
2727 dtb = self._decompress(dtb_data)
2728 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2730 def testExtractCompressed(self):
2731 """Test extracting compressed data"""
2732 data = self._RunExtractCmd('section/u-boot-dtb')
2733 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2735 def testExtractRaw(self):
2736 """Test extracting compressed data without decompressing it"""
2737 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2738 dtb = self._decompress(data)
2739 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2741 def testExtractCbfs(self):
2742 """Test extracting CBFS data"""
2743 data = self._RunExtractCmd('section/cbfs/u-boot')
2744 self.assertEqual(U_BOOT_DATA, data)
2746 def testExtractCbfsCompressed(self):
2747 """Test extracting CBFS compressed data"""
2748 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2749 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2751 def testExtractCbfsRaw(self):
2752 """Test extracting CBFS compressed data without decompressing it"""
2753 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2754 dtb = tools.Decompress(data, 'lzma', with_header=False)
2755 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2757 def testExtractBadEntry(self):
2758 """Test extracting a bad section path"""
2759 with self.assertRaises(ValueError) as e:
2760 self._RunExtractCmd('section/does-not-exist')
2761 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2764 def testExtractMissingFile(self):
2765 """Test extracting file that does not exist"""
2766 with self.assertRaises(IOError) as e:
2767 control.ReadEntry('missing-file', 'name')
2769 def testExtractBadFile(self):
2770 """Test extracting an invalid file"""
2771 fname = os.path.join(self._indir, 'badfile')
2772 tools.WriteFile(fname, b'')
2773 with self.assertRaises(ValueError) as e:
2774 control.ReadEntry(fname, 'name')
2776 def testExtractCmd(self):
2777 """Test extracting a file fron an image on the command line"""
2779 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2780 fname = os.path.join(self._indir, 'output.extact')
2782 tmpdir, updated_fname = self._SetupImageInTmpdir()
2783 with test_util.capture_sys_output() as (stdout, stderr):
2784 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2787 shutil.rmtree(tmpdir)
2788 data = tools.ReadFile(fname)
2789 self.assertEqual(U_BOOT_DATA, data)
2791 def testExtractOneEntry(self):
2792 """Test extracting a single entry fron an image """
2794 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2795 image_fname = tools.GetOutputFilename('image.bin')
2796 fname = os.path.join(self._indir, 'output.extact')
2797 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2798 data = tools.ReadFile(fname)
2799 self.assertEqual(U_BOOT_DATA, data)
2801 def _CheckExtractOutput(self, decomp):
2802 """Helper to test file output with and without decompression
2805 decomp: True to decompress entry data, False to output it raw
2807 def _CheckPresent(entry_path, expect_data, expect_size=None):
2808 """Check and remove expected file
2810 This checks the data/size of a file and removes the file both from
2811 the outfiles set and from the output directory. Once all files are
2812 processed, both the set and directory should be empty.
2815 entry_path: Entry path
2816 expect_data: Data to expect in file, or None to skip check
2817 expect_size: Size of data to expect in file, or None to skip
2819 path = os.path.join(outdir, entry_path)
2820 data = tools.ReadFile(path)
2823 self.assertEqual(expect_data, data)
2825 self.assertEqual(expect_size, len(data))
2826 outfiles.remove(path)
2828 def _CheckDirPresent(name):
2829 """Remove expected directory
2831 This gives an error if the directory does not exist as expected
2834 name: Name of directory to remove
2836 path = os.path.join(outdir, name)
2839 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2840 image_fname = tools.GetOutputFilename('image.bin')
2841 outdir = os.path.join(self._indir, 'extract')
2842 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2844 # Create a set of all file that were output (should be 9)
2846 for root, dirs, files in os.walk(outdir):
2847 outfiles |= set([os.path.join(root, fname) for fname in files])
2848 self.assertEqual(9, len(outfiles))
2849 self.assertEqual(9, len(einfos))
2851 image = control.images['image']
2852 entries = image.GetEntries()
2854 # Check the 9 files in various ways
2855 section = entries['section']
2856 section_entries = section.GetEntries()
2857 cbfs_entries = section_entries['cbfs'].GetEntries()
2858 _CheckPresent('u-boot', U_BOOT_DATA)
2859 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2860 dtb_len = EXTRACT_DTB_SIZE
2862 dtb_len = cbfs_entries['u-boot-dtb'].size
2863 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2865 dtb_len = section_entries['u-boot-dtb'].size
2866 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2868 fdtmap = entries['fdtmap']
2869 _CheckPresent('fdtmap', fdtmap.data)
2870 hdr = entries['image-header']
2871 _CheckPresent('image-header', hdr.data)
2873 _CheckPresent('section/root', section.data)
2874 cbfs = section_entries['cbfs']
2875 _CheckPresent('section/cbfs/root', cbfs.data)
2876 data = tools.ReadFile(image_fname)
2877 _CheckPresent('root', data)
2879 # There should be no files left. Remove all the directories to check.
2880 # If there are any files/dirs remaining, one of these checks will fail.
2881 self.assertEqual(0, len(outfiles))
2882 _CheckDirPresent('section/cbfs')
2883 _CheckDirPresent('section')
2884 _CheckDirPresent('')
2885 self.assertFalse(os.path.exists(outdir))
2887 def testExtractAllEntries(self):
2888 """Test extracting all entries"""
2890 self._CheckExtractOutput(decomp=True)
2892 def testExtractAllEntriesRaw(self):
2893 """Test extracting all entries without decompressing them"""
2895 self._CheckExtractOutput(decomp=False)
2897 def testExtractSelectedEntries(self):
2898 """Test extracting some entries"""
2900 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2901 image_fname = tools.GetOutputFilename('image.bin')
2902 outdir = os.path.join(self._indir, 'extract')
2903 einfos = control.ExtractEntries(image_fname, None, outdir,
2906 # File output is tested by testExtractAllEntries(), so just check that
2907 # the expected entries are selected
2908 names = [einfo.name for einfo in einfos]
2909 self.assertEqual(names,
2910 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2912 def testExtractNoEntryPaths(self):
2913 """Test extracting some entries"""
2915 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2916 image_fname = tools.GetOutputFilename('image.bin')
2917 with self.assertRaises(ValueError) as e:
2918 control.ExtractEntries(image_fname, 'fname', None, [])
2919 self.assertIn('Must specify an entry path to write with -f',
2922 def testExtractTooManyEntryPaths(self):
2923 """Test extracting some entries"""
2925 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2926 image_fname = tools.GetOutputFilename('image.bin')
2927 with self.assertRaises(ValueError) as e:
2928 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2929 self.assertIn('Must specify exactly one entry path to write with -f',
2932 def testPackAlignSection(self):
2933 """Test that sections can have alignment"""
2934 self._DoReadFile('131_pack_align_section.dts')
2936 self.assertIn('image', control.images)
2937 image = control.images['image']
2938 entries = image.GetEntries()
2939 self.assertEqual(3, len(entries))
2942 self.assertIn('u-boot', entries)
2943 entry = entries['u-boot']
2944 self.assertEqual(0, entry.offset)
2945 self.assertEqual(0, entry.image_pos)
2946 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2947 self.assertEqual(len(U_BOOT_DATA), entry.size)
2950 self.assertIn('section0', entries)
2951 section0 = entries['section0']
2952 self.assertEqual(0x10, section0.offset)
2953 self.assertEqual(0x10, section0.image_pos)
2954 self.assertEqual(len(U_BOOT_DATA), section0.size)
2957 section_entries = section0.GetEntries()
2958 self.assertIn('u-boot', section_entries)
2959 entry = section_entries['u-boot']
2960 self.assertEqual(0, entry.offset)
2961 self.assertEqual(0x10, entry.image_pos)
2962 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2963 self.assertEqual(len(U_BOOT_DATA), entry.size)
2966 self.assertIn('section1', entries)
2967 section1 = entries['section1']
2968 self.assertEqual(0x14, section1.offset)
2969 self.assertEqual(0x14, section1.image_pos)
2970 self.assertEqual(0x20, section1.size)
2973 section_entries = section1.GetEntries()
2974 self.assertIn('u-boot', section_entries)
2975 entry = section_entries['u-boot']
2976 self.assertEqual(0, entry.offset)
2977 self.assertEqual(0x14, entry.image_pos)
2978 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2979 self.assertEqual(len(U_BOOT_DATA), entry.size)
2982 self.assertIn('section2', section_entries)
2983 section2 = section_entries['section2']
2984 self.assertEqual(0x4, section2.offset)
2985 self.assertEqual(0x18, section2.image_pos)
2986 self.assertEqual(4, section2.size)
2989 section_entries = section2.GetEntries()
2990 self.assertIn('u-boot', section_entries)
2991 entry = section_entries['u-boot']
2992 self.assertEqual(0, entry.offset)
2993 self.assertEqual(0x18, entry.image_pos)
2994 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2995 self.assertEqual(len(U_BOOT_DATA), entry.size)
2997 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2998 dts='132_replace.dts'):
2999 """Replace an entry in an image
3001 This writes the entry data to update it, then opens the updated file and
3002 returns the value that it now finds there.
3005 entry_name: Entry name to replace
3006 data: Data to replace it with
3007 decomp: True to compress the data if needed, False if data is
3008 already compressed so should be used as is
3009 allow_resize: True to allow entries to change size, False to raise
3015 data from fdtmap (excluding header)
3016 Image object that was modified
3018 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
3021 self.assertIn('image', control.images)
3022 image = control.images['image']
3023 entries = image.GetEntries()
3024 orig_dtb_data = entries['u-boot-dtb'].data
3025 orig_fdtmap_data = entries['fdtmap'].data
3027 image_fname = tools.GetOutputFilename('image.bin')
3028 updated_fname = tools.GetOutputFilename('image-updated.bin')
3029 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3030 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3032 data = control.ReadEntry(updated_fname, entry_name, decomp)
3034 # The DT data should not change unless resized:
3035 if not allow_resize:
3036 new_dtb_data = entries['u-boot-dtb'].data
3037 self.assertEqual(new_dtb_data, orig_dtb_data)
3038 new_fdtmap_data = entries['fdtmap'].data
3039 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
3041 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
3043 def testReplaceSimple(self):
3044 """Test replacing a single file"""
3045 expected = b'x' * len(U_BOOT_DATA)
3046 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3048 self.assertEqual(expected, data)
3050 # Test that the state looks right. There should be an FDT for the fdtmap
3051 # that we jsut read back in, and it should match what we find in the
3052 # 'control' tables. Checking for an FDT that does not exist should
3054 path, fdtmap = state.GetFdtContents('fdtmap')
3055 self.assertIsNotNone(path)
3056 self.assertEqual(expected_fdtmap, fdtmap)
3058 dtb = state.GetFdtForEtype('fdtmap')
3059 self.assertEqual(dtb.GetContents(), fdtmap)
3061 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3062 self.assertIsNone(missing_path)
3063 self.assertIsNone(missing_fdtmap)
3065 missing_dtb = state.GetFdtForEtype('missing')
3066 self.assertIsNone(missing_dtb)
3068 self.assertEqual('/binman', state.fdt_path_prefix)
3070 def testReplaceResizeFail(self):
3071 """Test replacing a file by something larger"""
3072 expected = U_BOOT_DATA + b'x'
3073 with self.assertRaises(ValueError) as e:
3074 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3075 dts='139_replace_repack.dts')
3076 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3079 def testReplaceMulti(self):
3080 """Test replacing entry data where multiple images are generated"""
3081 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3083 expected = b'x' * len(U_BOOT_DATA)
3084 updated_fname = tools.GetOutputFilename('image-updated.bin')
3085 tools.WriteFile(updated_fname, data)
3086 entry_name = 'u-boot'
3087 control.WriteEntry(updated_fname, entry_name, expected,
3089 data = control.ReadEntry(updated_fname, entry_name)
3090 self.assertEqual(expected, data)
3092 # Check the state looks right.
3093 self.assertEqual('/binman/image', state.fdt_path_prefix)
3095 # Now check we can write the first image
3096 image_fname = tools.GetOutputFilename('first-image.bin')
3097 updated_fname = tools.GetOutputFilename('first-updated.bin')
3098 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3099 entry_name = 'u-boot'
3100 control.WriteEntry(updated_fname, entry_name, expected,
3102 data = control.ReadEntry(updated_fname, entry_name)
3103 self.assertEqual(expected, data)
3105 # Check the state looks right.
3106 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
3108 def testUpdateFdtAllRepack(self):
3109 """Test that all device trees are updated with offset/size info"""
3110 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3111 SECTION_SIZE = 0x300
3116 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3118 'section:offset': 0,
3119 'section:size': SECTION_SIZE,
3120 'section:image-pos': 0,
3121 'section/u-boot-dtb:offset': 4,
3122 'section/u-boot-dtb:size': 636,
3123 'section/u-boot-dtb:image-pos': 4,
3124 'u-boot-spl-dtb:offset': SECTION_SIZE,
3125 'u-boot-spl-dtb:size': DTB_SIZE,
3126 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3127 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3128 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3129 'u-boot-tpl-dtb:size': DTB_SIZE,
3130 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3131 'fdtmap:size': FDTMAP_SIZE,
3132 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3135 'section:orig-size': SECTION_SIZE,
3136 'section/u-boot-dtb:orig-offset': 4,
3139 # We expect three device-tree files in the output, with the first one
3140 # within a fixed-size section.
3141 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3142 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3143 # main U-Boot tree. All three should have the same positions and offset
3144 # except that the main tree should include the main_expected properties
3146 for item in ['', 'spl', 'tpl', None]:
3148 start += 16 # Move past fdtmap header
3149 dtb = fdt.Fdt.FromData(data[start:])
3151 props = self._GetPropTree(dtb,
3152 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3153 prefix='/' if item is None else '/binman/')
3154 expected = dict(base_expected)
3158 # Main DTB and fdtdec should include the 'orig-' properties
3159 expected.update(main_expected)
3160 # Helpful for debugging:
3161 #for prop in sorted(props):
3162 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3163 self.assertEqual(expected, props)
3165 start = SECTION_SIZE
3167 start += dtb._fdt_obj.totalsize()
3169 def testFdtmapHeaderMiddle(self):
3170 """Test an FDT map in the middle of an image when it should be at end"""
3171 with self.assertRaises(ValueError) as e:
3172 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3173 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3176 def testFdtmapHeaderStartBad(self):
3177 """Test an FDT map in middle of an image when it should be at start"""
3178 with self.assertRaises(ValueError) as e:
3179 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3180 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3183 def testFdtmapHeaderEndBad(self):
3184 """Test an FDT map at the start of an image when it should be at end"""
3185 with self.assertRaises(ValueError) as e:
3186 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3187 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3190 def testFdtmapHeaderNoSize(self):
3191 """Test an image header at the end of an image with undefined size"""
3192 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3194 def testReplaceResize(self):
3195 """Test replacing a single file in an entry with a larger file"""
3196 expected = U_BOOT_DATA + b'x'
3197 data, _, image = self._RunReplaceCmd('u-boot', expected,
3198 dts='139_replace_repack.dts')
3199 self.assertEqual(expected, data)
3201 entries = image.GetEntries()
3202 dtb_data = entries['u-boot-dtb'].data
3203 dtb = fdt.Fdt.FromData(dtb_data)
3206 # The u-boot section should now be larger in the dtb
3207 node = dtb.GetNode('/binman/u-boot')
3208 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3210 # Same for the fdtmap
3211 fdata = entries['fdtmap'].data
3212 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3214 fnode = fdtb.GetNode('/u-boot')
3215 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3217 def testReplaceResizeNoRepack(self):
3218 """Test replacing an entry with a larger file when not allowed"""
3219 expected = U_BOOT_DATA + b'x'
3220 with self.assertRaises(ValueError) as e:
3221 self._RunReplaceCmd('u-boot', expected)
3222 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3225 def testEntryShrink(self):
3226 """Test contracting an entry after it is packed"""
3228 state.SetAllowEntryContraction(True)
3229 data = self._DoReadFileDtb('140_entry_shrink.dts',
3232 state.SetAllowEntryContraction(False)
3233 self.assertEqual(b'a', data[:1])
3234 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3235 self.assertEqual(b'a', data[-1:])
3237 def testEntryShrinkFail(self):
3238 """Test not being allowed to contract an entry after it is packed"""
3239 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3241 # In this case there is a spare byte at the end of the data. The size of
3242 # the contents is only 1 byte but we still have the size before it
3244 self.assertEqual(b'a\0', data[:2])
3245 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3246 self.assertEqual(b'a\0', data[-2:])
3248 def testDescriptorOffset(self):
3249 """Test that the Intel descriptor is always placed at at the start"""
3250 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3251 image = control.images['image']
3252 entries = image.GetEntries()
3253 desc = entries['intel-descriptor']
3254 self.assertEqual(0xff800000, desc.offset);
3255 self.assertEqual(0xff800000, desc.image_pos);
3257 def testReplaceCbfs(self):
3258 """Test replacing a single file in CBFS without changing the size"""
3260 expected = b'x' * len(U_BOOT_DATA)
3261 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3262 updated_fname = tools.GetOutputFilename('image-updated.bin')
3263 tools.WriteFile(updated_fname, data)
3264 entry_name = 'section/cbfs/u-boot'
3265 control.WriteEntry(updated_fname, entry_name, expected,
3267 data = control.ReadEntry(updated_fname, entry_name)
3268 self.assertEqual(expected, data)
3270 def testReplaceResizeCbfs(self):
3271 """Test replacing a single file in CBFS with one of a different size"""
3273 expected = U_BOOT_DATA + b'x'
3274 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3275 updated_fname = tools.GetOutputFilename('image-updated.bin')
3276 tools.WriteFile(updated_fname, data)
3277 entry_name = 'section/cbfs/u-boot'
3278 control.WriteEntry(updated_fname, entry_name, expected,
3280 data = control.ReadEntry(updated_fname, entry_name)
3281 self.assertEqual(expected, data)
3283 def _SetupForReplace(self):
3284 """Set up some files to use to replace entries
3286 This generates an image, copies it to a new file, extracts all the files
3287 in it and updates some of them
3293 Expected values for updated entries, each a string
3295 data = self._DoReadFileRealDtb('143_replace_all.dts')
3297 updated_fname = tools.GetOutputFilename('image-updated.bin')
3298 tools.WriteFile(updated_fname, data)
3300 outdir = os.path.join(self._indir, 'extract')
3301 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3303 expected1 = b'x' + U_BOOT_DATA + b'y'
3304 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3305 tools.WriteFile(u_boot_fname1, expected1)
3307 expected2 = b'a' + U_BOOT_DATA + b'b'
3308 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3309 tools.WriteFile(u_boot_fname2, expected2)
3311 expected_text = b'not the same text'
3312 text_fname = os.path.join(outdir, 'text')
3313 tools.WriteFile(text_fname, expected_text)
3315 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3316 dtb = fdt.FdtScan(dtb_fname)
3317 node = dtb.GetNode('/binman/text')
3318 node.AddString('my-property', 'the value')
3319 dtb.Sync(auto_resize=True)
3322 return updated_fname, outdir, expected1, expected2, expected_text
3324 def _CheckReplaceMultiple(self, entry_paths):
3325 """Handle replacing the contents of multiple entries
3328 entry_paths: List of entry paths to replace
3332 Dict of entries in the image:
3335 Expected values for updated entries, each a string
3337 updated_fname, outdir, expected1, expected2, expected_text = (
3338 self._SetupForReplace())
3339 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3341 image = Image.FromFile(updated_fname)
3343 return image.GetEntries(), expected1, expected2, expected_text
3345 def testReplaceAll(self):
3346 """Test replacing the contents of all entries"""
3347 entries, expected1, expected2, expected_text = (
3348 self._CheckReplaceMultiple([]))
3349 data = entries['u-boot'].data
3350 self.assertEqual(expected1, data)
3352 data = entries['u-boot2'].data
3353 self.assertEqual(expected2, data)
3355 data = entries['text'].data
3356 self.assertEqual(expected_text, data)
3358 # Check that the device tree is updated
3359 data = entries['u-boot-dtb'].data
3360 dtb = fdt.Fdt.FromData(data)
3362 node = dtb.GetNode('/binman/text')
3363 self.assertEqual('the value', node.props['my-property'].value)
3365 def testReplaceSome(self):
3366 """Test replacing the contents of a few entries"""
3367 entries, expected1, expected2, expected_text = (
3368 self._CheckReplaceMultiple(['u-boot2', 'text']))
3370 # This one should not change
3371 data = entries['u-boot'].data
3372 self.assertEqual(U_BOOT_DATA, data)
3374 data = entries['u-boot2'].data
3375 self.assertEqual(expected2, data)
3377 data = entries['text'].data
3378 self.assertEqual(expected_text, data)
3380 def testReplaceCmd(self):
3381 """Test replacing a file fron an image on the command line"""
3382 self._DoReadFileRealDtb('143_replace_all.dts')
3385 tmpdir, updated_fname = self._SetupImageInTmpdir()
3387 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3388 expected = b'x' * len(U_BOOT_DATA)
3389 tools.WriteFile(fname, expected)
3391 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3392 data = tools.ReadFile(updated_fname)
3393 self.assertEqual(expected, data[:len(expected)])
3394 map_fname = os.path.join(tmpdir, 'image-updated.map')
3395 self.assertFalse(os.path.exists(map_fname))
3397 shutil.rmtree(tmpdir)
3399 def testReplaceCmdSome(self):
3400 """Test replacing some files fron an image on the command line"""
3401 updated_fname, outdir, expected1, expected2, expected_text = (
3402 self._SetupForReplace())
3404 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3407 tools.PrepareOutputDir(None)
3408 image = Image.FromFile(updated_fname)
3410 entries = image.GetEntries()
3412 # This one should not change
3413 data = entries['u-boot'].data
3414 self.assertEqual(U_BOOT_DATA, data)
3416 data = entries['u-boot2'].data
3417 self.assertEqual(expected2, data)
3419 data = entries['text'].data
3420 self.assertEqual(expected_text, data)
3422 def testReplaceMissing(self):
3423 """Test replacing entries where the file is missing"""
3424 updated_fname, outdir, expected1, expected2, expected_text = (
3425 self._SetupForReplace())
3427 # Remove one of the files, to generate a warning
3428 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3429 os.remove(u_boot_fname1)
3431 with test_util.capture_sys_output() as (stdout, stderr):
3432 control.ReplaceEntries(updated_fname, None, outdir, [])
3433 self.assertIn("Skipping entry '/u-boot' from missing file",
3436 def testReplaceCmdMap(self):
3437 """Test replacing a file fron an image on the command line"""
3438 self._DoReadFileRealDtb('143_replace_all.dts')
3441 tmpdir, updated_fname = self._SetupImageInTmpdir()
3443 fname = os.path.join(self._indir, 'update-u-boot.bin')
3444 expected = b'x' * len(U_BOOT_DATA)
3445 tools.WriteFile(fname, expected)
3447 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3449 map_fname = os.path.join(tmpdir, 'image-updated.map')
3450 self.assertTrue(os.path.exists(map_fname))
3452 shutil.rmtree(tmpdir)
3454 def testReplaceNoEntryPaths(self):
3455 """Test replacing an entry without an entry path"""
3456 self._DoReadFileRealDtb('143_replace_all.dts')
3457 image_fname = tools.GetOutputFilename('image.bin')
3458 with self.assertRaises(ValueError) as e:
3459 control.ReplaceEntries(image_fname, 'fname', None, [])
3460 self.assertIn('Must specify an entry path to read with -f',
3463 def testReplaceTooManyEntryPaths(self):
3464 """Test extracting some entries"""
3465 self._DoReadFileRealDtb('143_replace_all.dts')
3466 image_fname = tools.GetOutputFilename('image.bin')
3467 with self.assertRaises(ValueError) as e:
3468 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3469 self.assertIn('Must specify exactly one entry path to write with -f',
3472 def testPackReset16(self):
3473 """Test that an image with an x86 reset16 region can be created"""
3474 data = self._DoReadFile('144_x86_reset16.dts')
3475 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3477 def testPackReset16Spl(self):
3478 """Test that an image with an x86 reset16-spl region can be created"""
3479 data = self._DoReadFile('145_x86_reset16_spl.dts')
3480 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3482 def testPackReset16Tpl(self):
3483 """Test that an image with an x86 reset16-tpl region can be created"""
3484 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3485 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3487 def testPackIntelFit(self):
3488 """Test that an image with an Intel FIT and pointer can be created"""
3489 data = self._DoReadFile('147_intel_fit.dts')
3490 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3492 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3493 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3495 image = control.images['image']
3496 entries = image.GetEntries()
3497 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3498 self.assertEqual(expected_ptr, ptr)
3500 def testPackIntelFitMissing(self):
3501 """Test detection of a FIT pointer with not FIT region"""
3502 with self.assertRaises(ValueError) as e:
3503 self._DoReadFile('148_intel_fit_missing.dts')
3504 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3507 def _CheckSymbolsTplSection(self, dts, expected_vals):
3508 data = self._DoReadFile(dts)
3509 sym_values = struct.pack('<LQLL', *expected_vals)
3510 upto1 = 4 + len(U_BOOT_SPL_DATA)
3511 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3512 self.assertEqual(expected1, data[:upto1])
3514 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3515 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3516 self.assertEqual(expected2, data[upto1:upto2])
3518 upto3 = 0x34 + len(U_BOOT_DATA)
3519 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3520 self.assertEqual(expected3, data[upto2:upto3])
3522 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3523 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3525 def testSymbolsTplSection(self):
3526 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3527 self._SetupSplElf('u_boot_binman_syms')
3528 self._SetupTplElf('u_boot_binman_syms')
3529 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3530 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3532 def testSymbolsTplSectionX86(self):
3533 """Test binman can assign symbols in a section with end-at-4gb"""
3534 self._SetupSplElf('u_boot_binman_syms_x86')
3535 self._SetupTplElf('u_boot_binman_syms_x86')
3536 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3537 [0xffffff04, 0xffffff1c, 0xffffff34,
3540 def testPackX86RomIfwiSectiom(self):
3541 """Test that a section can be placed in an IFWI region"""
3542 self._SetupIfwi('fitimage.bin')
3543 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3544 self._CheckIfwi(data)
3546 def testPackFspM(self):
3547 """Test that an image with a FSP memory-init binary can be created"""
3548 data = self._DoReadFile('152_intel_fsp_m.dts')
3549 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3551 def testPackFspS(self):
3552 """Test that an image with a FSP silicon-init binary can be created"""
3553 data = self._DoReadFile('153_intel_fsp_s.dts')
3554 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3556 def testPackFspT(self):
3557 """Test that an image with a FSP temp-ram-init binary can be created"""
3558 data = self._DoReadFile('154_intel_fsp_t.dts')
3559 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3561 def testMkimage(self):
3562 """Test using mkimage to build an image"""
3563 data = self._DoReadFile('156_mkimage.dts')
3565 # Just check that the data appears in the file somewhere
3566 self.assertIn(U_BOOT_SPL_DATA, data)
3568 def testExtblob(self):
3569 """Test an image with an external blob"""
3570 data = self._DoReadFile('157_blob_ext.dts')
3571 self.assertEqual(REFCODE_DATA, data)
3573 def testExtblobMissing(self):
3574 """Test an image with a missing external blob"""
3575 with self.assertRaises(ValueError) as e:
3576 self._DoReadFile('158_blob_ext_missing.dts')
3577 self.assertIn("Filename 'missing-file' not found in input path",
3580 def testExtblobMissingOk(self):
3581 """Test an image with an missing external blob that is allowed"""
3582 with test_util.capture_sys_output() as (stdout, stderr):
3583 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3584 err = stderr.getvalue()
3585 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3587 def testExtblobMissingOkSect(self):
3588 """Test an image with an missing external blob that is allowed"""
3589 with test_util.capture_sys_output() as (stdout, stderr):
3590 self._DoTestFile('159_blob_ext_missing_sect.dts',
3592 err = stderr.getvalue()
3593 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3594 "blob-ext blob-ext2")
3596 def testPackX86RomMeMissingDesc(self):
3597 """Test that an missing Intel descriptor entry is allowed"""
3598 with test_util.capture_sys_output() as (stdout, stderr):
3599 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3600 err = stderr.getvalue()
3601 self.assertRegex(err,
3602 "Image 'main-section'.*missing.*: intel-descriptor")
3604 def testPackX86RomMissingIfwi(self):
3605 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3606 self._SetupIfwi('fitimage.bin')
3607 pathname = os.path.join(self._indir, 'fitimage.bin')
3609 with test_util.capture_sys_output() as (stdout, stderr):
3610 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3611 err = stderr.getvalue()
3612 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3614 def testPackOverlap(self):
3615 """Test that zero-size overlapping regions are ignored"""
3616 self._DoTestFile('160_pack_overlap_zero.dts')
3618 def testSimpleFit(self):
3619 """Test an image with a FIT inside"""
3620 data = self._DoReadFile('161_fit.dts')
3621 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3622 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3623 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3625 # The data should be inside the FIT
3626 dtb = fdt.Fdt.FromData(fit_data)
3628 fnode = dtb.GetNode('/images/kernel')
3629 self.assertIn('data', fnode.props)
3631 fname = os.path.join(self._indir, 'fit_data.fit')
3632 tools.WriteFile(fname, fit_data)
3633 out = tools.Run('dumpimage', '-l', fname)
3635 # Check a few features to make sure the plumbing works. We don't need
3636 # to test the operation of mkimage or dumpimage here. First convert the
3637 # output into a dict where the keys are the fields printed by dumpimage
3638 # and the values are a list of values for each field
3639 lines = out.splitlines()
3641 # Converts "Compression: gzip compressed" into two groups:
3642 # 'Compression' and 'gzip compressed'
3643 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3644 vals = collections.defaultdict(list)
3646 mat = re_line.match(line)
3647 vals[mat.group(1)].append(mat.group(2))
3649 self.assertEquals('FIT description: test-desc', lines[0])
3650 self.assertIn('Created:', lines[1])
3651 self.assertIn('Image 0 (kernel)', vals)
3652 self.assertIn('Hash value', vals)
3653 data_sizes = vals.get('Data Size')
3654 self.assertIsNotNone(data_sizes)
3655 self.assertEqual(2, len(data_sizes))
3656 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3657 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3658 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3660 def testFitExternal(self):
3661 """Test an image with an FIT with external images"""
3662 data = self._DoReadFile('162_fit_external.dts')
3663 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3665 # The data should be outside the FIT
3666 dtb = fdt.Fdt.FromData(fit_data)
3668 fnode = dtb.GetNode('/images/kernel')
3669 self.assertNotIn('data', fnode.props)
3671 def testSectionIgnoreHashSignature(self):
3672 """Test that sections ignore hash, signature nodes for its data"""
3673 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3674 expected = (U_BOOT_DATA + U_BOOT_DATA)
3675 self.assertEqual(expected, data)
3677 def testPadInSections(self):
3678 """Test pad-before, pad-after for entries in sections"""
3679 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3680 '166_pad_in_sections.dts', update_dtb=True)
3681 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3682 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3684 self.assertEqual(expected, data)
3686 dtb = fdt.Fdt(out_dtb_fname)
3688 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3692 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3694 'section:image-pos': 0,
3695 'section:offset': 0,
3696 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3698 'section/before:image-pos': 0,
3699 'section/before:offset': 0,
3700 'section/before:size': len(U_BOOT_DATA),
3702 'section/u-boot:image-pos': 4,
3703 'section/u-boot:offset': 4,
3704 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3706 'section/after:image-pos': 26,
3707 'section/after:offset': 26,
3708 'section/after:size': len(U_BOOT_DATA),
3710 self.assertEqual(expected, props)
3712 def testFitImageSubentryAlignment(self):
3713 """Test relative alignability of FIT image subentries"""
3715 'test-id': TEXT_DATA,
3717 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3718 entry_args=entry_args)
3719 dtb = fdt.Fdt.FromData(data)
3722 node = dtb.GetNode('/images/kernel')
3723 data = dtb.GetProps(node)["data"].bytes
3724 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3725 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3726 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3727 self.assertEqual(expected, data)
3729 node = dtb.GetNode('/images/fdt-1')
3730 data = dtb.GetProps(node)["data"].bytes
3731 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3732 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3734 self.assertEqual(expected, data)
3736 def testFitExtblobMissingOk(self):
3737 """Test a FIT with a missing external blob that is allowed"""
3738 with test_util.capture_sys_output() as (stdout, stderr):
3739 self._DoTestFile('168_fit_missing_blob.dts',
3741 err = stderr.getvalue()
3742 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3744 def testBlobNamedByArgMissing(self):
3745 """Test handling of a missing entry arg"""
3746 with self.assertRaises(ValueError) as e:
3747 self._DoReadFile('068_blob_named_by_arg.dts')
3748 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3751 def testPackBl31(self):
3752 """Test that an image with an ATF BL31 binary can be created"""
3753 data = self._DoReadFile('169_atf_bl31.dts')
3754 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3756 def testPackScp(self):
3757 """Test that an image with an SCP binary can be created"""
3758 data = self._DoReadFile('172_scp.dts')
3759 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3761 def testFitFdt(self):
3762 """Test an image with an FIT with multiple FDT images"""
3763 def _CheckFdt(seq, expected_data):
3764 """Check the FDT nodes
3767 seq: Sequence number to check (0 or 1)
3768 expected_data: Expected contents of 'data' property
3770 name = 'fdt-%d' % seq
3771 fnode = dtb.GetNode('/images/%s' % name)
3772 self.assertIsNotNone(fnode)
3773 self.assertEqual({'description','type', 'compression', 'data'},
3774 set(fnode.props.keys()))
3775 self.assertEqual(expected_data, fnode.props['data'].bytes)
3776 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3777 fnode.props['description'].value)
3779 def _CheckConfig(seq, expected_data):
3780 """Check the configuration nodes
3783 seq: Sequence number to check (0 or 1)
3784 expected_data: Expected contents of 'data' property
3786 cnode = dtb.GetNode('/configurations')
3787 self.assertIn('default', cnode.props)
3788 self.assertEqual('config-2', cnode.props['default'].value)
3790 name = 'config-%d' % seq
3791 fnode = dtb.GetNode('/configurations/%s' % name)
3792 self.assertIsNotNone(fnode)
3793 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3794 set(fnode.props.keys()))
3795 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3796 fnode.props['description'].value)
3797 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3800 'of-list': 'test-fdt1 test-fdt2',
3801 'default-dt': 'test-fdt2',
3803 data = self._DoReadFileDtb(
3805 entry_args=entry_args,
3806 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3807 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3808 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3810 dtb = fdt.Fdt.FromData(fit_data)
3812 fnode = dtb.GetNode('/images/kernel')
3813 self.assertIn('data', fnode.props)
3815 # Check all the properties in fdt-1 and fdt-2
3816 _CheckFdt(1, TEST_FDT1_DATA)
3817 _CheckFdt(2, TEST_FDT2_DATA)
3819 # Check configurations
3820 _CheckConfig(1, TEST_FDT1_DATA)
3821 _CheckConfig(2, TEST_FDT2_DATA)
3823 def testFitFdtMissingList(self):
3824 """Test handling of a missing 'of-list' entry arg"""
3825 with self.assertRaises(ValueError) as e:
3826 self._DoReadFile('172_fit_fdt.dts')
3827 self.assertIn("Generator node requires 'of-list' entry argument",
3830 def testFitFdtEmptyList(self):
3831 """Test handling of an empty 'of-list' entry arg"""
3835 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3837 def testFitFdtMissingProp(self):
3838 """Test handling of a missing 'fit,fdt-list' property"""
3839 with self.assertRaises(ValueError) as e:
3840 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3841 self.assertIn("Generator node requires 'fit,fdt-list' property",
3844 def testFitFdtEmptyList(self):
3845 """Test handling of an empty 'of-list' entry arg"""
3849 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3851 def testFitFdtMissing(self):
3852 """Test handling of a missing 'default-dt' entry arg"""
3854 'of-list': 'test-fdt1 test-fdt2',
3856 with self.assertRaises(ValueError) as e:
3857 self._DoReadFileDtb(
3859 entry_args=entry_args,
3860 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3861 self.assertIn("Generated 'default' node requires default-dt entry argument",
3864 def testFitFdtNotInList(self):
3865 """Test handling of a default-dt that is not in the of-list"""
3867 'of-list': 'test-fdt1 test-fdt2',
3868 'default-dt': 'test-fdt3',
3870 with self.assertRaises(ValueError) as e:
3871 self._DoReadFileDtb(
3873 entry_args=entry_args,
3874 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3875 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3878 def testFitExtblobMissingHelp(self):
3879 """Test display of help messages when an external blob is missing"""
3880 control.missing_blob_help = control._ReadMissingBlobHelp()
3881 control.missing_blob_help['wibble'] = 'Wibble test'
3882 control.missing_blob_help['another'] = 'Another test'
3883 with test_util.capture_sys_output() as (stdout, stderr):
3884 self._DoTestFile('168_fit_missing_blob.dts',
3886 err = stderr.getvalue()
3888 # We can get the tag from the name, the type or the missing-msg
3889 # property. Check all three.
3890 self.assertIn('You may need to build ARM Trusted', err)
3891 self.assertIn('Wibble test', err)
3892 self.assertIn('Another test', err)
3894 def testMissingBlob(self):
3895 """Test handling of a blob containing a missing file"""
3896 with self.assertRaises(ValueError) as e:
3897 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3898 self.assertIn("Filename 'missing' not found in input path",
3901 def testEnvironment(self):
3902 """Test adding a U-Boot environment"""
3903 data = self._DoReadFile('174_env.dts')
3904 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3905 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3906 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3907 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3910 def testEnvironmentNoSize(self):
3911 """Test that a missing 'size' property is detected"""
3912 with self.assertRaises(ValueError) as e:
3913 self._DoTestFile('175_env_no_size.dts')
3914 self.assertIn("'u-boot-env' entry must have a size property",
3917 def testEnvironmentTooSmall(self):
3918 """Test handling of an environment that does not fit"""
3919 with self.assertRaises(ValueError) as e:
3920 self._DoTestFile('176_env_too_small.dts')
3922 # checksum, start byte, environment with \0 terminator, final \0
3923 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3925 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3928 def testSkipAtStart(self):
3929 """Test handling of skip-at-start section"""
3930 data = self._DoReadFile('177_skip_at_start.dts')
3931 self.assertEqual(U_BOOT_DATA, data)
3933 image = control.images['image']
3934 entries = image.GetEntries()
3935 section = entries['section']
3936 self.assertEqual(0, section.offset)
3937 self.assertEqual(len(U_BOOT_DATA), section.size)
3938 self.assertEqual(U_BOOT_DATA, section.GetData())
3940 entry = section.GetEntries()['u-boot']
3941 self.assertEqual(16, entry.offset)
3942 self.assertEqual(len(U_BOOT_DATA), entry.size)
3943 self.assertEqual(U_BOOT_DATA, entry.data)
3945 def testSkipAtStartPad(self):
3946 """Test handling of skip-at-start section with padded entry"""
3947 data = self._DoReadFile('178_skip_at_start_pad.dts')
3948 before = tools.GetBytes(0, 8)
3949 after = tools.GetBytes(0, 4)
3950 all = before + U_BOOT_DATA + after
3951 self.assertEqual(all, data)
3953 image = control.images['image']
3954 entries = image.GetEntries()
3955 section = entries['section']
3956 self.assertEqual(0, section.offset)
3957 self.assertEqual(len(all), section.size)
3958 self.assertEqual(all, section.GetData())
3960 entry = section.GetEntries()['u-boot']
3961 self.assertEqual(16, entry.offset)
3962 self.assertEqual(len(all), entry.size)
3963 self.assertEqual(U_BOOT_DATA, entry.data)
3965 def testSkipAtStartSectionPad(self):
3966 """Test handling of skip-at-start section with padding"""
3967 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3968 before = tools.GetBytes(0, 8)
3969 after = tools.GetBytes(0, 4)
3970 all = before + U_BOOT_DATA + after
3971 self.assertEqual(all, data)
3973 image = control.images['image']
3974 entries = image.GetEntries()
3975 section = entries['section']
3976 self.assertEqual(0, section.offset)
3977 self.assertEqual(len(all), section.size)
3978 self.assertEqual(U_BOOT_DATA, section.data)
3979 self.assertEqual(all, section.GetPaddedData())
3981 entry = section.GetEntries()['u-boot']
3982 self.assertEqual(16, entry.offset)
3983 self.assertEqual(len(U_BOOT_DATA), entry.size)
3984 self.assertEqual(U_BOOT_DATA, entry.data)
3986 def testSectionPad(self):
3987 """Testing padding with sections"""
3988 data = self._DoReadFile('180_section_pad.dts')
3989 expected = (tools.GetBytes(ord('&'), 3) +
3990 tools.GetBytes(ord('!'), 5) +
3992 tools.GetBytes(ord('!'), 1) +
3993 tools.GetBytes(ord('&'), 2))
3994 self.assertEqual(expected, data)
3996 def testSectionAlign(self):
3997 """Testing alignment with sections"""
3998 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
3999 expected = (b'\0' + # fill section
4000 tools.GetBytes(ord('&'), 1) + # padding to section align
4001 b'\0' + # fill section
4002 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4004 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4005 tools.GetBytes(ord('!'), 4)) # padding to section size
4006 self.assertEqual(expected, data)
4008 def testCompressImage(self):
4009 """Test compression of the entire image"""
4011 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4012 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4013 dtb = fdt.Fdt(out_dtb_fname)
4015 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4017 orig = self._decompress(data)
4018 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4020 # Do a sanity check on various fields
4021 image = control.images['image']
4022 entries = image.GetEntries()
4023 self.assertEqual(2, len(entries))
4025 entry = entries['blob']
4026 self.assertEqual(COMPRESS_DATA, entry.data)
4027 self.assertEqual(len(COMPRESS_DATA), entry.size)
4029 entry = entries['u-boot']
4030 self.assertEqual(U_BOOT_DATA, entry.data)
4031 self.assertEqual(len(U_BOOT_DATA), entry.size)
4033 self.assertEqual(len(data), image.size)
4034 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4035 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4036 orig = self._decompress(image.data)
4037 self.assertEqual(orig, image.uncomp_data)
4041 'blob:size': len(COMPRESS_DATA),
4042 'u-boot:offset': len(COMPRESS_DATA),
4043 'u-boot:size': len(U_BOOT_DATA),
4044 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4049 self.assertEqual(expected, props)
4051 def testCompressImageLess(self):
4052 """Test compression where compression reduces the image size"""
4054 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4055 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4056 dtb = fdt.Fdt(out_dtb_fname)
4058 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4060 orig = self._decompress(data)
4062 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4064 # Do a sanity check on various fields
4065 image = control.images['image']
4066 entries = image.GetEntries()
4067 self.assertEqual(2, len(entries))
4069 entry = entries['blob']
4070 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4071 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4073 entry = entries['u-boot']
4074 self.assertEqual(U_BOOT_DATA, entry.data)
4075 self.assertEqual(len(U_BOOT_DATA), entry.size)
4077 self.assertEqual(len(data), image.size)
4078 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4079 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4081 orig = self._decompress(image.data)
4082 self.assertEqual(orig, image.uncomp_data)
4086 'blob:size': len(COMPRESS_DATA_BIG),
4087 'u-boot:offset': len(COMPRESS_DATA_BIG),
4088 'u-boot:size': len(U_BOOT_DATA),
4089 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4094 self.assertEqual(expected, props)
4096 def testCompressSectionSize(self):
4097 """Test compression of a section with a fixed size"""
4099 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4100 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4101 dtb = fdt.Fdt(out_dtb_fname)
4103 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4105 orig = self._decompress(data)
4106 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4108 'section/blob:offset': 0,
4109 'section/blob:size': len(COMPRESS_DATA),
4110 'section/u-boot:offset': len(COMPRESS_DATA),
4111 'section/u-boot:size': len(U_BOOT_DATA),
4112 'section:offset': 0,
4113 'section:image-pos': 0,
4114 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4115 'section:size': 0x30,
4120 self.assertEqual(expected, props)
4122 def testCompressSection(self):
4123 """Test compression of a section with no fixed size"""
4125 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4126 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4127 dtb = fdt.Fdt(out_dtb_fname)
4129 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4131 orig = self._decompress(data)
4132 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4134 'section/blob:offset': 0,
4135 'section/blob:size': len(COMPRESS_DATA),
4136 'section/u-boot:offset': len(COMPRESS_DATA),
4137 'section/u-boot:size': len(U_BOOT_DATA),
4138 'section:offset': 0,
4139 'section:image-pos': 0,
4140 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4141 'section:size': len(data),
4146 self.assertEqual(expected, props)
4148 def testCompressExtra(self):
4149 """Test compression of a section with no fixed size"""
4151 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4152 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4153 dtb = fdt.Fdt(out_dtb_fname)
4155 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4158 base = data[len(U_BOOT_DATA):]
4159 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4160 rest = base[len(U_BOOT_DATA):]
4162 # Check compressed data
4163 section1 = self._decompress(rest)
4164 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4165 self.assertEquals(expect1, rest[:len(expect1)])
4166 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4167 rest1 = rest[len(expect1):]
4169 section2 = self._decompress(rest1)
4170 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4171 self.assertEquals(expect2, rest1[:len(expect2)])
4172 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4173 rest2 = rest1[len(expect2):]
4175 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4176 len(expect2) + len(U_BOOT_DATA))
4177 #self.assertEquals(expect_size, len(data))
4179 #self.assertEquals(U_BOOT_DATA, rest2)
4184 'u-boot:image-pos': 0,
4185 'u-boot:size': len(U_BOOT_DATA),
4187 'base:offset': len(U_BOOT_DATA),
4188 'base:image-pos': len(U_BOOT_DATA),
4189 'base:size': len(data) - len(U_BOOT_DATA),
4190 'base/u-boot:offset': 0,
4191 'base/u-boot:image-pos': len(U_BOOT_DATA),
4192 'base/u-boot:size': len(U_BOOT_DATA),
4193 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4195 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4197 'base/u-boot2:size': len(U_BOOT_DATA),
4199 'base/section:offset': len(U_BOOT_DATA),
4200 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4201 'base/section:size': len(expect1),
4202 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4203 'base/section/blob:offset': 0,
4204 'base/section/blob:size': len(COMPRESS_DATA),
4205 'base/section/u-boot:offset': len(COMPRESS_DATA),
4206 'base/section/u-boot:size': len(U_BOOT_DATA),
4208 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4209 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4210 'base/section2:size': len(expect2),
4211 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4212 'base/section2/blob:offset': 0,
4213 'base/section2/blob:size': len(COMPRESS_DATA),
4214 'base/section2/blob2:offset': len(COMPRESS_DATA),
4215 'base/section2/blob2:size': len(COMPRESS_DATA),
4221 self.assertEqual(expected, props)
4223 def testSymbolsSubsection(self):
4224 """Test binman can assign symbols from a subsection"""
4225 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
4227 def testReadImageEntryArg(self):
4228 """Test reading an image that would need an entry arg to generate"""
4230 'cros-ec-rw-path': 'ecrw.bin',
4232 data = self.data = self._DoReadFileDtb(
4233 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4234 entry_args=entry_args)
4236 image_fname = tools.GetOutputFilename('image.bin')
4237 orig_image = control.images['image']
4239 # This should not generate an error about the missing 'cros-ec-rw-path'
4240 # since we are reading the image from a file. Compare with
4241 # testEntryArgsRequired()
4242 image = Image.FromFile(image_fname)
4243 self.assertEqual(orig_image.GetEntries().keys(),
4244 image.GetEntries().keys())
4246 def testFilesAlign(self):
4247 """Test alignment with files"""
4248 data = self._DoReadFile('190_files_align.dts')
4250 # The first string is 15 bytes so will align to 16
4251 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4252 self.assertEqual(expect, data)
4254 def testReadImageSkip(self):
4255 """Test reading an image and accessing its FDT map"""
4256 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4257 image_fname = tools.GetOutputFilename('image.bin')
4258 orig_image = control.images['image']
4259 image = Image.FromFile(image_fname)
4260 self.assertEqual(orig_image.GetEntries().keys(),
4261 image.GetEntries().keys())
4263 orig_entry = orig_image.GetEntries()['fdtmap']
4264 entry = image.GetEntries()['fdtmap']
4265 self.assertEqual(orig_entry.offset, entry.offset)
4266 self.assertEqual(orig_entry.size, entry.size)
4267 self.assertEqual(16, entry.image_pos)
4269 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4271 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4273 def testTplNoDtb(self):
4274 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4275 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4276 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4277 data[:len(U_BOOT_TPL_NODTB_DATA)])
4279 def testTplBssPad(self):
4280 """Test that we can pad TPL's BSS with zeros"""
4281 # ELF file with a '__bss_size' symbol
4283 data = self._DoReadFile('193_tpl_bss_pad.dts')
4284 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4287 def testTplBssPadMissing(self):
4288 """Test that a missing symbol is detected"""
4289 self._SetupTplElf('u_boot_ucode_ptr')
4290 with self.assertRaises(ValueError) as e:
4291 self._DoReadFile('193_tpl_bss_pad.dts')
4292 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4295 def checkDtbSizes(self, data, pad_len, start):
4296 """Check the size arguments in a dtb embedded in an image
4299 data: The image data
4300 pad_len: Length of the pad section in the image, in bytes
4301 start: Start offset of the devicetree to examine, within the image
4304 Size of the devicetree in bytes
4306 dtb_data = data[start:]
4307 dtb = fdt.Fdt.FromData(dtb_data)
4308 fdt_size = dtb.GetFdtObj().totalsize()
4310 props = self._GetPropTree(dtb, 'size')
4313 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4314 'u-boot-spl/u-boot-spl-dtb:size': 801,
4315 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4316 'u-boot-spl:size': 860,
4317 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4318 'u-boot/u-boot-dtb:size': 781,
4319 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4324 def testExpanded(self):
4325 """Test that an expanded entry type is selected when needed"""
4329 # SPL has a devicetree, TPL does not
4335 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4336 entry_args=entry_args)
4337 image = control.images['image']
4338 entries = image.GetEntries()
4339 self.assertEqual(3, len(entries))
4341 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4342 self.assertIn('u-boot', entries)
4343 entry = entries['u-boot']
4344 self.assertEqual('u-boot-expanded', entry.etype)
4345 subent = entry.GetEntries()
4346 self.assertEqual(2, len(subent))
4347 self.assertIn('u-boot-nodtb', subent)
4348 self.assertIn('u-boot-dtb', subent)
4350 # Second, u-boot-spl, which should be expanded into three parts
4351 self.assertIn('u-boot-spl', entries)
4352 entry = entries['u-boot-spl']
4353 self.assertEqual('u-boot-spl-expanded', entry.etype)
4354 subent = entry.GetEntries()
4355 self.assertEqual(3, len(subent))
4356 self.assertIn('u-boot-spl-nodtb', subent)
4357 self.assertIn('u-boot-spl-bss-pad', subent)
4358 self.assertIn('u-boot-spl-dtb', subent)
4360 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4362 self.assertIn('u-boot-tpl', entries)
4363 entry = entries['u-boot-tpl']
4364 self.assertEqual('u-boot-tpl', entry.etype)
4365 self.assertEqual(None, entry.GetEntries())
4367 def testExpandedTpl(self):
4368 """Test that an expanded entry type is selected for TPL when needed"""
4375 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4376 entry_args=entry_args)
4377 image = control.images['image']
4378 entries = image.GetEntries()
4379 self.assertEqual(1, len(entries))
4381 # We only have u-boot-tpl, which be expanded
4382 self.assertIn('u-boot-tpl', entries)
4383 entry = entries['u-boot-tpl']
4384 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4385 subent = entry.GetEntries()
4386 self.assertEqual(3, len(subent))
4387 self.assertIn('u-boot-tpl-nodtb', subent)
4388 self.assertIn('u-boot-tpl-bss-pad', subent)
4389 self.assertIn('u-boot-tpl-dtb', subent)
4391 def testExpandedNoPad(self):
4392 """Test an expanded entry without BSS pad enabled"""
4396 # SPL has a devicetree, TPL does not
4398 'spl-dtb': 'something',
4402 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4403 entry_args=entry_args)
4404 image = control.images['image']
4405 entries = image.GetEntries()
4407 # Just check u-boot-spl, which should be expanded into two parts
4408 self.assertIn('u-boot-spl', entries)
4409 entry = entries['u-boot-spl']
4410 self.assertEqual('u-boot-spl-expanded', entry.etype)
4411 subent = entry.GetEntries()
4412 self.assertEqual(2, len(subent))
4413 self.assertIn('u-boot-spl-nodtb', subent)
4414 self.assertIn('u-boot-spl-dtb', subent)
4416 def testExpandedTplNoPad(self):
4417 """Test that an expanded entry type with padding disabled in TPL"""
4424 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4425 entry_args=entry_args)
4426 image = control.images['image']
4427 entries = image.GetEntries()
4428 self.assertEqual(1, len(entries))
4430 # We only have u-boot-tpl, which be expanded
4431 self.assertIn('u-boot-tpl', entries)
4432 entry = entries['u-boot-tpl']
4433 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4434 subent = entry.GetEntries()
4435 self.assertEqual(2, len(subent))
4436 self.assertIn('u-boot-tpl-nodtb', subent)
4437 self.assertIn('u-boot-tpl-dtb', subent)
4439 def testFdtInclude(self):
4440 """Test that an Fdt is update within all binaries"""
4444 # SPL has a devicetree, TPL does not
4451 # Build the image. It includes two separate devicetree binaries, each
4452 # with their own contents, but all contain the binman definition.
4453 data = self._DoReadFileDtb(
4454 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4455 update_dtb=True, entry_args=entry_args)[0]
4458 # Check the U-Boot dtb
4459 start = len(U_BOOT_NODTB_DATA)
4460 fdt_size = self.checkDtbSizes(data, pad_len, start)
4463 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4464 fdt_size = self.checkDtbSizes(data, pad_len, start)
4466 # TPL has no devicetree
4467 start += fdt_size + len(U_BOOT_TPL_DATA)
4468 self.assertEqual(len(data), start)
4470 def testSymbolsExpanded(self):
4471 """Test binman can assign symbols in expanded entries"""
4475 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4476 U_BOOT_SPL_DTB_DATA, 0x38,
4477 entry_args=entry_args, use_expanded=True)
4479 def testCollection(self):
4480 """Test a collection"""
4481 data = self._DoReadFile('198_collection.dts')
4482 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4483 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4484 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4487 if __name__ == "__main__":