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 REFCODE_DATA = b'refcode'
77 ATF_BL31_DATA = b'bl31'
79 TEST_FDT1_DATA = b'fdt1'
80 TEST_FDT2_DATA = b'test-fdt2'
81 ENV_DATA = b'var1=1\nvar2="2"'
83 # Subdirectory of the input dir to use to put test FDTs
84 TEST_FDT_SUBDIR = 'fdts'
86 # The expected size for the device tree in some tests
87 EXTRACT_DTB_SIZE = 0x3c9
89 # Properties expected to be in the device tree when update_dtb is used
90 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
92 # Extra properties expected to be in the device tree when allow-repack is used
93 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
96 class TestFunctional(unittest.TestCase):
97 """Functional tests for binman
99 Most of these use a sample .dts file to build an image and then check
100 that it looks correct. The sample files are in the test/ subdirectory
103 For each entry type a very small test file is created using fixed
104 string contents. This makes it easy to test that things look right, and
107 In some cases a 'real' file must be used - these are also supplied in
108 the test/ diurectory.
113 from binman import entry
115 # Handle the case where argv[0] is 'python'
116 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
117 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
119 # Create a temporary directory for input files
120 cls._indir = tempfile.mkdtemp(prefix='binmant.')
122 # Create some test files
123 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
124 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
125 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
126 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
127 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
128 TestFunctional._MakeInputFile('me.bin', ME_DATA)
129 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
132 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
134 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
135 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
136 X86_START16_SPL_DATA)
137 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
138 X86_START16_TPL_DATA)
140 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
142 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
143 X86_RESET16_SPL_DATA)
144 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
145 X86_RESET16_TPL_DATA)
147 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
148 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
149 U_BOOT_SPL_NODTB_DATA)
150 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
151 U_BOOT_TPL_NODTB_DATA)
152 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
153 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
154 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
155 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
156 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
157 TestFunctional._MakeInputDir('devkeys')
158 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
159 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
160 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
161 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
162 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
164 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
165 elf_test.BuildElfTestFiles(cls._elf_testdir)
167 # ELF file with a '_dt_ucode_base_size' symbol
168 TestFunctional._MakeInputFile('u-boot',
169 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
171 # Intel flash descriptor file
172 cls._SetupDescriptor()
174 shutil.copytree(cls.TestFile('files'),
175 os.path.join(cls._indir, 'files'))
177 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
178 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
179 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
181 # Add a few .dtb files for testing
182 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
184 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
187 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
189 # Travis-CI may have an old lz4
192 tools.Run('lz4', '--no-frame-crc', '-c',
193 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
198 def tearDownClass(cls):
199 """Remove the temporary input directory and its contents"""
200 if cls.preserve_indir:
201 print('Preserving input dir: %s' % cls._indir)
204 shutil.rmtree(cls._indir)
208 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
209 toolpath=None, verbosity=None):
210 """Accept arguments controlling test execution
213 preserve_indir: Preserve the shared input directory used by all
215 preserve_outdir: Preserve the output directories used by tests. Each
216 test has its own, so this is normally only useful when running a
218 toolpath: ist of paths to use for tools
220 cls.preserve_indir = preserve_indir
221 cls.preserve_outdirs = preserve_outdirs
222 cls.toolpath = toolpath
223 cls.verbosity = verbosity
226 if not self.have_lz4:
227 self.skipTest('lz4 --no-frame-crc not available')
229 def _CleanupOutputDir(self):
230 """Remove the temporary output directory"""
231 if self.preserve_outdirs:
232 print('Preserving output dir: %s' % tools.outdir)
234 tools._FinaliseForTest()
237 # Enable this to turn on debugging output
238 # tout.Init(tout.DEBUG)
239 command.test_result = None
242 """Remove the temporary output directory"""
243 self._CleanupOutputDir()
245 def _SetupImageInTmpdir(self):
246 """Set up the output image in a new temporary directory
248 This is used when an image has been generated in the output directory,
249 but we want to run binman again. This will create a new output
250 directory and fail to delete the original one.
252 This creates a new temporary directory, copies the image to it (with a
253 new name) and removes the old output directory.
257 Temporary directory to use
260 image_fname = tools.GetOutputFilename('image.bin')
261 tmpdir = tempfile.mkdtemp(prefix='binman.')
262 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
263 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
264 self._CleanupOutputDir()
265 return tmpdir, updated_fname
269 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
270 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
271 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
273 def _RunBinman(self, *args, **kwargs):
274 """Run binman using the command line
277 Arguments to pass, as a list of strings
278 kwargs: Arguments to pass to Command.RunPipe()
280 result = command.RunPipe([[self._binman_pathname] + list(args)],
281 capture=True, capture_stderr=True, raise_on_error=False)
282 if result.return_code and kwargs.get('raise_on_error', True):
283 raise Exception("Error running '%s': %s" % (' '.join(args),
284 result.stdout + result.stderr))
287 def _DoBinman(self, *argv):
288 """Run binman using directly (in the same process)
291 Arguments to pass, as a list of strings
293 Return value (0 for success)
296 args = cmdline.ParseArgs(argv)
297 args.pager = 'binman-invalid-pager'
298 args.build_dir = self._indir
300 # For testing, you can force an increase in verbosity here
301 # args.verbosity = tout.DEBUG
302 return control.Binman(args)
304 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
305 entry_args=None, images=None, use_real_dtb=False,
306 verbosity=None, allow_missing=False, extra_indirs=None):
307 """Run binman with a given test file
310 fname: Device-tree source filename to use (e.g. 005_simple.dts)
311 debug: True to enable debugging output
312 map: True to output map files for the images
313 update_dtb: Update the offset and size of each entry in the device
314 tree before packing it into the image
315 entry_args: Dict of entry args to supply to binman
317 value: value of that arg
318 images: List of image names to build
319 use_real_dtb: True to use the test file as the contents of
320 the u-boot-dtb entry. Normally this is not needed and the
321 test contents (the U_BOOT_DTB_DATA string) can be used.
322 But in some test we need the real contents.
323 verbosity: Verbosity level to use (0-3, None=don't set it)
324 allow_missing: Set the '--allow-missing' flag so that missing
325 external binaries just produce a warning instead of an error
326 extra_indirs: Extra input directories to add using -I
331 if verbosity is not None:
332 args.append('-v%d' % verbosity)
334 args.append('-v%d' % self.verbosity)
336 for path in self.toolpath:
337 args += ['--toolpath', path]
338 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
344 args.append('--fake-dtb')
346 for arg, value in entry_args.items():
347 args.append('-a%s=%s' % (arg, value))
352 args += ['-i', image]
354 for indir in extra_indirs:
355 args += ['-I', indir]
356 return self._DoBinman(*args)
358 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
359 """Set up a new test device-tree file
361 The given file is compiled and set up as the device tree to be used
365 fname: Filename of .dts file to read
366 outfile: Output filename for compiled device-tree binary
369 Contents of device-tree binary
371 tmpdir = tempfile.mkdtemp(prefix='binmant.')
372 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
373 with open(dtb, 'rb') as fd:
375 TestFunctional._MakeInputFile(outfile, data)
376 shutil.rmtree(tmpdir)
379 def _GetDtbContentsForSplTpl(self, dtb_data, name):
380 """Create a version of the main DTB for SPL or SPL
382 For testing we don't actually have different versions of the DTB. With
383 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
384 we don't normally have any unwanted nodes.
386 We still want the DTBs for SPL and TPL to be different though, since
387 otherwise it is confusing to know which one we are looking at. So add
388 an 'spl' or 'tpl' property to the top-level node.
391 dtb_data: dtb data to modify (this should be a value devicetree)
392 name: Name of a new property to add
395 New dtb data with the property added
397 dtb = fdt.Fdt.FromData(dtb_data)
399 dtb.GetNode('/binman').AddZeroProp(name)
400 dtb.Sync(auto_resize=True)
402 return dtb.GetContents()
404 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
405 update_dtb=False, entry_args=None, reset_dtbs=True,
407 """Run binman and return the resulting image
409 This runs binman with a given test file and then reads the resulting
410 output file. It is a shortcut function since most tests need to do
413 Raises an assertion failure if binman returns a non-zero exit code.
416 fname: Device-tree source filename to use (e.g. 005_simple.dts)
417 use_real_dtb: True to use the test file as the contents of
418 the u-boot-dtb entry. Normally this is not needed and the
419 test contents (the U_BOOT_DTB_DATA string) can be used.
420 But in some test we need the real contents.
421 map: True to output map files for the images
422 update_dtb: Update the offset and size of each entry in the device
423 tree before packing it into the image
424 entry_args: Dict of entry args to supply to binman
426 value: value of that arg
427 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
428 function. If reset_dtbs is True, then the original test dtb
429 is written back before this function finishes
430 extra_indirs: Extra input directories to add using -I
434 Resulting image contents
436 Map data showing contents of image (or None if none)
437 Output device tree binary filename ('u-boot.dtb' path)
440 # Use the compiled test file as the u-boot-dtb input
442 dtb_data = self._SetupDtb(fname)
444 # For testing purposes, make a copy of the DT for SPL and TPL. Add
445 # a node indicating which it is, so aid verification.
446 for name in ['spl', 'tpl']:
447 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
448 outfile = os.path.join(self._indir, dtb_fname)
449 TestFunctional._MakeInputFile(dtb_fname,
450 self._GetDtbContentsForSplTpl(dtb_data, name))
453 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
454 entry_args=entry_args, use_real_dtb=use_real_dtb,
455 extra_indirs=extra_indirs)
456 self.assertEqual(0, retcode)
457 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
459 # Find the (only) image, read it and return its contents
460 image = control.images['image']
461 image_fname = tools.GetOutputFilename('image.bin')
462 self.assertTrue(os.path.exists(image_fname))
464 map_fname = tools.GetOutputFilename('image.map')
465 with open(map_fname) as fd:
469 with open(image_fname, 'rb') as fd:
470 return fd.read(), dtb_data, map_data, out_dtb_fname
472 # Put the test file back
473 if reset_dtbs and use_real_dtb:
476 def _DoReadFileRealDtb(self, fname):
477 """Run binman with a real .dtb file and return the resulting data
480 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
483 Resulting image contents
485 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
487 def _DoReadFile(self, fname, use_real_dtb=False):
488 """Helper function which discards the device-tree binary
491 fname: Device-tree source filename to use (e.g. 005_simple.dts)
492 use_real_dtb: True to use the test file as the contents of
493 the u-boot-dtb entry. Normally this is not needed and the
494 test contents (the U_BOOT_DTB_DATA string) can be used.
495 But in some test we need the real contents.
498 Resulting image contents
500 return self._DoReadFileDtb(fname, use_real_dtb)[0]
503 def _MakeInputFile(cls, fname, contents):
504 """Create a new test input file, creating directories as needed
507 fname: Filename to create
508 contents: File contents to write in to the file
510 Full pathname of file created
512 pathname = os.path.join(cls._indir, fname)
513 dirname = os.path.dirname(pathname)
514 if dirname and not os.path.exists(dirname):
516 with open(pathname, 'wb') as fd:
521 def _MakeInputDir(cls, dirname):
522 """Create a new test input directory, creating directories as needed
525 dirname: Directory name to create
528 Full pathname of directory created
530 pathname = os.path.join(cls._indir, dirname)
531 if not os.path.exists(pathname):
532 os.makedirs(pathname)
536 def _SetupSplElf(cls, src_fname='bss_data'):
537 """Set up an ELF file with a '_dt_ucode_base_size' symbol
540 Filename of ELF file to use as SPL
542 TestFunctional._MakeInputFile('spl/u-boot-spl',
543 tools.ReadFile(cls.ElfTestFile(src_fname)))
546 def _SetupTplElf(cls, src_fname='bss_data'):
547 """Set up an ELF file with a '_dt_ucode_base_size' symbol
550 Filename of ELF file to use as TPL
552 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
553 tools.ReadFile(cls.ElfTestFile(src_fname)))
556 def _SetupDescriptor(cls):
557 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
558 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
561 def TestFile(cls, fname):
562 return os.path.join(cls._binman_dir, 'test', fname)
565 def ElfTestFile(cls, fname):
566 return os.path.join(cls._elf_testdir, fname)
568 def AssertInList(self, grep_list, target):
569 """Assert that at least one of a list of things is in a target
572 grep_list: List of strings to check
573 target: Target string
575 for grep in grep_list:
578 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
580 def CheckNoGaps(self, entries):
581 """Check that all entries fit together without gaps
584 entries: List of entries to check
587 for entry in entries.values():
588 self.assertEqual(offset, entry.offset)
591 def GetFdtLen(self, dtb):
592 """Get the totalsize field from a device-tree binary
595 dtb: Device-tree binary contents
598 Total size of device-tree binary, from the header
600 return struct.unpack('>L', dtb[4:8])[0]
602 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
603 def AddNode(node, path):
605 path += '/' + node.name
606 for prop in node.props.values():
607 if prop.name in prop_names:
608 prop_path = path + ':' + prop.name
609 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
611 for subnode in node.subnodes:
612 AddNode(subnode, path)
615 AddNode(dtb.GetRoot(), '')
619 """Test a basic run with valid args"""
620 result = self._RunBinman('-h')
622 def testFullHelp(self):
623 """Test that the full help is displayed with -H"""
624 result = self._RunBinman('-H')
625 help_file = os.path.join(self._binman_dir, 'README')
626 # Remove possible extraneous strings
627 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
628 gothelp = result.stdout.replace(extra, '')
629 self.assertEqual(len(gothelp), os.path.getsize(help_file))
630 self.assertEqual(0, len(result.stderr))
631 self.assertEqual(0, result.return_code)
633 def testFullHelpInternal(self):
634 """Test that the full help is displayed with -H"""
636 command.test_result = command.CommandResult()
637 result = self._DoBinman('-H')
638 help_file = os.path.join(self._binman_dir, 'README')
640 command.test_result = None
643 """Test that the basic help is displayed with -h"""
644 result = self._RunBinman('-h')
645 self.assertTrue(len(result.stdout) > 200)
646 self.assertEqual(0, len(result.stderr))
647 self.assertEqual(0, result.return_code)
650 """Test that we can run it with a specific board"""
651 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
652 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
653 result = self._DoBinman('build', '-b', 'sandbox')
654 self.assertEqual(0, result)
656 def testNeedBoard(self):
657 """Test that we get an error when no board ius supplied"""
658 with self.assertRaises(ValueError) as e:
659 result = self._DoBinman('build')
660 self.assertIn("Must provide a board to process (use -b <board>)",
663 def testMissingDt(self):
664 """Test that an invalid device-tree file generates an error"""
665 with self.assertRaises(Exception) as e:
666 self._RunBinman('build', '-d', 'missing_file')
667 # We get one error from libfdt, and a different one from fdtget.
668 self.AssertInList(["Couldn't open blob from 'missing_file'",
669 'No such file or directory'], str(e.exception))
671 def testBrokenDt(self):
672 """Test that an invalid device-tree source file generates an error
674 Since this is a source file it should be compiled and the error
675 will come from the device-tree compiler (dtc).
677 with self.assertRaises(Exception) as e:
678 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
679 self.assertIn("FATAL ERROR: Unable to parse input tree",
682 def testMissingNode(self):
683 """Test that a device tree without a 'binman' node generates an error"""
684 with self.assertRaises(Exception) as e:
685 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
686 self.assertIn("does not have a 'binman' node", str(e.exception))
689 """Test that an empty binman node works OK (i.e. does nothing)"""
690 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
691 self.assertEqual(0, len(result.stderr))
692 self.assertEqual(0, result.return_code)
694 def testInvalidEntry(self):
695 """Test that an invalid entry is flagged"""
696 with self.assertRaises(Exception) as e:
697 result = self._RunBinman('build', '-d',
698 self.TestFile('004_invalid_entry.dts'))
699 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
700 "'/binman/not-a-valid-type'", str(e.exception))
702 def testSimple(self):
703 """Test a simple binman with a single file"""
704 data = self._DoReadFile('005_simple.dts')
705 self.assertEqual(U_BOOT_DATA, data)
707 def testSimpleDebug(self):
708 """Test a simple binman run with debugging enabled"""
709 self._DoTestFile('005_simple.dts', debug=True)
712 """Test that we can handle creating two images
714 This also tests image padding.
716 retcode = self._DoTestFile('006_dual_image.dts')
717 self.assertEqual(0, retcode)
719 image = control.images['image1']
720 self.assertEqual(len(U_BOOT_DATA), image.size)
721 fname = tools.GetOutputFilename('image1.bin')
722 self.assertTrue(os.path.exists(fname))
723 with open(fname, 'rb') as fd:
725 self.assertEqual(U_BOOT_DATA, data)
727 image = control.images['image2']
728 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
729 fname = tools.GetOutputFilename('image2.bin')
730 self.assertTrue(os.path.exists(fname))
731 with open(fname, 'rb') as fd:
733 self.assertEqual(U_BOOT_DATA, data[3:7])
734 self.assertEqual(tools.GetBytes(0, 3), data[:3])
735 self.assertEqual(tools.GetBytes(0, 5), data[7:])
737 def testBadAlign(self):
738 """Test that an invalid alignment value is detected"""
739 with self.assertRaises(ValueError) as e:
740 self._DoTestFile('007_bad_align.dts')
741 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
742 "of two", str(e.exception))
744 def testPackSimple(self):
745 """Test that packing works as expected"""
746 retcode = self._DoTestFile('008_pack.dts')
747 self.assertEqual(0, retcode)
748 self.assertIn('image', control.images)
749 image = control.images['image']
750 entries = image.GetEntries()
751 self.assertEqual(5, len(entries))
754 self.assertIn('u-boot', entries)
755 entry = entries['u-boot']
756 self.assertEqual(0, entry.offset)
757 self.assertEqual(len(U_BOOT_DATA), entry.size)
759 # Second u-boot, aligned to 16-byte boundary
760 self.assertIn('u-boot-align', entries)
761 entry = entries['u-boot-align']
762 self.assertEqual(16, entry.offset)
763 self.assertEqual(len(U_BOOT_DATA), entry.size)
765 # Third u-boot, size 23 bytes
766 self.assertIn('u-boot-size', entries)
767 entry = entries['u-boot-size']
768 self.assertEqual(20, entry.offset)
769 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
770 self.assertEqual(23, entry.size)
772 # Fourth u-boot, placed immediate after the above
773 self.assertIn('u-boot-next', entries)
774 entry = entries['u-boot-next']
775 self.assertEqual(43, entry.offset)
776 self.assertEqual(len(U_BOOT_DATA), entry.size)
778 # Fifth u-boot, placed at a fixed offset
779 self.assertIn('u-boot-fixed', entries)
780 entry = entries['u-boot-fixed']
781 self.assertEqual(61, entry.offset)
782 self.assertEqual(len(U_BOOT_DATA), entry.size)
784 self.assertEqual(65, image.size)
786 def testPackExtra(self):
787 """Test that extra packing feature works as expected"""
788 data = self._DoReadFile('009_pack_extra.dts')
790 self.assertIn('image', control.images)
791 image = control.images['image']
792 entries = image.GetEntries()
793 self.assertEqual(5, len(entries))
795 # First u-boot with padding before and after
796 self.assertIn('u-boot', entries)
797 entry = entries['u-boot']
798 self.assertEqual(0, entry.offset)
799 self.assertEqual(3, entry.pad_before)
800 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
801 self.assertEqual(U_BOOT_DATA, entry.data)
802 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
803 tools.GetBytes(0, 5), data[:entry.size])
806 # Second u-boot has an aligned size, but it has no effect
807 self.assertIn('u-boot-align-size-nop', entries)
808 entry = entries['u-boot-align-size-nop']
809 self.assertEqual(pos, entry.offset)
810 self.assertEqual(len(U_BOOT_DATA), entry.size)
811 self.assertEqual(U_BOOT_DATA, entry.data)
812 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
815 # Third u-boot has an aligned size too
816 self.assertIn('u-boot-align-size', entries)
817 entry = entries['u-boot-align-size']
818 self.assertEqual(pos, entry.offset)
819 self.assertEqual(32, entry.size)
820 self.assertEqual(U_BOOT_DATA, entry.data)
821 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
822 data[pos:pos + entry.size])
825 # Fourth u-boot has an aligned end
826 self.assertIn('u-boot-align-end', entries)
827 entry = entries['u-boot-align-end']
828 self.assertEqual(48, entry.offset)
829 self.assertEqual(16, entry.size)
830 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
831 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
832 data[pos:pos + entry.size])
835 # Fifth u-boot immediately afterwards
836 self.assertIn('u-boot-align-both', entries)
837 entry = entries['u-boot-align-both']
838 self.assertEqual(64, entry.offset)
839 self.assertEqual(64, entry.size)
840 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
841 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
842 data[pos:pos + entry.size])
844 self.CheckNoGaps(entries)
845 self.assertEqual(128, image.size)
847 def testPackAlignPowerOf2(self):
848 """Test that invalid entry alignment is detected"""
849 with self.assertRaises(ValueError) as e:
850 self._DoTestFile('010_pack_align_power2.dts')
851 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
852 "of two", str(e.exception))
854 def testPackAlignSizePowerOf2(self):
855 """Test that invalid entry size alignment is detected"""
856 with self.assertRaises(ValueError) as e:
857 self._DoTestFile('011_pack_align_size_power2.dts')
858 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
859 "power of two", str(e.exception))
861 def testPackInvalidAlign(self):
862 """Test detection of an offset that does not match its alignment"""
863 with self.assertRaises(ValueError) as e:
864 self._DoTestFile('012_pack_inv_align.dts')
865 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
866 "align 0x4 (4)", str(e.exception))
868 def testPackInvalidSizeAlign(self):
869 """Test that invalid entry size alignment is detected"""
870 with self.assertRaises(ValueError) as e:
871 self._DoTestFile('013_pack_inv_size_align.dts')
872 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
873 "align-size 0x4 (4)", str(e.exception))
875 def testPackOverlap(self):
876 """Test that overlapping regions are detected"""
877 with self.assertRaises(ValueError) as e:
878 self._DoTestFile('014_pack_overlap.dts')
879 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
880 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
883 def testPackEntryOverflow(self):
884 """Test that entries that overflow their size are detected"""
885 with self.assertRaises(ValueError) as e:
886 self._DoTestFile('015_pack_overflow.dts')
887 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
888 "but entry size is 0x3 (3)", str(e.exception))
890 def testPackImageOverflow(self):
891 """Test that entries which overflow the image size are detected"""
892 with self.assertRaises(ValueError) as e:
893 self._DoTestFile('016_pack_image_overflow.dts')
894 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
895 "size 0x3 (3)", str(e.exception))
897 def testPackImageSize(self):
898 """Test that the image size can be set"""
899 retcode = self._DoTestFile('017_pack_image_size.dts')
900 self.assertEqual(0, retcode)
901 self.assertIn('image', control.images)
902 image = control.images['image']
903 self.assertEqual(7, image.size)
905 def testPackImageSizeAlign(self):
906 """Test that image size alignemnt works as expected"""
907 retcode = self._DoTestFile('018_pack_image_align.dts')
908 self.assertEqual(0, retcode)
909 self.assertIn('image', control.images)
910 image = control.images['image']
911 self.assertEqual(16, image.size)
913 def testPackInvalidImageAlign(self):
914 """Test that invalid image alignment is detected"""
915 with self.assertRaises(ValueError) as e:
916 self._DoTestFile('019_pack_inv_image_align.dts')
917 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
918 "align-size 0x8 (8)", str(e.exception))
920 def testPackAlignPowerOf2(self):
921 """Test that invalid image alignment is detected"""
922 with self.assertRaises(ValueError) as e:
923 self._DoTestFile('020_pack_inv_image_align_power2.dts')
924 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
925 "two", str(e.exception))
927 def testImagePadByte(self):
928 """Test that the image pad byte can be specified"""
930 data = self._DoReadFile('021_image_pad.dts')
931 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
934 def testImageName(self):
935 """Test that image files can be named"""
936 retcode = self._DoTestFile('022_image_name.dts')
937 self.assertEqual(0, retcode)
938 image = control.images['image1']
939 fname = tools.GetOutputFilename('test-name')
940 self.assertTrue(os.path.exists(fname))
942 image = control.images['image2']
943 fname = tools.GetOutputFilename('test-name.xx')
944 self.assertTrue(os.path.exists(fname))
946 def testBlobFilename(self):
947 """Test that generic blobs can be provided by filename"""
948 data = self._DoReadFile('023_blob.dts')
949 self.assertEqual(BLOB_DATA, data)
951 def testPackSorted(self):
952 """Test that entries can be sorted"""
954 data = self._DoReadFile('024_sorted.dts')
955 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
956 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
958 def testPackZeroOffset(self):
959 """Test that an entry at offset 0 is not given a new offset"""
960 with self.assertRaises(ValueError) as e:
961 self._DoTestFile('025_pack_zero_size.dts')
962 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
963 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
966 def testPackUbootDtb(self):
967 """Test that a device tree can be added to U-Boot"""
968 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
969 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
971 def testPackX86RomNoSize(self):
972 """Test that the end-at-4gb property requires a size property"""
973 with self.assertRaises(ValueError) as e:
974 self._DoTestFile('027_pack_4gb_no_size.dts')
975 self.assertIn("Image '/binman': Section size must be provided when "
976 "using end-at-4gb", str(e.exception))
978 def test4gbAndSkipAtStartTogether(self):
979 """Test that the end-at-4gb and skip-at-size property can't be used
981 with self.assertRaises(ValueError) as e:
982 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
983 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
984 "'skip-at-start'", str(e.exception))
986 def testPackX86RomOutside(self):
987 """Test that the end-at-4gb property checks for offset boundaries"""
988 with self.assertRaises(ValueError) as e:
989 self._DoTestFile('028_pack_4gb_outside.dts')
990 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
991 "is outside the section '/binman' starting at "
992 '0xffffffe0 (4294967264) of size 0x20 (32)',
995 def testPackX86Rom(self):
996 """Test that a basic x86 ROM can be created"""
998 data = self._DoReadFile('029_x86_rom.dts')
999 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
1000 tools.GetBytes(0, 2), data)
1002 def testPackX86RomMeNoDesc(self):
1003 """Test that an invalid Intel descriptor entry is detected"""
1005 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
1006 with self.assertRaises(ValueError) as e:
1007 self._DoTestFile('163_x86_rom_me_empty.dts')
1008 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1011 self._SetupDescriptor()
1013 def testPackX86RomBadDesc(self):
1014 """Test that the Intel requires a descriptor entry"""
1015 with self.assertRaises(ValueError) as e:
1016 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1017 self.assertIn("Node '/binman/intel-me': No offset set with "
1018 "offset-unset: should another entry provide this correct "
1019 "offset?", str(e.exception))
1021 def testPackX86RomMe(self):
1022 """Test that an x86 ROM with an ME region can be created"""
1023 data = self._DoReadFile('031_x86_rom_me.dts')
1024 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1025 if data[:0x1000] != expected_desc:
1026 self.fail('Expected descriptor binary at start of image')
1027 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1029 def testPackVga(self):
1030 """Test that an image with a VGA binary can be created"""
1031 data = self._DoReadFile('032_intel_vga.dts')
1032 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1034 def testPackStart16(self):
1035 """Test that an image with an x86 start16 region can be created"""
1036 data = self._DoReadFile('033_x86_start16.dts')
1037 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1039 def testPackPowerpcMpc85xxBootpgResetvec(self):
1040 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1042 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1043 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1045 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1046 """Handle running a test for insertion of microcode
1049 dts_fname: Name of test .dts file
1050 nodtb_data: Data that we expect in the first section
1051 ucode_second: True if the microsecond entry is second instead of
1056 Contents of first region (U-Boot or SPL)
1057 Offset and size components of microcode pointer, as inserted
1058 in the above (two 4-byte words)
1060 data = self._DoReadFile(dts_fname, True)
1062 # Now check the device tree has no microcode
1064 ucode_content = data[len(nodtb_data):]
1065 ucode_pos = len(nodtb_data)
1066 dtb_with_ucode = ucode_content[16:]
1067 fdt_len = self.GetFdtLen(dtb_with_ucode)
1069 dtb_with_ucode = data[len(nodtb_data):]
1070 fdt_len = self.GetFdtLen(dtb_with_ucode)
1071 ucode_content = dtb_with_ucode[fdt_len:]
1072 ucode_pos = len(nodtb_data) + fdt_len
1073 fname = tools.GetOutputFilename('test.dtb')
1074 with open(fname, 'wb') as fd:
1075 fd.write(dtb_with_ucode)
1076 dtb = fdt.FdtScan(fname)
1077 ucode = dtb.GetNode('/microcode')
1078 self.assertTrue(ucode)
1079 for node in ucode.subnodes:
1080 self.assertFalse(node.props.get('data'))
1082 # Check that the microcode appears immediately after the Fdt
1083 # This matches the concatenation of the data properties in
1084 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1085 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1087 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1089 # Check that the microcode pointer was inserted. It should match the
1090 # expected offset and size
1091 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1093 u_boot = data[:len(nodtb_data)]
1094 return u_boot, pos_and_size
1096 def testPackUbootMicrocode(self):
1097 """Test that x86 microcode can be handled correctly
1099 We expect to see the following in the image, in order:
1100 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1102 u-boot.dtb with the microcode removed
1105 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1107 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1108 b' somewhere in here', first)
1110 def _RunPackUbootSingleMicrocode(self):
1111 """Test that x86 microcode can be handled correctly
1113 We expect to see the following in the image, in order:
1114 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1116 u-boot.dtb with the microcode
1117 an empty microcode region
1119 # We need the libfdt library to run this test since only that allows
1120 # finding the offset of a property. This is required by
1121 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1122 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1124 second = data[len(U_BOOT_NODTB_DATA):]
1126 fdt_len = self.GetFdtLen(second)
1127 third = second[fdt_len:]
1128 second = second[:fdt_len]
1130 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1131 self.assertIn(ucode_data, second)
1132 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1134 # Check that the microcode pointer was inserted. It should match the
1135 # expected offset and size
1136 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1138 first = data[:len(U_BOOT_NODTB_DATA)]
1139 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1140 b' somewhere in here', first)
1142 def testPackUbootSingleMicrocode(self):
1143 """Test that x86 microcode can be handled correctly with fdt_normal.
1145 self._RunPackUbootSingleMicrocode()
1147 def testUBootImg(self):
1148 """Test that u-boot.img can be put in a file"""
1149 data = self._DoReadFile('036_u_boot_img.dts')
1150 self.assertEqual(U_BOOT_IMG_DATA, data)
1152 def testNoMicrocode(self):
1153 """Test that a missing microcode region is detected"""
1154 with self.assertRaises(ValueError) as e:
1155 self._DoReadFile('037_x86_no_ucode.dts', True)
1156 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1157 "node found in ", str(e.exception))
1159 def testMicrocodeWithoutNode(self):
1160 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1161 with self.assertRaises(ValueError) as e:
1162 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1163 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1164 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1166 def testMicrocodeWithoutNode2(self):
1167 """Test that a missing u-boot-ucode node is detected"""
1168 with self.assertRaises(ValueError) as e:
1169 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1170 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1171 "microcode region u-boot-ucode", str(e.exception))
1173 def testMicrocodeWithoutPtrInElf(self):
1174 """Test that a U-Boot binary without the microcode symbol is detected"""
1175 # ELF file without a '_dt_ucode_base_size' symbol
1177 TestFunctional._MakeInputFile('u-boot',
1178 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1180 with self.assertRaises(ValueError) as e:
1181 self._RunPackUbootSingleMicrocode()
1182 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1183 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1186 # Put the original file back
1187 TestFunctional._MakeInputFile('u-boot',
1188 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1190 def testMicrocodeNotInImage(self):
1191 """Test that microcode must be placed within the image"""
1192 with self.assertRaises(ValueError) as e:
1193 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1194 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1195 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1196 "section ranging from 00000000 to 0000002e", str(e.exception))
1198 def testWithoutMicrocode(self):
1199 """Test that we can cope with an image without microcode (e.g. qemu)"""
1200 TestFunctional._MakeInputFile('u-boot',
1201 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1202 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1204 # Now check the device tree has no microcode
1205 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1206 second = data[len(U_BOOT_NODTB_DATA):]
1208 fdt_len = self.GetFdtLen(second)
1209 self.assertEqual(dtb, second[:fdt_len])
1211 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1212 third = data[used_len:]
1213 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1215 def testUnknownPosSize(self):
1216 """Test that microcode must be placed within the image"""
1217 with self.assertRaises(ValueError) as e:
1218 self._DoReadFile('041_unknown_pos_size.dts', True)
1219 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1220 "entry 'invalid-entry'", str(e.exception))
1222 def testPackFsp(self):
1223 """Test that an image with a FSP binary can be created"""
1224 data = self._DoReadFile('042_intel_fsp.dts')
1225 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1227 def testPackCmc(self):
1228 """Test that an image with a CMC binary can be created"""
1229 data = self._DoReadFile('043_intel_cmc.dts')
1230 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1232 def testPackVbt(self):
1233 """Test that an image with a VBT binary can be created"""
1234 data = self._DoReadFile('046_intel_vbt.dts')
1235 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1237 def testSplBssPad(self):
1238 """Test that we can pad SPL's BSS with zeros"""
1239 # ELF file with a '__bss_size' symbol
1241 data = self._DoReadFile('047_spl_bss_pad.dts')
1242 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1245 def testSplBssPadMissing(self):
1246 """Test that a missing symbol is detected"""
1247 self._SetupSplElf('u_boot_ucode_ptr')
1248 with self.assertRaises(ValueError) as e:
1249 self._DoReadFile('047_spl_bss_pad.dts')
1250 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1253 def testPackStart16Spl(self):
1254 """Test that an image with an x86 start16 SPL region can be created"""
1255 data = self._DoReadFile('048_x86_start16_spl.dts')
1256 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1258 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1259 """Helper function for microcode tests
1261 We expect to see the following in the image, in order:
1262 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1264 u-boot.dtb with the microcode removed
1268 dts: Device tree file to use for test
1269 ucode_second: True if the microsecond entry is second instead of
1272 self._SetupSplElf('u_boot_ucode_ptr')
1273 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1274 ucode_second=ucode_second)
1275 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1276 b'ter somewhere in here', first)
1278 def testPackUbootSplMicrocode(self):
1279 """Test that x86 microcode can be handled correctly in SPL"""
1280 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1282 def testPackUbootSplMicrocodeReorder(self):
1283 """Test that order doesn't matter for microcode entries
1285 This is the same as testPackUbootSplMicrocode but when we process the
1286 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1287 entry, so we reply on binman to try later.
1289 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1292 def testPackMrc(self):
1293 """Test that an image with an MRC binary can be created"""
1294 data = self._DoReadFile('050_intel_mrc.dts')
1295 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1297 def testSplDtb(self):
1298 """Test that an image with spl/u-boot-spl.dtb can be created"""
1299 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1300 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1302 def testSplNoDtb(self):
1303 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1304 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1305 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1307 def testSymbols(self):
1308 """Test binman can assign symbols embedded in U-Boot"""
1309 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1310 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1311 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1312 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1314 self._SetupSplElf('u_boot_binman_syms')
1315 data = self._DoReadFile('053_symbols.dts')
1316 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
1317 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
1318 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1319 U_BOOT_SPL_DATA[20:])
1320 self.assertEqual(expected, data)
1322 def testPackUnitAddress(self):
1323 """Test that we support multiple binaries with the same name"""
1324 data = self._DoReadFile('054_unit_address.dts')
1325 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1327 def testSections(self):
1328 """Basic test of sections"""
1329 data = self._DoReadFile('055_sections.dts')
1330 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1331 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1332 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1333 self.assertEqual(expected, data)
1336 """Tests outputting a map of the images"""
1337 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1338 self.assertEqual('''ImagePos Offset Size Name
1339 00000000 00000000 00000028 main-section
1340 00000000 00000000 00000010 section@0
1341 00000000 00000000 00000004 u-boot
1342 00000010 00000010 00000010 section@1
1343 00000010 00000000 00000004 u-boot
1344 00000020 00000020 00000004 section@2
1345 00000020 00000000 00000004 u-boot
1348 def testNamePrefix(self):
1349 """Tests that name prefixes are used"""
1350 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1351 self.assertEqual('''ImagePos Offset Size Name
1352 00000000 00000000 00000028 main-section
1353 00000000 00000000 00000010 section@0
1354 00000000 00000000 00000004 ro-u-boot
1355 00000010 00000010 00000010 section@1
1356 00000010 00000000 00000004 rw-u-boot
1359 def testUnknownContents(self):
1360 """Test that obtaining the contents works as expected"""
1361 with self.assertRaises(ValueError) as e:
1362 self._DoReadFile('057_unknown_contents.dts', True)
1363 self.assertIn("Image '/binman': Internal error: Could not complete "
1364 "processing of contents: remaining ["
1365 "<binman.etype._testing.Entry__testing ", str(e.exception))
1367 def testBadChangeSize(self):
1368 """Test that trying to change the size of an entry fails"""
1370 state.SetAllowEntryExpansion(False)
1371 with self.assertRaises(ValueError) as e:
1372 self._DoReadFile('059_change_size.dts', True)
1373 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1376 state.SetAllowEntryExpansion(True)
1378 def testUpdateFdt(self):
1379 """Test that we can update the device tree with offset/size info"""
1380 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1382 dtb = fdt.Fdt(out_dtb_fname)
1384 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1388 '_testing:offset': 32,
1390 '_testing:image-pos': 32,
1391 'section@0/u-boot:offset': 0,
1392 'section@0/u-boot:size': len(U_BOOT_DATA),
1393 'section@0/u-boot:image-pos': 0,
1394 'section@0:offset': 0,
1395 'section@0:size': 16,
1396 'section@0:image-pos': 0,
1398 'section@1/u-boot:offset': 0,
1399 'section@1/u-boot:size': len(U_BOOT_DATA),
1400 'section@1/u-boot:image-pos': 16,
1401 'section@1:offset': 16,
1402 'section@1:size': 16,
1403 'section@1:image-pos': 16,
1407 def testUpdateFdtBad(self):
1408 """Test that we detect when ProcessFdt never completes"""
1409 with self.assertRaises(ValueError) as e:
1410 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1411 self.assertIn('Could not complete processing of Fdt: remaining '
1412 '[<binman.etype._testing.Entry__testing',
1415 def testEntryArgs(self):
1416 """Test passing arguments to entries from the command line"""
1418 'test-str-arg': 'test1',
1419 'test-int-arg': '456',
1421 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1422 self.assertIn('image', control.images)
1423 entry = control.images['image'].GetEntries()['_testing']
1424 self.assertEqual('test0', entry.test_str_fdt)
1425 self.assertEqual('test1', entry.test_str_arg)
1426 self.assertEqual(123, entry.test_int_fdt)
1427 self.assertEqual(456, entry.test_int_arg)
1429 def testEntryArgsMissing(self):
1430 """Test missing arguments and properties"""
1432 'test-int-arg': '456',
1434 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1435 entry = control.images['image'].GetEntries()['_testing']
1436 self.assertEqual('test0', entry.test_str_fdt)
1437 self.assertEqual(None, entry.test_str_arg)
1438 self.assertEqual(None, entry.test_int_fdt)
1439 self.assertEqual(456, entry.test_int_arg)
1441 def testEntryArgsRequired(self):
1442 """Test missing arguments and properties"""
1444 'test-int-arg': '456',
1446 with self.assertRaises(ValueError) as e:
1447 self._DoReadFileDtb('064_entry_args_required.dts')
1448 self.assertIn("Node '/binman/_testing': "
1449 'Missing required properties/entry args: test-str-arg, '
1450 'test-int-fdt, test-int-arg',
1453 def testEntryArgsInvalidFormat(self):
1454 """Test that an invalid entry-argument format is detected"""
1455 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1457 with self.assertRaises(ValueError) as e:
1458 self._DoBinman(*args)
1459 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1461 def testEntryArgsInvalidInteger(self):
1462 """Test that an invalid entry-argument integer is detected"""
1464 'test-int-arg': 'abc',
1466 with self.assertRaises(ValueError) as e:
1467 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1468 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1469 "'test-int-arg' (value 'abc') to integer",
1472 def testEntryArgsInvalidDatatype(self):
1473 """Test that an invalid entry-argument datatype is detected
1475 This test could be written in entry_test.py except that it needs
1476 access to control.entry_args, which seems more than that module should
1480 'test-bad-datatype-arg': '12',
1482 with self.assertRaises(ValueError) as e:
1483 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1484 entry_args=entry_args)
1485 self.assertIn('GetArg() internal error: Unknown data type ',
1489 """Test for a text entry type"""
1491 'test-id': TEXT_DATA,
1492 'test-id2': TEXT_DATA2,
1493 'test-id3': TEXT_DATA3,
1495 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1496 entry_args=entry_args)
1497 expected = (tools.ToBytes(TEXT_DATA) +
1498 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1499 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1500 b'some text' + b'more text')
1501 self.assertEqual(expected, data)
1503 def testEntryDocs(self):
1504 """Test for creation of entry documentation"""
1505 with test_util.capture_sys_output() as (stdout, stderr):
1506 control.WriteEntryDocs(control.GetEntryModules())
1507 self.assertTrue(len(stdout.getvalue()) > 0)
1509 def testEntryDocsMissing(self):
1510 """Test handling of missing entry documentation"""
1511 with self.assertRaises(ValueError) as e:
1512 with test_util.capture_sys_output() as (stdout, stderr):
1513 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1514 self.assertIn('Documentation is missing for modules: u_boot',
1518 """Basic test of generation of a flashrom fmap"""
1519 data = self._DoReadFile('067_fmap.dts')
1520 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1521 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1522 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1523 self.assertEqual(expected, data[:32])
1524 self.assertEqual(b'__FMAP__', fhdr.signature)
1525 self.assertEqual(1, fhdr.ver_major)
1526 self.assertEqual(0, fhdr.ver_minor)
1527 self.assertEqual(0, fhdr.base)
1528 self.assertEqual(16 + 16 +
1529 fmap_util.FMAP_HEADER_LEN +
1530 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1531 self.assertEqual(b'FMAP', fhdr.name)
1532 self.assertEqual(3, fhdr.nareas)
1533 for fentry in fentries:
1534 self.assertEqual(0, fentry.flags)
1536 self.assertEqual(0, fentries[0].offset)
1537 self.assertEqual(4, fentries[0].size)
1538 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1540 self.assertEqual(16, fentries[1].offset)
1541 self.assertEqual(4, fentries[1].size)
1542 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1544 self.assertEqual(32, fentries[2].offset)
1545 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1546 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1547 self.assertEqual(b'FMAP', fentries[2].name)
1549 def testBlobNamedByArg(self):
1550 """Test we can add a blob with the filename coming from an entry arg"""
1552 'cros-ec-rw-path': 'ecrw.bin',
1554 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1557 """Test for an fill entry type"""
1558 data = self._DoReadFile('069_fill.dts')
1559 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1560 self.assertEqual(expected, data)
1562 def testFillNoSize(self):
1563 """Test for an fill entry type with no size"""
1564 with self.assertRaises(ValueError) as e:
1565 self._DoReadFile('070_fill_no_size.dts')
1566 self.assertIn("'fill' entry must have a size property",
1569 def _HandleGbbCommand(self, pipe_list):
1570 """Fake calls to the futility utility"""
1571 if pipe_list[0][0] == 'futility':
1572 fname = pipe_list[0][-1]
1573 # Append our GBB data to the file, which will happen every time the
1574 # futility command is called.
1575 with open(fname, 'ab') as fd:
1577 return command.CommandResult()
1580 """Test for the Chromium OS Google Binary Block"""
1581 command.test_result = self._HandleGbbCommand
1583 'keydir': 'devkeys',
1584 'bmpblk': 'bmpblk.bin',
1586 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1589 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1590 tools.GetBytes(0, 0x2180 - 16))
1591 self.assertEqual(expected, data)
1593 def testGbbTooSmall(self):
1594 """Test for the Chromium OS Google Binary Block being large enough"""
1595 with self.assertRaises(ValueError) as e:
1596 self._DoReadFileDtb('072_gbb_too_small.dts')
1597 self.assertIn("Node '/binman/gbb': GBB is too small",
1600 def testGbbNoSize(self):
1601 """Test for the Chromium OS Google Binary Block having a size"""
1602 with self.assertRaises(ValueError) as e:
1603 self._DoReadFileDtb('073_gbb_no_size.dts')
1604 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1607 def _HandleVblockCommand(self, pipe_list):
1608 """Fake calls to the futility utility"""
1609 if pipe_list[0][0] == 'futility':
1610 fname = pipe_list[0][3]
1611 with open(fname, 'wb') as fd:
1612 fd.write(VBLOCK_DATA)
1613 return command.CommandResult()
1615 def testVblock(self):
1616 """Test for the Chromium OS Verified Boot Block"""
1617 command.test_result = self._HandleVblockCommand
1619 'keydir': 'devkeys',
1621 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1622 entry_args=entry_args)
1623 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1624 self.assertEqual(expected, data)
1626 def testVblockNoContent(self):
1627 """Test we detect a vblock which has no content to sign"""
1628 with self.assertRaises(ValueError) as e:
1629 self._DoReadFile('075_vblock_no_content.dts')
1630 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1631 'property', str(e.exception))
1633 def testVblockBadPhandle(self):
1634 """Test that we detect a vblock with an invalid phandle in contents"""
1635 with self.assertRaises(ValueError) as e:
1636 self._DoReadFile('076_vblock_bad_phandle.dts')
1637 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1638 '1000', str(e.exception))
1640 def testVblockBadEntry(self):
1641 """Test that we detect an entry that points to a non-entry"""
1642 with self.assertRaises(ValueError) as e:
1643 self._DoReadFile('077_vblock_bad_entry.dts')
1644 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1645 "'other'", str(e.exception))
1648 """Test that an image with TPL and its device tree can be created"""
1649 # ELF file with a '__bss_size' symbol
1651 data = self._DoReadFile('078_u_boot_tpl.dts')
1652 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1654 def testUsesPos(self):
1655 """Test that the 'pos' property cannot be used anymore"""
1656 with self.assertRaises(ValueError) as e:
1657 data = self._DoReadFile('079_uses_pos.dts')
1658 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1659 "'pos'", str(e.exception))
1661 def testFillZero(self):
1662 """Test for an fill entry type with a size of 0"""
1663 data = self._DoReadFile('080_fill_empty.dts')
1664 self.assertEqual(tools.GetBytes(0, 16), data)
1666 def testTextMissing(self):
1667 """Test for a text entry type where there is no text"""
1668 with self.assertRaises(ValueError) as e:
1669 self._DoReadFileDtb('066_text.dts',)
1670 self.assertIn("Node '/binman/text': No value provided for text label "
1671 "'test-id'", str(e.exception))
1673 def testPackStart16Tpl(self):
1674 """Test that an image with an x86 start16 TPL region can be created"""
1675 data = self._DoReadFile('081_x86_start16_tpl.dts')
1676 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1678 def testSelectImage(self):
1679 """Test that we can select which images to build"""
1680 expected = 'Skipping images: image1'
1682 # We should only get the expected message in verbose mode
1683 for verbosity in (0, 2):
1684 with test_util.capture_sys_output() as (stdout, stderr):
1685 retcode = self._DoTestFile('006_dual_image.dts',
1686 verbosity=verbosity,
1688 self.assertEqual(0, retcode)
1690 self.assertIn(expected, stdout.getvalue())
1692 self.assertNotIn(expected, stdout.getvalue())
1694 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1695 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1696 self._CleanupOutputDir()
1698 def testUpdateFdtAll(self):
1699 """Test that all device trees are updated with offset/size info"""
1700 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1703 'section:image-pos': 0,
1704 'u-boot-tpl-dtb:size': 513,
1705 'u-boot-spl-dtb:size': 513,
1706 'u-boot-spl-dtb:offset': 493,
1708 'section/u-boot-dtb:image-pos': 0,
1709 'u-boot-spl-dtb:image-pos': 493,
1710 'section/u-boot-dtb:size': 493,
1711 'u-boot-tpl-dtb:image-pos': 1006,
1712 'section/u-boot-dtb:offset': 0,
1713 'section:size': 493,
1715 'section:offset': 0,
1716 'u-boot-tpl-dtb:offset': 1006,
1720 # We expect three device-tree files in the output, one after the other.
1721 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1722 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1723 # main U-Boot tree. All three should have the same postions and offset.
1725 for item in ['', 'spl', 'tpl']:
1726 dtb = fdt.Fdt.FromData(data[start:])
1728 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1730 expected = dict(base_expected)
1733 self.assertEqual(expected, props)
1734 start += dtb._fdt_obj.totalsize()
1736 def testUpdateFdtOutput(self):
1737 """Test that output DTB files are updated"""
1739 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1740 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1742 # Unfortunately, compiling a source file always results in a file
1743 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1744 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1745 # binman as a file called u-boot.dtb. To fix this, copy the file
1746 # over to the expected place.
1748 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1749 'tpl/u-boot-tpl.dtb.out']:
1750 dtb = fdt.Fdt.FromData(data[start:])
1751 size = dtb._fdt_obj.totalsize()
1752 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1753 outdata = tools.ReadFile(pathname)
1754 name = os.path.split(fname)[0]
1757 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1759 orig_indata = dtb_data
1760 self.assertNotEqual(outdata, orig_indata,
1761 "Expected output file '%s' be updated" % pathname)
1762 self.assertEqual(outdata, data[start:start + size],
1763 "Expected output file '%s' to match output image" %
1769 def _decompress(self, data):
1770 return tools.Decompress(data, 'lz4')
1772 def testCompress(self):
1773 """Test compression of blobs"""
1775 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1776 use_real_dtb=True, update_dtb=True)
1777 dtb = fdt.Fdt(out_dtb_fname)
1779 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1780 orig = self._decompress(data)
1781 self.assertEquals(COMPRESS_DATA, orig)
1783 'blob:uncomp-size': len(COMPRESS_DATA),
1784 'blob:size': len(data),
1787 self.assertEqual(expected, props)
1789 def testFiles(self):
1790 """Test bringing in multiple files"""
1791 data = self._DoReadFile('084_files.dts')
1792 self.assertEqual(FILES_DATA, data)
1794 def testFilesCompress(self):
1795 """Test bringing in multiple files and compressing them"""
1797 data = self._DoReadFile('085_files_compress.dts')
1799 image = control.images['image']
1800 entries = image.GetEntries()
1801 files = entries['files']
1802 entries = files._entries
1805 for i in range(1, 3):
1807 start = entries[key].image_pos
1808 len = entries[key].size
1809 chunk = data[start:start + len]
1810 orig += self._decompress(chunk)
1812 self.assertEqual(FILES_DATA, orig)
1814 def testFilesMissing(self):
1815 """Test missing files"""
1816 with self.assertRaises(ValueError) as e:
1817 data = self._DoReadFile('086_files_none.dts')
1818 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1819 'no files', str(e.exception))
1821 def testFilesNoPattern(self):
1822 """Test missing files"""
1823 with self.assertRaises(ValueError) as e:
1824 data = self._DoReadFile('087_files_no_pattern.dts')
1825 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1828 def testExpandSize(self):
1829 """Test an expanding entry"""
1830 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1832 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1833 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1834 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1835 tools.GetBytes(ord('d'), 8))
1836 self.assertEqual(expect, data)
1837 self.assertEqual('''ImagePos Offset Size Name
1838 00000000 00000000 00000028 main-section
1839 00000000 00000000 00000008 fill
1840 00000008 00000008 00000004 u-boot
1841 0000000c 0000000c 00000004 section
1842 0000000c 00000000 00000003 intel-mrc
1843 00000010 00000010 00000004 u-boot2
1844 00000014 00000014 0000000c section2
1845 00000014 00000000 00000008 fill
1846 0000001c 00000008 00000004 u-boot
1847 00000020 00000020 00000008 fill2
1850 def testExpandSizeBad(self):
1851 """Test an expanding entry which fails to provide contents"""
1852 with test_util.capture_sys_output() as (stdout, stderr):
1853 with self.assertRaises(ValueError) as e:
1854 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1855 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1856 'expanding entry', str(e.exception))
1859 """Test hashing of the contents of an entry"""
1860 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1861 use_real_dtb=True, update_dtb=True)
1862 dtb = fdt.Fdt(out_dtb_fname)
1864 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1865 m = hashlib.sha256()
1866 m.update(U_BOOT_DATA)
1867 self.assertEqual(m.digest(), b''.join(hash_node.value))
1869 def testHashNoAlgo(self):
1870 with self.assertRaises(ValueError) as e:
1871 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1872 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1873 'hash node', str(e.exception))
1875 def testHashBadAlgo(self):
1876 with self.assertRaises(ValueError) as e:
1877 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1878 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1881 def testHashSection(self):
1882 """Test hashing of the contents of an entry"""
1883 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1884 use_real_dtb=True, update_dtb=True)
1885 dtb = fdt.Fdt(out_dtb_fname)
1887 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1888 m = hashlib.sha256()
1889 m.update(U_BOOT_DATA)
1890 m.update(tools.GetBytes(ord('a'), 16))
1891 self.assertEqual(m.digest(), b''.join(hash_node.value))
1893 def testPackUBootTplMicrocode(self):
1894 """Test that x86 microcode can be handled correctly in TPL
1896 We expect to see the following in the image, in order:
1897 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1899 u-boot-tpl.dtb with the microcode removed
1902 self._SetupTplElf('u_boot_ucode_ptr')
1903 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1904 U_BOOT_TPL_NODTB_DATA)
1905 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1906 b'ter somewhere in here', first)
1908 def testFmapX86(self):
1909 """Basic test of generation of a flashrom fmap"""
1910 data = self._DoReadFile('094_fmap_x86.dts')
1911 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1912 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1913 self.assertEqual(expected, data[:32])
1914 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1916 self.assertEqual(0x100, fhdr.image_size)
1918 self.assertEqual(0, fentries[0].offset)
1919 self.assertEqual(4, fentries[0].size)
1920 self.assertEqual(b'U_BOOT', fentries[0].name)
1922 self.assertEqual(4, fentries[1].offset)
1923 self.assertEqual(3, fentries[1].size)
1924 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1926 self.assertEqual(32, fentries[2].offset)
1927 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1928 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1929 self.assertEqual(b'FMAP', fentries[2].name)
1931 def testFmapX86Section(self):
1932 """Basic test of generation of a flashrom fmap"""
1933 data = self._DoReadFile('095_fmap_x86_section.dts')
1934 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1935 self.assertEqual(expected, data[:32])
1936 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1938 self.assertEqual(0x100, fhdr.image_size)
1940 self.assertEqual(0, fentries[0].offset)
1941 self.assertEqual(4, fentries[0].size)
1942 self.assertEqual(b'U_BOOT', fentries[0].name)
1944 self.assertEqual(4, fentries[1].offset)
1945 self.assertEqual(3, fentries[1].size)
1946 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1948 self.assertEqual(36, fentries[2].offset)
1949 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1950 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1951 self.assertEqual(b'FMAP', fentries[2].name)
1954 """Basic test of ELF entries"""
1957 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1958 TestFunctional._MakeInputFile('-boot', fd.read())
1959 data = self._DoReadFile('096_elf.dts')
1961 def testElfStrip(self):
1962 """Basic test of ELF entries"""
1964 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1965 TestFunctional._MakeInputFile('-boot', fd.read())
1966 data = self._DoReadFile('097_elf_strip.dts')
1968 def testPackOverlapMap(self):
1969 """Test that overlapping regions are detected"""
1970 with test_util.capture_sys_output() as (stdout, stderr):
1971 with self.assertRaises(ValueError) as e:
1972 self._DoTestFile('014_pack_overlap.dts', map=True)
1973 map_fname = tools.GetOutputFilename('image.map')
1974 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1977 # We should not get an inmage, but there should be a map file
1978 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1979 self.assertTrue(os.path.exists(map_fname))
1980 map_data = tools.ReadFile(map_fname, binary=False)
1981 self.assertEqual('''ImagePos Offset Size Name
1982 <none> 00000000 00000007 main-section
1983 <none> 00000000 00000004 u-boot
1984 <none> 00000003 00000004 u-boot-align
1987 def testPackRefCode(self):
1988 """Test that an image with an Intel Reference code binary works"""
1989 data = self._DoReadFile('100_intel_refcode.dts')
1990 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1992 def testSectionOffset(self):
1993 """Tests use of a section with an offset"""
1994 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1996 self.assertEqual('''ImagePos Offset Size Name
1997 00000000 00000000 00000038 main-section
1998 00000004 00000004 00000010 section@0
1999 00000004 00000000 00000004 u-boot
2000 00000018 00000018 00000010 section@1
2001 00000018 00000000 00000004 u-boot
2002 0000002c 0000002c 00000004 section@2
2003 0000002c 00000000 00000004 u-boot
2005 self.assertEqual(data,
2006 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2007 tools.GetBytes(0x21, 12) +
2008 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2009 tools.GetBytes(0x61, 12) +
2010 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2011 tools.GetBytes(0x26, 8))
2013 def testCbfsRaw(self):
2014 """Test base handling of a Coreboot Filesystem (CBFS)
2016 The exact contents of the CBFS is verified by similar tests in
2017 cbfs_util_test.py. The tests here merely check that the files added to
2018 the CBFS can be found in the final image.
2020 data = self._DoReadFile('102_cbfs_raw.dts')
2023 cbfs = cbfs_util.CbfsReader(data)
2024 self.assertEqual(size, cbfs.rom_size)
2026 self.assertIn('u-boot-dtb', cbfs.files)
2027 cfile = cbfs.files['u-boot-dtb']
2028 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2030 def testCbfsArch(self):
2031 """Test on non-x86 architecture"""
2032 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2035 cbfs = cbfs_util.CbfsReader(data)
2036 self.assertEqual(size, cbfs.rom_size)
2038 self.assertIn('u-boot-dtb', cbfs.files)
2039 cfile = cbfs.files['u-boot-dtb']
2040 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2042 def testCbfsStage(self):
2043 """Tests handling of a Coreboot Filesystem (CBFS)"""
2044 if not elf.ELF_TOOLS:
2045 self.skipTest('Python elftools not available')
2046 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2047 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2050 data = self._DoReadFile('104_cbfs_stage.dts')
2051 cbfs = cbfs_util.CbfsReader(data)
2052 self.assertEqual(size, cbfs.rom_size)
2054 self.assertIn('u-boot', cbfs.files)
2055 cfile = cbfs.files['u-boot']
2056 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2058 def testCbfsRawCompress(self):
2059 """Test handling of compressing raw files"""
2061 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2064 cbfs = cbfs_util.CbfsReader(data)
2065 self.assertIn('u-boot', cbfs.files)
2066 cfile = cbfs.files['u-boot']
2067 self.assertEqual(COMPRESS_DATA, cfile.data)
2069 def testCbfsBadArch(self):
2070 """Test handling of a bad architecture"""
2071 with self.assertRaises(ValueError) as e:
2072 self._DoReadFile('106_cbfs_bad_arch.dts')
2073 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2075 def testCbfsNoSize(self):
2076 """Test handling of a missing size property"""
2077 with self.assertRaises(ValueError) as e:
2078 self._DoReadFile('107_cbfs_no_size.dts')
2079 self.assertIn('entry must have a size property', str(e.exception))
2081 def testCbfsNoCOntents(self):
2082 """Test handling of a CBFS entry which does not provide contentsy"""
2083 with self.assertRaises(ValueError) as e:
2084 self._DoReadFile('108_cbfs_no_contents.dts')
2085 self.assertIn('Could not complete processing of contents',
2088 def testCbfsBadCompress(self):
2089 """Test handling of a bad architecture"""
2090 with self.assertRaises(ValueError) as e:
2091 self._DoReadFile('109_cbfs_bad_compress.dts')
2092 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2095 def testCbfsNamedEntries(self):
2096 """Test handling of named entries"""
2097 data = self._DoReadFile('110_cbfs_name.dts')
2099 cbfs = cbfs_util.CbfsReader(data)
2100 self.assertIn('FRED', cbfs.files)
2101 cfile1 = cbfs.files['FRED']
2102 self.assertEqual(U_BOOT_DATA, cfile1.data)
2104 self.assertIn('hello', cbfs.files)
2105 cfile2 = cbfs.files['hello']
2106 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2108 def _SetupIfwi(self, fname):
2109 """Set up to run an IFWI test
2112 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2117 # Intel Integrated Firmware Image (IFWI) file
2118 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2120 TestFunctional._MakeInputFile(fname,data)
2122 def _CheckIfwi(self, data):
2123 """Check that an image with an IFWI contains the correct output
2126 data: Conents of output file
2128 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2129 if data[:0x1000] != expected_desc:
2130 self.fail('Expected descriptor binary at start of image')
2132 # We expect to find the TPL wil in subpart IBBP entry IBBL
2133 image_fname = tools.GetOutputFilename('image.bin')
2134 tpl_fname = tools.GetOutputFilename('tpl.out')
2135 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2136 subpart='IBBP', entry_name='IBBL')
2138 tpl_data = tools.ReadFile(tpl_fname)
2139 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2141 def testPackX86RomIfwi(self):
2142 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2143 self._SetupIfwi('fitimage.bin')
2144 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2145 self._CheckIfwi(data)
2147 def testPackX86RomIfwiNoDesc(self):
2148 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2149 self._SetupIfwi('ifwi.bin')
2150 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2151 self._CheckIfwi(data)
2153 def testPackX86RomIfwiNoData(self):
2154 """Test that an x86 ROM with IFWI handles missing data"""
2155 self._SetupIfwi('ifwi.bin')
2156 with self.assertRaises(ValueError) as e:
2157 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2158 self.assertIn('Could not complete processing of contents',
2161 def testCbfsOffset(self):
2162 """Test a CBFS with files at particular offsets
2164 Like all CFBS tests, this is just checking the logic that calls
2165 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2167 data = self._DoReadFile('114_cbfs_offset.dts')
2170 cbfs = cbfs_util.CbfsReader(data)
2171 self.assertEqual(size, cbfs.rom_size)
2173 self.assertIn('u-boot', cbfs.files)
2174 cfile = cbfs.files['u-boot']
2175 self.assertEqual(U_BOOT_DATA, cfile.data)
2176 self.assertEqual(0x40, cfile.cbfs_offset)
2178 self.assertIn('u-boot-dtb', cbfs.files)
2179 cfile2 = cbfs.files['u-boot-dtb']
2180 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2181 self.assertEqual(0x140, cfile2.cbfs_offset)
2183 def testFdtmap(self):
2184 """Test an FDT map can be inserted in the image"""
2185 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2186 fdtmap_data = data[len(U_BOOT_DATA):]
2187 magic = fdtmap_data[:8]
2188 self.assertEqual(b'_FDTMAP_', magic)
2189 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2191 fdt_data = fdtmap_data[16:]
2192 dtb = fdt.Fdt.FromData(fdt_data)
2194 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2199 'u-boot:size': len(U_BOOT_DATA),
2200 'u-boot:image-pos': 0,
2201 'fdtmap:image-pos': 4,
2203 'fdtmap:size': len(fdtmap_data),
2207 def testFdtmapNoMatch(self):
2208 """Check handling of an FDT map when the section cannot be found"""
2209 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2211 # Mangle the section name, which should cause a mismatch between the
2212 # correct FDT path and the one expected by the section
2213 image = control.images['image']
2214 image._node.path += '-suffix'
2215 entries = image.GetEntries()
2216 fdtmap = entries['fdtmap']
2217 with self.assertRaises(ValueError) as e:
2219 self.assertIn("Cannot locate node for path '/binman-suffix'",
2222 def testFdtmapHeader(self):
2223 """Test an FDT map and image header can be inserted in the image"""
2224 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2225 fdtmap_pos = len(U_BOOT_DATA)
2226 fdtmap_data = data[fdtmap_pos:]
2227 fdt_data = fdtmap_data[16:]
2228 dtb = fdt.Fdt.FromData(fdt_data)
2229 fdt_size = dtb.GetFdtObj().totalsize()
2230 hdr_data = data[-8:]
2231 self.assertEqual(b'BinM', hdr_data[:4])
2232 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2233 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2235 def testFdtmapHeaderStart(self):
2236 """Test an image header can be inserted at the image start"""
2237 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2238 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2240 self.assertEqual(b'BinM', hdr_data[:4])
2241 offset = struct.unpack('<I', hdr_data[4:])[0]
2242 self.assertEqual(fdtmap_pos, offset)
2244 def testFdtmapHeaderPos(self):
2245 """Test an image header can be inserted at a chosen position"""
2246 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2247 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2248 hdr_data = data[0x80:0x88]
2249 self.assertEqual(b'BinM', hdr_data[:4])
2250 offset = struct.unpack('<I', hdr_data[4:])[0]
2251 self.assertEqual(fdtmap_pos, offset)
2253 def testHeaderMissingFdtmap(self):
2254 """Test an image header requires an fdtmap"""
2255 with self.assertRaises(ValueError) as e:
2256 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2257 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2260 def testHeaderNoLocation(self):
2261 """Test an image header with a no specified location is detected"""
2262 with self.assertRaises(ValueError) as e:
2263 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2264 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2267 def testEntryExpand(self):
2268 """Test expanding an entry after it is packed"""
2269 data = self._DoReadFile('121_entry_expand.dts')
2270 self.assertEqual(b'aaa', data[:3])
2271 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2272 self.assertEqual(b'aaa', data[-3:])
2274 def testEntryExpandBad(self):
2275 """Test expanding an entry after it is packed, twice"""
2276 with self.assertRaises(ValueError) as e:
2277 self._DoReadFile('122_entry_expand_twice.dts')
2278 self.assertIn("Image '/binman': Entries changed size after packing",
2281 def testEntryExpandSection(self):
2282 """Test expanding an entry within a section after it is packed"""
2283 data = self._DoReadFile('123_entry_expand_section.dts')
2284 self.assertEqual(b'aaa', data[:3])
2285 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2286 self.assertEqual(b'aaa', data[-3:])
2288 def testCompressDtb(self):
2289 """Test that compress of device-tree files is supported"""
2291 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2292 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2293 comp_data = data[len(U_BOOT_DATA):]
2294 orig = self._decompress(comp_data)
2295 dtb = fdt.Fdt.FromData(orig)
2297 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2299 'u-boot:size': len(U_BOOT_DATA),
2300 'u-boot-dtb:uncomp-size': len(orig),
2301 'u-boot-dtb:size': len(comp_data),
2304 self.assertEqual(expected, props)
2306 def testCbfsUpdateFdt(self):
2307 """Test that we can update the device tree with CBFS offset/size info"""
2309 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2311 dtb = fdt.Fdt(out_dtb_fname)
2313 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2314 del props['cbfs/u-boot:size']
2320 'cbfs:size': len(data),
2321 'cbfs:image-pos': 0,
2322 'cbfs/u-boot:offset': 0x38,
2323 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2324 'cbfs/u-boot:image-pos': 0x38,
2325 'cbfs/u-boot-dtb:offset': 0xb8,
2326 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2327 'cbfs/u-boot-dtb:image-pos': 0xb8,
2330 def testCbfsBadType(self):
2331 """Test an image header with a no specified location is detected"""
2332 with self.assertRaises(ValueError) as e:
2333 self._DoReadFile('126_cbfs_bad_type.dts')
2334 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2337 """Test listing the files in an image"""
2339 data = self._DoReadFile('127_list.dts')
2340 image = control.images['image']
2341 entries = image.BuildEntryList()
2342 self.assertEqual(7, len(entries))
2345 self.assertEqual(0, ent.indent)
2346 self.assertEqual('main-section', ent.name)
2347 self.assertEqual('section', ent.etype)
2348 self.assertEqual(len(data), ent.size)
2349 self.assertEqual(0, ent.image_pos)
2350 self.assertEqual(None, ent.uncomp_size)
2351 self.assertEqual(0, ent.offset)
2354 self.assertEqual(1, ent.indent)
2355 self.assertEqual('u-boot', ent.name)
2356 self.assertEqual('u-boot', ent.etype)
2357 self.assertEqual(len(U_BOOT_DATA), ent.size)
2358 self.assertEqual(0, ent.image_pos)
2359 self.assertEqual(None, ent.uncomp_size)
2360 self.assertEqual(0, ent.offset)
2363 self.assertEqual(1, ent.indent)
2364 self.assertEqual('section', ent.name)
2365 self.assertEqual('section', ent.etype)
2366 section_size = ent.size
2367 self.assertEqual(0x100, ent.image_pos)
2368 self.assertEqual(None, ent.uncomp_size)
2369 self.assertEqual(0x100, ent.offset)
2372 self.assertEqual(2, ent.indent)
2373 self.assertEqual('cbfs', ent.name)
2374 self.assertEqual('cbfs', ent.etype)
2375 self.assertEqual(0x400, ent.size)
2376 self.assertEqual(0x100, ent.image_pos)
2377 self.assertEqual(None, ent.uncomp_size)
2378 self.assertEqual(0, ent.offset)
2381 self.assertEqual(3, ent.indent)
2382 self.assertEqual('u-boot', ent.name)
2383 self.assertEqual('u-boot', ent.etype)
2384 self.assertEqual(len(U_BOOT_DATA), ent.size)
2385 self.assertEqual(0x138, ent.image_pos)
2386 self.assertEqual(None, ent.uncomp_size)
2387 self.assertEqual(0x38, ent.offset)
2390 self.assertEqual(3, ent.indent)
2391 self.assertEqual('u-boot-dtb', ent.name)
2392 self.assertEqual('text', ent.etype)
2393 self.assertGreater(len(COMPRESS_DATA), ent.size)
2394 self.assertEqual(0x178, ent.image_pos)
2395 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2396 self.assertEqual(0x78, ent.offset)
2399 self.assertEqual(2, ent.indent)
2400 self.assertEqual('u-boot-dtb', ent.name)
2401 self.assertEqual('u-boot-dtb', ent.etype)
2402 self.assertEqual(0x500, ent.image_pos)
2403 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2405 # Compressing this data expands it since headers are added
2406 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2407 self.assertEqual(0x400, ent.offset)
2409 self.assertEqual(len(data), 0x100 + section_size)
2410 self.assertEqual(section_size, 0x400 + dtb_size)
2412 def testFindFdtmap(self):
2413 """Test locating an FDT map in an image"""
2415 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2416 image = control.images['image']
2417 entries = image.GetEntries()
2418 entry = entries['fdtmap']
2419 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2421 def testFindFdtmapMissing(self):
2422 """Test failing to locate an FDP map"""
2423 data = self._DoReadFile('005_simple.dts')
2424 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2426 def testFindImageHeader(self):
2427 """Test locating a image header"""
2429 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2430 image = control.images['image']
2431 entries = image.GetEntries()
2432 entry = entries['fdtmap']
2433 # The header should point to the FDT map
2434 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2436 def testFindImageHeaderStart(self):
2437 """Test locating a image header located at the start of an image"""
2438 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2439 image = control.images['image']
2440 entries = image.GetEntries()
2441 entry = entries['fdtmap']
2442 # The header should point to the FDT map
2443 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2445 def testFindImageHeaderMissing(self):
2446 """Test failing to locate an image header"""
2447 data = self._DoReadFile('005_simple.dts')
2448 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2450 def testReadImage(self):
2451 """Test reading an image and accessing its FDT map"""
2453 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2454 image_fname = tools.GetOutputFilename('image.bin')
2455 orig_image = control.images['image']
2456 image = Image.FromFile(image_fname)
2457 self.assertEqual(orig_image.GetEntries().keys(),
2458 image.GetEntries().keys())
2460 orig_entry = orig_image.GetEntries()['fdtmap']
2461 entry = image.GetEntries()['fdtmap']
2462 self.assertEquals(orig_entry.offset, entry.offset)
2463 self.assertEquals(orig_entry.size, entry.size)
2464 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2466 def testReadImageNoHeader(self):
2467 """Test accessing an image's FDT map without an image header"""
2469 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2470 image_fname = tools.GetOutputFilename('image.bin')
2471 image = Image.FromFile(image_fname)
2472 self.assertTrue(isinstance(image, Image))
2473 self.assertEqual('image', image.image_name[-5:])
2475 def testReadImageFail(self):
2476 """Test failing to read an image image's FDT map"""
2477 self._DoReadFile('005_simple.dts')
2478 image_fname = tools.GetOutputFilename('image.bin')
2479 with self.assertRaises(ValueError) as e:
2480 image = Image.FromFile(image_fname)
2481 self.assertIn("Cannot find FDT map in image", str(e.exception))
2483 def testListCmd(self):
2484 """Test listing the files in an image using an Fdtmap"""
2486 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2488 # lz4 compression size differs depending on the version
2489 image = control.images['image']
2490 entries = image.GetEntries()
2491 section_size = entries['section'].size
2492 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2493 fdtmap_offset = entries['fdtmap'].offset
2496 tmpdir, updated_fname = self._SetupImageInTmpdir()
2497 with test_util.capture_sys_output() as (stdout, stderr):
2498 self._DoBinman('ls', '-i', updated_fname)
2500 shutil.rmtree(tmpdir)
2501 lines = stdout.getvalue().splitlines()
2503 'Name Image-pos Size Entry-type Offset Uncomp-size',
2504 '----------------------------------------------------------------------',
2505 'main-section 0 c00 section 0',
2506 ' u-boot 0 4 u-boot 0',
2507 ' section 100 %x section 100' % section_size,
2508 ' cbfs 100 400 cbfs 0',
2509 ' u-boot 138 4 u-boot 38',
2510 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2511 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2512 ' fdtmap %x 3bd fdtmap %x' %
2513 (fdtmap_offset, fdtmap_offset),
2514 ' image-header bf8 8 image-header bf8',
2516 self.assertEqual(expected, lines)
2518 def testListCmdFail(self):
2519 """Test failing to list an image"""
2520 self._DoReadFile('005_simple.dts')
2522 tmpdir, updated_fname = self._SetupImageInTmpdir()
2523 with self.assertRaises(ValueError) as e:
2524 self._DoBinman('ls', '-i', updated_fname)
2526 shutil.rmtree(tmpdir)
2527 self.assertIn("Cannot find FDT map in image", str(e.exception))
2529 def _RunListCmd(self, paths, expected):
2530 """List out entries and check the result
2533 paths: List of paths to pass to the list command
2534 expected: Expected list of filenames to be returned, in order
2537 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2538 image_fname = tools.GetOutputFilename('image.bin')
2539 image = Image.FromFile(image_fname)
2540 lines = image.GetListEntries(paths)[1]
2541 files = [line[0].strip() for line in lines[1:]]
2542 self.assertEqual(expected, files)
2544 def testListCmdSection(self):
2545 """Test listing the files in a section"""
2546 self._RunListCmd(['section'],
2547 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2549 def testListCmdFile(self):
2550 """Test listing a particular file"""
2551 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2553 def testListCmdWildcard(self):
2554 """Test listing a wildcarded file"""
2555 self._RunListCmd(['*boot*'],
2556 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2558 def testListCmdWildcardMulti(self):
2559 """Test listing a wildcarded file"""
2560 self._RunListCmd(['*cb*', '*head*'],
2561 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2563 def testListCmdEmpty(self):
2564 """Test listing a wildcarded file"""
2565 self._RunListCmd(['nothing'], [])
2567 def testListCmdPath(self):
2568 """Test listing the files in a sub-entry of a section"""
2569 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2571 def _RunExtractCmd(self, entry_name, decomp=True):
2572 """Extract an entry from an image
2575 entry_name: Entry name to extract
2576 decomp: True to decompress the data if compressed, False to leave
2577 it in its raw uncompressed format
2583 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2584 image_fname = tools.GetOutputFilename('image.bin')
2585 return control.ReadEntry(image_fname, entry_name, decomp)
2587 def testExtractSimple(self):
2588 """Test extracting a single file"""
2589 data = self._RunExtractCmd('u-boot')
2590 self.assertEqual(U_BOOT_DATA, data)
2592 def testExtractSection(self):
2593 """Test extracting the files in a section"""
2594 data = self._RunExtractCmd('section')
2595 cbfs_data = data[:0x400]
2596 cbfs = cbfs_util.CbfsReader(cbfs_data)
2597 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2598 dtb_data = data[0x400:]
2599 dtb = self._decompress(dtb_data)
2600 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2602 def testExtractCompressed(self):
2603 """Test extracting compressed data"""
2604 data = self._RunExtractCmd('section/u-boot-dtb')
2605 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2607 def testExtractRaw(self):
2608 """Test extracting compressed data without decompressing it"""
2609 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2610 dtb = self._decompress(data)
2611 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2613 def testExtractCbfs(self):
2614 """Test extracting CBFS data"""
2615 data = self._RunExtractCmd('section/cbfs/u-boot')
2616 self.assertEqual(U_BOOT_DATA, data)
2618 def testExtractCbfsCompressed(self):
2619 """Test extracting CBFS compressed data"""
2620 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2621 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2623 def testExtractCbfsRaw(self):
2624 """Test extracting CBFS compressed data without decompressing it"""
2625 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2626 dtb = tools.Decompress(data, 'lzma', with_header=False)
2627 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2629 def testExtractBadEntry(self):
2630 """Test extracting a bad section path"""
2631 with self.assertRaises(ValueError) as e:
2632 self._RunExtractCmd('section/does-not-exist')
2633 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2636 def testExtractMissingFile(self):
2637 """Test extracting file that does not exist"""
2638 with self.assertRaises(IOError) as e:
2639 control.ReadEntry('missing-file', 'name')
2641 def testExtractBadFile(self):
2642 """Test extracting an invalid file"""
2643 fname = os.path.join(self._indir, 'badfile')
2644 tools.WriteFile(fname, b'')
2645 with self.assertRaises(ValueError) as e:
2646 control.ReadEntry(fname, 'name')
2648 def testExtractCmd(self):
2649 """Test extracting a file fron an image on the command line"""
2651 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2652 fname = os.path.join(self._indir, 'output.extact')
2654 tmpdir, updated_fname = self._SetupImageInTmpdir()
2655 with test_util.capture_sys_output() as (stdout, stderr):
2656 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2659 shutil.rmtree(tmpdir)
2660 data = tools.ReadFile(fname)
2661 self.assertEqual(U_BOOT_DATA, data)
2663 def testExtractOneEntry(self):
2664 """Test extracting a single entry fron an image """
2666 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2667 image_fname = tools.GetOutputFilename('image.bin')
2668 fname = os.path.join(self._indir, 'output.extact')
2669 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2670 data = tools.ReadFile(fname)
2671 self.assertEqual(U_BOOT_DATA, data)
2673 def _CheckExtractOutput(self, decomp):
2674 """Helper to test file output with and without decompression
2677 decomp: True to decompress entry data, False to output it raw
2679 def _CheckPresent(entry_path, expect_data, expect_size=None):
2680 """Check and remove expected file
2682 This checks the data/size of a file and removes the file both from
2683 the outfiles set and from the output directory. Once all files are
2684 processed, both the set and directory should be empty.
2687 entry_path: Entry path
2688 expect_data: Data to expect in file, or None to skip check
2689 expect_size: Size of data to expect in file, or None to skip
2691 path = os.path.join(outdir, entry_path)
2692 data = tools.ReadFile(path)
2695 self.assertEqual(expect_data, data)
2697 self.assertEqual(expect_size, len(data))
2698 outfiles.remove(path)
2700 def _CheckDirPresent(name):
2701 """Remove expected directory
2703 This gives an error if the directory does not exist as expected
2706 name: Name of directory to remove
2708 path = os.path.join(outdir, name)
2711 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2712 image_fname = tools.GetOutputFilename('image.bin')
2713 outdir = os.path.join(self._indir, 'extract')
2714 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2716 # Create a set of all file that were output (should be 9)
2718 for root, dirs, files in os.walk(outdir):
2719 outfiles |= set([os.path.join(root, fname) for fname in files])
2720 self.assertEqual(9, len(outfiles))
2721 self.assertEqual(9, len(einfos))
2723 image = control.images['image']
2724 entries = image.GetEntries()
2726 # Check the 9 files in various ways
2727 section = entries['section']
2728 section_entries = section.GetEntries()
2729 cbfs_entries = section_entries['cbfs'].GetEntries()
2730 _CheckPresent('u-boot', U_BOOT_DATA)
2731 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2732 dtb_len = EXTRACT_DTB_SIZE
2734 dtb_len = cbfs_entries['u-boot-dtb'].size
2735 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2737 dtb_len = section_entries['u-boot-dtb'].size
2738 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2740 fdtmap = entries['fdtmap']
2741 _CheckPresent('fdtmap', fdtmap.data)
2742 hdr = entries['image-header']
2743 _CheckPresent('image-header', hdr.data)
2745 _CheckPresent('section/root', section.data)
2746 cbfs = section_entries['cbfs']
2747 _CheckPresent('section/cbfs/root', cbfs.data)
2748 data = tools.ReadFile(image_fname)
2749 _CheckPresent('root', data)
2751 # There should be no files left. Remove all the directories to check.
2752 # If there are any files/dirs remaining, one of these checks will fail.
2753 self.assertEqual(0, len(outfiles))
2754 _CheckDirPresent('section/cbfs')
2755 _CheckDirPresent('section')
2756 _CheckDirPresent('')
2757 self.assertFalse(os.path.exists(outdir))
2759 def testExtractAllEntries(self):
2760 """Test extracting all entries"""
2762 self._CheckExtractOutput(decomp=True)
2764 def testExtractAllEntriesRaw(self):
2765 """Test extracting all entries without decompressing them"""
2767 self._CheckExtractOutput(decomp=False)
2769 def testExtractSelectedEntries(self):
2770 """Test extracting some entries"""
2772 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2773 image_fname = tools.GetOutputFilename('image.bin')
2774 outdir = os.path.join(self._indir, 'extract')
2775 einfos = control.ExtractEntries(image_fname, None, outdir,
2778 # File output is tested by testExtractAllEntries(), so just check that
2779 # the expected entries are selected
2780 names = [einfo.name for einfo in einfos]
2781 self.assertEqual(names,
2782 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2784 def testExtractNoEntryPaths(self):
2785 """Test extracting some entries"""
2787 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2788 image_fname = tools.GetOutputFilename('image.bin')
2789 with self.assertRaises(ValueError) as e:
2790 control.ExtractEntries(image_fname, 'fname', None, [])
2791 self.assertIn('Must specify an entry path to write with -f',
2794 def testExtractTooManyEntryPaths(self):
2795 """Test extracting some entries"""
2797 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2798 image_fname = tools.GetOutputFilename('image.bin')
2799 with self.assertRaises(ValueError) as e:
2800 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2801 self.assertIn('Must specify exactly one entry path to write with -f',
2804 def testPackAlignSection(self):
2805 """Test that sections can have alignment"""
2806 self._DoReadFile('131_pack_align_section.dts')
2808 self.assertIn('image', control.images)
2809 image = control.images['image']
2810 entries = image.GetEntries()
2811 self.assertEqual(3, len(entries))
2814 self.assertIn('u-boot', entries)
2815 entry = entries['u-boot']
2816 self.assertEqual(0, entry.offset)
2817 self.assertEqual(0, entry.image_pos)
2818 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2819 self.assertEqual(len(U_BOOT_DATA), entry.size)
2822 self.assertIn('section0', entries)
2823 section0 = entries['section0']
2824 self.assertEqual(0x10, section0.offset)
2825 self.assertEqual(0x10, section0.image_pos)
2826 self.assertEqual(len(U_BOOT_DATA), section0.size)
2829 section_entries = section0.GetEntries()
2830 self.assertIn('u-boot', section_entries)
2831 entry = section_entries['u-boot']
2832 self.assertEqual(0, entry.offset)
2833 self.assertEqual(0x10, entry.image_pos)
2834 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2835 self.assertEqual(len(U_BOOT_DATA), entry.size)
2838 self.assertIn('section1', entries)
2839 section1 = entries['section1']
2840 self.assertEqual(0x14, section1.offset)
2841 self.assertEqual(0x14, section1.image_pos)
2842 self.assertEqual(0x20, section1.size)
2845 section_entries = section1.GetEntries()
2846 self.assertIn('u-boot', section_entries)
2847 entry = section_entries['u-boot']
2848 self.assertEqual(0, entry.offset)
2849 self.assertEqual(0x14, entry.image_pos)
2850 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2851 self.assertEqual(len(U_BOOT_DATA), entry.size)
2854 self.assertIn('section2', section_entries)
2855 section2 = section_entries['section2']
2856 self.assertEqual(0x4, section2.offset)
2857 self.assertEqual(0x18, section2.image_pos)
2858 self.assertEqual(4, section2.size)
2861 section_entries = section2.GetEntries()
2862 self.assertIn('u-boot', section_entries)
2863 entry = section_entries['u-boot']
2864 self.assertEqual(0, entry.offset)
2865 self.assertEqual(0x18, entry.image_pos)
2866 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2867 self.assertEqual(len(U_BOOT_DATA), entry.size)
2869 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2870 dts='132_replace.dts'):
2871 """Replace an entry in an image
2873 This writes the entry data to update it, then opens the updated file and
2874 returns the value that it now finds there.
2877 entry_name: Entry name to replace
2878 data: Data to replace it with
2879 decomp: True to compress the data if needed, False if data is
2880 already compressed so should be used as is
2881 allow_resize: True to allow entries to change size, False to raise
2887 data from fdtmap (excluding header)
2888 Image object that was modified
2890 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2893 self.assertIn('image', control.images)
2894 image = control.images['image']
2895 entries = image.GetEntries()
2896 orig_dtb_data = entries['u-boot-dtb'].data
2897 orig_fdtmap_data = entries['fdtmap'].data
2899 image_fname = tools.GetOutputFilename('image.bin')
2900 updated_fname = tools.GetOutputFilename('image-updated.bin')
2901 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2902 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2904 data = control.ReadEntry(updated_fname, entry_name, decomp)
2906 # The DT data should not change unless resized:
2907 if not allow_resize:
2908 new_dtb_data = entries['u-boot-dtb'].data
2909 self.assertEqual(new_dtb_data, orig_dtb_data)
2910 new_fdtmap_data = entries['fdtmap'].data
2911 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2913 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2915 def testReplaceSimple(self):
2916 """Test replacing a single file"""
2917 expected = b'x' * len(U_BOOT_DATA)
2918 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2920 self.assertEqual(expected, data)
2922 # Test that the state looks right. There should be an FDT for the fdtmap
2923 # that we jsut read back in, and it should match what we find in the
2924 # 'control' tables. Checking for an FDT that does not exist should
2926 path, fdtmap = state.GetFdtContents('fdtmap')
2927 self.assertIsNotNone(path)
2928 self.assertEqual(expected_fdtmap, fdtmap)
2930 dtb = state.GetFdtForEtype('fdtmap')
2931 self.assertEqual(dtb.GetContents(), fdtmap)
2933 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2934 self.assertIsNone(missing_path)
2935 self.assertIsNone(missing_fdtmap)
2937 missing_dtb = state.GetFdtForEtype('missing')
2938 self.assertIsNone(missing_dtb)
2940 self.assertEqual('/binman', state.fdt_path_prefix)
2942 def testReplaceResizeFail(self):
2943 """Test replacing a file by something larger"""
2944 expected = U_BOOT_DATA + b'x'
2945 with self.assertRaises(ValueError) as e:
2946 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2947 dts='139_replace_repack.dts')
2948 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2951 def testReplaceMulti(self):
2952 """Test replacing entry data where multiple images are generated"""
2953 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2955 expected = b'x' * len(U_BOOT_DATA)
2956 updated_fname = tools.GetOutputFilename('image-updated.bin')
2957 tools.WriteFile(updated_fname, data)
2958 entry_name = 'u-boot'
2959 control.WriteEntry(updated_fname, entry_name, expected,
2961 data = control.ReadEntry(updated_fname, entry_name)
2962 self.assertEqual(expected, data)
2964 # Check the state looks right.
2965 self.assertEqual('/binman/image', state.fdt_path_prefix)
2967 # Now check we can write the first image
2968 image_fname = tools.GetOutputFilename('first-image.bin')
2969 updated_fname = tools.GetOutputFilename('first-updated.bin')
2970 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2971 entry_name = 'u-boot'
2972 control.WriteEntry(updated_fname, entry_name, expected,
2974 data = control.ReadEntry(updated_fname, entry_name)
2975 self.assertEqual(expected, data)
2977 # Check the state looks right.
2978 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2980 def testUpdateFdtAllRepack(self):
2981 """Test that all device trees are updated with offset/size info"""
2982 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2983 SECTION_SIZE = 0x300
2988 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2990 'section:offset': 0,
2991 'section:size': SECTION_SIZE,
2992 'section:image-pos': 0,
2993 'section/u-boot-dtb:offset': 4,
2994 'section/u-boot-dtb:size': 636,
2995 'section/u-boot-dtb:image-pos': 4,
2996 'u-boot-spl-dtb:offset': SECTION_SIZE,
2997 'u-boot-spl-dtb:size': DTB_SIZE,
2998 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2999 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3000 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3001 'u-boot-tpl-dtb:size': DTB_SIZE,
3002 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3003 'fdtmap:size': FDTMAP_SIZE,
3004 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3007 'section:orig-size': SECTION_SIZE,
3008 'section/u-boot-dtb:orig-offset': 4,
3011 # We expect three device-tree files in the output, with the first one
3012 # within a fixed-size section.
3013 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3014 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3015 # main U-Boot tree. All three should have the same positions and offset
3016 # except that the main tree should include the main_expected properties
3018 for item in ['', 'spl', 'tpl', None]:
3020 start += 16 # Move past fdtmap header
3021 dtb = fdt.Fdt.FromData(data[start:])
3023 props = self._GetPropTree(dtb,
3024 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3025 prefix='/' if item is None else '/binman/')
3026 expected = dict(base_expected)
3030 # Main DTB and fdtdec should include the 'orig-' properties
3031 expected.update(main_expected)
3032 # Helpful for debugging:
3033 #for prop in sorted(props):
3034 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3035 self.assertEqual(expected, props)
3037 start = SECTION_SIZE
3039 start += dtb._fdt_obj.totalsize()
3041 def testFdtmapHeaderMiddle(self):
3042 """Test an FDT map in the middle of an image when it should be at end"""
3043 with self.assertRaises(ValueError) as e:
3044 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3045 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3048 def testFdtmapHeaderStartBad(self):
3049 """Test an FDT map in middle of an image when it should be at start"""
3050 with self.assertRaises(ValueError) as e:
3051 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3052 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3055 def testFdtmapHeaderEndBad(self):
3056 """Test an FDT map at the start of an image when it should be at end"""
3057 with self.assertRaises(ValueError) as e:
3058 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3059 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3062 def testFdtmapHeaderNoSize(self):
3063 """Test an image header at the end of an image with undefined size"""
3064 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3066 def testReplaceResize(self):
3067 """Test replacing a single file in an entry with a larger file"""
3068 expected = U_BOOT_DATA + b'x'
3069 data, _, image = self._RunReplaceCmd('u-boot', expected,
3070 dts='139_replace_repack.dts')
3071 self.assertEqual(expected, data)
3073 entries = image.GetEntries()
3074 dtb_data = entries['u-boot-dtb'].data
3075 dtb = fdt.Fdt.FromData(dtb_data)
3078 # The u-boot section should now be larger in the dtb
3079 node = dtb.GetNode('/binman/u-boot')
3080 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3082 # Same for the fdtmap
3083 fdata = entries['fdtmap'].data
3084 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3086 fnode = fdtb.GetNode('/u-boot')
3087 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3089 def testReplaceResizeNoRepack(self):
3090 """Test replacing an entry with a larger file when not allowed"""
3091 expected = U_BOOT_DATA + b'x'
3092 with self.assertRaises(ValueError) as e:
3093 self._RunReplaceCmd('u-boot', expected)
3094 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3097 def testEntryShrink(self):
3098 """Test contracting an entry after it is packed"""
3100 state.SetAllowEntryContraction(True)
3101 data = self._DoReadFileDtb('140_entry_shrink.dts',
3104 state.SetAllowEntryContraction(False)
3105 self.assertEqual(b'a', data[:1])
3106 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3107 self.assertEqual(b'a', data[-1:])
3109 def testEntryShrinkFail(self):
3110 """Test not being allowed to contract an entry after it is packed"""
3111 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3113 # In this case there is a spare byte at the end of the data. The size of
3114 # the contents is only 1 byte but we still have the size before it
3116 self.assertEqual(b'a\0', data[:2])
3117 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3118 self.assertEqual(b'a\0', data[-2:])
3120 def testDescriptorOffset(self):
3121 """Test that the Intel descriptor is always placed at at the start"""
3122 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3123 image = control.images['image']
3124 entries = image.GetEntries()
3125 desc = entries['intel-descriptor']
3126 self.assertEqual(0xff800000, desc.offset);
3127 self.assertEqual(0xff800000, desc.image_pos);
3129 def testReplaceCbfs(self):
3130 """Test replacing a single file in CBFS without changing the size"""
3132 expected = b'x' * len(U_BOOT_DATA)
3133 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3134 updated_fname = tools.GetOutputFilename('image-updated.bin')
3135 tools.WriteFile(updated_fname, data)
3136 entry_name = 'section/cbfs/u-boot'
3137 control.WriteEntry(updated_fname, entry_name, expected,
3139 data = control.ReadEntry(updated_fname, entry_name)
3140 self.assertEqual(expected, data)
3142 def testReplaceResizeCbfs(self):
3143 """Test replacing a single file in CBFS with one of a different size"""
3145 expected = U_BOOT_DATA + b'x'
3146 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3147 updated_fname = tools.GetOutputFilename('image-updated.bin')
3148 tools.WriteFile(updated_fname, data)
3149 entry_name = 'section/cbfs/u-boot'
3150 control.WriteEntry(updated_fname, entry_name, expected,
3152 data = control.ReadEntry(updated_fname, entry_name)
3153 self.assertEqual(expected, data)
3155 def _SetupForReplace(self):
3156 """Set up some files to use to replace entries
3158 This generates an image, copies it to a new file, extracts all the files
3159 in it and updates some of them
3165 Expected values for updated entries, each a string
3167 data = self._DoReadFileRealDtb('143_replace_all.dts')
3169 updated_fname = tools.GetOutputFilename('image-updated.bin')
3170 tools.WriteFile(updated_fname, data)
3172 outdir = os.path.join(self._indir, 'extract')
3173 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3175 expected1 = b'x' + U_BOOT_DATA + b'y'
3176 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3177 tools.WriteFile(u_boot_fname1, expected1)
3179 expected2 = b'a' + U_BOOT_DATA + b'b'
3180 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3181 tools.WriteFile(u_boot_fname2, expected2)
3183 expected_text = b'not the same text'
3184 text_fname = os.path.join(outdir, 'text')
3185 tools.WriteFile(text_fname, expected_text)
3187 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3188 dtb = fdt.FdtScan(dtb_fname)
3189 node = dtb.GetNode('/binman/text')
3190 node.AddString('my-property', 'the value')
3191 dtb.Sync(auto_resize=True)
3194 return updated_fname, outdir, expected1, expected2, expected_text
3196 def _CheckReplaceMultiple(self, entry_paths):
3197 """Handle replacing the contents of multiple entries
3200 entry_paths: List of entry paths to replace
3204 Dict of entries in the image:
3207 Expected values for updated entries, each a string
3209 updated_fname, outdir, expected1, expected2, expected_text = (
3210 self._SetupForReplace())
3211 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3213 image = Image.FromFile(updated_fname)
3215 return image.GetEntries(), expected1, expected2, expected_text
3217 def testReplaceAll(self):
3218 """Test replacing the contents of all entries"""
3219 entries, expected1, expected2, expected_text = (
3220 self._CheckReplaceMultiple([]))
3221 data = entries['u-boot'].data
3222 self.assertEqual(expected1, data)
3224 data = entries['u-boot2'].data
3225 self.assertEqual(expected2, data)
3227 data = entries['text'].data
3228 self.assertEqual(expected_text, data)
3230 # Check that the device tree is updated
3231 data = entries['u-boot-dtb'].data
3232 dtb = fdt.Fdt.FromData(data)
3234 node = dtb.GetNode('/binman/text')
3235 self.assertEqual('the value', node.props['my-property'].value)
3237 def testReplaceSome(self):
3238 """Test replacing the contents of a few entries"""
3239 entries, expected1, expected2, expected_text = (
3240 self._CheckReplaceMultiple(['u-boot2', 'text']))
3242 # This one should not change
3243 data = entries['u-boot'].data
3244 self.assertEqual(U_BOOT_DATA, data)
3246 data = entries['u-boot2'].data
3247 self.assertEqual(expected2, data)
3249 data = entries['text'].data
3250 self.assertEqual(expected_text, data)
3252 def testReplaceCmd(self):
3253 """Test replacing a file fron an image on the command line"""
3254 self._DoReadFileRealDtb('143_replace_all.dts')
3257 tmpdir, updated_fname = self._SetupImageInTmpdir()
3259 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3260 expected = b'x' * len(U_BOOT_DATA)
3261 tools.WriteFile(fname, expected)
3263 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3264 data = tools.ReadFile(updated_fname)
3265 self.assertEqual(expected, data[:len(expected)])
3266 map_fname = os.path.join(tmpdir, 'image-updated.map')
3267 self.assertFalse(os.path.exists(map_fname))
3269 shutil.rmtree(tmpdir)
3271 def testReplaceCmdSome(self):
3272 """Test replacing some files fron an image on the command line"""
3273 updated_fname, outdir, expected1, expected2, expected_text = (
3274 self._SetupForReplace())
3276 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3279 tools.PrepareOutputDir(None)
3280 image = Image.FromFile(updated_fname)
3282 entries = image.GetEntries()
3284 # This one should not change
3285 data = entries['u-boot'].data
3286 self.assertEqual(U_BOOT_DATA, data)
3288 data = entries['u-boot2'].data
3289 self.assertEqual(expected2, data)
3291 data = entries['text'].data
3292 self.assertEqual(expected_text, data)
3294 def testReplaceMissing(self):
3295 """Test replacing entries where the file is missing"""
3296 updated_fname, outdir, expected1, expected2, expected_text = (
3297 self._SetupForReplace())
3299 # Remove one of the files, to generate a warning
3300 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3301 os.remove(u_boot_fname1)
3303 with test_util.capture_sys_output() as (stdout, stderr):
3304 control.ReplaceEntries(updated_fname, None, outdir, [])
3305 self.assertIn("Skipping entry '/u-boot' from missing file",
3308 def testReplaceCmdMap(self):
3309 """Test replacing a file fron an image on the command line"""
3310 self._DoReadFileRealDtb('143_replace_all.dts')
3313 tmpdir, updated_fname = self._SetupImageInTmpdir()
3315 fname = os.path.join(self._indir, 'update-u-boot.bin')
3316 expected = b'x' * len(U_BOOT_DATA)
3317 tools.WriteFile(fname, expected)
3319 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3321 map_fname = os.path.join(tmpdir, 'image-updated.map')
3322 self.assertTrue(os.path.exists(map_fname))
3324 shutil.rmtree(tmpdir)
3326 def testReplaceNoEntryPaths(self):
3327 """Test replacing an entry without an entry path"""
3328 self._DoReadFileRealDtb('143_replace_all.dts')
3329 image_fname = tools.GetOutputFilename('image.bin')
3330 with self.assertRaises(ValueError) as e:
3331 control.ReplaceEntries(image_fname, 'fname', None, [])
3332 self.assertIn('Must specify an entry path to read with -f',
3335 def testReplaceTooManyEntryPaths(self):
3336 """Test extracting some entries"""
3337 self._DoReadFileRealDtb('143_replace_all.dts')
3338 image_fname = tools.GetOutputFilename('image.bin')
3339 with self.assertRaises(ValueError) as e:
3340 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3341 self.assertIn('Must specify exactly one entry path to write with -f',
3344 def testPackReset16(self):
3345 """Test that an image with an x86 reset16 region can be created"""
3346 data = self._DoReadFile('144_x86_reset16.dts')
3347 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3349 def testPackReset16Spl(self):
3350 """Test that an image with an x86 reset16-spl region can be created"""
3351 data = self._DoReadFile('145_x86_reset16_spl.dts')
3352 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3354 def testPackReset16Tpl(self):
3355 """Test that an image with an x86 reset16-tpl region can be created"""
3356 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3357 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3359 def testPackIntelFit(self):
3360 """Test that an image with an Intel FIT and pointer can be created"""
3361 data = self._DoReadFile('147_intel_fit.dts')
3362 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3364 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3365 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3367 image = control.images['image']
3368 entries = image.GetEntries()
3369 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3370 self.assertEqual(expected_ptr, ptr)
3372 def testPackIntelFitMissing(self):
3373 """Test detection of a FIT pointer with not FIT region"""
3374 with self.assertRaises(ValueError) as e:
3375 self._DoReadFile('148_intel_fit_missing.dts')
3376 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3379 def _CheckSymbolsTplSection(self, dts, expected_vals):
3380 data = self._DoReadFile(dts)
3381 sym_values = struct.pack('<LQLL', *expected_vals)
3382 upto1 = 4 + len(U_BOOT_SPL_DATA)
3383 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3384 self.assertEqual(expected1, data[:upto1])
3386 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3387 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3388 self.assertEqual(expected2, data[upto1:upto2])
3390 upto3 = 0x34 + len(U_BOOT_DATA)
3391 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3392 self.assertEqual(expected3, data[upto2:upto3])
3394 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3395 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3397 def testSymbolsTplSection(self):
3398 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3399 self._SetupSplElf('u_boot_binman_syms')
3400 self._SetupTplElf('u_boot_binman_syms')
3401 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3402 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3404 def testSymbolsTplSectionX86(self):
3405 """Test binman can assign symbols in a section with end-at-4gb"""
3406 self._SetupSplElf('u_boot_binman_syms_x86')
3407 self._SetupTplElf('u_boot_binman_syms_x86')
3408 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3409 [0xffffff04, 0xffffff1c, 0xffffff34,
3412 def testPackX86RomIfwiSectiom(self):
3413 """Test that a section can be placed in an IFWI region"""
3414 self._SetupIfwi('fitimage.bin')
3415 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3416 self._CheckIfwi(data)
3418 def testPackFspM(self):
3419 """Test that an image with a FSP memory-init binary can be created"""
3420 data = self._DoReadFile('152_intel_fsp_m.dts')
3421 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3423 def testPackFspS(self):
3424 """Test that an image with a FSP silicon-init binary can be created"""
3425 data = self._DoReadFile('153_intel_fsp_s.dts')
3426 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3428 def testPackFspT(self):
3429 """Test that an image with a FSP temp-ram-init binary can be created"""
3430 data = self._DoReadFile('154_intel_fsp_t.dts')
3431 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3433 def testMkimage(self):
3434 """Test using mkimage to build an image"""
3435 data = self._DoReadFile('156_mkimage.dts')
3437 # Just check that the data appears in the file somewhere
3438 self.assertIn(U_BOOT_SPL_DATA, data)
3440 def testExtblob(self):
3441 """Test an image with an external blob"""
3442 data = self._DoReadFile('157_blob_ext.dts')
3443 self.assertEqual(REFCODE_DATA, data)
3445 def testExtblobMissing(self):
3446 """Test an image with a missing external blob"""
3447 with self.assertRaises(ValueError) as e:
3448 self._DoReadFile('158_blob_ext_missing.dts')
3449 self.assertIn("Filename 'missing-file' not found in input path",
3452 def testExtblobMissingOk(self):
3453 """Test an image with an missing external blob that is allowed"""
3454 with test_util.capture_sys_output() as (stdout, stderr):
3455 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3456 err = stderr.getvalue()
3457 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3459 def testExtblobMissingOkSect(self):
3460 """Test an image with an missing external blob that is allowed"""
3461 with test_util.capture_sys_output() as (stdout, stderr):
3462 self._DoTestFile('159_blob_ext_missing_sect.dts',
3464 err = stderr.getvalue()
3465 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3466 "blob-ext blob-ext2")
3468 def testPackX86RomMeMissingDesc(self):
3469 """Test that an missing Intel descriptor entry is allowed"""
3470 with test_util.capture_sys_output() as (stdout, stderr):
3471 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3472 err = stderr.getvalue()
3473 self.assertRegex(err,
3474 "Image 'main-section'.*missing.*: intel-descriptor")
3476 def testPackX86RomMissingIfwi(self):
3477 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3478 self._SetupIfwi('fitimage.bin')
3479 pathname = os.path.join(self._indir, 'fitimage.bin')
3481 with test_util.capture_sys_output() as (stdout, stderr):
3482 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3483 err = stderr.getvalue()
3484 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3486 def testPackOverlap(self):
3487 """Test that zero-size overlapping regions are ignored"""
3488 self._DoTestFile('160_pack_overlap_zero.dts')
3490 def testSimpleFit(self):
3491 """Test an image with a FIT inside"""
3492 data = self._DoReadFile('161_fit.dts')
3493 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3494 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3495 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3497 # The data should be inside the FIT
3498 dtb = fdt.Fdt.FromData(fit_data)
3500 fnode = dtb.GetNode('/images/kernel')
3501 self.assertIn('data', fnode.props)
3503 fname = os.path.join(self._indir, 'fit_data.fit')
3504 tools.WriteFile(fname, fit_data)
3505 out = tools.Run('dumpimage', '-l', fname)
3507 # Check a few features to make sure the plumbing works. We don't need
3508 # to test the operation of mkimage or dumpimage here. First convert the
3509 # output into a dict where the keys are the fields printed by dumpimage
3510 # and the values are a list of values for each field
3511 lines = out.splitlines()
3513 # Converts "Compression: gzip compressed" into two groups:
3514 # 'Compression' and 'gzip compressed'
3515 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3516 vals = collections.defaultdict(list)
3518 mat = re_line.match(line)
3519 vals[mat.group(1)].append(mat.group(2))
3521 self.assertEquals('FIT description: test-desc', lines[0])
3522 self.assertIn('Created:', lines[1])
3523 self.assertIn('Image 0 (kernel)', vals)
3524 self.assertIn('Hash value', vals)
3525 data_sizes = vals.get('Data Size')
3526 self.assertIsNotNone(data_sizes)
3527 self.assertEqual(2, len(data_sizes))
3528 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3529 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3530 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3532 def testFitExternal(self):
3533 """Test an image with an FIT with external images"""
3534 data = self._DoReadFile('162_fit_external.dts')
3535 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3537 # The data should be outside the FIT
3538 dtb = fdt.Fdt.FromData(fit_data)
3540 fnode = dtb.GetNode('/images/kernel')
3541 self.assertNotIn('data', fnode.props)
3543 def testSectionIgnoreHashSignature(self):
3544 """Test that sections ignore hash, signature nodes for its data"""
3545 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3546 expected = (U_BOOT_DATA + U_BOOT_DATA)
3547 self.assertEqual(expected, data)
3549 def testPadInSections(self):
3550 """Test pad-before, pad-after for entries in sections"""
3551 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3552 '166_pad_in_sections.dts', update_dtb=True)
3553 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3554 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3556 self.assertEqual(expected, data)
3558 dtb = fdt.Fdt(out_dtb_fname)
3560 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3564 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3566 'section:image-pos': 0,
3567 'section:offset': 0,
3568 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3570 'section/before:image-pos': 0,
3571 'section/before:offset': 0,
3572 'section/before:size': len(U_BOOT_DATA),
3574 'section/u-boot:image-pos': 4,
3575 'section/u-boot:offset': 4,
3576 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3578 'section/after:image-pos': 26,
3579 'section/after:offset': 26,
3580 'section/after:size': len(U_BOOT_DATA),
3582 self.assertEqual(expected, props)
3584 def testFitImageSubentryAlignment(self):
3585 """Test relative alignability of FIT image subentries"""
3587 'test-id': TEXT_DATA,
3589 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3590 entry_args=entry_args)
3591 dtb = fdt.Fdt.FromData(data)
3594 node = dtb.GetNode('/images/kernel')
3595 data = dtb.GetProps(node)["data"].bytes
3596 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3597 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3598 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3599 self.assertEqual(expected, data)
3601 node = dtb.GetNode('/images/fdt-1')
3602 data = dtb.GetProps(node)["data"].bytes
3603 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3604 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3606 self.assertEqual(expected, data)
3608 def testFitExtblobMissingOk(self):
3609 """Test a FIT with a missing external blob that is allowed"""
3610 with test_util.capture_sys_output() as (stdout, stderr):
3611 self._DoTestFile('168_fit_missing_blob.dts',
3613 err = stderr.getvalue()
3614 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3616 def testBlobNamedByArgMissing(self):
3617 """Test handling of a missing entry arg"""
3618 with self.assertRaises(ValueError) as e:
3619 self._DoReadFile('068_blob_named_by_arg.dts')
3620 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3623 def testPackBl31(self):
3624 """Test that an image with an ATF BL31 binary can be created"""
3625 data = self._DoReadFile('169_atf_bl31.dts')
3626 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3628 def testPackScp(self):
3629 """Test that an image with an SCP binary can be created"""
3630 data = self._DoReadFile('172_scp.dts')
3631 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3633 def testFitFdt(self):
3634 """Test an image with an FIT with multiple FDT images"""
3635 def _CheckFdt(seq, expected_data):
3636 """Check the FDT nodes
3639 seq: Sequence number to check (0 or 1)
3640 expected_data: Expected contents of 'data' property
3642 name = 'fdt-%d' % seq
3643 fnode = dtb.GetNode('/images/%s' % name)
3644 self.assertIsNotNone(fnode)
3645 self.assertEqual({'description','type', 'compression', 'data'},
3646 set(fnode.props.keys()))
3647 self.assertEqual(expected_data, fnode.props['data'].bytes)
3648 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3649 fnode.props['description'].value)
3651 def _CheckConfig(seq, expected_data):
3652 """Check the configuration nodes
3655 seq: Sequence number to check (0 or 1)
3656 expected_data: Expected contents of 'data' property
3658 cnode = dtb.GetNode('/configurations')
3659 self.assertIn('default', cnode.props)
3660 self.assertEqual('config-2', cnode.props['default'].value)
3662 name = 'config-%d' % seq
3663 fnode = dtb.GetNode('/configurations/%s' % name)
3664 self.assertIsNotNone(fnode)
3665 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3666 set(fnode.props.keys()))
3667 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3668 fnode.props['description'].value)
3669 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3672 'of-list': 'test-fdt1 test-fdt2',
3673 'default-dt': 'test-fdt2',
3675 data = self._DoReadFileDtb(
3677 entry_args=entry_args,
3678 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3679 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3680 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3682 dtb = fdt.Fdt.FromData(fit_data)
3684 fnode = dtb.GetNode('/images/kernel')
3685 self.assertIn('data', fnode.props)
3687 # Check all the properties in fdt-1 and fdt-2
3688 _CheckFdt(1, TEST_FDT1_DATA)
3689 _CheckFdt(2, TEST_FDT2_DATA)
3691 # Check configurations
3692 _CheckConfig(1, TEST_FDT1_DATA)
3693 _CheckConfig(2, TEST_FDT2_DATA)
3695 def testFitFdtMissingList(self):
3696 """Test handling of a missing 'of-list' entry arg"""
3697 with self.assertRaises(ValueError) as e:
3698 self._DoReadFile('172_fit_fdt.dts')
3699 self.assertIn("Generator node requires 'of-list' entry argument",
3702 def testFitFdtEmptyList(self):
3703 """Test handling of an empty 'of-list' entry arg"""
3707 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3709 def testFitFdtMissingProp(self):
3710 """Test handling of a missing 'fit,fdt-list' property"""
3711 with self.assertRaises(ValueError) as e:
3712 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3713 self.assertIn("Generator node requires 'fit,fdt-list' property",
3716 def testFitFdtEmptyList(self):
3717 """Test handling of an empty 'of-list' entry arg"""
3721 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3723 def testFitFdtMissing(self):
3724 """Test handling of a missing 'default-dt' entry arg"""
3726 'of-list': 'test-fdt1 test-fdt2',
3728 with self.assertRaises(ValueError) as e:
3729 self._DoReadFileDtb(
3731 entry_args=entry_args,
3732 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3733 self.assertIn("Generated 'default' node requires default-dt entry argument",
3736 def testFitFdtNotInList(self):
3737 """Test handling of a default-dt that is not in the of-list"""
3739 'of-list': 'test-fdt1 test-fdt2',
3740 'default-dt': 'test-fdt3',
3742 with self.assertRaises(ValueError) as e:
3743 self._DoReadFileDtb(
3745 entry_args=entry_args,
3746 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3747 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3750 def testFitExtblobMissingHelp(self):
3751 """Test display of help messages when an external blob is missing"""
3752 control.missing_blob_help = control._ReadMissingBlobHelp()
3753 control.missing_blob_help['wibble'] = 'Wibble test'
3754 control.missing_blob_help['another'] = 'Another test'
3755 with test_util.capture_sys_output() as (stdout, stderr):
3756 self._DoTestFile('168_fit_missing_blob.dts',
3758 err = stderr.getvalue()
3760 # We can get the tag from the name, the type or the missing-msg
3761 # property. Check all three.
3762 self.assertIn('You may need to build ARM Trusted', err)
3763 self.assertIn('Wibble test', err)
3764 self.assertIn('Another test', err)
3766 def testMissingBlob(self):
3767 """Test handling of a blob containing a missing file"""
3768 with self.assertRaises(ValueError) as e:
3769 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3770 self.assertIn("Filename 'missing' not found in input path",
3773 def testEnvironment(self):
3774 """Test adding a U-Boot environment"""
3775 data = self._DoReadFile('174_env.dts')
3776 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3777 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3778 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3779 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3782 def testEnvironmentNoSize(self):
3783 """Test that a missing 'size' property is detected"""
3784 with self.assertRaises(ValueError) as e:
3785 self._DoTestFile('175_env_no_size.dts')
3786 self.assertIn("'u-boot-env' entry must have a size property",
3789 def testEnvironmentTooSmall(self):
3790 """Test handling of an environment that does not fit"""
3791 with self.assertRaises(ValueError) as e:
3792 self._DoTestFile('176_env_too_small.dts')
3794 # checksum, start byte, environment with \0 terminator, final \0
3795 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3797 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3800 def testSkipAtStart(self):
3801 """Test handling of skip-at-start section"""
3802 data = self._DoReadFile('177_skip_at_start.dts')
3803 self.assertEqual(U_BOOT_DATA, data)
3805 image = control.images['image']
3806 entries = image.GetEntries()
3807 section = entries['section']
3808 self.assertEqual(0, section.offset)
3809 self.assertEqual(len(U_BOOT_DATA), section.size)
3810 self.assertEqual(U_BOOT_DATA, section.GetData())
3812 entry = section.GetEntries()['u-boot']
3813 self.assertEqual(16, entry.offset)
3814 self.assertEqual(len(U_BOOT_DATA), entry.size)
3815 self.assertEqual(U_BOOT_DATA, entry.data)
3817 def testSkipAtStartPad(self):
3818 """Test handling of skip-at-start section with padded entry"""
3819 data = self._DoReadFile('178_skip_at_start_pad.dts')
3820 before = tools.GetBytes(0, 8)
3821 after = tools.GetBytes(0, 4)
3822 all = before + U_BOOT_DATA + after
3823 self.assertEqual(all, data)
3825 image = control.images['image']
3826 entries = image.GetEntries()
3827 section = entries['section']
3828 self.assertEqual(0, section.offset)
3829 self.assertEqual(len(all), section.size)
3830 self.assertEqual(all, section.GetData())
3832 entry = section.GetEntries()['u-boot']
3833 self.assertEqual(16, entry.offset)
3834 self.assertEqual(len(all), entry.size)
3835 self.assertEqual(U_BOOT_DATA, entry.data)
3837 def testSkipAtStartSectionPad(self):
3838 """Test handling of skip-at-start section with padding"""
3839 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3840 before = tools.GetBytes(0, 8)
3841 after = tools.GetBytes(0, 4)
3842 all = before + U_BOOT_DATA + after
3844 # This is not correct, but it is what binman currently produces
3845 self.assertEqual(tools.GetBytes(0, 16) + U_BOOT_DATA + after, data)
3847 image = control.images['image']
3848 entries = image.GetEntries()
3849 section = entries['section']
3850 self.assertEqual(0, section.offset)
3851 self.assertEqual(len(all), section.size)
3852 self.assertIsNone(section.data)
3853 self.assertEqual(all, section.GetData())
3855 entry = section.GetEntries()['u-boot']
3856 self.assertEqual(16, entry.offset)
3857 self.assertEqual(len(U_BOOT_DATA), entry.size)
3858 self.assertEqual(U_BOOT_DATA, entry.data)
3860 if __name__ == "__main__":