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 retcode = self._DoTestFile('009_pack_extra.dts')
790 self.assertEqual(0, retcode)
791 self.assertIn('image', control.images)
792 image = control.images['image']
793 entries = image.GetEntries()
794 self.assertEqual(5, len(entries))
796 # First u-boot with padding before and after
797 self.assertIn('u-boot', entries)
798 entry = entries['u-boot']
799 self.assertEqual(0, entry.offset)
800 self.assertEqual(3, entry.pad_before)
801 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
803 # Second u-boot has an aligned size, but it has no effect
804 self.assertIn('u-boot-align-size-nop', entries)
805 entry = entries['u-boot-align-size-nop']
806 self.assertEqual(12, entry.offset)
807 self.assertEqual(4, entry.size)
809 # Third u-boot has an aligned size too
810 self.assertIn('u-boot-align-size', entries)
811 entry = entries['u-boot-align-size']
812 self.assertEqual(16, entry.offset)
813 self.assertEqual(32, entry.size)
815 # Fourth u-boot has an aligned end
816 self.assertIn('u-boot-align-end', entries)
817 entry = entries['u-boot-align-end']
818 self.assertEqual(48, entry.offset)
819 self.assertEqual(16, entry.size)
821 # Fifth u-boot immediately afterwards
822 self.assertIn('u-boot-align-both', entries)
823 entry = entries['u-boot-align-both']
824 self.assertEqual(64, entry.offset)
825 self.assertEqual(64, entry.size)
827 self.CheckNoGaps(entries)
828 self.assertEqual(128, image.size)
830 def testPackAlignPowerOf2(self):
831 """Test that invalid entry alignment is detected"""
832 with self.assertRaises(ValueError) as e:
833 self._DoTestFile('010_pack_align_power2.dts')
834 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
835 "of two", str(e.exception))
837 def testPackAlignSizePowerOf2(self):
838 """Test that invalid entry size alignment is detected"""
839 with self.assertRaises(ValueError) as e:
840 self._DoTestFile('011_pack_align_size_power2.dts')
841 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
842 "power of two", str(e.exception))
844 def testPackInvalidAlign(self):
845 """Test detection of an offset that does not match its alignment"""
846 with self.assertRaises(ValueError) as e:
847 self._DoTestFile('012_pack_inv_align.dts')
848 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
849 "align 0x4 (4)", str(e.exception))
851 def testPackInvalidSizeAlign(self):
852 """Test that invalid entry size alignment is detected"""
853 with self.assertRaises(ValueError) as e:
854 self._DoTestFile('013_pack_inv_size_align.dts')
855 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
856 "align-size 0x4 (4)", str(e.exception))
858 def testPackOverlap(self):
859 """Test that overlapping regions are detected"""
860 with self.assertRaises(ValueError) as e:
861 self._DoTestFile('014_pack_overlap.dts')
862 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
863 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
866 def testPackEntryOverflow(self):
867 """Test that entries that overflow their size are detected"""
868 with self.assertRaises(ValueError) as e:
869 self._DoTestFile('015_pack_overflow.dts')
870 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
871 "but entry size is 0x3 (3)", str(e.exception))
873 def testPackImageOverflow(self):
874 """Test that entries which overflow the image size are detected"""
875 with self.assertRaises(ValueError) as e:
876 self._DoTestFile('016_pack_image_overflow.dts')
877 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
878 "size 0x3 (3)", str(e.exception))
880 def testPackImageSize(self):
881 """Test that the image size can be set"""
882 retcode = self._DoTestFile('017_pack_image_size.dts')
883 self.assertEqual(0, retcode)
884 self.assertIn('image', control.images)
885 image = control.images['image']
886 self.assertEqual(7, image.size)
888 def testPackImageSizeAlign(self):
889 """Test that image size alignemnt works as expected"""
890 retcode = self._DoTestFile('018_pack_image_align.dts')
891 self.assertEqual(0, retcode)
892 self.assertIn('image', control.images)
893 image = control.images['image']
894 self.assertEqual(16, image.size)
896 def testPackInvalidImageAlign(self):
897 """Test that invalid image alignment is detected"""
898 with self.assertRaises(ValueError) as e:
899 self._DoTestFile('019_pack_inv_image_align.dts')
900 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
901 "align-size 0x8 (8)", str(e.exception))
903 def testPackAlignPowerOf2(self):
904 """Test that invalid image alignment is detected"""
905 with self.assertRaises(ValueError) as e:
906 self._DoTestFile('020_pack_inv_image_align_power2.dts')
907 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
908 "two", str(e.exception))
910 def testImagePadByte(self):
911 """Test that the image pad byte can be specified"""
913 data = self._DoReadFile('021_image_pad.dts')
914 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
917 def testImageName(self):
918 """Test that image files can be named"""
919 retcode = self._DoTestFile('022_image_name.dts')
920 self.assertEqual(0, retcode)
921 image = control.images['image1']
922 fname = tools.GetOutputFilename('test-name')
923 self.assertTrue(os.path.exists(fname))
925 image = control.images['image2']
926 fname = tools.GetOutputFilename('test-name.xx')
927 self.assertTrue(os.path.exists(fname))
929 def testBlobFilename(self):
930 """Test that generic blobs can be provided by filename"""
931 data = self._DoReadFile('023_blob.dts')
932 self.assertEqual(BLOB_DATA, data)
934 def testPackSorted(self):
935 """Test that entries can be sorted"""
937 data = self._DoReadFile('024_sorted.dts')
938 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
939 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
941 def testPackZeroOffset(self):
942 """Test that an entry at offset 0 is not given a new offset"""
943 with self.assertRaises(ValueError) as e:
944 self._DoTestFile('025_pack_zero_size.dts')
945 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
946 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
949 def testPackUbootDtb(self):
950 """Test that a device tree can be added to U-Boot"""
951 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
952 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
954 def testPackX86RomNoSize(self):
955 """Test that the end-at-4gb property requires a size property"""
956 with self.assertRaises(ValueError) as e:
957 self._DoTestFile('027_pack_4gb_no_size.dts')
958 self.assertIn("Image '/binman': Section size must be provided when "
959 "using end-at-4gb", str(e.exception))
961 def test4gbAndSkipAtStartTogether(self):
962 """Test that the end-at-4gb and skip-at-size property can't be used
964 with self.assertRaises(ValueError) as e:
965 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
966 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
967 "'skip-at-start'", str(e.exception))
969 def testPackX86RomOutside(self):
970 """Test that the end-at-4gb property checks for offset boundaries"""
971 with self.assertRaises(ValueError) as e:
972 self._DoTestFile('028_pack_4gb_outside.dts')
973 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
974 "is outside the section '/binman' starting at "
975 '0xffffffe0 (4294967264) of size 0x20 (32)',
978 def testPackX86Rom(self):
979 """Test that a basic x86 ROM can be created"""
981 data = self._DoReadFile('029_x86_rom.dts')
982 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
983 tools.GetBytes(0, 2), data)
985 def testPackX86RomMeNoDesc(self):
986 """Test that an invalid Intel descriptor entry is detected"""
988 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
989 with self.assertRaises(ValueError) as e:
990 self._DoTestFile('163_x86_rom_me_empty.dts')
991 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
994 self._SetupDescriptor()
996 def testPackX86RomBadDesc(self):
997 """Test that the Intel requires a descriptor entry"""
998 with self.assertRaises(ValueError) as e:
999 self._DoTestFile('030_x86_rom_me_no_desc.dts')
1000 self.assertIn("Node '/binman/intel-me': No offset set with "
1001 "offset-unset: should another entry provide this correct "
1002 "offset?", str(e.exception))
1004 def testPackX86RomMe(self):
1005 """Test that an x86 ROM with an ME region can be created"""
1006 data = self._DoReadFile('031_x86_rom_me.dts')
1007 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1008 if data[:0x1000] != expected_desc:
1009 self.fail('Expected descriptor binary at start of image')
1010 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1012 def testPackVga(self):
1013 """Test that an image with a VGA binary can be created"""
1014 data = self._DoReadFile('032_intel_vga.dts')
1015 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1017 def testPackStart16(self):
1018 """Test that an image with an x86 start16 region can be created"""
1019 data = self._DoReadFile('033_x86_start16.dts')
1020 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1022 def testPackPowerpcMpc85xxBootpgResetvec(self):
1023 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1025 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
1026 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1028 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
1029 """Handle running a test for insertion of microcode
1032 dts_fname: Name of test .dts file
1033 nodtb_data: Data that we expect in the first section
1034 ucode_second: True if the microsecond entry is second instead of
1039 Contents of first region (U-Boot or SPL)
1040 Offset and size components of microcode pointer, as inserted
1041 in the above (two 4-byte words)
1043 data = self._DoReadFile(dts_fname, True)
1045 # Now check the device tree has no microcode
1047 ucode_content = data[len(nodtb_data):]
1048 ucode_pos = len(nodtb_data)
1049 dtb_with_ucode = ucode_content[16:]
1050 fdt_len = self.GetFdtLen(dtb_with_ucode)
1052 dtb_with_ucode = data[len(nodtb_data):]
1053 fdt_len = self.GetFdtLen(dtb_with_ucode)
1054 ucode_content = dtb_with_ucode[fdt_len:]
1055 ucode_pos = len(nodtb_data) + fdt_len
1056 fname = tools.GetOutputFilename('test.dtb')
1057 with open(fname, 'wb') as fd:
1058 fd.write(dtb_with_ucode)
1059 dtb = fdt.FdtScan(fname)
1060 ucode = dtb.GetNode('/microcode')
1061 self.assertTrue(ucode)
1062 for node in ucode.subnodes:
1063 self.assertFalse(node.props.get('data'))
1065 # Check that the microcode appears immediately after the Fdt
1066 # This matches the concatenation of the data properties in
1067 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1068 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1070 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1072 # Check that the microcode pointer was inserted. It should match the
1073 # expected offset and size
1074 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1076 u_boot = data[:len(nodtb_data)]
1077 return u_boot, pos_and_size
1079 def testPackUbootMicrocode(self):
1080 """Test that x86 microcode can be handled correctly
1082 We expect to see the following in the image, in order:
1083 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1085 u-boot.dtb with the microcode removed
1088 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1090 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1091 b' somewhere in here', first)
1093 def _RunPackUbootSingleMicrocode(self):
1094 """Test that x86 microcode can be handled correctly
1096 We expect to see the following in the image, in order:
1097 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1099 u-boot.dtb with the microcode
1100 an empty microcode region
1102 # We need the libfdt library to run this test since only that allows
1103 # finding the offset of a property. This is required by
1104 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1105 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1107 second = data[len(U_BOOT_NODTB_DATA):]
1109 fdt_len = self.GetFdtLen(second)
1110 third = second[fdt_len:]
1111 second = second[:fdt_len]
1113 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1114 self.assertIn(ucode_data, second)
1115 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1117 # Check that the microcode pointer was inserted. It should match the
1118 # expected offset and size
1119 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1121 first = data[:len(U_BOOT_NODTB_DATA)]
1122 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1123 b' somewhere in here', first)
1125 def testPackUbootSingleMicrocode(self):
1126 """Test that x86 microcode can be handled correctly with fdt_normal.
1128 self._RunPackUbootSingleMicrocode()
1130 def testUBootImg(self):
1131 """Test that u-boot.img can be put in a file"""
1132 data = self._DoReadFile('036_u_boot_img.dts')
1133 self.assertEqual(U_BOOT_IMG_DATA, data)
1135 def testNoMicrocode(self):
1136 """Test that a missing microcode region is detected"""
1137 with self.assertRaises(ValueError) as e:
1138 self._DoReadFile('037_x86_no_ucode.dts', True)
1139 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1140 "node found in ", str(e.exception))
1142 def testMicrocodeWithoutNode(self):
1143 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1144 with self.assertRaises(ValueError) as e:
1145 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1146 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1147 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1149 def testMicrocodeWithoutNode2(self):
1150 """Test that a missing u-boot-ucode node is detected"""
1151 with self.assertRaises(ValueError) as e:
1152 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1153 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1154 "microcode region u-boot-ucode", str(e.exception))
1156 def testMicrocodeWithoutPtrInElf(self):
1157 """Test that a U-Boot binary without the microcode symbol is detected"""
1158 # ELF file without a '_dt_ucode_base_size' symbol
1160 TestFunctional._MakeInputFile('u-boot',
1161 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1163 with self.assertRaises(ValueError) as e:
1164 self._RunPackUbootSingleMicrocode()
1165 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1166 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1169 # Put the original file back
1170 TestFunctional._MakeInputFile('u-boot',
1171 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1173 def testMicrocodeNotInImage(self):
1174 """Test that microcode must be placed within the image"""
1175 with self.assertRaises(ValueError) as e:
1176 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1177 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1178 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1179 "section ranging from 00000000 to 0000002e", str(e.exception))
1181 def testWithoutMicrocode(self):
1182 """Test that we can cope with an image without microcode (e.g. qemu)"""
1183 TestFunctional._MakeInputFile('u-boot',
1184 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1185 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1187 # Now check the device tree has no microcode
1188 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1189 second = data[len(U_BOOT_NODTB_DATA):]
1191 fdt_len = self.GetFdtLen(second)
1192 self.assertEqual(dtb, second[:fdt_len])
1194 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1195 third = data[used_len:]
1196 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1198 def testUnknownPosSize(self):
1199 """Test that microcode must be placed within the image"""
1200 with self.assertRaises(ValueError) as e:
1201 self._DoReadFile('041_unknown_pos_size.dts', True)
1202 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1203 "entry 'invalid-entry'", str(e.exception))
1205 def testPackFsp(self):
1206 """Test that an image with a FSP binary can be created"""
1207 data = self._DoReadFile('042_intel_fsp.dts')
1208 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1210 def testPackCmc(self):
1211 """Test that an image with a CMC binary can be created"""
1212 data = self._DoReadFile('043_intel_cmc.dts')
1213 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1215 def testPackVbt(self):
1216 """Test that an image with a VBT binary can be created"""
1217 data = self._DoReadFile('046_intel_vbt.dts')
1218 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1220 def testSplBssPad(self):
1221 """Test that we can pad SPL's BSS with zeros"""
1222 # ELF file with a '__bss_size' symbol
1224 data = self._DoReadFile('047_spl_bss_pad.dts')
1225 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1228 def testSplBssPadMissing(self):
1229 """Test that a missing symbol is detected"""
1230 self._SetupSplElf('u_boot_ucode_ptr')
1231 with self.assertRaises(ValueError) as e:
1232 self._DoReadFile('047_spl_bss_pad.dts')
1233 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1236 def testPackStart16Spl(self):
1237 """Test that an image with an x86 start16 SPL region can be created"""
1238 data = self._DoReadFile('048_x86_start16_spl.dts')
1239 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1241 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1242 """Helper function for microcode tests
1244 We expect to see the following in the image, in order:
1245 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1247 u-boot.dtb with the microcode removed
1251 dts: Device tree file to use for test
1252 ucode_second: True if the microsecond entry is second instead of
1255 self._SetupSplElf('u_boot_ucode_ptr')
1256 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1257 ucode_second=ucode_second)
1258 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1259 b'ter somewhere in here', first)
1261 def testPackUbootSplMicrocode(self):
1262 """Test that x86 microcode can be handled correctly in SPL"""
1263 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1265 def testPackUbootSplMicrocodeReorder(self):
1266 """Test that order doesn't matter for microcode entries
1268 This is the same as testPackUbootSplMicrocode but when we process the
1269 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1270 entry, so we reply on binman to try later.
1272 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1275 def testPackMrc(self):
1276 """Test that an image with an MRC binary can be created"""
1277 data = self._DoReadFile('050_intel_mrc.dts')
1278 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1280 def testSplDtb(self):
1281 """Test that an image with spl/u-boot-spl.dtb can be created"""
1282 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1283 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1285 def testSplNoDtb(self):
1286 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1287 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1288 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1290 def testSymbols(self):
1291 """Test binman can assign symbols embedded in U-Boot"""
1292 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1293 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1294 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1295 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1297 self._SetupSplElf('u_boot_binman_syms')
1298 data = self._DoReadFile('053_symbols.dts')
1299 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
1300 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
1301 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1302 U_BOOT_SPL_DATA[20:])
1303 self.assertEqual(expected, data)
1305 def testPackUnitAddress(self):
1306 """Test that we support multiple binaries with the same name"""
1307 data = self._DoReadFile('054_unit_address.dts')
1308 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1310 def testSections(self):
1311 """Basic test of sections"""
1312 data = self._DoReadFile('055_sections.dts')
1313 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1314 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1315 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1316 self.assertEqual(expected, data)
1319 """Tests outputting a map of the images"""
1320 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1321 self.assertEqual('''ImagePos Offset Size Name
1322 00000000 00000000 00000028 main-section
1323 00000000 00000000 00000010 section@0
1324 00000000 00000000 00000004 u-boot
1325 00000010 00000010 00000010 section@1
1326 00000010 00000000 00000004 u-boot
1327 00000020 00000020 00000004 section@2
1328 00000020 00000000 00000004 u-boot
1331 def testNamePrefix(self):
1332 """Tests that name prefixes are used"""
1333 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1334 self.assertEqual('''ImagePos Offset Size Name
1335 00000000 00000000 00000028 main-section
1336 00000000 00000000 00000010 section@0
1337 00000000 00000000 00000004 ro-u-boot
1338 00000010 00000010 00000010 section@1
1339 00000010 00000000 00000004 rw-u-boot
1342 def testUnknownContents(self):
1343 """Test that obtaining the contents works as expected"""
1344 with self.assertRaises(ValueError) as e:
1345 self._DoReadFile('057_unknown_contents.dts', True)
1346 self.assertIn("Image '/binman': Internal error: Could not complete "
1347 "processing of contents: remaining ["
1348 "<binman.etype._testing.Entry__testing ", str(e.exception))
1350 def testBadChangeSize(self):
1351 """Test that trying to change the size of an entry fails"""
1353 state.SetAllowEntryExpansion(False)
1354 with self.assertRaises(ValueError) as e:
1355 self._DoReadFile('059_change_size.dts', True)
1356 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1359 state.SetAllowEntryExpansion(True)
1361 def testUpdateFdt(self):
1362 """Test that we can update the device tree with offset/size info"""
1363 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1365 dtb = fdt.Fdt(out_dtb_fname)
1367 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1371 '_testing:offset': 32,
1373 '_testing:image-pos': 32,
1374 'section@0/u-boot:offset': 0,
1375 'section@0/u-boot:size': len(U_BOOT_DATA),
1376 'section@0/u-boot:image-pos': 0,
1377 'section@0:offset': 0,
1378 'section@0:size': 16,
1379 'section@0:image-pos': 0,
1381 'section@1/u-boot:offset': 0,
1382 'section@1/u-boot:size': len(U_BOOT_DATA),
1383 'section@1/u-boot:image-pos': 16,
1384 'section@1:offset': 16,
1385 'section@1:size': 16,
1386 'section@1:image-pos': 16,
1390 def testUpdateFdtBad(self):
1391 """Test that we detect when ProcessFdt never completes"""
1392 with self.assertRaises(ValueError) as e:
1393 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1394 self.assertIn('Could not complete processing of Fdt: remaining '
1395 '[<binman.etype._testing.Entry__testing',
1398 def testEntryArgs(self):
1399 """Test passing arguments to entries from the command line"""
1401 'test-str-arg': 'test1',
1402 'test-int-arg': '456',
1404 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1405 self.assertIn('image', control.images)
1406 entry = control.images['image'].GetEntries()['_testing']
1407 self.assertEqual('test0', entry.test_str_fdt)
1408 self.assertEqual('test1', entry.test_str_arg)
1409 self.assertEqual(123, entry.test_int_fdt)
1410 self.assertEqual(456, entry.test_int_arg)
1412 def testEntryArgsMissing(self):
1413 """Test missing arguments and properties"""
1415 'test-int-arg': '456',
1417 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1418 entry = control.images['image'].GetEntries()['_testing']
1419 self.assertEqual('test0', entry.test_str_fdt)
1420 self.assertEqual(None, entry.test_str_arg)
1421 self.assertEqual(None, entry.test_int_fdt)
1422 self.assertEqual(456, entry.test_int_arg)
1424 def testEntryArgsRequired(self):
1425 """Test missing arguments and properties"""
1427 'test-int-arg': '456',
1429 with self.assertRaises(ValueError) as e:
1430 self._DoReadFileDtb('064_entry_args_required.dts')
1431 self.assertIn("Node '/binman/_testing': "
1432 'Missing required properties/entry args: test-str-arg, '
1433 'test-int-fdt, test-int-arg',
1436 def testEntryArgsInvalidFormat(self):
1437 """Test that an invalid entry-argument format is detected"""
1438 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1440 with self.assertRaises(ValueError) as e:
1441 self._DoBinman(*args)
1442 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1444 def testEntryArgsInvalidInteger(self):
1445 """Test that an invalid entry-argument integer is detected"""
1447 'test-int-arg': 'abc',
1449 with self.assertRaises(ValueError) as e:
1450 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1451 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1452 "'test-int-arg' (value 'abc') to integer",
1455 def testEntryArgsInvalidDatatype(self):
1456 """Test that an invalid entry-argument datatype is detected
1458 This test could be written in entry_test.py except that it needs
1459 access to control.entry_args, which seems more than that module should
1463 'test-bad-datatype-arg': '12',
1465 with self.assertRaises(ValueError) as e:
1466 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1467 entry_args=entry_args)
1468 self.assertIn('GetArg() internal error: Unknown data type ',
1472 """Test for a text entry type"""
1474 'test-id': TEXT_DATA,
1475 'test-id2': TEXT_DATA2,
1476 'test-id3': TEXT_DATA3,
1478 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1479 entry_args=entry_args)
1480 expected = (tools.ToBytes(TEXT_DATA) +
1481 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1482 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1483 b'some text' + b'more text')
1484 self.assertEqual(expected, data)
1486 def testEntryDocs(self):
1487 """Test for creation of entry documentation"""
1488 with test_util.capture_sys_output() as (stdout, stderr):
1489 control.WriteEntryDocs(control.GetEntryModules())
1490 self.assertTrue(len(stdout.getvalue()) > 0)
1492 def testEntryDocsMissing(self):
1493 """Test handling of missing entry documentation"""
1494 with self.assertRaises(ValueError) as e:
1495 with test_util.capture_sys_output() as (stdout, stderr):
1496 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1497 self.assertIn('Documentation is missing for modules: u_boot',
1501 """Basic test of generation of a flashrom fmap"""
1502 data = self._DoReadFile('067_fmap.dts')
1503 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1504 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1505 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1506 self.assertEqual(expected, data[:32])
1507 self.assertEqual(b'__FMAP__', fhdr.signature)
1508 self.assertEqual(1, fhdr.ver_major)
1509 self.assertEqual(0, fhdr.ver_minor)
1510 self.assertEqual(0, fhdr.base)
1511 self.assertEqual(16 + 16 +
1512 fmap_util.FMAP_HEADER_LEN +
1513 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1514 self.assertEqual(b'FMAP', fhdr.name)
1515 self.assertEqual(3, fhdr.nareas)
1516 for fentry in fentries:
1517 self.assertEqual(0, fentry.flags)
1519 self.assertEqual(0, fentries[0].offset)
1520 self.assertEqual(4, fentries[0].size)
1521 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1523 self.assertEqual(16, fentries[1].offset)
1524 self.assertEqual(4, fentries[1].size)
1525 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1527 self.assertEqual(32, fentries[2].offset)
1528 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1529 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1530 self.assertEqual(b'FMAP', fentries[2].name)
1532 def testBlobNamedByArg(self):
1533 """Test we can add a blob with the filename coming from an entry arg"""
1535 'cros-ec-rw-path': 'ecrw.bin',
1537 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1540 """Test for an fill entry type"""
1541 data = self._DoReadFile('069_fill.dts')
1542 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1543 self.assertEqual(expected, data)
1545 def testFillNoSize(self):
1546 """Test for an fill entry type with no size"""
1547 with self.assertRaises(ValueError) as e:
1548 self._DoReadFile('070_fill_no_size.dts')
1549 self.assertIn("'fill' entry must have a size property",
1552 def _HandleGbbCommand(self, pipe_list):
1553 """Fake calls to the futility utility"""
1554 if pipe_list[0][0] == 'futility':
1555 fname = pipe_list[0][-1]
1556 # Append our GBB data to the file, which will happen every time the
1557 # futility command is called.
1558 with open(fname, 'ab') as fd:
1560 return command.CommandResult()
1563 """Test for the Chromium OS Google Binary Block"""
1564 command.test_result = self._HandleGbbCommand
1566 'keydir': 'devkeys',
1567 'bmpblk': 'bmpblk.bin',
1569 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1572 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1573 tools.GetBytes(0, 0x2180 - 16))
1574 self.assertEqual(expected, data)
1576 def testGbbTooSmall(self):
1577 """Test for the Chromium OS Google Binary Block being large enough"""
1578 with self.assertRaises(ValueError) as e:
1579 self._DoReadFileDtb('072_gbb_too_small.dts')
1580 self.assertIn("Node '/binman/gbb': GBB is too small",
1583 def testGbbNoSize(self):
1584 """Test for the Chromium OS Google Binary Block having a size"""
1585 with self.assertRaises(ValueError) as e:
1586 self._DoReadFileDtb('073_gbb_no_size.dts')
1587 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1590 def _HandleVblockCommand(self, pipe_list):
1591 """Fake calls to the futility utility"""
1592 if pipe_list[0][0] == 'futility':
1593 fname = pipe_list[0][3]
1594 with open(fname, 'wb') as fd:
1595 fd.write(VBLOCK_DATA)
1596 return command.CommandResult()
1598 def testVblock(self):
1599 """Test for the Chromium OS Verified Boot Block"""
1600 command.test_result = self._HandleVblockCommand
1602 'keydir': 'devkeys',
1604 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1605 entry_args=entry_args)
1606 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1607 self.assertEqual(expected, data)
1609 def testVblockNoContent(self):
1610 """Test we detect a vblock which has no content to sign"""
1611 with self.assertRaises(ValueError) as e:
1612 self._DoReadFile('075_vblock_no_content.dts')
1613 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1614 'property', str(e.exception))
1616 def testVblockBadPhandle(self):
1617 """Test that we detect a vblock with an invalid phandle in contents"""
1618 with self.assertRaises(ValueError) as e:
1619 self._DoReadFile('076_vblock_bad_phandle.dts')
1620 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1621 '1000', str(e.exception))
1623 def testVblockBadEntry(self):
1624 """Test that we detect an entry that points to a non-entry"""
1625 with self.assertRaises(ValueError) as e:
1626 self._DoReadFile('077_vblock_bad_entry.dts')
1627 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1628 "'other'", str(e.exception))
1631 """Test that an image with TPL and its device tree can be created"""
1632 # ELF file with a '__bss_size' symbol
1634 data = self._DoReadFile('078_u_boot_tpl.dts')
1635 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1637 def testUsesPos(self):
1638 """Test that the 'pos' property cannot be used anymore"""
1639 with self.assertRaises(ValueError) as e:
1640 data = self._DoReadFile('079_uses_pos.dts')
1641 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1642 "'pos'", str(e.exception))
1644 def testFillZero(self):
1645 """Test for an fill entry type with a size of 0"""
1646 data = self._DoReadFile('080_fill_empty.dts')
1647 self.assertEqual(tools.GetBytes(0, 16), data)
1649 def testTextMissing(self):
1650 """Test for a text entry type where there is no text"""
1651 with self.assertRaises(ValueError) as e:
1652 self._DoReadFileDtb('066_text.dts',)
1653 self.assertIn("Node '/binman/text': No value provided for text label "
1654 "'test-id'", str(e.exception))
1656 def testPackStart16Tpl(self):
1657 """Test that an image with an x86 start16 TPL region can be created"""
1658 data = self._DoReadFile('081_x86_start16_tpl.dts')
1659 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1661 def testSelectImage(self):
1662 """Test that we can select which images to build"""
1663 expected = 'Skipping images: image1'
1665 # We should only get the expected message in verbose mode
1666 for verbosity in (0, 2):
1667 with test_util.capture_sys_output() as (stdout, stderr):
1668 retcode = self._DoTestFile('006_dual_image.dts',
1669 verbosity=verbosity,
1671 self.assertEqual(0, retcode)
1673 self.assertIn(expected, stdout.getvalue())
1675 self.assertNotIn(expected, stdout.getvalue())
1677 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1678 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1679 self._CleanupOutputDir()
1681 def testUpdateFdtAll(self):
1682 """Test that all device trees are updated with offset/size info"""
1683 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1686 'section:image-pos': 0,
1687 'u-boot-tpl-dtb:size': 513,
1688 'u-boot-spl-dtb:size': 513,
1689 'u-boot-spl-dtb:offset': 493,
1691 'section/u-boot-dtb:image-pos': 0,
1692 'u-boot-spl-dtb:image-pos': 493,
1693 'section/u-boot-dtb:size': 493,
1694 'u-boot-tpl-dtb:image-pos': 1006,
1695 'section/u-boot-dtb:offset': 0,
1696 'section:size': 493,
1698 'section:offset': 0,
1699 'u-boot-tpl-dtb:offset': 1006,
1703 # We expect three device-tree files in the output, one after the other.
1704 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1705 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1706 # main U-Boot tree. All three should have the same postions and offset.
1708 for item in ['', 'spl', 'tpl']:
1709 dtb = fdt.Fdt.FromData(data[start:])
1711 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1713 expected = dict(base_expected)
1716 self.assertEqual(expected, props)
1717 start += dtb._fdt_obj.totalsize()
1719 def testUpdateFdtOutput(self):
1720 """Test that output DTB files are updated"""
1722 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1723 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1725 # Unfortunately, compiling a source file always results in a file
1726 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1727 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1728 # binman as a file called u-boot.dtb. To fix this, copy the file
1729 # over to the expected place.
1731 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1732 'tpl/u-boot-tpl.dtb.out']:
1733 dtb = fdt.Fdt.FromData(data[start:])
1734 size = dtb._fdt_obj.totalsize()
1735 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1736 outdata = tools.ReadFile(pathname)
1737 name = os.path.split(fname)[0]
1740 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1742 orig_indata = dtb_data
1743 self.assertNotEqual(outdata, orig_indata,
1744 "Expected output file '%s' be updated" % pathname)
1745 self.assertEqual(outdata, data[start:start + size],
1746 "Expected output file '%s' to match output image" %
1752 def _decompress(self, data):
1753 return tools.Decompress(data, 'lz4')
1755 def testCompress(self):
1756 """Test compression of blobs"""
1758 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1759 use_real_dtb=True, update_dtb=True)
1760 dtb = fdt.Fdt(out_dtb_fname)
1762 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1763 orig = self._decompress(data)
1764 self.assertEquals(COMPRESS_DATA, orig)
1766 'blob:uncomp-size': len(COMPRESS_DATA),
1767 'blob:size': len(data),
1770 self.assertEqual(expected, props)
1772 def testFiles(self):
1773 """Test bringing in multiple files"""
1774 data = self._DoReadFile('084_files.dts')
1775 self.assertEqual(FILES_DATA, data)
1777 def testFilesCompress(self):
1778 """Test bringing in multiple files and compressing them"""
1780 data = self._DoReadFile('085_files_compress.dts')
1782 image = control.images['image']
1783 entries = image.GetEntries()
1784 files = entries['files']
1785 entries = files._entries
1788 for i in range(1, 3):
1790 start = entries[key].image_pos
1791 len = entries[key].size
1792 chunk = data[start:start + len]
1793 orig += self._decompress(chunk)
1795 self.assertEqual(FILES_DATA, orig)
1797 def testFilesMissing(self):
1798 """Test missing files"""
1799 with self.assertRaises(ValueError) as e:
1800 data = self._DoReadFile('086_files_none.dts')
1801 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1802 'no files', str(e.exception))
1804 def testFilesNoPattern(self):
1805 """Test missing files"""
1806 with self.assertRaises(ValueError) as e:
1807 data = self._DoReadFile('087_files_no_pattern.dts')
1808 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1811 def testExpandSize(self):
1812 """Test an expanding entry"""
1813 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1815 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1816 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1817 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1818 tools.GetBytes(ord('d'), 8))
1819 self.assertEqual(expect, data)
1820 self.assertEqual('''ImagePos Offset Size Name
1821 00000000 00000000 00000028 main-section
1822 00000000 00000000 00000008 fill
1823 00000008 00000008 00000004 u-boot
1824 0000000c 0000000c 00000004 section
1825 0000000c 00000000 00000003 intel-mrc
1826 00000010 00000010 00000004 u-boot2
1827 00000014 00000014 0000000c section2
1828 00000014 00000000 00000008 fill
1829 0000001c 00000008 00000004 u-boot
1830 00000020 00000020 00000008 fill2
1833 def testExpandSizeBad(self):
1834 """Test an expanding entry which fails to provide contents"""
1835 with test_util.capture_sys_output() as (stdout, stderr):
1836 with self.assertRaises(ValueError) as e:
1837 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1838 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1839 'expanding entry', str(e.exception))
1842 """Test hashing of the contents of an entry"""
1843 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1844 use_real_dtb=True, update_dtb=True)
1845 dtb = fdt.Fdt(out_dtb_fname)
1847 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1848 m = hashlib.sha256()
1849 m.update(U_BOOT_DATA)
1850 self.assertEqual(m.digest(), b''.join(hash_node.value))
1852 def testHashNoAlgo(self):
1853 with self.assertRaises(ValueError) as e:
1854 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1855 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1856 'hash node', str(e.exception))
1858 def testHashBadAlgo(self):
1859 with self.assertRaises(ValueError) as e:
1860 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1861 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1864 def testHashSection(self):
1865 """Test hashing of the contents of an entry"""
1866 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1867 use_real_dtb=True, update_dtb=True)
1868 dtb = fdt.Fdt(out_dtb_fname)
1870 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1871 m = hashlib.sha256()
1872 m.update(U_BOOT_DATA)
1873 m.update(tools.GetBytes(ord('a'), 16))
1874 self.assertEqual(m.digest(), b''.join(hash_node.value))
1876 def testPackUBootTplMicrocode(self):
1877 """Test that x86 microcode can be handled correctly in TPL
1879 We expect to see the following in the image, in order:
1880 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1882 u-boot-tpl.dtb with the microcode removed
1885 self._SetupTplElf('u_boot_ucode_ptr')
1886 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1887 U_BOOT_TPL_NODTB_DATA)
1888 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1889 b'ter somewhere in here', first)
1891 def testFmapX86(self):
1892 """Basic test of generation of a flashrom fmap"""
1893 data = self._DoReadFile('094_fmap_x86.dts')
1894 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1895 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1896 self.assertEqual(expected, data[:32])
1897 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1899 self.assertEqual(0x100, fhdr.image_size)
1901 self.assertEqual(0, fentries[0].offset)
1902 self.assertEqual(4, fentries[0].size)
1903 self.assertEqual(b'U_BOOT', fentries[0].name)
1905 self.assertEqual(4, fentries[1].offset)
1906 self.assertEqual(3, fentries[1].size)
1907 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1909 self.assertEqual(32, fentries[2].offset)
1910 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1911 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1912 self.assertEqual(b'FMAP', fentries[2].name)
1914 def testFmapX86Section(self):
1915 """Basic test of generation of a flashrom fmap"""
1916 data = self._DoReadFile('095_fmap_x86_section.dts')
1917 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1918 self.assertEqual(expected, data[:32])
1919 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1921 self.assertEqual(0x100, fhdr.image_size)
1923 self.assertEqual(0, fentries[0].offset)
1924 self.assertEqual(4, fentries[0].size)
1925 self.assertEqual(b'U_BOOT', fentries[0].name)
1927 self.assertEqual(4, fentries[1].offset)
1928 self.assertEqual(3, fentries[1].size)
1929 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1931 self.assertEqual(36, fentries[2].offset)
1932 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1933 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1934 self.assertEqual(b'FMAP', fentries[2].name)
1937 """Basic test of ELF entries"""
1940 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1941 TestFunctional._MakeInputFile('-boot', fd.read())
1942 data = self._DoReadFile('096_elf.dts')
1944 def testElfStrip(self):
1945 """Basic test of ELF entries"""
1947 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1948 TestFunctional._MakeInputFile('-boot', fd.read())
1949 data = self._DoReadFile('097_elf_strip.dts')
1951 def testPackOverlapMap(self):
1952 """Test that overlapping regions are detected"""
1953 with test_util.capture_sys_output() as (stdout, stderr):
1954 with self.assertRaises(ValueError) as e:
1955 self._DoTestFile('014_pack_overlap.dts', map=True)
1956 map_fname = tools.GetOutputFilename('image.map')
1957 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1960 # We should not get an inmage, but there should be a map file
1961 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1962 self.assertTrue(os.path.exists(map_fname))
1963 map_data = tools.ReadFile(map_fname, binary=False)
1964 self.assertEqual('''ImagePos Offset Size Name
1965 <none> 00000000 00000007 main-section
1966 <none> 00000000 00000004 u-boot
1967 <none> 00000003 00000004 u-boot-align
1970 def testPackRefCode(self):
1971 """Test that an image with an Intel Reference code binary works"""
1972 data = self._DoReadFile('100_intel_refcode.dts')
1973 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1975 def testSectionOffset(self):
1976 """Tests use of a section with an offset"""
1977 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1979 self.assertEqual('''ImagePos Offset Size Name
1980 00000000 00000000 00000038 main-section
1981 00000004 00000004 00000010 section@0
1982 00000004 00000000 00000004 u-boot
1983 00000018 00000018 00000010 section@1
1984 00000018 00000000 00000004 u-boot
1985 0000002c 0000002c 00000004 section@2
1986 0000002c 00000000 00000004 u-boot
1988 self.assertEqual(data,
1989 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1990 tools.GetBytes(0x21, 12) +
1991 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1992 tools.GetBytes(0x61, 12) +
1993 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1994 tools.GetBytes(0x26, 8))
1996 def testCbfsRaw(self):
1997 """Test base handling of a Coreboot Filesystem (CBFS)
1999 The exact contents of the CBFS is verified by similar tests in
2000 cbfs_util_test.py. The tests here merely check that the files added to
2001 the CBFS can be found in the final image.
2003 data = self._DoReadFile('102_cbfs_raw.dts')
2006 cbfs = cbfs_util.CbfsReader(data)
2007 self.assertEqual(size, cbfs.rom_size)
2009 self.assertIn('u-boot-dtb', cbfs.files)
2010 cfile = cbfs.files['u-boot-dtb']
2011 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2013 def testCbfsArch(self):
2014 """Test on non-x86 architecture"""
2015 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2018 cbfs = cbfs_util.CbfsReader(data)
2019 self.assertEqual(size, cbfs.rom_size)
2021 self.assertIn('u-boot-dtb', cbfs.files)
2022 cfile = cbfs.files['u-boot-dtb']
2023 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2025 def testCbfsStage(self):
2026 """Tests handling of a Coreboot Filesystem (CBFS)"""
2027 if not elf.ELF_TOOLS:
2028 self.skipTest('Python elftools not available')
2029 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2030 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2033 data = self._DoReadFile('104_cbfs_stage.dts')
2034 cbfs = cbfs_util.CbfsReader(data)
2035 self.assertEqual(size, cbfs.rom_size)
2037 self.assertIn('u-boot', cbfs.files)
2038 cfile = cbfs.files['u-boot']
2039 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2041 def testCbfsRawCompress(self):
2042 """Test handling of compressing raw files"""
2044 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2047 cbfs = cbfs_util.CbfsReader(data)
2048 self.assertIn('u-boot', cbfs.files)
2049 cfile = cbfs.files['u-boot']
2050 self.assertEqual(COMPRESS_DATA, cfile.data)
2052 def testCbfsBadArch(self):
2053 """Test handling of a bad architecture"""
2054 with self.assertRaises(ValueError) as e:
2055 self._DoReadFile('106_cbfs_bad_arch.dts')
2056 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2058 def testCbfsNoSize(self):
2059 """Test handling of a missing size property"""
2060 with self.assertRaises(ValueError) as e:
2061 self._DoReadFile('107_cbfs_no_size.dts')
2062 self.assertIn('entry must have a size property', str(e.exception))
2064 def testCbfsNoCOntents(self):
2065 """Test handling of a CBFS entry which does not provide contentsy"""
2066 with self.assertRaises(ValueError) as e:
2067 self._DoReadFile('108_cbfs_no_contents.dts')
2068 self.assertIn('Could not complete processing of contents',
2071 def testCbfsBadCompress(self):
2072 """Test handling of a bad architecture"""
2073 with self.assertRaises(ValueError) as e:
2074 self._DoReadFile('109_cbfs_bad_compress.dts')
2075 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2078 def testCbfsNamedEntries(self):
2079 """Test handling of named entries"""
2080 data = self._DoReadFile('110_cbfs_name.dts')
2082 cbfs = cbfs_util.CbfsReader(data)
2083 self.assertIn('FRED', cbfs.files)
2084 cfile1 = cbfs.files['FRED']
2085 self.assertEqual(U_BOOT_DATA, cfile1.data)
2087 self.assertIn('hello', cbfs.files)
2088 cfile2 = cbfs.files['hello']
2089 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2091 def _SetupIfwi(self, fname):
2092 """Set up to run an IFWI test
2095 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2100 # Intel Integrated Firmware Image (IFWI) file
2101 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2103 TestFunctional._MakeInputFile(fname,data)
2105 def _CheckIfwi(self, data):
2106 """Check that an image with an IFWI contains the correct output
2109 data: Conents of output file
2111 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2112 if data[:0x1000] != expected_desc:
2113 self.fail('Expected descriptor binary at start of image')
2115 # We expect to find the TPL wil in subpart IBBP entry IBBL
2116 image_fname = tools.GetOutputFilename('image.bin')
2117 tpl_fname = tools.GetOutputFilename('tpl.out')
2118 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2119 subpart='IBBP', entry_name='IBBL')
2121 tpl_data = tools.ReadFile(tpl_fname)
2122 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2124 def testPackX86RomIfwi(self):
2125 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2126 self._SetupIfwi('fitimage.bin')
2127 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2128 self._CheckIfwi(data)
2130 def testPackX86RomIfwiNoDesc(self):
2131 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2132 self._SetupIfwi('ifwi.bin')
2133 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2134 self._CheckIfwi(data)
2136 def testPackX86RomIfwiNoData(self):
2137 """Test that an x86 ROM with IFWI handles missing data"""
2138 self._SetupIfwi('ifwi.bin')
2139 with self.assertRaises(ValueError) as e:
2140 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2141 self.assertIn('Could not complete processing of contents',
2144 def testCbfsOffset(self):
2145 """Test a CBFS with files at particular offsets
2147 Like all CFBS tests, this is just checking the logic that calls
2148 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2150 data = self._DoReadFile('114_cbfs_offset.dts')
2153 cbfs = cbfs_util.CbfsReader(data)
2154 self.assertEqual(size, cbfs.rom_size)
2156 self.assertIn('u-boot', cbfs.files)
2157 cfile = cbfs.files['u-boot']
2158 self.assertEqual(U_BOOT_DATA, cfile.data)
2159 self.assertEqual(0x40, cfile.cbfs_offset)
2161 self.assertIn('u-boot-dtb', cbfs.files)
2162 cfile2 = cbfs.files['u-boot-dtb']
2163 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2164 self.assertEqual(0x140, cfile2.cbfs_offset)
2166 def testFdtmap(self):
2167 """Test an FDT map can be inserted in the image"""
2168 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2169 fdtmap_data = data[len(U_BOOT_DATA):]
2170 magic = fdtmap_data[:8]
2171 self.assertEqual(b'_FDTMAP_', magic)
2172 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2174 fdt_data = fdtmap_data[16:]
2175 dtb = fdt.Fdt.FromData(fdt_data)
2177 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2182 'u-boot:size': len(U_BOOT_DATA),
2183 'u-boot:image-pos': 0,
2184 'fdtmap:image-pos': 4,
2186 'fdtmap:size': len(fdtmap_data),
2190 def testFdtmapNoMatch(self):
2191 """Check handling of an FDT map when the section cannot be found"""
2192 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2194 # Mangle the section name, which should cause a mismatch between the
2195 # correct FDT path and the one expected by the section
2196 image = control.images['image']
2197 image._node.path += '-suffix'
2198 entries = image.GetEntries()
2199 fdtmap = entries['fdtmap']
2200 with self.assertRaises(ValueError) as e:
2202 self.assertIn("Cannot locate node for path '/binman-suffix'",
2205 def testFdtmapHeader(self):
2206 """Test an FDT map and image header can be inserted in the image"""
2207 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2208 fdtmap_pos = len(U_BOOT_DATA)
2209 fdtmap_data = data[fdtmap_pos:]
2210 fdt_data = fdtmap_data[16:]
2211 dtb = fdt.Fdt.FromData(fdt_data)
2212 fdt_size = dtb.GetFdtObj().totalsize()
2213 hdr_data = data[-8:]
2214 self.assertEqual(b'BinM', hdr_data[:4])
2215 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2216 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2218 def testFdtmapHeaderStart(self):
2219 """Test an image header can be inserted at the image start"""
2220 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2221 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2223 self.assertEqual(b'BinM', hdr_data[:4])
2224 offset = struct.unpack('<I', hdr_data[4:])[0]
2225 self.assertEqual(fdtmap_pos, offset)
2227 def testFdtmapHeaderPos(self):
2228 """Test an image header can be inserted at a chosen position"""
2229 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2230 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2231 hdr_data = data[0x80:0x88]
2232 self.assertEqual(b'BinM', hdr_data[:4])
2233 offset = struct.unpack('<I', hdr_data[4:])[0]
2234 self.assertEqual(fdtmap_pos, offset)
2236 def testHeaderMissingFdtmap(self):
2237 """Test an image header requires an fdtmap"""
2238 with self.assertRaises(ValueError) as e:
2239 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2240 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2243 def testHeaderNoLocation(self):
2244 """Test an image header with a no specified location is detected"""
2245 with self.assertRaises(ValueError) as e:
2246 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2247 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2250 def testEntryExpand(self):
2251 """Test expanding an entry after it is packed"""
2252 data = self._DoReadFile('121_entry_expand.dts')
2253 self.assertEqual(b'aaa', data[:3])
2254 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2255 self.assertEqual(b'aaa', data[-3:])
2257 def testEntryExpandBad(self):
2258 """Test expanding an entry after it is packed, twice"""
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFile('122_entry_expand_twice.dts')
2261 self.assertIn("Image '/binman': Entries changed size after packing",
2264 def testEntryExpandSection(self):
2265 """Test expanding an entry within a section after it is packed"""
2266 data = self._DoReadFile('123_entry_expand_section.dts')
2267 self.assertEqual(b'aaa', data[:3])
2268 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2269 self.assertEqual(b'aaa', data[-3:])
2271 def testCompressDtb(self):
2272 """Test that compress of device-tree files is supported"""
2274 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2275 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2276 comp_data = data[len(U_BOOT_DATA):]
2277 orig = self._decompress(comp_data)
2278 dtb = fdt.Fdt.FromData(orig)
2280 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2282 'u-boot:size': len(U_BOOT_DATA),
2283 'u-boot-dtb:uncomp-size': len(orig),
2284 'u-boot-dtb:size': len(comp_data),
2287 self.assertEqual(expected, props)
2289 def testCbfsUpdateFdt(self):
2290 """Test that we can update the device tree with CBFS offset/size info"""
2292 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2294 dtb = fdt.Fdt(out_dtb_fname)
2296 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2297 del props['cbfs/u-boot:size']
2303 'cbfs:size': len(data),
2304 'cbfs:image-pos': 0,
2305 'cbfs/u-boot:offset': 0x38,
2306 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2307 'cbfs/u-boot:image-pos': 0x38,
2308 'cbfs/u-boot-dtb:offset': 0xb8,
2309 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2310 'cbfs/u-boot-dtb:image-pos': 0xb8,
2313 def testCbfsBadType(self):
2314 """Test an image header with a no specified location is detected"""
2315 with self.assertRaises(ValueError) as e:
2316 self._DoReadFile('126_cbfs_bad_type.dts')
2317 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2320 """Test listing the files in an image"""
2322 data = self._DoReadFile('127_list.dts')
2323 image = control.images['image']
2324 entries = image.BuildEntryList()
2325 self.assertEqual(7, len(entries))
2328 self.assertEqual(0, ent.indent)
2329 self.assertEqual('main-section', ent.name)
2330 self.assertEqual('section', ent.etype)
2331 self.assertEqual(len(data), ent.size)
2332 self.assertEqual(0, ent.image_pos)
2333 self.assertEqual(None, ent.uncomp_size)
2334 self.assertEqual(0, ent.offset)
2337 self.assertEqual(1, ent.indent)
2338 self.assertEqual('u-boot', ent.name)
2339 self.assertEqual('u-boot', ent.etype)
2340 self.assertEqual(len(U_BOOT_DATA), ent.size)
2341 self.assertEqual(0, ent.image_pos)
2342 self.assertEqual(None, ent.uncomp_size)
2343 self.assertEqual(0, ent.offset)
2346 self.assertEqual(1, ent.indent)
2347 self.assertEqual('section', ent.name)
2348 self.assertEqual('section', ent.etype)
2349 section_size = ent.size
2350 self.assertEqual(0x100, ent.image_pos)
2351 self.assertEqual(None, ent.uncomp_size)
2352 self.assertEqual(0x100, ent.offset)
2355 self.assertEqual(2, ent.indent)
2356 self.assertEqual('cbfs', ent.name)
2357 self.assertEqual('cbfs', ent.etype)
2358 self.assertEqual(0x400, ent.size)
2359 self.assertEqual(0x100, ent.image_pos)
2360 self.assertEqual(None, ent.uncomp_size)
2361 self.assertEqual(0, ent.offset)
2364 self.assertEqual(3, ent.indent)
2365 self.assertEqual('u-boot', ent.name)
2366 self.assertEqual('u-boot', ent.etype)
2367 self.assertEqual(len(U_BOOT_DATA), ent.size)
2368 self.assertEqual(0x138, ent.image_pos)
2369 self.assertEqual(None, ent.uncomp_size)
2370 self.assertEqual(0x38, ent.offset)
2373 self.assertEqual(3, ent.indent)
2374 self.assertEqual('u-boot-dtb', ent.name)
2375 self.assertEqual('text', ent.etype)
2376 self.assertGreater(len(COMPRESS_DATA), ent.size)
2377 self.assertEqual(0x178, ent.image_pos)
2378 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2379 self.assertEqual(0x78, ent.offset)
2382 self.assertEqual(2, ent.indent)
2383 self.assertEqual('u-boot-dtb', ent.name)
2384 self.assertEqual('u-boot-dtb', ent.etype)
2385 self.assertEqual(0x500, ent.image_pos)
2386 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2388 # Compressing this data expands it since headers are added
2389 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2390 self.assertEqual(0x400, ent.offset)
2392 self.assertEqual(len(data), 0x100 + section_size)
2393 self.assertEqual(section_size, 0x400 + dtb_size)
2395 def testFindFdtmap(self):
2396 """Test locating an FDT map in an image"""
2398 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2399 image = control.images['image']
2400 entries = image.GetEntries()
2401 entry = entries['fdtmap']
2402 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2404 def testFindFdtmapMissing(self):
2405 """Test failing to locate an FDP map"""
2406 data = self._DoReadFile('005_simple.dts')
2407 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2409 def testFindImageHeader(self):
2410 """Test locating a image header"""
2412 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2413 image = control.images['image']
2414 entries = image.GetEntries()
2415 entry = entries['fdtmap']
2416 # The header should point to the FDT map
2417 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2419 def testFindImageHeaderStart(self):
2420 """Test locating a image header located at the start of an image"""
2421 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2422 image = control.images['image']
2423 entries = image.GetEntries()
2424 entry = entries['fdtmap']
2425 # The header should point to the FDT map
2426 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2428 def testFindImageHeaderMissing(self):
2429 """Test failing to locate an image header"""
2430 data = self._DoReadFile('005_simple.dts')
2431 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2433 def testReadImage(self):
2434 """Test reading an image and accessing its FDT map"""
2436 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2437 image_fname = tools.GetOutputFilename('image.bin')
2438 orig_image = control.images['image']
2439 image = Image.FromFile(image_fname)
2440 self.assertEqual(orig_image.GetEntries().keys(),
2441 image.GetEntries().keys())
2443 orig_entry = orig_image.GetEntries()['fdtmap']
2444 entry = image.GetEntries()['fdtmap']
2445 self.assertEquals(orig_entry.offset, entry.offset)
2446 self.assertEquals(orig_entry.size, entry.size)
2447 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2449 def testReadImageNoHeader(self):
2450 """Test accessing an image's FDT map without an image header"""
2452 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2453 image_fname = tools.GetOutputFilename('image.bin')
2454 image = Image.FromFile(image_fname)
2455 self.assertTrue(isinstance(image, Image))
2456 self.assertEqual('image', image.image_name[-5:])
2458 def testReadImageFail(self):
2459 """Test failing to read an image image's FDT map"""
2460 self._DoReadFile('005_simple.dts')
2461 image_fname = tools.GetOutputFilename('image.bin')
2462 with self.assertRaises(ValueError) as e:
2463 image = Image.FromFile(image_fname)
2464 self.assertIn("Cannot find FDT map in image", str(e.exception))
2466 def testListCmd(self):
2467 """Test listing the files in an image using an Fdtmap"""
2469 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2471 # lz4 compression size differs depending on the version
2472 image = control.images['image']
2473 entries = image.GetEntries()
2474 section_size = entries['section'].size
2475 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2476 fdtmap_offset = entries['fdtmap'].offset
2479 tmpdir, updated_fname = self._SetupImageInTmpdir()
2480 with test_util.capture_sys_output() as (stdout, stderr):
2481 self._DoBinman('ls', '-i', updated_fname)
2483 shutil.rmtree(tmpdir)
2484 lines = stdout.getvalue().splitlines()
2486 'Name Image-pos Size Entry-type Offset Uncomp-size',
2487 '----------------------------------------------------------------------',
2488 'main-section 0 c00 section 0',
2489 ' u-boot 0 4 u-boot 0',
2490 ' section 100 %x section 100' % section_size,
2491 ' cbfs 100 400 cbfs 0',
2492 ' u-boot 138 4 u-boot 38',
2493 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2494 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2495 ' fdtmap %x 3bd fdtmap %x' %
2496 (fdtmap_offset, fdtmap_offset),
2497 ' image-header bf8 8 image-header bf8',
2499 self.assertEqual(expected, lines)
2501 def testListCmdFail(self):
2502 """Test failing to list an image"""
2503 self._DoReadFile('005_simple.dts')
2505 tmpdir, updated_fname = self._SetupImageInTmpdir()
2506 with self.assertRaises(ValueError) as e:
2507 self._DoBinman('ls', '-i', updated_fname)
2509 shutil.rmtree(tmpdir)
2510 self.assertIn("Cannot find FDT map in image", str(e.exception))
2512 def _RunListCmd(self, paths, expected):
2513 """List out entries and check the result
2516 paths: List of paths to pass to the list command
2517 expected: Expected list of filenames to be returned, in order
2520 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2521 image_fname = tools.GetOutputFilename('image.bin')
2522 image = Image.FromFile(image_fname)
2523 lines = image.GetListEntries(paths)[1]
2524 files = [line[0].strip() for line in lines[1:]]
2525 self.assertEqual(expected, files)
2527 def testListCmdSection(self):
2528 """Test listing the files in a section"""
2529 self._RunListCmd(['section'],
2530 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2532 def testListCmdFile(self):
2533 """Test listing a particular file"""
2534 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2536 def testListCmdWildcard(self):
2537 """Test listing a wildcarded file"""
2538 self._RunListCmd(['*boot*'],
2539 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2541 def testListCmdWildcardMulti(self):
2542 """Test listing a wildcarded file"""
2543 self._RunListCmd(['*cb*', '*head*'],
2544 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2546 def testListCmdEmpty(self):
2547 """Test listing a wildcarded file"""
2548 self._RunListCmd(['nothing'], [])
2550 def testListCmdPath(self):
2551 """Test listing the files in a sub-entry of a section"""
2552 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2554 def _RunExtractCmd(self, entry_name, decomp=True):
2555 """Extract an entry from an image
2558 entry_name: Entry name to extract
2559 decomp: True to decompress the data if compressed, False to leave
2560 it in its raw uncompressed format
2566 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2567 image_fname = tools.GetOutputFilename('image.bin')
2568 return control.ReadEntry(image_fname, entry_name, decomp)
2570 def testExtractSimple(self):
2571 """Test extracting a single file"""
2572 data = self._RunExtractCmd('u-boot')
2573 self.assertEqual(U_BOOT_DATA, data)
2575 def testExtractSection(self):
2576 """Test extracting the files in a section"""
2577 data = self._RunExtractCmd('section')
2578 cbfs_data = data[:0x400]
2579 cbfs = cbfs_util.CbfsReader(cbfs_data)
2580 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2581 dtb_data = data[0x400:]
2582 dtb = self._decompress(dtb_data)
2583 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2585 def testExtractCompressed(self):
2586 """Test extracting compressed data"""
2587 data = self._RunExtractCmd('section/u-boot-dtb')
2588 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2590 def testExtractRaw(self):
2591 """Test extracting compressed data without decompressing it"""
2592 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2593 dtb = self._decompress(data)
2594 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2596 def testExtractCbfs(self):
2597 """Test extracting CBFS data"""
2598 data = self._RunExtractCmd('section/cbfs/u-boot')
2599 self.assertEqual(U_BOOT_DATA, data)
2601 def testExtractCbfsCompressed(self):
2602 """Test extracting CBFS compressed data"""
2603 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2604 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2606 def testExtractCbfsRaw(self):
2607 """Test extracting CBFS compressed data without decompressing it"""
2608 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2609 dtb = tools.Decompress(data, 'lzma', with_header=False)
2610 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2612 def testExtractBadEntry(self):
2613 """Test extracting a bad section path"""
2614 with self.assertRaises(ValueError) as e:
2615 self._RunExtractCmd('section/does-not-exist')
2616 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2619 def testExtractMissingFile(self):
2620 """Test extracting file that does not exist"""
2621 with self.assertRaises(IOError) as e:
2622 control.ReadEntry('missing-file', 'name')
2624 def testExtractBadFile(self):
2625 """Test extracting an invalid file"""
2626 fname = os.path.join(self._indir, 'badfile')
2627 tools.WriteFile(fname, b'')
2628 with self.assertRaises(ValueError) as e:
2629 control.ReadEntry(fname, 'name')
2631 def testExtractCmd(self):
2632 """Test extracting a file fron an image on the command line"""
2634 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2635 fname = os.path.join(self._indir, 'output.extact')
2637 tmpdir, updated_fname = self._SetupImageInTmpdir()
2638 with test_util.capture_sys_output() as (stdout, stderr):
2639 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2642 shutil.rmtree(tmpdir)
2643 data = tools.ReadFile(fname)
2644 self.assertEqual(U_BOOT_DATA, data)
2646 def testExtractOneEntry(self):
2647 """Test extracting a single entry fron an image """
2649 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2650 image_fname = tools.GetOutputFilename('image.bin')
2651 fname = os.path.join(self._indir, 'output.extact')
2652 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2653 data = tools.ReadFile(fname)
2654 self.assertEqual(U_BOOT_DATA, data)
2656 def _CheckExtractOutput(self, decomp):
2657 """Helper to test file output with and without decompression
2660 decomp: True to decompress entry data, False to output it raw
2662 def _CheckPresent(entry_path, expect_data, expect_size=None):
2663 """Check and remove expected file
2665 This checks the data/size of a file and removes the file both from
2666 the outfiles set and from the output directory. Once all files are
2667 processed, both the set and directory should be empty.
2670 entry_path: Entry path
2671 expect_data: Data to expect in file, or None to skip check
2672 expect_size: Size of data to expect in file, or None to skip
2674 path = os.path.join(outdir, entry_path)
2675 data = tools.ReadFile(path)
2678 self.assertEqual(expect_data, data)
2680 self.assertEqual(expect_size, len(data))
2681 outfiles.remove(path)
2683 def _CheckDirPresent(name):
2684 """Remove expected directory
2686 This gives an error if the directory does not exist as expected
2689 name: Name of directory to remove
2691 path = os.path.join(outdir, name)
2694 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2695 image_fname = tools.GetOutputFilename('image.bin')
2696 outdir = os.path.join(self._indir, 'extract')
2697 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2699 # Create a set of all file that were output (should be 9)
2701 for root, dirs, files in os.walk(outdir):
2702 outfiles |= set([os.path.join(root, fname) for fname in files])
2703 self.assertEqual(9, len(outfiles))
2704 self.assertEqual(9, len(einfos))
2706 image = control.images['image']
2707 entries = image.GetEntries()
2709 # Check the 9 files in various ways
2710 section = entries['section']
2711 section_entries = section.GetEntries()
2712 cbfs_entries = section_entries['cbfs'].GetEntries()
2713 _CheckPresent('u-boot', U_BOOT_DATA)
2714 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2715 dtb_len = EXTRACT_DTB_SIZE
2717 dtb_len = cbfs_entries['u-boot-dtb'].size
2718 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2720 dtb_len = section_entries['u-boot-dtb'].size
2721 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2723 fdtmap = entries['fdtmap']
2724 _CheckPresent('fdtmap', fdtmap.data)
2725 hdr = entries['image-header']
2726 _CheckPresent('image-header', hdr.data)
2728 _CheckPresent('section/root', section.data)
2729 cbfs = section_entries['cbfs']
2730 _CheckPresent('section/cbfs/root', cbfs.data)
2731 data = tools.ReadFile(image_fname)
2732 _CheckPresent('root', data)
2734 # There should be no files left. Remove all the directories to check.
2735 # If there are any files/dirs remaining, one of these checks will fail.
2736 self.assertEqual(0, len(outfiles))
2737 _CheckDirPresent('section/cbfs')
2738 _CheckDirPresent('section')
2739 _CheckDirPresent('')
2740 self.assertFalse(os.path.exists(outdir))
2742 def testExtractAllEntries(self):
2743 """Test extracting all entries"""
2745 self._CheckExtractOutput(decomp=True)
2747 def testExtractAllEntriesRaw(self):
2748 """Test extracting all entries without decompressing them"""
2750 self._CheckExtractOutput(decomp=False)
2752 def testExtractSelectedEntries(self):
2753 """Test extracting some entries"""
2755 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2756 image_fname = tools.GetOutputFilename('image.bin')
2757 outdir = os.path.join(self._indir, 'extract')
2758 einfos = control.ExtractEntries(image_fname, None, outdir,
2761 # File output is tested by testExtractAllEntries(), so just check that
2762 # the expected entries are selected
2763 names = [einfo.name for einfo in einfos]
2764 self.assertEqual(names,
2765 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2767 def testExtractNoEntryPaths(self):
2768 """Test extracting some entries"""
2770 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2771 image_fname = tools.GetOutputFilename('image.bin')
2772 with self.assertRaises(ValueError) as e:
2773 control.ExtractEntries(image_fname, 'fname', None, [])
2774 self.assertIn('Must specify an entry path to write with -f',
2777 def testExtractTooManyEntryPaths(self):
2778 """Test extracting some entries"""
2780 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2781 image_fname = tools.GetOutputFilename('image.bin')
2782 with self.assertRaises(ValueError) as e:
2783 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2784 self.assertIn('Must specify exactly one entry path to write with -f',
2787 def testPackAlignSection(self):
2788 """Test that sections can have alignment"""
2789 self._DoReadFile('131_pack_align_section.dts')
2791 self.assertIn('image', control.images)
2792 image = control.images['image']
2793 entries = image.GetEntries()
2794 self.assertEqual(3, len(entries))
2797 self.assertIn('u-boot', entries)
2798 entry = entries['u-boot']
2799 self.assertEqual(0, entry.offset)
2800 self.assertEqual(0, entry.image_pos)
2801 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2802 self.assertEqual(len(U_BOOT_DATA), entry.size)
2805 self.assertIn('section0', entries)
2806 section0 = entries['section0']
2807 self.assertEqual(0x10, section0.offset)
2808 self.assertEqual(0x10, section0.image_pos)
2809 self.assertEqual(len(U_BOOT_DATA), section0.size)
2812 section_entries = section0.GetEntries()
2813 self.assertIn('u-boot', section_entries)
2814 entry = section_entries['u-boot']
2815 self.assertEqual(0, entry.offset)
2816 self.assertEqual(0x10, entry.image_pos)
2817 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2818 self.assertEqual(len(U_BOOT_DATA), entry.size)
2821 self.assertIn('section1', entries)
2822 section1 = entries['section1']
2823 self.assertEqual(0x14, section1.offset)
2824 self.assertEqual(0x14, section1.image_pos)
2825 self.assertEqual(0x20, section1.size)
2828 section_entries = section1.GetEntries()
2829 self.assertIn('u-boot', section_entries)
2830 entry = section_entries['u-boot']
2831 self.assertEqual(0, entry.offset)
2832 self.assertEqual(0x14, entry.image_pos)
2833 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2834 self.assertEqual(len(U_BOOT_DATA), entry.size)
2837 self.assertIn('section2', section_entries)
2838 section2 = section_entries['section2']
2839 self.assertEqual(0x4, section2.offset)
2840 self.assertEqual(0x18, section2.image_pos)
2841 self.assertEqual(4, section2.size)
2844 section_entries = section2.GetEntries()
2845 self.assertIn('u-boot', section_entries)
2846 entry = section_entries['u-boot']
2847 self.assertEqual(0, entry.offset)
2848 self.assertEqual(0x18, entry.image_pos)
2849 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2850 self.assertEqual(len(U_BOOT_DATA), entry.size)
2852 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2853 dts='132_replace.dts'):
2854 """Replace an entry in an image
2856 This writes the entry data to update it, then opens the updated file and
2857 returns the value that it now finds there.
2860 entry_name: Entry name to replace
2861 data: Data to replace it with
2862 decomp: True to compress the data if needed, False if data is
2863 already compressed so should be used as is
2864 allow_resize: True to allow entries to change size, False to raise
2870 data from fdtmap (excluding header)
2871 Image object that was modified
2873 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2876 self.assertIn('image', control.images)
2877 image = control.images['image']
2878 entries = image.GetEntries()
2879 orig_dtb_data = entries['u-boot-dtb'].data
2880 orig_fdtmap_data = entries['fdtmap'].data
2882 image_fname = tools.GetOutputFilename('image.bin')
2883 updated_fname = tools.GetOutputFilename('image-updated.bin')
2884 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2885 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2887 data = control.ReadEntry(updated_fname, entry_name, decomp)
2889 # The DT data should not change unless resized:
2890 if not allow_resize:
2891 new_dtb_data = entries['u-boot-dtb'].data
2892 self.assertEqual(new_dtb_data, orig_dtb_data)
2893 new_fdtmap_data = entries['fdtmap'].data
2894 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2896 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2898 def testReplaceSimple(self):
2899 """Test replacing a single file"""
2900 expected = b'x' * len(U_BOOT_DATA)
2901 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2903 self.assertEqual(expected, data)
2905 # Test that the state looks right. There should be an FDT for the fdtmap
2906 # that we jsut read back in, and it should match what we find in the
2907 # 'control' tables. Checking for an FDT that does not exist should
2909 path, fdtmap = state.GetFdtContents('fdtmap')
2910 self.assertIsNotNone(path)
2911 self.assertEqual(expected_fdtmap, fdtmap)
2913 dtb = state.GetFdtForEtype('fdtmap')
2914 self.assertEqual(dtb.GetContents(), fdtmap)
2916 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2917 self.assertIsNone(missing_path)
2918 self.assertIsNone(missing_fdtmap)
2920 missing_dtb = state.GetFdtForEtype('missing')
2921 self.assertIsNone(missing_dtb)
2923 self.assertEqual('/binman', state.fdt_path_prefix)
2925 def testReplaceResizeFail(self):
2926 """Test replacing a file by something larger"""
2927 expected = U_BOOT_DATA + b'x'
2928 with self.assertRaises(ValueError) as e:
2929 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2930 dts='139_replace_repack.dts')
2931 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2934 def testReplaceMulti(self):
2935 """Test replacing entry data where multiple images are generated"""
2936 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2938 expected = b'x' * len(U_BOOT_DATA)
2939 updated_fname = tools.GetOutputFilename('image-updated.bin')
2940 tools.WriteFile(updated_fname, data)
2941 entry_name = 'u-boot'
2942 control.WriteEntry(updated_fname, entry_name, expected,
2944 data = control.ReadEntry(updated_fname, entry_name)
2945 self.assertEqual(expected, data)
2947 # Check the state looks right.
2948 self.assertEqual('/binman/image', state.fdt_path_prefix)
2950 # Now check we can write the first image
2951 image_fname = tools.GetOutputFilename('first-image.bin')
2952 updated_fname = tools.GetOutputFilename('first-updated.bin')
2953 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2954 entry_name = 'u-boot'
2955 control.WriteEntry(updated_fname, entry_name, expected,
2957 data = control.ReadEntry(updated_fname, entry_name)
2958 self.assertEqual(expected, data)
2960 # Check the state looks right.
2961 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2963 def testUpdateFdtAllRepack(self):
2964 """Test that all device trees are updated with offset/size info"""
2965 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2966 SECTION_SIZE = 0x300
2971 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2973 'section:offset': 0,
2974 'section:size': SECTION_SIZE,
2975 'section:image-pos': 0,
2976 'section/u-boot-dtb:offset': 4,
2977 'section/u-boot-dtb:size': 636,
2978 'section/u-boot-dtb:image-pos': 4,
2979 'u-boot-spl-dtb:offset': SECTION_SIZE,
2980 'u-boot-spl-dtb:size': DTB_SIZE,
2981 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2982 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2983 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2984 'u-boot-tpl-dtb:size': DTB_SIZE,
2985 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2986 'fdtmap:size': FDTMAP_SIZE,
2987 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2990 'section:orig-size': SECTION_SIZE,
2991 'section/u-boot-dtb:orig-offset': 4,
2994 # We expect three device-tree files in the output, with the first one
2995 # within a fixed-size section.
2996 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2997 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2998 # main U-Boot tree. All three should have the same positions and offset
2999 # except that the main tree should include the main_expected properties
3001 for item in ['', 'spl', 'tpl', None]:
3003 start += 16 # Move past fdtmap header
3004 dtb = fdt.Fdt.FromData(data[start:])
3006 props = self._GetPropTree(dtb,
3007 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3008 prefix='/' if item is None else '/binman/')
3009 expected = dict(base_expected)
3013 # Main DTB and fdtdec should include the 'orig-' properties
3014 expected.update(main_expected)
3015 # Helpful for debugging:
3016 #for prop in sorted(props):
3017 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3018 self.assertEqual(expected, props)
3020 start = SECTION_SIZE
3022 start += dtb._fdt_obj.totalsize()
3024 def testFdtmapHeaderMiddle(self):
3025 """Test an FDT map in the middle of an image when it should be at end"""
3026 with self.assertRaises(ValueError) as e:
3027 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3028 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3031 def testFdtmapHeaderStartBad(self):
3032 """Test an FDT map in middle of an image when it should be at start"""
3033 with self.assertRaises(ValueError) as e:
3034 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3035 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3038 def testFdtmapHeaderEndBad(self):
3039 """Test an FDT map at the start of an image when it should be at end"""
3040 with self.assertRaises(ValueError) as e:
3041 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3042 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3045 def testFdtmapHeaderNoSize(self):
3046 """Test an image header at the end of an image with undefined size"""
3047 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3049 def testReplaceResize(self):
3050 """Test replacing a single file in an entry with a larger file"""
3051 expected = U_BOOT_DATA + b'x'
3052 data, _, image = self._RunReplaceCmd('u-boot', expected,
3053 dts='139_replace_repack.dts')
3054 self.assertEqual(expected, data)
3056 entries = image.GetEntries()
3057 dtb_data = entries['u-boot-dtb'].data
3058 dtb = fdt.Fdt.FromData(dtb_data)
3061 # The u-boot section should now be larger in the dtb
3062 node = dtb.GetNode('/binman/u-boot')
3063 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3065 # Same for the fdtmap
3066 fdata = entries['fdtmap'].data
3067 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3069 fnode = fdtb.GetNode('/u-boot')
3070 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3072 def testReplaceResizeNoRepack(self):
3073 """Test replacing an entry with a larger file when not allowed"""
3074 expected = U_BOOT_DATA + b'x'
3075 with self.assertRaises(ValueError) as e:
3076 self._RunReplaceCmd('u-boot', expected)
3077 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3080 def testEntryShrink(self):
3081 """Test contracting an entry after it is packed"""
3083 state.SetAllowEntryContraction(True)
3084 data = self._DoReadFileDtb('140_entry_shrink.dts',
3087 state.SetAllowEntryContraction(False)
3088 self.assertEqual(b'a', data[:1])
3089 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3090 self.assertEqual(b'a', data[-1:])
3092 def testEntryShrinkFail(self):
3093 """Test not being allowed to contract an entry after it is packed"""
3094 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3096 # In this case there is a spare byte at the end of the data. The size of
3097 # the contents is only 1 byte but we still have the size before it
3099 self.assertEqual(b'a\0', data[:2])
3100 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3101 self.assertEqual(b'a\0', data[-2:])
3103 def testDescriptorOffset(self):
3104 """Test that the Intel descriptor is always placed at at the start"""
3105 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3106 image = control.images['image']
3107 entries = image.GetEntries()
3108 desc = entries['intel-descriptor']
3109 self.assertEqual(0xff800000, desc.offset);
3110 self.assertEqual(0xff800000, desc.image_pos);
3112 def testReplaceCbfs(self):
3113 """Test replacing a single file in CBFS without changing the size"""
3115 expected = b'x' * len(U_BOOT_DATA)
3116 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3117 updated_fname = tools.GetOutputFilename('image-updated.bin')
3118 tools.WriteFile(updated_fname, data)
3119 entry_name = 'section/cbfs/u-boot'
3120 control.WriteEntry(updated_fname, entry_name, expected,
3122 data = control.ReadEntry(updated_fname, entry_name)
3123 self.assertEqual(expected, data)
3125 def testReplaceResizeCbfs(self):
3126 """Test replacing a single file in CBFS with one of a different size"""
3128 expected = U_BOOT_DATA + b'x'
3129 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3130 updated_fname = tools.GetOutputFilename('image-updated.bin')
3131 tools.WriteFile(updated_fname, data)
3132 entry_name = 'section/cbfs/u-boot'
3133 control.WriteEntry(updated_fname, entry_name, expected,
3135 data = control.ReadEntry(updated_fname, entry_name)
3136 self.assertEqual(expected, data)
3138 def _SetupForReplace(self):
3139 """Set up some files to use to replace entries
3141 This generates an image, copies it to a new file, extracts all the files
3142 in it and updates some of them
3148 Expected values for updated entries, each a string
3150 data = self._DoReadFileRealDtb('143_replace_all.dts')
3152 updated_fname = tools.GetOutputFilename('image-updated.bin')
3153 tools.WriteFile(updated_fname, data)
3155 outdir = os.path.join(self._indir, 'extract')
3156 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3158 expected1 = b'x' + U_BOOT_DATA + b'y'
3159 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3160 tools.WriteFile(u_boot_fname1, expected1)
3162 expected2 = b'a' + U_BOOT_DATA + b'b'
3163 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3164 tools.WriteFile(u_boot_fname2, expected2)
3166 expected_text = b'not the same text'
3167 text_fname = os.path.join(outdir, 'text')
3168 tools.WriteFile(text_fname, expected_text)
3170 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3171 dtb = fdt.FdtScan(dtb_fname)
3172 node = dtb.GetNode('/binman/text')
3173 node.AddString('my-property', 'the value')
3174 dtb.Sync(auto_resize=True)
3177 return updated_fname, outdir, expected1, expected2, expected_text
3179 def _CheckReplaceMultiple(self, entry_paths):
3180 """Handle replacing the contents of multiple entries
3183 entry_paths: List of entry paths to replace
3187 Dict of entries in the image:
3190 Expected values for updated entries, each a string
3192 updated_fname, outdir, expected1, expected2, expected_text = (
3193 self._SetupForReplace())
3194 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3196 image = Image.FromFile(updated_fname)
3198 return image.GetEntries(), expected1, expected2, expected_text
3200 def testReplaceAll(self):
3201 """Test replacing the contents of all entries"""
3202 entries, expected1, expected2, expected_text = (
3203 self._CheckReplaceMultiple([]))
3204 data = entries['u-boot'].data
3205 self.assertEqual(expected1, data)
3207 data = entries['u-boot2'].data
3208 self.assertEqual(expected2, data)
3210 data = entries['text'].data
3211 self.assertEqual(expected_text, data)
3213 # Check that the device tree is updated
3214 data = entries['u-boot-dtb'].data
3215 dtb = fdt.Fdt.FromData(data)
3217 node = dtb.GetNode('/binman/text')
3218 self.assertEqual('the value', node.props['my-property'].value)
3220 def testReplaceSome(self):
3221 """Test replacing the contents of a few entries"""
3222 entries, expected1, expected2, expected_text = (
3223 self._CheckReplaceMultiple(['u-boot2', 'text']))
3225 # This one should not change
3226 data = entries['u-boot'].data
3227 self.assertEqual(U_BOOT_DATA, data)
3229 data = entries['u-boot2'].data
3230 self.assertEqual(expected2, data)
3232 data = entries['text'].data
3233 self.assertEqual(expected_text, data)
3235 def testReplaceCmd(self):
3236 """Test replacing a file fron an image on the command line"""
3237 self._DoReadFileRealDtb('143_replace_all.dts')
3240 tmpdir, updated_fname = self._SetupImageInTmpdir()
3242 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3243 expected = b'x' * len(U_BOOT_DATA)
3244 tools.WriteFile(fname, expected)
3246 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3247 data = tools.ReadFile(updated_fname)
3248 self.assertEqual(expected, data[:len(expected)])
3249 map_fname = os.path.join(tmpdir, 'image-updated.map')
3250 self.assertFalse(os.path.exists(map_fname))
3252 shutil.rmtree(tmpdir)
3254 def testReplaceCmdSome(self):
3255 """Test replacing some files fron an image on the command line"""
3256 updated_fname, outdir, expected1, expected2, expected_text = (
3257 self._SetupForReplace())
3259 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3262 tools.PrepareOutputDir(None)
3263 image = Image.FromFile(updated_fname)
3265 entries = image.GetEntries()
3267 # This one should not change
3268 data = entries['u-boot'].data
3269 self.assertEqual(U_BOOT_DATA, data)
3271 data = entries['u-boot2'].data
3272 self.assertEqual(expected2, data)
3274 data = entries['text'].data
3275 self.assertEqual(expected_text, data)
3277 def testReplaceMissing(self):
3278 """Test replacing entries where the file is missing"""
3279 updated_fname, outdir, expected1, expected2, expected_text = (
3280 self._SetupForReplace())
3282 # Remove one of the files, to generate a warning
3283 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3284 os.remove(u_boot_fname1)
3286 with test_util.capture_sys_output() as (stdout, stderr):
3287 control.ReplaceEntries(updated_fname, None, outdir, [])
3288 self.assertIn("Skipping entry '/u-boot' from missing file",
3291 def testReplaceCmdMap(self):
3292 """Test replacing a file fron an image on the command line"""
3293 self._DoReadFileRealDtb('143_replace_all.dts')
3296 tmpdir, updated_fname = self._SetupImageInTmpdir()
3298 fname = os.path.join(self._indir, 'update-u-boot.bin')
3299 expected = b'x' * len(U_BOOT_DATA)
3300 tools.WriteFile(fname, expected)
3302 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3304 map_fname = os.path.join(tmpdir, 'image-updated.map')
3305 self.assertTrue(os.path.exists(map_fname))
3307 shutil.rmtree(tmpdir)
3309 def testReplaceNoEntryPaths(self):
3310 """Test replacing an entry without an entry path"""
3311 self._DoReadFileRealDtb('143_replace_all.dts')
3312 image_fname = tools.GetOutputFilename('image.bin')
3313 with self.assertRaises(ValueError) as e:
3314 control.ReplaceEntries(image_fname, 'fname', None, [])
3315 self.assertIn('Must specify an entry path to read with -f',
3318 def testReplaceTooManyEntryPaths(self):
3319 """Test extracting some entries"""
3320 self._DoReadFileRealDtb('143_replace_all.dts')
3321 image_fname = tools.GetOutputFilename('image.bin')
3322 with self.assertRaises(ValueError) as e:
3323 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3324 self.assertIn('Must specify exactly one entry path to write with -f',
3327 def testPackReset16(self):
3328 """Test that an image with an x86 reset16 region can be created"""
3329 data = self._DoReadFile('144_x86_reset16.dts')
3330 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3332 def testPackReset16Spl(self):
3333 """Test that an image with an x86 reset16-spl region can be created"""
3334 data = self._DoReadFile('145_x86_reset16_spl.dts')
3335 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3337 def testPackReset16Tpl(self):
3338 """Test that an image with an x86 reset16-tpl region can be created"""
3339 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3340 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3342 def testPackIntelFit(self):
3343 """Test that an image with an Intel FIT and pointer can be created"""
3344 data = self._DoReadFile('147_intel_fit.dts')
3345 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3347 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3348 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3350 image = control.images['image']
3351 entries = image.GetEntries()
3352 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3353 self.assertEqual(expected_ptr, ptr)
3355 def testPackIntelFitMissing(self):
3356 """Test detection of a FIT pointer with not FIT region"""
3357 with self.assertRaises(ValueError) as e:
3358 self._DoReadFile('148_intel_fit_missing.dts')
3359 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3362 def _CheckSymbolsTplSection(self, dts, expected_vals):
3363 data = self._DoReadFile(dts)
3364 sym_values = struct.pack('<LQLL', *expected_vals)
3365 upto1 = 4 + len(U_BOOT_SPL_DATA)
3366 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3367 self.assertEqual(expected1, data[:upto1])
3369 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3370 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3371 self.assertEqual(expected2, data[upto1:upto2])
3373 upto3 = 0x34 + len(U_BOOT_DATA)
3374 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3375 self.assertEqual(expected3, data[upto2:upto3])
3377 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3378 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3380 def testSymbolsTplSection(self):
3381 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3382 self._SetupSplElf('u_boot_binman_syms')
3383 self._SetupTplElf('u_boot_binman_syms')
3384 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3385 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3387 def testSymbolsTplSectionX86(self):
3388 """Test binman can assign symbols in a section with end-at-4gb"""
3389 self._SetupSplElf('u_boot_binman_syms_x86')
3390 self._SetupTplElf('u_boot_binman_syms_x86')
3391 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3392 [0xffffff04, 0xffffff1c, 0xffffff34,
3395 def testPackX86RomIfwiSectiom(self):
3396 """Test that a section can be placed in an IFWI region"""
3397 self._SetupIfwi('fitimage.bin')
3398 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3399 self._CheckIfwi(data)
3401 def testPackFspM(self):
3402 """Test that an image with a FSP memory-init binary can be created"""
3403 data = self._DoReadFile('152_intel_fsp_m.dts')
3404 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3406 def testPackFspS(self):
3407 """Test that an image with a FSP silicon-init binary can be created"""
3408 data = self._DoReadFile('153_intel_fsp_s.dts')
3409 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3411 def testPackFspT(self):
3412 """Test that an image with a FSP temp-ram-init binary can be created"""
3413 data = self._DoReadFile('154_intel_fsp_t.dts')
3414 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3416 def testMkimage(self):
3417 """Test using mkimage to build an image"""
3418 data = self._DoReadFile('156_mkimage.dts')
3420 # Just check that the data appears in the file somewhere
3421 self.assertIn(U_BOOT_SPL_DATA, data)
3423 def testExtblob(self):
3424 """Test an image with an external blob"""
3425 data = self._DoReadFile('157_blob_ext.dts')
3426 self.assertEqual(REFCODE_DATA, data)
3428 def testExtblobMissing(self):
3429 """Test an image with a missing external blob"""
3430 with self.assertRaises(ValueError) as e:
3431 self._DoReadFile('158_blob_ext_missing.dts')
3432 self.assertIn("Filename 'missing-file' not found in input path",
3435 def testExtblobMissingOk(self):
3436 """Test an image with an missing external blob that is allowed"""
3437 with test_util.capture_sys_output() as (stdout, stderr):
3438 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3439 err = stderr.getvalue()
3440 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3442 def testExtblobMissingOkSect(self):
3443 """Test an image with an missing external blob that is allowed"""
3444 with test_util.capture_sys_output() as (stdout, stderr):
3445 self._DoTestFile('159_blob_ext_missing_sect.dts',
3447 err = stderr.getvalue()
3448 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3449 "blob-ext blob-ext2")
3451 def testPackX86RomMeMissingDesc(self):
3452 """Test that an missing Intel descriptor entry is allowed"""
3453 with test_util.capture_sys_output() as (stdout, stderr):
3454 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3455 err = stderr.getvalue()
3456 self.assertRegex(err,
3457 "Image 'main-section'.*missing.*: intel-descriptor")
3459 def testPackX86RomMissingIfwi(self):
3460 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3461 self._SetupIfwi('fitimage.bin')
3462 pathname = os.path.join(self._indir, 'fitimage.bin')
3464 with test_util.capture_sys_output() as (stdout, stderr):
3465 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3466 err = stderr.getvalue()
3467 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3469 def testPackOverlap(self):
3470 """Test that zero-size overlapping regions are ignored"""
3471 self._DoTestFile('160_pack_overlap_zero.dts')
3473 def testSimpleFit(self):
3474 """Test an image with a FIT inside"""
3475 data = self._DoReadFile('161_fit.dts')
3476 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3477 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3478 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3480 # The data should be inside the FIT
3481 dtb = fdt.Fdt.FromData(fit_data)
3483 fnode = dtb.GetNode('/images/kernel')
3484 self.assertIn('data', fnode.props)
3486 fname = os.path.join(self._indir, 'fit_data.fit')
3487 tools.WriteFile(fname, fit_data)
3488 out = tools.Run('dumpimage', '-l', fname)
3490 # Check a few features to make sure the plumbing works. We don't need
3491 # to test the operation of mkimage or dumpimage here. First convert the
3492 # output into a dict where the keys are the fields printed by dumpimage
3493 # and the values are a list of values for each field
3494 lines = out.splitlines()
3496 # Converts "Compression: gzip compressed" into two groups:
3497 # 'Compression' and 'gzip compressed'
3498 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3499 vals = collections.defaultdict(list)
3501 mat = re_line.match(line)
3502 vals[mat.group(1)].append(mat.group(2))
3504 self.assertEquals('FIT description: test-desc', lines[0])
3505 self.assertIn('Created:', lines[1])
3506 self.assertIn('Image 0 (kernel)', vals)
3507 self.assertIn('Hash value', vals)
3508 data_sizes = vals.get('Data Size')
3509 self.assertIsNotNone(data_sizes)
3510 self.assertEqual(2, len(data_sizes))
3511 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3512 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3513 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3515 def testFitExternal(self):
3516 """Test an image with an FIT with external images"""
3517 data = self._DoReadFile('162_fit_external.dts')
3518 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3520 # The data should be outside the FIT
3521 dtb = fdt.Fdt.FromData(fit_data)
3523 fnode = dtb.GetNode('/images/kernel')
3524 self.assertNotIn('data', fnode.props)
3526 def testSectionIgnoreHashSignature(self):
3527 """Test that sections ignore hash, signature nodes for its data"""
3528 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3529 expected = (U_BOOT_DATA + U_BOOT_DATA)
3530 self.assertEqual(expected, data)
3532 def testPadInSections(self):
3533 """Test pad-before, pad-after for entries in sections"""
3534 data = self._DoReadFile('166_pad_in_sections.dts')
3535 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3536 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3538 self.assertEqual(expected, data)
3540 def testFitImageSubentryAlignment(self):
3541 """Test relative alignability of FIT image subentries"""
3543 'test-id': TEXT_DATA,
3545 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3546 entry_args=entry_args)
3547 dtb = fdt.Fdt.FromData(data)
3550 node = dtb.GetNode('/images/kernel')
3551 data = dtb.GetProps(node)["data"].bytes
3552 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3553 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3554 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3555 self.assertEqual(expected, data)
3557 node = dtb.GetNode('/images/fdt-1')
3558 data = dtb.GetProps(node)["data"].bytes
3559 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3560 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3562 self.assertEqual(expected, data)
3564 def testFitExtblobMissingOk(self):
3565 """Test a FIT with a missing external blob that is allowed"""
3566 with test_util.capture_sys_output() as (stdout, stderr):
3567 self._DoTestFile('168_fit_missing_blob.dts',
3569 err = stderr.getvalue()
3570 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
3572 def testBlobNamedByArgMissing(self):
3573 """Test handling of a missing entry arg"""
3574 with self.assertRaises(ValueError) as e:
3575 self._DoReadFile('068_blob_named_by_arg.dts')
3576 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3579 def testPackBl31(self):
3580 """Test that an image with an ATF BL31 binary can be created"""
3581 data = self._DoReadFile('169_atf_bl31.dts')
3582 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3584 def testPackScp(self):
3585 """Test that an image with an SCP binary can be created"""
3586 data = self._DoReadFile('172_scp.dts')
3587 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3589 def testFitFdt(self):
3590 """Test an image with an FIT with multiple FDT images"""
3591 def _CheckFdt(seq, expected_data):
3592 """Check the FDT nodes
3595 seq: Sequence number to check (0 or 1)
3596 expected_data: Expected contents of 'data' property
3598 name = 'fdt-%d' % seq
3599 fnode = dtb.GetNode('/images/%s' % name)
3600 self.assertIsNotNone(fnode)
3601 self.assertEqual({'description','type', 'compression', 'data'},
3602 set(fnode.props.keys()))
3603 self.assertEqual(expected_data, fnode.props['data'].bytes)
3604 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3605 fnode.props['description'].value)
3607 def _CheckConfig(seq, expected_data):
3608 """Check the configuration nodes
3611 seq: Sequence number to check (0 or 1)
3612 expected_data: Expected contents of 'data' property
3614 cnode = dtb.GetNode('/configurations')
3615 self.assertIn('default', cnode.props)
3616 self.assertEqual('config-2', cnode.props['default'].value)
3618 name = 'config-%d' % seq
3619 fnode = dtb.GetNode('/configurations/%s' % name)
3620 self.assertIsNotNone(fnode)
3621 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3622 set(fnode.props.keys()))
3623 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3624 fnode.props['description'].value)
3625 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3628 'of-list': 'test-fdt1 test-fdt2',
3629 'default-dt': 'test-fdt2',
3631 data = self._DoReadFileDtb(
3633 entry_args=entry_args,
3634 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3635 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3636 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3638 dtb = fdt.Fdt.FromData(fit_data)
3640 fnode = dtb.GetNode('/images/kernel')
3641 self.assertIn('data', fnode.props)
3643 # Check all the properties in fdt-1 and fdt-2
3644 _CheckFdt(1, TEST_FDT1_DATA)
3645 _CheckFdt(2, TEST_FDT2_DATA)
3647 # Check configurations
3648 _CheckConfig(1, TEST_FDT1_DATA)
3649 _CheckConfig(2, TEST_FDT2_DATA)
3651 def testFitFdtMissingList(self):
3652 """Test handling of a missing 'of-list' entry arg"""
3653 with self.assertRaises(ValueError) as e:
3654 self._DoReadFile('172_fit_fdt.dts')
3655 self.assertIn("Generator node requires 'of-list' entry argument",
3658 def testFitFdtEmptyList(self):
3659 """Test handling of an empty 'of-list' entry arg"""
3663 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3665 def testFitFdtMissingProp(self):
3666 """Test handling of a missing 'fit,fdt-list' property"""
3667 with self.assertRaises(ValueError) as e:
3668 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3669 self.assertIn("Generator node requires 'fit,fdt-list' property",
3672 def testFitFdtEmptyList(self):
3673 """Test handling of an empty 'of-list' entry arg"""
3677 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3679 def testFitFdtMissing(self):
3680 """Test handling of a missing 'default-dt' entry arg"""
3682 'of-list': 'test-fdt1 test-fdt2',
3684 with self.assertRaises(ValueError) as e:
3685 self._DoReadFileDtb(
3687 entry_args=entry_args,
3688 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3689 self.assertIn("Generated 'default' node requires default-dt entry argument",
3692 def testFitFdtNotInList(self):
3693 """Test handling of a default-dt that is not in the of-list"""
3695 'of-list': 'test-fdt1 test-fdt2',
3696 'default-dt': 'test-fdt3',
3698 with self.assertRaises(ValueError) as e:
3699 self._DoReadFileDtb(
3701 entry_args=entry_args,
3702 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3703 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3706 def testFitExtblobMissingHelp(self):
3707 """Test display of help messages when an external blob is missing"""
3708 control.missing_blob_help = control._ReadMissingBlobHelp()
3709 control.missing_blob_help['wibble'] = 'Wibble test'
3710 control.missing_blob_help['another'] = 'Another test'
3711 with test_util.capture_sys_output() as (stdout, stderr):
3712 self._DoTestFile('168_fit_missing_blob.dts',
3714 err = stderr.getvalue()
3716 # We can get the tag from the name, the type or the missing-msg
3717 # property. Check all three.
3718 self.assertIn('You may need to build ARM Trusted', err)
3719 self.assertIn('Wibble test', err)
3720 self.assertIn('Another test', err)
3722 def testMissingBlob(self):
3723 """Test handling of a blob containing a missing file"""
3724 with self.assertRaises(ValueError) as e:
3725 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3726 self.assertIn("Filename 'missing' not found in input path",
3729 def testEnvironment(self):
3730 """Test adding a U-Boot environment"""
3731 data = self._DoReadFile('174_env.dts')
3732 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3733 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3734 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3735 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3738 def testEnvironmentNoSize(self):
3739 """Test that a missing 'size' property is detected"""
3740 with self.assertRaises(ValueError) as e:
3741 self._DoTestFile('175_env_no_size.dts')
3742 self.assertIn("'u-boot-env' entry must have a size property",
3745 def testEnvironmentTooSmall(self):
3746 """Test handling of an environment that does not fit"""
3747 with self.assertRaises(ValueError) as e:
3748 self._DoTestFile('176_env_too_small.dts')
3750 # checksum, start byte, environment with \0 terminator, final \0
3751 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3753 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3756 def testSkipAtStart(self):
3757 """Test handling of skip-at-start section"""
3758 data = self._DoReadFile('177_skip_at_start.dts')
3759 self.assertEqual(U_BOOT_DATA, data)
3761 image = control.images['image']
3762 entries = image.GetEntries()
3763 section = entries['section']
3764 self.assertEqual(0, section.offset)
3765 self.assertEqual(len(U_BOOT_DATA), section.size)
3766 self.assertEqual(U_BOOT_DATA, section.GetData())
3768 entry = section.GetEntries()['u-boot']
3769 self.assertEqual(16, entry.offset)
3770 self.assertEqual(len(U_BOOT_DATA), entry.size)
3771 self.assertEqual(U_BOOT_DATA, entry.data)
3773 def testSkipAtStartPad(self):
3774 """Test handling of skip-at-start section with padded entry"""
3775 data = self._DoReadFile('178_skip_at_start_pad.dts')
3776 before = tools.GetBytes(0, 8)
3777 after = tools.GetBytes(0, 4)
3778 all = before + U_BOOT_DATA + after
3779 self.assertEqual(all, data)
3781 image = control.images['image']
3782 entries = image.GetEntries()
3783 section = entries['section']
3784 self.assertEqual(0, section.offset)
3785 self.assertEqual(len(all), section.size)
3786 self.assertEqual(all, section.GetData())
3788 entry = section.GetEntries()['u-boot']
3789 self.assertEqual(16, entry.offset)
3790 self.assertEqual(len(all), entry.size)
3791 self.assertEqual(U_BOOT_DATA, entry.data)
3793 def testSkipAtStartSectionPad(self):
3794 """Test handling of skip-at-start section with padding"""
3795 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3796 before = tools.GetBytes(0, 8)
3797 after = tools.GetBytes(0, 4)
3798 all = before + U_BOOT_DATA + after
3800 # This is not correct, but it is what binman currently produces
3801 self.assertEqual(tools.GetBytes(0, 16) + U_BOOT_DATA + after, data)
3803 image = control.images['image']
3804 entries = image.GetEntries()
3805 section = entries['section']
3806 self.assertEqual(0, section.offset)
3807 self.assertEqual(len(all), section.size)
3808 self.assertIsNone(section.data)
3809 self.assertEqual(all, section.GetData())
3811 entry = section.GetEntries()['u-boot']
3812 self.assertEqual(16, entry.offset)
3813 self.assertEqual(len(U_BOOT_DATA), entry.size)
3814 self.assertEqual(U_BOOT_DATA, entry.data)
3816 if __name__ == "__main__":