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'
78 # The expected size for the device tree in some tests
79 EXTRACT_DTB_SIZE = 0x3c9
81 # Properties expected to be in the device tree when update_dtb is used
82 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
84 # Extra properties expected to be in the device tree when allow-repack is used
85 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
88 class TestFunctional(unittest.TestCase):
89 """Functional tests for binman
91 Most of these use a sample .dts file to build an image and then check
92 that it looks correct. The sample files are in the test/ subdirectory
95 For each entry type a very small test file is created using fixed
96 string contents. This makes it easy to test that things look right, and
99 In some cases a 'real' file must be used - these are also supplied in
100 the test/ diurectory.
105 from binman import entry
107 # Handle the case where argv[0] is 'python'
108 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
109 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
111 # Create a temporary directory for input files
112 cls._indir = tempfile.mkdtemp(prefix='binmant.')
114 # Create some test files
115 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
116 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
117 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
118 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
119 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
120 TestFunctional._MakeInputFile('me.bin', ME_DATA)
121 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
124 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
126 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
127 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
128 X86_START16_SPL_DATA)
129 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
130 X86_START16_TPL_DATA)
132 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
134 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
135 X86_RESET16_SPL_DATA)
136 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
137 X86_RESET16_TPL_DATA)
139 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
140 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
141 U_BOOT_SPL_NODTB_DATA)
142 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
143 U_BOOT_TPL_NODTB_DATA)
144 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
145 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
146 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
147 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
148 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
149 TestFunctional._MakeInputDir('devkeys')
150 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
151 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
152 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
153 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
154 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
156 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
157 elf_test.BuildElfTestFiles(cls._elf_testdir)
159 # ELF file with a '_dt_ucode_base_size' symbol
160 TestFunctional._MakeInputFile('u-boot',
161 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
163 # Intel flash descriptor file
164 cls._SetupDescriptor()
166 shutil.copytree(cls.TestFile('files'),
167 os.path.join(cls._indir, 'files'))
169 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
171 # Travis-CI may have an old lz4
174 tools.Run('lz4', '--no-frame-crc', '-c',
175 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
180 def tearDownClass(cls):
181 """Remove the temporary input directory and its contents"""
182 if cls.preserve_indir:
183 print('Preserving input dir: %s' % cls._indir)
186 shutil.rmtree(cls._indir)
190 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
191 toolpath=None, verbosity=None):
192 """Accept arguments controlling test execution
195 preserve_indir: Preserve the shared input directory used by all
197 preserve_outdir: Preserve the output directories used by tests. Each
198 test has its own, so this is normally only useful when running a
200 toolpath: ist of paths to use for tools
202 cls.preserve_indir = preserve_indir
203 cls.preserve_outdirs = preserve_outdirs
204 cls.toolpath = toolpath
205 cls.verbosity = verbosity
208 if not self.have_lz4:
209 self.skipTest('lz4 --no-frame-crc not available')
211 def _CleanupOutputDir(self):
212 """Remove the temporary output directory"""
213 if self.preserve_outdirs:
214 print('Preserving output dir: %s' % tools.outdir)
216 tools._FinaliseForTest()
219 # Enable this to turn on debugging output
220 # tout.Init(tout.DEBUG)
221 command.test_result = None
224 """Remove the temporary output directory"""
225 self._CleanupOutputDir()
227 def _SetupImageInTmpdir(self):
228 """Set up the output image in a new temporary directory
230 This is used when an image has been generated in the output directory,
231 but we want to run binman again. This will create a new output
232 directory and fail to delete the original one.
234 This creates a new temporary directory, copies the image to it (with a
235 new name) and removes the old output directory.
239 Temporary directory to use
242 image_fname = tools.GetOutputFilename('image.bin')
243 tmpdir = tempfile.mkdtemp(prefix='binman.')
244 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
245 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
246 self._CleanupOutputDir()
247 return tmpdir, updated_fname
251 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
252 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
253 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
255 def _RunBinman(self, *args, **kwargs):
256 """Run binman using the command line
259 Arguments to pass, as a list of strings
260 kwargs: Arguments to pass to Command.RunPipe()
262 result = command.RunPipe([[self._binman_pathname] + list(args)],
263 capture=True, capture_stderr=True, raise_on_error=False)
264 if result.return_code and kwargs.get('raise_on_error', True):
265 raise Exception("Error running '%s': %s" % (' '.join(args),
266 result.stdout + result.stderr))
269 def _DoBinman(self, *argv):
270 """Run binman using directly (in the same process)
273 Arguments to pass, as a list of strings
275 Return value (0 for success)
278 args = cmdline.ParseArgs(argv)
279 args.pager = 'binman-invalid-pager'
280 args.build_dir = self._indir
282 # For testing, you can force an increase in verbosity here
283 # args.verbosity = tout.DEBUG
284 return control.Binman(args)
286 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
287 entry_args=None, images=None, use_real_dtb=False,
288 verbosity=None, allow_missing=False):
289 """Run binman with a given test file
292 fname: Device-tree source filename to use (e.g. 005_simple.dts)
293 debug: True to enable debugging output
294 map: True to output map files for the images
295 update_dtb: Update the offset and size of each entry in the device
296 tree before packing it into the image
297 entry_args: Dict of entry args to supply to binman
299 value: value of that arg
300 images: List of image names to build
305 if verbosity is not None:
306 args.append('-v%d' % verbosity)
308 args.append('-v%d' % self.verbosity)
310 for path in self.toolpath:
311 args += ['--toolpath', path]
312 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
318 args.append('--fake-dtb')
320 for arg, value in entry_args.items():
321 args.append('-a%s=%s' % (arg, value))
326 args += ['-i', image]
327 return self._DoBinman(*args)
329 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
330 """Set up a new test device-tree file
332 The given file is compiled and set up as the device tree to be used
336 fname: Filename of .dts file to read
337 outfile: Output filename for compiled device-tree binary
340 Contents of device-tree binary
342 tmpdir = tempfile.mkdtemp(prefix='binmant.')
343 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
344 with open(dtb, 'rb') as fd:
346 TestFunctional._MakeInputFile(outfile, data)
347 shutil.rmtree(tmpdir)
350 def _GetDtbContentsForSplTpl(self, dtb_data, name):
351 """Create a version of the main DTB for SPL or SPL
353 For testing we don't actually have different versions of the DTB. With
354 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
355 we don't normally have any unwanted nodes.
357 We still want the DTBs for SPL and TPL to be different though, since
358 otherwise it is confusing to know which one we are looking at. So add
359 an 'spl' or 'tpl' property to the top-level node.
361 dtb = fdt.Fdt.FromData(dtb_data)
363 dtb.GetNode('/binman').AddZeroProp(name)
364 dtb.Sync(auto_resize=True)
366 return dtb.GetContents()
368 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
369 update_dtb=False, entry_args=None, reset_dtbs=True):
370 """Run binman and return the resulting image
372 This runs binman with a given test file and then reads the resulting
373 output file. It is a shortcut function since most tests need to do
376 Raises an assertion failure if binman returns a non-zero exit code.
379 fname: Device-tree source filename to use (e.g. 005_simple.dts)
380 use_real_dtb: True to use the test file as the contents of
381 the u-boot-dtb entry. Normally this is not needed and the
382 test contents (the U_BOOT_DTB_DATA string) can be used.
383 But in some test we need the real contents.
384 map: True to output map files for the images
385 update_dtb: Update the offset and size of each entry in the device
386 tree before packing it into the image
390 Resulting image contents
392 Map data showing contents of image (or None if none)
393 Output device tree binary filename ('u-boot.dtb' path)
396 # Use the compiled test file as the u-boot-dtb input
398 dtb_data = self._SetupDtb(fname)
400 # For testing purposes, make a copy of the DT for SPL and TPL. Add
401 # a node indicating which it is, so aid verification.
402 for name in ['spl', 'tpl']:
403 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
404 outfile = os.path.join(self._indir, dtb_fname)
405 TestFunctional._MakeInputFile(dtb_fname,
406 self._GetDtbContentsForSplTpl(dtb_data, name))
409 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
410 entry_args=entry_args, use_real_dtb=use_real_dtb)
411 self.assertEqual(0, retcode)
412 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
414 # Find the (only) image, read it and return its contents
415 image = control.images['image']
416 image_fname = tools.GetOutputFilename('image.bin')
417 self.assertTrue(os.path.exists(image_fname))
419 map_fname = tools.GetOutputFilename('image.map')
420 with open(map_fname) as fd:
424 with open(image_fname, 'rb') as fd:
425 return fd.read(), dtb_data, map_data, out_dtb_fname
427 # Put the test file back
428 if reset_dtbs and use_real_dtb:
431 def _DoReadFileRealDtb(self, fname):
432 """Run binman with a real .dtb file and return the resulting data
435 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
438 Resulting image contents
440 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
442 def _DoReadFile(self, fname, use_real_dtb=False):
443 """Helper function which discards the device-tree binary
446 fname: Device-tree source filename to use (e.g. 005_simple.dts)
447 use_real_dtb: True to use the test file as the contents of
448 the u-boot-dtb entry. Normally this is not needed and the
449 test contents (the U_BOOT_DTB_DATA string) can be used.
450 But in some test we need the real contents.
453 Resulting image contents
455 return self._DoReadFileDtb(fname, use_real_dtb)[0]
458 def _MakeInputFile(cls, fname, contents):
459 """Create a new test input file, creating directories as needed
462 fname: Filename to create
463 contents: File contents to write in to the file
465 Full pathname of file created
467 pathname = os.path.join(cls._indir, fname)
468 dirname = os.path.dirname(pathname)
469 if dirname and not os.path.exists(dirname):
471 with open(pathname, 'wb') as fd:
476 def _MakeInputDir(cls, dirname):
477 """Create a new test input directory, creating directories as needed
480 dirname: Directory name to create
483 Full pathname of directory created
485 pathname = os.path.join(cls._indir, dirname)
486 if not os.path.exists(pathname):
487 os.makedirs(pathname)
491 def _SetupSplElf(cls, src_fname='bss_data'):
492 """Set up an ELF file with a '_dt_ucode_base_size' symbol
495 Filename of ELF file to use as SPL
497 TestFunctional._MakeInputFile('spl/u-boot-spl',
498 tools.ReadFile(cls.ElfTestFile(src_fname)))
501 def _SetupTplElf(cls, src_fname='bss_data'):
502 """Set up an ELF file with a '_dt_ucode_base_size' symbol
505 Filename of ELF file to use as TPL
507 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
508 tools.ReadFile(cls.ElfTestFile(src_fname)))
511 def _SetupDescriptor(cls):
512 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
513 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
516 def TestFile(cls, fname):
517 return os.path.join(cls._binman_dir, 'test', fname)
520 def ElfTestFile(cls, fname):
521 return os.path.join(cls._elf_testdir, fname)
523 def AssertInList(self, grep_list, target):
524 """Assert that at least one of a list of things is in a target
527 grep_list: List of strings to check
528 target: Target string
530 for grep in grep_list:
533 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
535 def CheckNoGaps(self, entries):
536 """Check that all entries fit together without gaps
539 entries: List of entries to check
542 for entry in entries.values():
543 self.assertEqual(offset, entry.offset)
546 def GetFdtLen(self, dtb):
547 """Get the totalsize field from a device-tree binary
550 dtb: Device-tree binary contents
553 Total size of device-tree binary, from the header
555 return struct.unpack('>L', dtb[4:8])[0]
557 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
558 def AddNode(node, path):
560 path += '/' + node.name
561 for prop in node.props.values():
562 if prop.name in prop_names:
563 prop_path = path + ':' + prop.name
564 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
566 for subnode in node.subnodes:
567 AddNode(subnode, path)
570 AddNode(dtb.GetRoot(), '')
574 """Test a basic run with valid args"""
575 result = self._RunBinman('-h')
577 def testFullHelp(self):
578 """Test that the full help is displayed with -H"""
579 result = self._RunBinman('-H')
580 help_file = os.path.join(self._binman_dir, 'README')
581 # Remove possible extraneous strings
582 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
583 gothelp = result.stdout.replace(extra, '')
584 self.assertEqual(len(gothelp), os.path.getsize(help_file))
585 self.assertEqual(0, len(result.stderr))
586 self.assertEqual(0, result.return_code)
588 def testFullHelpInternal(self):
589 """Test that the full help is displayed with -H"""
591 command.test_result = command.CommandResult()
592 result = self._DoBinman('-H')
593 help_file = os.path.join(self._binman_dir, 'README')
595 command.test_result = None
598 """Test that the basic help is displayed with -h"""
599 result = self._RunBinman('-h')
600 self.assertTrue(len(result.stdout) > 200)
601 self.assertEqual(0, len(result.stderr))
602 self.assertEqual(0, result.return_code)
605 """Test that we can run it with a specific board"""
606 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
607 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
608 result = self._DoBinman('build', '-b', 'sandbox')
609 self.assertEqual(0, result)
611 def testNeedBoard(self):
612 """Test that we get an error when no board ius supplied"""
613 with self.assertRaises(ValueError) as e:
614 result = self._DoBinman('build')
615 self.assertIn("Must provide a board to process (use -b <board>)",
618 def testMissingDt(self):
619 """Test that an invalid device-tree file generates an error"""
620 with self.assertRaises(Exception) as e:
621 self._RunBinman('build', '-d', 'missing_file')
622 # We get one error from libfdt, and a different one from fdtget.
623 self.AssertInList(["Couldn't open blob from 'missing_file'",
624 'No such file or directory'], str(e.exception))
626 def testBrokenDt(self):
627 """Test that an invalid device-tree source file generates an error
629 Since this is a source file it should be compiled and the error
630 will come from the device-tree compiler (dtc).
632 with self.assertRaises(Exception) as e:
633 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
634 self.assertIn("FATAL ERROR: Unable to parse input tree",
637 def testMissingNode(self):
638 """Test that a device tree without a 'binman' node generates an error"""
639 with self.assertRaises(Exception) as e:
640 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
641 self.assertIn("does not have a 'binman' node", str(e.exception))
644 """Test that an empty binman node works OK (i.e. does nothing)"""
645 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
646 self.assertEqual(0, len(result.stderr))
647 self.assertEqual(0, result.return_code)
649 def testInvalidEntry(self):
650 """Test that an invalid entry is flagged"""
651 with self.assertRaises(Exception) as e:
652 result = self._RunBinman('build', '-d',
653 self.TestFile('004_invalid_entry.dts'))
654 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
655 "'/binman/not-a-valid-type'", str(e.exception))
657 def testSimple(self):
658 """Test a simple binman with a single file"""
659 data = self._DoReadFile('005_simple.dts')
660 self.assertEqual(U_BOOT_DATA, data)
662 def testSimpleDebug(self):
663 """Test a simple binman run with debugging enabled"""
664 self._DoTestFile('005_simple.dts', debug=True)
667 """Test that we can handle creating two images
669 This also tests image padding.
671 retcode = self._DoTestFile('006_dual_image.dts')
672 self.assertEqual(0, retcode)
674 image = control.images['image1']
675 self.assertEqual(len(U_BOOT_DATA), image.size)
676 fname = tools.GetOutputFilename('image1.bin')
677 self.assertTrue(os.path.exists(fname))
678 with open(fname, 'rb') as fd:
680 self.assertEqual(U_BOOT_DATA, data)
682 image = control.images['image2']
683 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
684 fname = tools.GetOutputFilename('image2.bin')
685 self.assertTrue(os.path.exists(fname))
686 with open(fname, 'rb') as fd:
688 self.assertEqual(U_BOOT_DATA, data[3:7])
689 self.assertEqual(tools.GetBytes(0, 3), data[:3])
690 self.assertEqual(tools.GetBytes(0, 5), data[7:])
692 def testBadAlign(self):
693 """Test that an invalid alignment value is detected"""
694 with self.assertRaises(ValueError) as e:
695 self._DoTestFile('007_bad_align.dts')
696 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
697 "of two", str(e.exception))
699 def testPackSimple(self):
700 """Test that packing works as expected"""
701 retcode = self._DoTestFile('008_pack.dts')
702 self.assertEqual(0, retcode)
703 self.assertIn('image', control.images)
704 image = control.images['image']
705 entries = image.GetEntries()
706 self.assertEqual(5, len(entries))
709 self.assertIn('u-boot', entries)
710 entry = entries['u-boot']
711 self.assertEqual(0, entry.offset)
712 self.assertEqual(len(U_BOOT_DATA), entry.size)
714 # Second u-boot, aligned to 16-byte boundary
715 self.assertIn('u-boot-align', entries)
716 entry = entries['u-boot-align']
717 self.assertEqual(16, entry.offset)
718 self.assertEqual(len(U_BOOT_DATA), entry.size)
720 # Third u-boot, size 23 bytes
721 self.assertIn('u-boot-size', entries)
722 entry = entries['u-boot-size']
723 self.assertEqual(20, entry.offset)
724 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
725 self.assertEqual(23, entry.size)
727 # Fourth u-boot, placed immediate after the above
728 self.assertIn('u-boot-next', entries)
729 entry = entries['u-boot-next']
730 self.assertEqual(43, entry.offset)
731 self.assertEqual(len(U_BOOT_DATA), entry.size)
733 # Fifth u-boot, placed at a fixed offset
734 self.assertIn('u-boot-fixed', entries)
735 entry = entries['u-boot-fixed']
736 self.assertEqual(61, entry.offset)
737 self.assertEqual(len(U_BOOT_DATA), entry.size)
739 self.assertEqual(65, image.size)
741 def testPackExtra(self):
742 """Test that extra packing feature works as expected"""
743 retcode = self._DoTestFile('009_pack_extra.dts')
745 self.assertEqual(0, retcode)
746 self.assertIn('image', control.images)
747 image = control.images['image']
748 entries = image.GetEntries()
749 self.assertEqual(5, len(entries))
751 # First u-boot with padding before and after
752 self.assertIn('u-boot', entries)
753 entry = entries['u-boot']
754 self.assertEqual(0, entry.offset)
755 self.assertEqual(3, entry.pad_before)
756 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
758 # Second u-boot has an aligned size, but it has no effect
759 self.assertIn('u-boot-align-size-nop', entries)
760 entry = entries['u-boot-align-size-nop']
761 self.assertEqual(12, entry.offset)
762 self.assertEqual(4, entry.size)
764 # Third u-boot has an aligned size too
765 self.assertIn('u-boot-align-size', entries)
766 entry = entries['u-boot-align-size']
767 self.assertEqual(16, entry.offset)
768 self.assertEqual(32, entry.size)
770 # Fourth u-boot has an aligned end
771 self.assertIn('u-boot-align-end', entries)
772 entry = entries['u-boot-align-end']
773 self.assertEqual(48, entry.offset)
774 self.assertEqual(16, entry.size)
776 # Fifth u-boot immediately afterwards
777 self.assertIn('u-boot-align-both', entries)
778 entry = entries['u-boot-align-both']
779 self.assertEqual(64, entry.offset)
780 self.assertEqual(64, entry.size)
782 self.CheckNoGaps(entries)
783 self.assertEqual(128, image.size)
785 def testPackAlignPowerOf2(self):
786 """Test that invalid entry alignment is detected"""
787 with self.assertRaises(ValueError) as e:
788 self._DoTestFile('010_pack_align_power2.dts')
789 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
790 "of two", str(e.exception))
792 def testPackAlignSizePowerOf2(self):
793 """Test that invalid entry size alignment is detected"""
794 with self.assertRaises(ValueError) as e:
795 self._DoTestFile('011_pack_align_size_power2.dts')
796 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
797 "power of two", str(e.exception))
799 def testPackInvalidAlign(self):
800 """Test detection of an offset that does not match its alignment"""
801 with self.assertRaises(ValueError) as e:
802 self._DoTestFile('012_pack_inv_align.dts')
803 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
804 "align 0x4 (4)", str(e.exception))
806 def testPackInvalidSizeAlign(self):
807 """Test that invalid entry size alignment is detected"""
808 with self.assertRaises(ValueError) as e:
809 self._DoTestFile('013_pack_inv_size_align.dts')
810 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
811 "align-size 0x4 (4)", str(e.exception))
813 def testPackOverlap(self):
814 """Test that overlapping regions are detected"""
815 with self.assertRaises(ValueError) as e:
816 self._DoTestFile('014_pack_overlap.dts')
817 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
818 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
821 def testPackEntryOverflow(self):
822 """Test that entries that overflow their size are detected"""
823 with self.assertRaises(ValueError) as e:
824 self._DoTestFile('015_pack_overflow.dts')
825 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
826 "but entry size is 0x3 (3)", str(e.exception))
828 def testPackImageOverflow(self):
829 """Test that entries which overflow the image size are detected"""
830 with self.assertRaises(ValueError) as e:
831 self._DoTestFile('016_pack_image_overflow.dts')
832 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
833 "size 0x3 (3)", str(e.exception))
835 def testPackImageSize(self):
836 """Test that the image size can be set"""
837 retcode = self._DoTestFile('017_pack_image_size.dts')
838 self.assertEqual(0, retcode)
839 self.assertIn('image', control.images)
840 image = control.images['image']
841 self.assertEqual(7, image.size)
843 def testPackImageSizeAlign(self):
844 """Test that image size alignemnt works as expected"""
845 retcode = self._DoTestFile('018_pack_image_align.dts')
846 self.assertEqual(0, retcode)
847 self.assertIn('image', control.images)
848 image = control.images['image']
849 self.assertEqual(16, image.size)
851 def testPackInvalidImageAlign(self):
852 """Test that invalid image alignment is detected"""
853 with self.assertRaises(ValueError) as e:
854 self._DoTestFile('019_pack_inv_image_align.dts')
855 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
856 "align-size 0x8 (8)", str(e.exception))
858 def testPackAlignPowerOf2(self):
859 """Test that invalid image alignment is detected"""
860 with self.assertRaises(ValueError) as e:
861 self._DoTestFile('020_pack_inv_image_align_power2.dts')
862 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
863 "two", str(e.exception))
865 def testImagePadByte(self):
866 """Test that the image pad byte can be specified"""
868 data = self._DoReadFile('021_image_pad.dts')
869 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
872 def testImageName(self):
873 """Test that image files can be named"""
874 retcode = self._DoTestFile('022_image_name.dts')
875 self.assertEqual(0, retcode)
876 image = control.images['image1']
877 fname = tools.GetOutputFilename('test-name')
878 self.assertTrue(os.path.exists(fname))
880 image = control.images['image2']
881 fname = tools.GetOutputFilename('test-name.xx')
882 self.assertTrue(os.path.exists(fname))
884 def testBlobFilename(self):
885 """Test that generic blobs can be provided by filename"""
886 data = self._DoReadFile('023_blob.dts')
887 self.assertEqual(BLOB_DATA, data)
889 def testPackSorted(self):
890 """Test that entries can be sorted"""
892 data = self._DoReadFile('024_sorted.dts')
893 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
894 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
896 def testPackZeroOffset(self):
897 """Test that an entry at offset 0 is not given a new offset"""
898 with self.assertRaises(ValueError) as e:
899 self._DoTestFile('025_pack_zero_size.dts')
900 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
901 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
904 def testPackUbootDtb(self):
905 """Test that a device tree can be added to U-Boot"""
906 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
907 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
909 def testPackX86RomNoSize(self):
910 """Test that the end-at-4gb property requires a size property"""
911 with self.assertRaises(ValueError) as e:
912 self._DoTestFile('027_pack_4gb_no_size.dts')
913 self.assertIn("Image '/binman': Section size must be provided when "
914 "using end-at-4gb", str(e.exception))
916 def test4gbAndSkipAtStartTogether(self):
917 """Test that the end-at-4gb and skip-at-size property can't be used
919 with self.assertRaises(ValueError) as e:
920 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
921 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
922 "'skip-at-start'", str(e.exception))
924 def testPackX86RomOutside(self):
925 """Test that the end-at-4gb property checks for offset boundaries"""
926 with self.assertRaises(ValueError) as e:
927 self._DoTestFile('028_pack_4gb_outside.dts')
928 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
929 "the section starting at 0xffffffe0 (4294967264)",
932 def testPackX86Rom(self):
933 """Test that a basic x86 ROM can be created"""
935 data = self._DoReadFile('029_x86_rom.dts')
936 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
937 tools.GetBytes(0, 2), data)
939 def testPackX86RomMeNoDesc(self):
940 """Test that an invalid Intel descriptor entry is detected"""
942 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
943 with self.assertRaises(ValueError) as e:
944 self._DoTestFile('163_x86_rom_me_empty.dts')
945 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
948 self._SetupDescriptor()
950 def testPackX86RomBadDesc(self):
951 """Test that the Intel requires a descriptor entry"""
952 with self.assertRaises(ValueError) as e:
953 self._DoTestFile('030_x86_rom_me_no_desc.dts')
954 self.assertIn("Node '/binman/intel-me': No offset set with "
955 "offset-unset: should another entry provide this correct "
956 "offset?", str(e.exception))
958 def testPackX86RomMe(self):
959 """Test that an x86 ROM with an ME region can be created"""
960 data = self._DoReadFile('031_x86_rom_me.dts')
961 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
962 if data[:0x1000] != expected_desc:
963 self.fail('Expected descriptor binary at start of image')
964 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
966 def testPackVga(self):
967 """Test that an image with a VGA binary can be created"""
968 data = self._DoReadFile('032_intel_vga.dts')
969 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
971 def testPackStart16(self):
972 """Test that an image with an x86 start16 region can be created"""
973 data = self._DoReadFile('033_x86_start16.dts')
974 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
976 def testPackPowerpcMpc85xxBootpgResetvec(self):
977 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
979 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
980 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
982 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
983 """Handle running a test for insertion of microcode
986 dts_fname: Name of test .dts file
987 nodtb_data: Data that we expect in the first section
988 ucode_second: True if the microsecond entry is second instead of
993 Contents of first region (U-Boot or SPL)
994 Offset and size components of microcode pointer, as inserted
995 in the above (two 4-byte words)
997 data = self._DoReadFile(dts_fname, True)
999 # Now check the device tree has no microcode
1001 ucode_content = data[len(nodtb_data):]
1002 ucode_pos = len(nodtb_data)
1003 dtb_with_ucode = ucode_content[16:]
1004 fdt_len = self.GetFdtLen(dtb_with_ucode)
1006 dtb_with_ucode = data[len(nodtb_data):]
1007 fdt_len = self.GetFdtLen(dtb_with_ucode)
1008 ucode_content = dtb_with_ucode[fdt_len:]
1009 ucode_pos = len(nodtb_data) + fdt_len
1010 fname = tools.GetOutputFilename('test.dtb')
1011 with open(fname, 'wb') as fd:
1012 fd.write(dtb_with_ucode)
1013 dtb = fdt.FdtScan(fname)
1014 ucode = dtb.GetNode('/microcode')
1015 self.assertTrue(ucode)
1016 for node in ucode.subnodes:
1017 self.assertFalse(node.props.get('data'))
1019 # Check that the microcode appears immediately after the Fdt
1020 # This matches the concatenation of the data properties in
1021 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1022 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1024 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1026 # Check that the microcode pointer was inserted. It should match the
1027 # expected offset and size
1028 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1030 u_boot = data[:len(nodtb_data)]
1031 return u_boot, pos_and_size
1033 def testPackUbootMicrocode(self):
1034 """Test that x86 microcode can be handled correctly
1036 We expect to see the following in the image, in order:
1037 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1039 u-boot.dtb with the microcode removed
1042 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1044 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1045 b' somewhere in here', first)
1047 def _RunPackUbootSingleMicrocode(self):
1048 """Test that x86 microcode can be handled correctly
1050 We expect to see the following in the image, in order:
1051 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1053 u-boot.dtb with the microcode
1054 an empty microcode region
1056 # We need the libfdt library to run this test since only that allows
1057 # finding the offset of a property. This is required by
1058 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1059 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1061 second = data[len(U_BOOT_NODTB_DATA):]
1063 fdt_len = self.GetFdtLen(second)
1064 third = second[fdt_len:]
1065 second = second[:fdt_len]
1067 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1068 self.assertIn(ucode_data, second)
1069 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1071 # Check that the microcode pointer was inserted. It should match the
1072 # expected offset and size
1073 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1075 first = data[:len(U_BOOT_NODTB_DATA)]
1076 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1077 b' somewhere in here', first)
1079 def testPackUbootSingleMicrocode(self):
1080 """Test that x86 microcode can be handled correctly with fdt_normal.
1082 self._RunPackUbootSingleMicrocode()
1084 def testUBootImg(self):
1085 """Test that u-boot.img can be put in a file"""
1086 data = self._DoReadFile('036_u_boot_img.dts')
1087 self.assertEqual(U_BOOT_IMG_DATA, data)
1089 def testNoMicrocode(self):
1090 """Test that a missing microcode region is detected"""
1091 with self.assertRaises(ValueError) as e:
1092 self._DoReadFile('037_x86_no_ucode.dts', True)
1093 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1094 "node found in ", str(e.exception))
1096 def testMicrocodeWithoutNode(self):
1097 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1098 with self.assertRaises(ValueError) as e:
1099 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1100 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1101 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1103 def testMicrocodeWithoutNode2(self):
1104 """Test that a missing u-boot-ucode node is detected"""
1105 with self.assertRaises(ValueError) as e:
1106 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1107 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1108 "microcode region u-boot-ucode", str(e.exception))
1110 def testMicrocodeWithoutPtrInElf(self):
1111 """Test that a U-Boot binary without the microcode symbol is detected"""
1112 # ELF file without a '_dt_ucode_base_size' symbol
1114 TestFunctional._MakeInputFile('u-boot',
1115 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1117 with self.assertRaises(ValueError) as e:
1118 self._RunPackUbootSingleMicrocode()
1119 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1120 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1123 # Put the original file back
1124 TestFunctional._MakeInputFile('u-boot',
1125 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1127 def testMicrocodeNotInImage(self):
1128 """Test that microcode must be placed within the image"""
1129 with self.assertRaises(ValueError) as e:
1130 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1131 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1132 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1133 "section ranging from 00000000 to 0000002e", str(e.exception))
1135 def testWithoutMicrocode(self):
1136 """Test that we can cope with an image without microcode (e.g. qemu)"""
1137 TestFunctional._MakeInputFile('u-boot',
1138 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1139 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1141 # Now check the device tree has no microcode
1142 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1143 second = data[len(U_BOOT_NODTB_DATA):]
1145 fdt_len = self.GetFdtLen(second)
1146 self.assertEqual(dtb, second[:fdt_len])
1148 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1149 third = data[used_len:]
1150 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1152 def testUnknownPosSize(self):
1153 """Test that microcode must be placed within the image"""
1154 with self.assertRaises(ValueError) as e:
1155 self._DoReadFile('041_unknown_pos_size.dts', True)
1156 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1157 "entry 'invalid-entry'", str(e.exception))
1159 def testPackFsp(self):
1160 """Test that an image with a FSP binary can be created"""
1161 data = self._DoReadFile('042_intel_fsp.dts')
1162 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1164 def testPackCmc(self):
1165 """Test that an image with a CMC binary can be created"""
1166 data = self._DoReadFile('043_intel_cmc.dts')
1167 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1169 def testPackVbt(self):
1170 """Test that an image with a VBT binary can be created"""
1171 data = self._DoReadFile('046_intel_vbt.dts')
1172 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1174 def testSplBssPad(self):
1175 """Test that we can pad SPL's BSS with zeros"""
1176 # ELF file with a '__bss_size' symbol
1178 data = self._DoReadFile('047_spl_bss_pad.dts')
1179 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1182 def testSplBssPadMissing(self):
1183 """Test that a missing symbol is detected"""
1184 self._SetupSplElf('u_boot_ucode_ptr')
1185 with self.assertRaises(ValueError) as e:
1186 self._DoReadFile('047_spl_bss_pad.dts')
1187 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1190 def testPackStart16Spl(self):
1191 """Test that an image with an x86 start16 SPL region can be created"""
1192 data = self._DoReadFile('048_x86_start16_spl.dts')
1193 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1195 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1196 """Helper function for microcode tests
1198 We expect to see the following in the image, in order:
1199 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1201 u-boot.dtb with the microcode removed
1205 dts: Device tree file to use for test
1206 ucode_second: True if the microsecond entry is second instead of
1209 self._SetupSplElf('u_boot_ucode_ptr')
1210 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1211 ucode_second=ucode_second)
1212 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1213 b'ter somewhere in here', first)
1215 def testPackUbootSplMicrocode(self):
1216 """Test that x86 microcode can be handled correctly in SPL"""
1217 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1219 def testPackUbootSplMicrocodeReorder(self):
1220 """Test that order doesn't matter for microcode entries
1222 This is the same as testPackUbootSplMicrocode but when we process the
1223 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1224 entry, so we reply on binman to try later.
1226 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1229 def testPackMrc(self):
1230 """Test that an image with an MRC binary can be created"""
1231 data = self._DoReadFile('050_intel_mrc.dts')
1232 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1234 def testSplDtb(self):
1235 """Test that an image with spl/u-boot-spl.dtb can be created"""
1236 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1237 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1239 def testSplNoDtb(self):
1240 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1241 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1242 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1244 def testSymbols(self):
1245 """Test binman can assign symbols embedded in U-Boot"""
1246 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1247 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1248 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1249 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1251 self._SetupSplElf('u_boot_binman_syms')
1252 data = self._DoReadFile('053_symbols.dts')
1253 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
1254 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
1255 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1256 U_BOOT_SPL_DATA[20:])
1257 self.assertEqual(expected, data)
1259 def testPackUnitAddress(self):
1260 """Test that we support multiple binaries with the same name"""
1261 data = self._DoReadFile('054_unit_address.dts')
1262 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1264 def testSections(self):
1265 """Basic test of sections"""
1266 data = self._DoReadFile('055_sections.dts')
1267 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1268 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1269 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1270 self.assertEqual(expected, data)
1273 """Tests outputting a map of the images"""
1274 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1275 self.assertEqual('''ImagePos Offset Size Name
1276 00000000 00000000 00000028 main-section
1277 00000000 00000000 00000010 section@0
1278 00000000 00000000 00000004 u-boot
1279 00000010 00000010 00000010 section@1
1280 00000010 00000000 00000004 u-boot
1281 00000020 00000020 00000004 section@2
1282 00000020 00000000 00000004 u-boot
1285 def testNamePrefix(self):
1286 """Tests that name prefixes are used"""
1287 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1288 self.assertEqual('''ImagePos Offset Size Name
1289 00000000 00000000 00000028 main-section
1290 00000000 00000000 00000010 section@0
1291 00000000 00000000 00000004 ro-u-boot
1292 00000010 00000010 00000010 section@1
1293 00000010 00000000 00000004 rw-u-boot
1296 def testUnknownContents(self):
1297 """Test that obtaining the contents works as expected"""
1298 with self.assertRaises(ValueError) as e:
1299 self._DoReadFile('057_unknown_contents.dts', True)
1300 self.assertIn("Image '/binman': Internal error: Could not complete "
1301 "processing of contents: remaining ["
1302 "<binman.etype._testing.Entry__testing ", str(e.exception))
1304 def testBadChangeSize(self):
1305 """Test that trying to change the size of an entry fails"""
1307 state.SetAllowEntryExpansion(False)
1308 with self.assertRaises(ValueError) as e:
1309 self._DoReadFile('059_change_size.dts', True)
1310 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1313 state.SetAllowEntryExpansion(True)
1315 def testUpdateFdt(self):
1316 """Test that we can update the device tree with offset/size info"""
1317 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1319 dtb = fdt.Fdt(out_dtb_fname)
1321 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1325 '_testing:offset': 32,
1327 '_testing:image-pos': 32,
1328 'section@0/u-boot:offset': 0,
1329 'section@0/u-boot:size': len(U_BOOT_DATA),
1330 'section@0/u-boot:image-pos': 0,
1331 'section@0:offset': 0,
1332 'section@0:size': 16,
1333 'section@0:image-pos': 0,
1335 'section@1/u-boot:offset': 0,
1336 'section@1/u-boot:size': len(U_BOOT_DATA),
1337 'section@1/u-boot:image-pos': 16,
1338 'section@1:offset': 16,
1339 'section@1:size': 16,
1340 'section@1:image-pos': 16,
1344 def testUpdateFdtBad(self):
1345 """Test that we detect when ProcessFdt never completes"""
1346 with self.assertRaises(ValueError) as e:
1347 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1348 self.assertIn('Could not complete processing of Fdt: remaining '
1349 '[<binman.etype._testing.Entry__testing',
1352 def testEntryArgs(self):
1353 """Test passing arguments to entries from the command line"""
1355 'test-str-arg': 'test1',
1356 'test-int-arg': '456',
1358 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1359 self.assertIn('image', control.images)
1360 entry = control.images['image'].GetEntries()['_testing']
1361 self.assertEqual('test0', entry.test_str_fdt)
1362 self.assertEqual('test1', entry.test_str_arg)
1363 self.assertEqual(123, entry.test_int_fdt)
1364 self.assertEqual(456, entry.test_int_arg)
1366 def testEntryArgsMissing(self):
1367 """Test missing arguments and properties"""
1369 'test-int-arg': '456',
1371 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1372 entry = control.images['image'].GetEntries()['_testing']
1373 self.assertEqual('test0', entry.test_str_fdt)
1374 self.assertEqual(None, entry.test_str_arg)
1375 self.assertEqual(None, entry.test_int_fdt)
1376 self.assertEqual(456, entry.test_int_arg)
1378 def testEntryArgsRequired(self):
1379 """Test missing arguments and properties"""
1381 'test-int-arg': '456',
1383 with self.assertRaises(ValueError) as e:
1384 self._DoReadFileDtb('064_entry_args_required.dts')
1385 self.assertIn("Node '/binman/_testing': "
1386 'Missing required properties/entry args: test-str-arg, '
1387 'test-int-fdt, test-int-arg',
1390 def testEntryArgsInvalidFormat(self):
1391 """Test that an invalid entry-argument format is detected"""
1392 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1394 with self.assertRaises(ValueError) as e:
1395 self._DoBinman(*args)
1396 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1398 def testEntryArgsInvalidInteger(self):
1399 """Test that an invalid entry-argument integer is detected"""
1401 'test-int-arg': 'abc',
1403 with self.assertRaises(ValueError) as e:
1404 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1405 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1406 "'test-int-arg' (value 'abc') to integer",
1409 def testEntryArgsInvalidDatatype(self):
1410 """Test that an invalid entry-argument datatype is detected
1412 This test could be written in entry_test.py except that it needs
1413 access to control.entry_args, which seems more than that module should
1417 'test-bad-datatype-arg': '12',
1419 with self.assertRaises(ValueError) as e:
1420 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1421 entry_args=entry_args)
1422 self.assertIn('GetArg() internal error: Unknown data type ',
1426 """Test for a text entry type"""
1428 'test-id': TEXT_DATA,
1429 'test-id2': TEXT_DATA2,
1430 'test-id3': TEXT_DATA3,
1432 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1433 entry_args=entry_args)
1434 expected = (tools.ToBytes(TEXT_DATA) +
1435 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1436 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1437 b'some text' + b'more text')
1438 self.assertEqual(expected, data)
1440 def testEntryDocs(self):
1441 """Test for creation of entry documentation"""
1442 with test_util.capture_sys_output() as (stdout, stderr):
1443 control.WriteEntryDocs(control.GetEntryModules())
1444 self.assertTrue(len(stdout.getvalue()) > 0)
1446 def testEntryDocsMissing(self):
1447 """Test handling of missing entry documentation"""
1448 with self.assertRaises(ValueError) as e:
1449 with test_util.capture_sys_output() as (stdout, stderr):
1450 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
1451 self.assertIn('Documentation is missing for modules: u_boot',
1455 """Basic test of generation of a flashrom fmap"""
1456 data = self._DoReadFile('067_fmap.dts')
1457 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1458 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1459 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1460 self.assertEqual(expected, data[:32])
1461 self.assertEqual(b'__FMAP__', fhdr.signature)
1462 self.assertEqual(1, fhdr.ver_major)
1463 self.assertEqual(0, fhdr.ver_minor)
1464 self.assertEqual(0, fhdr.base)
1465 self.assertEqual(16 + 16 +
1466 fmap_util.FMAP_HEADER_LEN +
1467 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1468 self.assertEqual(b'FMAP', fhdr.name)
1469 self.assertEqual(3, fhdr.nareas)
1470 for fentry in fentries:
1471 self.assertEqual(0, fentry.flags)
1473 self.assertEqual(0, fentries[0].offset)
1474 self.assertEqual(4, fentries[0].size)
1475 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1477 self.assertEqual(16, fentries[1].offset)
1478 self.assertEqual(4, fentries[1].size)
1479 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1481 self.assertEqual(32, fentries[2].offset)
1482 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1483 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1484 self.assertEqual(b'FMAP', fentries[2].name)
1486 def testBlobNamedByArg(self):
1487 """Test we can add a blob with the filename coming from an entry arg"""
1489 'cros-ec-rw-path': 'ecrw.bin',
1491 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
1494 """Test for an fill entry type"""
1495 data = self._DoReadFile('069_fill.dts')
1496 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1497 self.assertEqual(expected, data)
1499 def testFillNoSize(self):
1500 """Test for an fill entry type with no size"""
1501 with self.assertRaises(ValueError) as e:
1502 self._DoReadFile('070_fill_no_size.dts')
1503 self.assertIn("'fill' entry must have a size property",
1506 def _HandleGbbCommand(self, pipe_list):
1507 """Fake calls to the futility utility"""
1508 if pipe_list[0][0] == 'futility':
1509 fname = pipe_list[0][-1]
1510 # Append our GBB data to the file, which will happen every time the
1511 # futility command is called.
1512 with open(fname, 'ab') as fd:
1514 return command.CommandResult()
1517 """Test for the Chromium OS Google Binary Block"""
1518 command.test_result = self._HandleGbbCommand
1520 'keydir': 'devkeys',
1521 'bmpblk': 'bmpblk.bin',
1523 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1526 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1527 tools.GetBytes(0, 0x2180 - 16))
1528 self.assertEqual(expected, data)
1530 def testGbbTooSmall(self):
1531 """Test for the Chromium OS Google Binary Block being large enough"""
1532 with self.assertRaises(ValueError) as e:
1533 self._DoReadFileDtb('072_gbb_too_small.dts')
1534 self.assertIn("Node '/binman/gbb': GBB is too small",
1537 def testGbbNoSize(self):
1538 """Test for the Chromium OS Google Binary Block having a size"""
1539 with self.assertRaises(ValueError) as e:
1540 self._DoReadFileDtb('073_gbb_no_size.dts')
1541 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1544 def _HandleVblockCommand(self, pipe_list):
1545 """Fake calls to the futility utility"""
1546 if pipe_list[0][0] == 'futility':
1547 fname = pipe_list[0][3]
1548 with open(fname, 'wb') as fd:
1549 fd.write(VBLOCK_DATA)
1550 return command.CommandResult()
1552 def testVblock(self):
1553 """Test for the Chromium OS Verified Boot Block"""
1554 command.test_result = self._HandleVblockCommand
1556 'keydir': 'devkeys',
1558 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1559 entry_args=entry_args)
1560 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1561 self.assertEqual(expected, data)
1563 def testVblockNoContent(self):
1564 """Test we detect a vblock which has no content to sign"""
1565 with self.assertRaises(ValueError) as e:
1566 self._DoReadFile('075_vblock_no_content.dts')
1567 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1568 'property', str(e.exception))
1570 def testVblockBadPhandle(self):
1571 """Test that we detect a vblock with an invalid phandle in contents"""
1572 with self.assertRaises(ValueError) as e:
1573 self._DoReadFile('076_vblock_bad_phandle.dts')
1574 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1575 '1000', str(e.exception))
1577 def testVblockBadEntry(self):
1578 """Test that we detect an entry that points to a non-entry"""
1579 with self.assertRaises(ValueError) as e:
1580 self._DoReadFile('077_vblock_bad_entry.dts')
1581 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1582 "'other'", str(e.exception))
1585 """Test that an image with TPL and its device tree can be created"""
1586 # ELF file with a '__bss_size' symbol
1588 data = self._DoReadFile('078_u_boot_tpl.dts')
1589 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1591 def testUsesPos(self):
1592 """Test that the 'pos' property cannot be used anymore"""
1593 with self.assertRaises(ValueError) as e:
1594 data = self._DoReadFile('079_uses_pos.dts')
1595 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1596 "'pos'", str(e.exception))
1598 def testFillZero(self):
1599 """Test for an fill entry type with a size of 0"""
1600 data = self._DoReadFile('080_fill_empty.dts')
1601 self.assertEqual(tools.GetBytes(0, 16), data)
1603 def testTextMissing(self):
1604 """Test for a text entry type where there is no text"""
1605 with self.assertRaises(ValueError) as e:
1606 self._DoReadFileDtb('066_text.dts',)
1607 self.assertIn("Node '/binman/text': No value provided for text label "
1608 "'test-id'", str(e.exception))
1610 def testPackStart16Tpl(self):
1611 """Test that an image with an x86 start16 TPL region can be created"""
1612 data = self._DoReadFile('081_x86_start16_tpl.dts')
1613 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1615 def testSelectImage(self):
1616 """Test that we can select which images to build"""
1617 expected = 'Skipping images: image1'
1619 # We should only get the expected message in verbose mode
1620 for verbosity in (0, 2):
1621 with test_util.capture_sys_output() as (stdout, stderr):
1622 retcode = self._DoTestFile('006_dual_image.dts',
1623 verbosity=verbosity,
1625 self.assertEqual(0, retcode)
1627 self.assertIn(expected, stdout.getvalue())
1629 self.assertNotIn(expected, stdout.getvalue())
1631 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1632 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1633 self._CleanupOutputDir()
1635 def testUpdateFdtAll(self):
1636 """Test that all device trees are updated with offset/size info"""
1637 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1640 'section:image-pos': 0,
1641 'u-boot-tpl-dtb:size': 513,
1642 'u-boot-spl-dtb:size': 513,
1643 'u-boot-spl-dtb:offset': 493,
1645 'section/u-boot-dtb:image-pos': 0,
1646 'u-boot-spl-dtb:image-pos': 493,
1647 'section/u-boot-dtb:size': 493,
1648 'u-boot-tpl-dtb:image-pos': 1006,
1649 'section/u-boot-dtb:offset': 0,
1650 'section:size': 493,
1652 'section:offset': 0,
1653 'u-boot-tpl-dtb:offset': 1006,
1657 # We expect three device-tree files in the output, one after the other.
1658 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1659 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1660 # main U-Boot tree. All three should have the same postions and offset.
1662 for item in ['', 'spl', 'tpl']:
1663 dtb = fdt.Fdt.FromData(data[start:])
1665 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1667 expected = dict(base_expected)
1670 self.assertEqual(expected, props)
1671 start += dtb._fdt_obj.totalsize()
1673 def testUpdateFdtOutput(self):
1674 """Test that output DTB files are updated"""
1676 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1677 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1679 # Unfortunately, compiling a source file always results in a file
1680 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1681 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1682 # binman as a file called u-boot.dtb. To fix this, copy the file
1683 # over to the expected place.
1685 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1686 'tpl/u-boot-tpl.dtb.out']:
1687 dtb = fdt.Fdt.FromData(data[start:])
1688 size = dtb._fdt_obj.totalsize()
1689 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1690 outdata = tools.ReadFile(pathname)
1691 name = os.path.split(fname)[0]
1694 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1696 orig_indata = dtb_data
1697 self.assertNotEqual(outdata, orig_indata,
1698 "Expected output file '%s' be updated" % pathname)
1699 self.assertEqual(outdata, data[start:start + size],
1700 "Expected output file '%s' to match output image" %
1706 def _decompress(self, data):
1707 return tools.Decompress(data, 'lz4')
1709 def testCompress(self):
1710 """Test compression of blobs"""
1712 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1713 use_real_dtb=True, update_dtb=True)
1714 dtb = fdt.Fdt(out_dtb_fname)
1716 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1717 orig = self._decompress(data)
1718 self.assertEquals(COMPRESS_DATA, orig)
1720 'blob:uncomp-size': len(COMPRESS_DATA),
1721 'blob:size': len(data),
1724 self.assertEqual(expected, props)
1726 def testFiles(self):
1727 """Test bringing in multiple files"""
1728 data = self._DoReadFile('084_files.dts')
1729 self.assertEqual(FILES_DATA, data)
1731 def testFilesCompress(self):
1732 """Test bringing in multiple files and compressing them"""
1734 data = self._DoReadFile('085_files_compress.dts')
1736 image = control.images['image']
1737 entries = image.GetEntries()
1738 files = entries['files']
1739 entries = files._entries
1742 for i in range(1, 3):
1744 start = entries[key].image_pos
1745 len = entries[key].size
1746 chunk = data[start:start + len]
1747 orig += self._decompress(chunk)
1749 self.assertEqual(FILES_DATA, orig)
1751 def testFilesMissing(self):
1752 """Test missing files"""
1753 with self.assertRaises(ValueError) as e:
1754 data = self._DoReadFile('086_files_none.dts')
1755 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1756 'no files', str(e.exception))
1758 def testFilesNoPattern(self):
1759 """Test missing files"""
1760 with self.assertRaises(ValueError) as e:
1761 data = self._DoReadFile('087_files_no_pattern.dts')
1762 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1765 def testExpandSize(self):
1766 """Test an expanding entry"""
1767 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1769 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1770 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1771 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1772 tools.GetBytes(ord('d'), 8))
1773 self.assertEqual(expect, data)
1774 self.assertEqual('''ImagePos Offset Size Name
1775 00000000 00000000 00000028 main-section
1776 00000000 00000000 00000008 fill
1777 00000008 00000008 00000004 u-boot
1778 0000000c 0000000c 00000004 section
1779 0000000c 00000000 00000003 intel-mrc
1780 00000010 00000010 00000004 u-boot2
1781 00000014 00000014 0000000c section2
1782 00000014 00000000 00000008 fill
1783 0000001c 00000008 00000004 u-boot
1784 00000020 00000020 00000008 fill2
1787 def testExpandSizeBad(self):
1788 """Test an expanding entry which fails to provide contents"""
1789 with test_util.capture_sys_output() as (stdout, stderr):
1790 with self.assertRaises(ValueError) as e:
1791 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1792 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1793 'expanding entry', str(e.exception))
1796 """Test hashing of the contents of an entry"""
1797 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1798 use_real_dtb=True, update_dtb=True)
1799 dtb = fdt.Fdt(out_dtb_fname)
1801 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1802 m = hashlib.sha256()
1803 m.update(U_BOOT_DATA)
1804 self.assertEqual(m.digest(), b''.join(hash_node.value))
1806 def testHashNoAlgo(self):
1807 with self.assertRaises(ValueError) as e:
1808 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1809 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1810 'hash node', str(e.exception))
1812 def testHashBadAlgo(self):
1813 with self.assertRaises(ValueError) as e:
1814 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1815 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1818 def testHashSection(self):
1819 """Test hashing of the contents of an entry"""
1820 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1821 use_real_dtb=True, update_dtb=True)
1822 dtb = fdt.Fdt(out_dtb_fname)
1824 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1825 m = hashlib.sha256()
1826 m.update(U_BOOT_DATA)
1827 m.update(tools.GetBytes(ord('a'), 16))
1828 self.assertEqual(m.digest(), b''.join(hash_node.value))
1830 def testPackUBootTplMicrocode(self):
1831 """Test that x86 microcode can be handled correctly in TPL
1833 We expect to see the following in the image, in order:
1834 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1836 u-boot-tpl.dtb with the microcode removed
1839 self._SetupTplElf('u_boot_ucode_ptr')
1840 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1841 U_BOOT_TPL_NODTB_DATA)
1842 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1843 b'ter somewhere in here', first)
1845 def testFmapX86(self):
1846 """Basic test of generation of a flashrom fmap"""
1847 data = self._DoReadFile('094_fmap_x86.dts')
1848 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1849 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1850 self.assertEqual(expected, data[:32])
1851 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1853 self.assertEqual(0x100, fhdr.image_size)
1855 self.assertEqual(0, fentries[0].offset)
1856 self.assertEqual(4, fentries[0].size)
1857 self.assertEqual(b'U_BOOT', fentries[0].name)
1859 self.assertEqual(4, fentries[1].offset)
1860 self.assertEqual(3, fentries[1].size)
1861 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1863 self.assertEqual(32, fentries[2].offset)
1864 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1865 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1866 self.assertEqual(b'FMAP', fentries[2].name)
1868 def testFmapX86Section(self):
1869 """Basic test of generation of a flashrom fmap"""
1870 data = self._DoReadFile('095_fmap_x86_section.dts')
1871 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1872 self.assertEqual(expected, data[:32])
1873 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1875 self.assertEqual(0x100, fhdr.image_size)
1877 self.assertEqual(0, fentries[0].offset)
1878 self.assertEqual(4, fentries[0].size)
1879 self.assertEqual(b'U_BOOT', fentries[0].name)
1881 self.assertEqual(4, fentries[1].offset)
1882 self.assertEqual(3, fentries[1].size)
1883 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1885 self.assertEqual(36, fentries[2].offset)
1886 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1887 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1888 self.assertEqual(b'FMAP', fentries[2].name)
1891 """Basic test of ELF entries"""
1894 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1895 TestFunctional._MakeInputFile('-boot', fd.read())
1896 data = self._DoReadFile('096_elf.dts')
1898 def testElfStrip(self):
1899 """Basic test of ELF entries"""
1901 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1902 TestFunctional._MakeInputFile('-boot', fd.read())
1903 data = self._DoReadFile('097_elf_strip.dts')
1905 def testPackOverlapMap(self):
1906 """Test that overlapping regions are detected"""
1907 with test_util.capture_sys_output() as (stdout, stderr):
1908 with self.assertRaises(ValueError) as e:
1909 self._DoTestFile('014_pack_overlap.dts', map=True)
1910 map_fname = tools.GetOutputFilename('image.map')
1911 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1914 # We should not get an inmage, but there should be a map file
1915 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1916 self.assertTrue(os.path.exists(map_fname))
1917 map_data = tools.ReadFile(map_fname, binary=False)
1918 self.assertEqual('''ImagePos Offset Size Name
1919 <none> 00000000 00000007 main-section
1920 <none> 00000000 00000004 u-boot
1921 <none> 00000003 00000004 u-boot-align
1924 def testPackRefCode(self):
1925 """Test that an image with an Intel Reference code binary works"""
1926 data = self._DoReadFile('100_intel_refcode.dts')
1927 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1929 def testSectionOffset(self):
1930 """Tests use of a section with an offset"""
1931 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1933 self.assertEqual('''ImagePos Offset Size Name
1934 00000000 00000000 00000038 main-section
1935 00000004 00000004 00000010 section@0
1936 00000004 00000000 00000004 u-boot
1937 00000018 00000018 00000010 section@1
1938 00000018 00000000 00000004 u-boot
1939 0000002c 0000002c 00000004 section@2
1940 0000002c 00000000 00000004 u-boot
1942 self.assertEqual(data,
1943 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1944 tools.GetBytes(0x21, 12) +
1945 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1946 tools.GetBytes(0x61, 12) +
1947 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1948 tools.GetBytes(0x26, 8))
1950 def testCbfsRaw(self):
1951 """Test base handling of a Coreboot Filesystem (CBFS)
1953 The exact contents of the CBFS is verified by similar tests in
1954 cbfs_util_test.py. The tests here merely check that the files added to
1955 the CBFS can be found in the final image.
1957 data = self._DoReadFile('102_cbfs_raw.dts')
1960 cbfs = cbfs_util.CbfsReader(data)
1961 self.assertEqual(size, cbfs.rom_size)
1963 self.assertIn('u-boot-dtb', cbfs.files)
1964 cfile = cbfs.files['u-boot-dtb']
1965 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1967 def testCbfsArch(self):
1968 """Test on non-x86 architecture"""
1969 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1972 cbfs = cbfs_util.CbfsReader(data)
1973 self.assertEqual(size, cbfs.rom_size)
1975 self.assertIn('u-boot-dtb', cbfs.files)
1976 cfile = cbfs.files['u-boot-dtb']
1977 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1979 def testCbfsStage(self):
1980 """Tests handling of a Coreboot Filesystem (CBFS)"""
1981 if not elf.ELF_TOOLS:
1982 self.skipTest('Python elftools not available')
1983 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1984 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1987 data = self._DoReadFile('104_cbfs_stage.dts')
1988 cbfs = cbfs_util.CbfsReader(data)
1989 self.assertEqual(size, cbfs.rom_size)
1991 self.assertIn('u-boot', cbfs.files)
1992 cfile = cbfs.files['u-boot']
1993 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1995 def testCbfsRawCompress(self):
1996 """Test handling of compressing raw files"""
1998 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2001 cbfs = cbfs_util.CbfsReader(data)
2002 self.assertIn('u-boot', cbfs.files)
2003 cfile = cbfs.files['u-boot']
2004 self.assertEqual(COMPRESS_DATA, cfile.data)
2006 def testCbfsBadArch(self):
2007 """Test handling of a bad architecture"""
2008 with self.assertRaises(ValueError) as e:
2009 self._DoReadFile('106_cbfs_bad_arch.dts')
2010 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2012 def testCbfsNoSize(self):
2013 """Test handling of a missing size property"""
2014 with self.assertRaises(ValueError) as e:
2015 self._DoReadFile('107_cbfs_no_size.dts')
2016 self.assertIn('entry must have a size property', str(e.exception))
2018 def testCbfsNoCOntents(self):
2019 """Test handling of a CBFS entry which does not provide contentsy"""
2020 with self.assertRaises(ValueError) as e:
2021 self._DoReadFile('108_cbfs_no_contents.dts')
2022 self.assertIn('Could not complete processing of contents',
2025 def testCbfsBadCompress(self):
2026 """Test handling of a bad architecture"""
2027 with self.assertRaises(ValueError) as e:
2028 self._DoReadFile('109_cbfs_bad_compress.dts')
2029 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2032 def testCbfsNamedEntries(self):
2033 """Test handling of named entries"""
2034 data = self._DoReadFile('110_cbfs_name.dts')
2036 cbfs = cbfs_util.CbfsReader(data)
2037 self.assertIn('FRED', cbfs.files)
2038 cfile1 = cbfs.files['FRED']
2039 self.assertEqual(U_BOOT_DATA, cfile1.data)
2041 self.assertIn('hello', cbfs.files)
2042 cfile2 = cbfs.files['hello']
2043 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2045 def _SetupIfwi(self, fname):
2046 """Set up to run an IFWI test
2049 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2054 # Intel Integrated Firmware Image (IFWI) file
2055 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2057 TestFunctional._MakeInputFile(fname,data)
2059 def _CheckIfwi(self, data):
2060 """Check that an image with an IFWI contains the correct output
2063 data: Conents of output file
2065 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2066 if data[:0x1000] != expected_desc:
2067 self.fail('Expected descriptor binary at start of image')
2069 # We expect to find the TPL wil in subpart IBBP entry IBBL
2070 image_fname = tools.GetOutputFilename('image.bin')
2071 tpl_fname = tools.GetOutputFilename('tpl.out')
2072 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2073 subpart='IBBP', entry_name='IBBL')
2075 tpl_data = tools.ReadFile(tpl_fname)
2076 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2078 def testPackX86RomIfwi(self):
2079 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2080 self._SetupIfwi('fitimage.bin')
2081 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2082 self._CheckIfwi(data)
2084 def testPackX86RomIfwiNoDesc(self):
2085 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2086 self._SetupIfwi('ifwi.bin')
2087 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2088 self._CheckIfwi(data)
2090 def testPackX86RomIfwiNoData(self):
2091 """Test that an x86 ROM with IFWI handles missing data"""
2092 self._SetupIfwi('ifwi.bin')
2093 with self.assertRaises(ValueError) as e:
2094 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2095 self.assertIn('Could not complete processing of contents',
2098 def testCbfsOffset(self):
2099 """Test a CBFS with files at particular offsets
2101 Like all CFBS tests, this is just checking the logic that calls
2102 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2104 data = self._DoReadFile('114_cbfs_offset.dts')
2107 cbfs = cbfs_util.CbfsReader(data)
2108 self.assertEqual(size, cbfs.rom_size)
2110 self.assertIn('u-boot', cbfs.files)
2111 cfile = cbfs.files['u-boot']
2112 self.assertEqual(U_BOOT_DATA, cfile.data)
2113 self.assertEqual(0x40, cfile.cbfs_offset)
2115 self.assertIn('u-boot-dtb', cbfs.files)
2116 cfile2 = cbfs.files['u-boot-dtb']
2117 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2118 self.assertEqual(0x140, cfile2.cbfs_offset)
2120 def testFdtmap(self):
2121 """Test an FDT map can be inserted in the image"""
2122 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2123 fdtmap_data = data[len(U_BOOT_DATA):]
2124 magic = fdtmap_data[:8]
2125 self.assertEqual(b'_FDTMAP_', magic)
2126 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2128 fdt_data = fdtmap_data[16:]
2129 dtb = fdt.Fdt.FromData(fdt_data)
2131 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2136 'u-boot:size': len(U_BOOT_DATA),
2137 'u-boot:image-pos': 0,
2138 'fdtmap:image-pos': 4,
2140 'fdtmap:size': len(fdtmap_data),
2144 def testFdtmapNoMatch(self):
2145 """Check handling of an FDT map when the section cannot be found"""
2146 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2148 # Mangle the section name, which should cause a mismatch between the
2149 # correct FDT path and the one expected by the section
2150 image = control.images['image']
2151 image._node.path += '-suffix'
2152 entries = image.GetEntries()
2153 fdtmap = entries['fdtmap']
2154 with self.assertRaises(ValueError) as e:
2156 self.assertIn("Cannot locate node for path '/binman-suffix'",
2159 def testFdtmapHeader(self):
2160 """Test an FDT map and image header can be inserted in the image"""
2161 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2162 fdtmap_pos = len(U_BOOT_DATA)
2163 fdtmap_data = data[fdtmap_pos:]
2164 fdt_data = fdtmap_data[16:]
2165 dtb = fdt.Fdt.FromData(fdt_data)
2166 fdt_size = dtb.GetFdtObj().totalsize()
2167 hdr_data = data[-8:]
2168 self.assertEqual(b'BinM', hdr_data[:4])
2169 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2170 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2172 def testFdtmapHeaderStart(self):
2173 """Test an image header can be inserted at the image start"""
2174 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2175 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2177 self.assertEqual(b'BinM', hdr_data[:4])
2178 offset = struct.unpack('<I', hdr_data[4:])[0]
2179 self.assertEqual(fdtmap_pos, offset)
2181 def testFdtmapHeaderPos(self):
2182 """Test an image header can be inserted at a chosen position"""
2183 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2184 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2185 hdr_data = data[0x80:0x88]
2186 self.assertEqual(b'BinM', hdr_data[:4])
2187 offset = struct.unpack('<I', hdr_data[4:])[0]
2188 self.assertEqual(fdtmap_pos, offset)
2190 def testHeaderMissingFdtmap(self):
2191 """Test an image header requires an fdtmap"""
2192 with self.assertRaises(ValueError) as e:
2193 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2194 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2197 def testHeaderNoLocation(self):
2198 """Test an image header with a no specified location is detected"""
2199 with self.assertRaises(ValueError) as e:
2200 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2201 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2204 def testEntryExpand(self):
2205 """Test expanding an entry after it is packed"""
2206 data = self._DoReadFile('121_entry_expand.dts')
2207 self.assertEqual(b'aaa', data[:3])
2208 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2209 self.assertEqual(b'aaa', data[-3:])
2211 def testEntryExpandBad(self):
2212 """Test expanding an entry after it is packed, twice"""
2213 with self.assertRaises(ValueError) as e:
2214 self._DoReadFile('122_entry_expand_twice.dts')
2215 self.assertIn("Image '/binman': Entries changed size after packing",
2218 def testEntryExpandSection(self):
2219 """Test expanding an entry within a section after it is packed"""
2220 data = self._DoReadFile('123_entry_expand_section.dts')
2221 self.assertEqual(b'aaa', data[:3])
2222 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2223 self.assertEqual(b'aaa', data[-3:])
2225 def testCompressDtb(self):
2226 """Test that compress of device-tree files is supported"""
2228 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2229 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2230 comp_data = data[len(U_BOOT_DATA):]
2231 orig = self._decompress(comp_data)
2232 dtb = fdt.Fdt.FromData(orig)
2234 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2236 'u-boot:size': len(U_BOOT_DATA),
2237 'u-boot-dtb:uncomp-size': len(orig),
2238 'u-boot-dtb:size': len(comp_data),
2241 self.assertEqual(expected, props)
2243 def testCbfsUpdateFdt(self):
2244 """Test that we can update the device tree with CBFS offset/size info"""
2246 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2248 dtb = fdt.Fdt(out_dtb_fname)
2250 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2251 del props['cbfs/u-boot:size']
2257 'cbfs:size': len(data),
2258 'cbfs:image-pos': 0,
2259 'cbfs/u-boot:offset': 0x38,
2260 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2261 'cbfs/u-boot:image-pos': 0x38,
2262 'cbfs/u-boot-dtb:offset': 0xb8,
2263 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2264 'cbfs/u-boot-dtb:image-pos': 0xb8,
2267 def testCbfsBadType(self):
2268 """Test an image header with a no specified location is detected"""
2269 with self.assertRaises(ValueError) as e:
2270 self._DoReadFile('126_cbfs_bad_type.dts')
2271 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2274 """Test listing the files in an image"""
2276 data = self._DoReadFile('127_list.dts')
2277 image = control.images['image']
2278 entries = image.BuildEntryList()
2279 self.assertEqual(7, len(entries))
2282 self.assertEqual(0, ent.indent)
2283 self.assertEqual('main-section', ent.name)
2284 self.assertEqual('section', ent.etype)
2285 self.assertEqual(len(data), ent.size)
2286 self.assertEqual(0, ent.image_pos)
2287 self.assertEqual(None, ent.uncomp_size)
2288 self.assertEqual(0, ent.offset)
2291 self.assertEqual(1, ent.indent)
2292 self.assertEqual('u-boot', ent.name)
2293 self.assertEqual('u-boot', ent.etype)
2294 self.assertEqual(len(U_BOOT_DATA), ent.size)
2295 self.assertEqual(0, ent.image_pos)
2296 self.assertEqual(None, ent.uncomp_size)
2297 self.assertEqual(0, ent.offset)
2300 self.assertEqual(1, ent.indent)
2301 self.assertEqual('section', ent.name)
2302 self.assertEqual('section', ent.etype)
2303 section_size = ent.size
2304 self.assertEqual(0x100, ent.image_pos)
2305 self.assertEqual(None, ent.uncomp_size)
2306 self.assertEqual(0x100, ent.offset)
2309 self.assertEqual(2, ent.indent)
2310 self.assertEqual('cbfs', ent.name)
2311 self.assertEqual('cbfs', ent.etype)
2312 self.assertEqual(0x400, ent.size)
2313 self.assertEqual(0x100, ent.image_pos)
2314 self.assertEqual(None, ent.uncomp_size)
2315 self.assertEqual(0, ent.offset)
2318 self.assertEqual(3, ent.indent)
2319 self.assertEqual('u-boot', ent.name)
2320 self.assertEqual('u-boot', ent.etype)
2321 self.assertEqual(len(U_BOOT_DATA), ent.size)
2322 self.assertEqual(0x138, ent.image_pos)
2323 self.assertEqual(None, ent.uncomp_size)
2324 self.assertEqual(0x38, ent.offset)
2327 self.assertEqual(3, ent.indent)
2328 self.assertEqual('u-boot-dtb', ent.name)
2329 self.assertEqual('text', ent.etype)
2330 self.assertGreater(len(COMPRESS_DATA), ent.size)
2331 self.assertEqual(0x178, ent.image_pos)
2332 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2333 self.assertEqual(0x78, ent.offset)
2336 self.assertEqual(2, ent.indent)
2337 self.assertEqual('u-boot-dtb', ent.name)
2338 self.assertEqual('u-boot-dtb', ent.etype)
2339 self.assertEqual(0x500, ent.image_pos)
2340 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2342 # Compressing this data expands it since headers are added
2343 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2344 self.assertEqual(0x400, ent.offset)
2346 self.assertEqual(len(data), 0x100 + section_size)
2347 self.assertEqual(section_size, 0x400 + dtb_size)
2349 def testFindFdtmap(self):
2350 """Test locating an FDT map in an image"""
2352 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2353 image = control.images['image']
2354 entries = image.GetEntries()
2355 entry = entries['fdtmap']
2356 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2358 def testFindFdtmapMissing(self):
2359 """Test failing to locate an FDP map"""
2360 data = self._DoReadFile('005_simple.dts')
2361 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2363 def testFindImageHeader(self):
2364 """Test locating a image header"""
2366 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2367 image = control.images['image']
2368 entries = image.GetEntries()
2369 entry = entries['fdtmap']
2370 # The header should point to the FDT map
2371 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2373 def testFindImageHeaderStart(self):
2374 """Test locating a image header located at the start of an image"""
2375 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2376 image = control.images['image']
2377 entries = image.GetEntries()
2378 entry = entries['fdtmap']
2379 # The header should point to the FDT map
2380 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2382 def testFindImageHeaderMissing(self):
2383 """Test failing to locate an image header"""
2384 data = self._DoReadFile('005_simple.dts')
2385 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2387 def testReadImage(self):
2388 """Test reading an image and accessing its FDT map"""
2390 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2391 image_fname = tools.GetOutputFilename('image.bin')
2392 orig_image = control.images['image']
2393 image = Image.FromFile(image_fname)
2394 self.assertEqual(orig_image.GetEntries().keys(),
2395 image.GetEntries().keys())
2397 orig_entry = orig_image.GetEntries()['fdtmap']
2398 entry = image.GetEntries()['fdtmap']
2399 self.assertEquals(orig_entry.offset, entry.offset)
2400 self.assertEquals(orig_entry.size, entry.size)
2401 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2403 def testReadImageNoHeader(self):
2404 """Test accessing an image's FDT map without an image header"""
2406 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2407 image_fname = tools.GetOutputFilename('image.bin')
2408 image = Image.FromFile(image_fname)
2409 self.assertTrue(isinstance(image, Image))
2410 self.assertEqual('image', image.image_name[-5:])
2412 def testReadImageFail(self):
2413 """Test failing to read an image image's FDT map"""
2414 self._DoReadFile('005_simple.dts')
2415 image_fname = tools.GetOutputFilename('image.bin')
2416 with self.assertRaises(ValueError) as e:
2417 image = Image.FromFile(image_fname)
2418 self.assertIn("Cannot find FDT map in image", str(e.exception))
2420 def testListCmd(self):
2421 """Test listing the files in an image using an Fdtmap"""
2423 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2425 # lz4 compression size differs depending on the version
2426 image = control.images['image']
2427 entries = image.GetEntries()
2428 section_size = entries['section'].size
2429 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2430 fdtmap_offset = entries['fdtmap'].offset
2433 tmpdir, updated_fname = self._SetupImageInTmpdir()
2434 with test_util.capture_sys_output() as (stdout, stderr):
2435 self._DoBinman('ls', '-i', updated_fname)
2437 shutil.rmtree(tmpdir)
2438 lines = stdout.getvalue().splitlines()
2440 'Name Image-pos Size Entry-type Offset Uncomp-size',
2441 '----------------------------------------------------------------------',
2442 'main-section 0 c00 section 0',
2443 ' u-boot 0 4 u-boot 0',
2444 ' section 100 %x section 100' % section_size,
2445 ' cbfs 100 400 cbfs 0',
2446 ' u-boot 138 4 u-boot 38',
2447 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2448 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2449 ' fdtmap %x 3bd fdtmap %x' %
2450 (fdtmap_offset, fdtmap_offset),
2451 ' image-header bf8 8 image-header bf8',
2453 self.assertEqual(expected, lines)
2455 def testListCmdFail(self):
2456 """Test failing to list an image"""
2457 self._DoReadFile('005_simple.dts')
2459 tmpdir, updated_fname = self._SetupImageInTmpdir()
2460 with self.assertRaises(ValueError) as e:
2461 self._DoBinman('ls', '-i', updated_fname)
2463 shutil.rmtree(tmpdir)
2464 self.assertIn("Cannot find FDT map in image", str(e.exception))
2466 def _RunListCmd(self, paths, expected):
2467 """List out entries and check the result
2470 paths: List of paths to pass to the list command
2471 expected: Expected list of filenames to be returned, in order
2474 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2475 image_fname = tools.GetOutputFilename('image.bin')
2476 image = Image.FromFile(image_fname)
2477 lines = image.GetListEntries(paths)[1]
2478 files = [line[0].strip() for line in lines[1:]]
2479 self.assertEqual(expected, files)
2481 def testListCmdSection(self):
2482 """Test listing the files in a section"""
2483 self._RunListCmd(['section'],
2484 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2486 def testListCmdFile(self):
2487 """Test listing a particular file"""
2488 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2490 def testListCmdWildcard(self):
2491 """Test listing a wildcarded file"""
2492 self._RunListCmd(['*boot*'],
2493 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2495 def testListCmdWildcardMulti(self):
2496 """Test listing a wildcarded file"""
2497 self._RunListCmd(['*cb*', '*head*'],
2498 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2500 def testListCmdEmpty(self):
2501 """Test listing a wildcarded file"""
2502 self._RunListCmd(['nothing'], [])
2504 def testListCmdPath(self):
2505 """Test listing the files in a sub-entry of a section"""
2506 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2508 def _RunExtractCmd(self, entry_name, decomp=True):
2509 """Extract an entry from an image
2512 entry_name: Entry name to extract
2513 decomp: True to decompress the data if compressed, False to leave
2514 it in its raw uncompressed format
2520 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2521 image_fname = tools.GetOutputFilename('image.bin')
2522 return control.ReadEntry(image_fname, entry_name, decomp)
2524 def testExtractSimple(self):
2525 """Test extracting a single file"""
2526 data = self._RunExtractCmd('u-boot')
2527 self.assertEqual(U_BOOT_DATA, data)
2529 def testExtractSection(self):
2530 """Test extracting the files in a section"""
2531 data = self._RunExtractCmd('section')
2532 cbfs_data = data[:0x400]
2533 cbfs = cbfs_util.CbfsReader(cbfs_data)
2534 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2535 dtb_data = data[0x400:]
2536 dtb = self._decompress(dtb_data)
2537 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2539 def testExtractCompressed(self):
2540 """Test extracting compressed data"""
2541 data = self._RunExtractCmd('section/u-boot-dtb')
2542 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2544 def testExtractRaw(self):
2545 """Test extracting compressed data without decompressing it"""
2546 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2547 dtb = self._decompress(data)
2548 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2550 def testExtractCbfs(self):
2551 """Test extracting CBFS data"""
2552 data = self._RunExtractCmd('section/cbfs/u-boot')
2553 self.assertEqual(U_BOOT_DATA, data)
2555 def testExtractCbfsCompressed(self):
2556 """Test extracting CBFS compressed data"""
2557 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2558 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2560 def testExtractCbfsRaw(self):
2561 """Test extracting CBFS compressed data without decompressing it"""
2562 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2563 dtb = tools.Decompress(data, 'lzma', with_header=False)
2564 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2566 def testExtractBadEntry(self):
2567 """Test extracting a bad section path"""
2568 with self.assertRaises(ValueError) as e:
2569 self._RunExtractCmd('section/does-not-exist')
2570 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2573 def testExtractMissingFile(self):
2574 """Test extracting file that does not exist"""
2575 with self.assertRaises(IOError) as e:
2576 control.ReadEntry('missing-file', 'name')
2578 def testExtractBadFile(self):
2579 """Test extracting an invalid file"""
2580 fname = os.path.join(self._indir, 'badfile')
2581 tools.WriteFile(fname, b'')
2582 with self.assertRaises(ValueError) as e:
2583 control.ReadEntry(fname, 'name')
2585 def testExtractCmd(self):
2586 """Test extracting a file fron an image on the command line"""
2588 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2589 fname = os.path.join(self._indir, 'output.extact')
2591 tmpdir, updated_fname = self._SetupImageInTmpdir()
2592 with test_util.capture_sys_output() as (stdout, stderr):
2593 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2596 shutil.rmtree(tmpdir)
2597 data = tools.ReadFile(fname)
2598 self.assertEqual(U_BOOT_DATA, data)
2600 def testExtractOneEntry(self):
2601 """Test extracting a single entry fron an image """
2603 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2604 image_fname = tools.GetOutputFilename('image.bin')
2605 fname = os.path.join(self._indir, 'output.extact')
2606 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2607 data = tools.ReadFile(fname)
2608 self.assertEqual(U_BOOT_DATA, data)
2610 def _CheckExtractOutput(self, decomp):
2611 """Helper to test file output with and without decompression
2614 decomp: True to decompress entry data, False to output it raw
2616 def _CheckPresent(entry_path, expect_data, expect_size=None):
2617 """Check and remove expected file
2619 This checks the data/size of a file and removes the file both from
2620 the outfiles set and from the output directory. Once all files are
2621 processed, both the set and directory should be empty.
2624 entry_path: Entry path
2625 expect_data: Data to expect in file, or None to skip check
2626 expect_size: Size of data to expect in file, or None to skip
2628 path = os.path.join(outdir, entry_path)
2629 data = tools.ReadFile(path)
2632 self.assertEqual(expect_data, data)
2634 self.assertEqual(expect_size, len(data))
2635 outfiles.remove(path)
2637 def _CheckDirPresent(name):
2638 """Remove expected directory
2640 This gives an error if the directory does not exist as expected
2643 name: Name of directory to remove
2645 path = os.path.join(outdir, name)
2648 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2649 image_fname = tools.GetOutputFilename('image.bin')
2650 outdir = os.path.join(self._indir, 'extract')
2651 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2653 # Create a set of all file that were output (should be 9)
2655 for root, dirs, files in os.walk(outdir):
2656 outfiles |= set([os.path.join(root, fname) for fname in files])
2657 self.assertEqual(9, len(outfiles))
2658 self.assertEqual(9, len(einfos))
2660 image = control.images['image']
2661 entries = image.GetEntries()
2663 # Check the 9 files in various ways
2664 section = entries['section']
2665 section_entries = section.GetEntries()
2666 cbfs_entries = section_entries['cbfs'].GetEntries()
2667 _CheckPresent('u-boot', U_BOOT_DATA)
2668 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2669 dtb_len = EXTRACT_DTB_SIZE
2671 dtb_len = cbfs_entries['u-boot-dtb'].size
2672 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2674 dtb_len = section_entries['u-boot-dtb'].size
2675 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2677 fdtmap = entries['fdtmap']
2678 _CheckPresent('fdtmap', fdtmap.data)
2679 hdr = entries['image-header']
2680 _CheckPresent('image-header', hdr.data)
2682 _CheckPresent('section/root', section.data)
2683 cbfs = section_entries['cbfs']
2684 _CheckPresent('section/cbfs/root', cbfs.data)
2685 data = tools.ReadFile(image_fname)
2686 _CheckPresent('root', data)
2688 # There should be no files left. Remove all the directories to check.
2689 # If there are any files/dirs remaining, one of these checks will fail.
2690 self.assertEqual(0, len(outfiles))
2691 _CheckDirPresent('section/cbfs')
2692 _CheckDirPresent('section')
2693 _CheckDirPresent('')
2694 self.assertFalse(os.path.exists(outdir))
2696 def testExtractAllEntries(self):
2697 """Test extracting all entries"""
2699 self._CheckExtractOutput(decomp=True)
2701 def testExtractAllEntriesRaw(self):
2702 """Test extracting all entries without decompressing them"""
2704 self._CheckExtractOutput(decomp=False)
2706 def testExtractSelectedEntries(self):
2707 """Test extracting some entries"""
2709 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2710 image_fname = tools.GetOutputFilename('image.bin')
2711 outdir = os.path.join(self._indir, 'extract')
2712 einfos = control.ExtractEntries(image_fname, None, outdir,
2715 # File output is tested by testExtractAllEntries(), so just check that
2716 # the expected entries are selected
2717 names = [einfo.name for einfo in einfos]
2718 self.assertEqual(names,
2719 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2721 def testExtractNoEntryPaths(self):
2722 """Test extracting some entries"""
2724 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2725 image_fname = tools.GetOutputFilename('image.bin')
2726 with self.assertRaises(ValueError) as e:
2727 control.ExtractEntries(image_fname, 'fname', None, [])
2728 self.assertIn('Must specify an entry path to write with -f',
2731 def testExtractTooManyEntryPaths(self):
2732 """Test extracting some entries"""
2734 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2735 image_fname = tools.GetOutputFilename('image.bin')
2736 with self.assertRaises(ValueError) as e:
2737 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2738 self.assertIn('Must specify exactly one entry path to write with -f',
2741 def testPackAlignSection(self):
2742 """Test that sections can have alignment"""
2743 self._DoReadFile('131_pack_align_section.dts')
2745 self.assertIn('image', control.images)
2746 image = control.images['image']
2747 entries = image.GetEntries()
2748 self.assertEqual(3, len(entries))
2751 self.assertIn('u-boot', entries)
2752 entry = entries['u-boot']
2753 self.assertEqual(0, entry.offset)
2754 self.assertEqual(0, entry.image_pos)
2755 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2756 self.assertEqual(len(U_BOOT_DATA), entry.size)
2759 self.assertIn('section0', entries)
2760 section0 = entries['section0']
2761 self.assertEqual(0x10, section0.offset)
2762 self.assertEqual(0x10, section0.image_pos)
2763 self.assertEqual(len(U_BOOT_DATA), section0.size)
2766 section_entries = section0.GetEntries()
2767 self.assertIn('u-boot', section_entries)
2768 entry = section_entries['u-boot']
2769 self.assertEqual(0, entry.offset)
2770 self.assertEqual(0x10, entry.image_pos)
2771 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2772 self.assertEqual(len(U_BOOT_DATA), entry.size)
2775 self.assertIn('section1', entries)
2776 section1 = entries['section1']
2777 self.assertEqual(0x14, section1.offset)
2778 self.assertEqual(0x14, section1.image_pos)
2779 self.assertEqual(0x20, section1.size)
2782 section_entries = section1.GetEntries()
2783 self.assertIn('u-boot', section_entries)
2784 entry = section_entries['u-boot']
2785 self.assertEqual(0, entry.offset)
2786 self.assertEqual(0x14, entry.image_pos)
2787 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2788 self.assertEqual(len(U_BOOT_DATA), entry.size)
2791 self.assertIn('section2', section_entries)
2792 section2 = section_entries['section2']
2793 self.assertEqual(0x4, section2.offset)
2794 self.assertEqual(0x18, section2.image_pos)
2795 self.assertEqual(4, section2.size)
2798 section_entries = section2.GetEntries()
2799 self.assertIn('u-boot', section_entries)
2800 entry = section_entries['u-boot']
2801 self.assertEqual(0, entry.offset)
2802 self.assertEqual(0x18, entry.image_pos)
2803 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2804 self.assertEqual(len(U_BOOT_DATA), entry.size)
2806 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2807 dts='132_replace.dts'):
2808 """Replace an entry in an image
2810 This writes the entry data to update it, then opens the updated file and
2811 returns the value that it now finds there.
2814 entry_name: Entry name to replace
2815 data: Data to replace it with
2816 decomp: True to compress the data if needed, False if data is
2817 already compressed so should be used as is
2818 allow_resize: True to allow entries to change size, False to raise
2824 data from fdtmap (excluding header)
2825 Image object that was modified
2827 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2830 self.assertIn('image', control.images)
2831 image = control.images['image']
2832 entries = image.GetEntries()
2833 orig_dtb_data = entries['u-boot-dtb'].data
2834 orig_fdtmap_data = entries['fdtmap'].data
2836 image_fname = tools.GetOutputFilename('image.bin')
2837 updated_fname = tools.GetOutputFilename('image-updated.bin')
2838 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2839 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2841 data = control.ReadEntry(updated_fname, entry_name, decomp)
2843 # The DT data should not change unless resized:
2844 if not allow_resize:
2845 new_dtb_data = entries['u-boot-dtb'].data
2846 self.assertEqual(new_dtb_data, orig_dtb_data)
2847 new_fdtmap_data = entries['fdtmap'].data
2848 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2850 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2852 def testReplaceSimple(self):
2853 """Test replacing a single file"""
2854 expected = b'x' * len(U_BOOT_DATA)
2855 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2857 self.assertEqual(expected, data)
2859 # Test that the state looks right. There should be an FDT for the fdtmap
2860 # that we jsut read back in, and it should match what we find in the
2861 # 'control' tables. Checking for an FDT that does not exist should
2863 path, fdtmap = state.GetFdtContents('fdtmap')
2864 self.assertIsNotNone(path)
2865 self.assertEqual(expected_fdtmap, fdtmap)
2867 dtb = state.GetFdtForEtype('fdtmap')
2868 self.assertEqual(dtb.GetContents(), fdtmap)
2870 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2871 self.assertIsNone(missing_path)
2872 self.assertIsNone(missing_fdtmap)
2874 missing_dtb = state.GetFdtForEtype('missing')
2875 self.assertIsNone(missing_dtb)
2877 self.assertEqual('/binman', state.fdt_path_prefix)
2879 def testReplaceResizeFail(self):
2880 """Test replacing a file by something larger"""
2881 expected = U_BOOT_DATA + b'x'
2882 with self.assertRaises(ValueError) as e:
2883 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2884 dts='139_replace_repack.dts')
2885 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2888 def testReplaceMulti(self):
2889 """Test replacing entry data where multiple images are generated"""
2890 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2892 expected = b'x' * len(U_BOOT_DATA)
2893 updated_fname = tools.GetOutputFilename('image-updated.bin')
2894 tools.WriteFile(updated_fname, data)
2895 entry_name = 'u-boot'
2896 control.WriteEntry(updated_fname, entry_name, expected,
2898 data = control.ReadEntry(updated_fname, entry_name)
2899 self.assertEqual(expected, data)
2901 # Check the state looks right.
2902 self.assertEqual('/binman/image', state.fdt_path_prefix)
2904 # Now check we can write the first image
2905 image_fname = tools.GetOutputFilename('first-image.bin')
2906 updated_fname = tools.GetOutputFilename('first-updated.bin')
2907 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2908 entry_name = 'u-boot'
2909 control.WriteEntry(updated_fname, entry_name, expected,
2911 data = control.ReadEntry(updated_fname, entry_name)
2912 self.assertEqual(expected, data)
2914 # Check the state looks right.
2915 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2917 def testUpdateFdtAllRepack(self):
2918 """Test that all device trees are updated with offset/size info"""
2919 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2920 SECTION_SIZE = 0x300
2925 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2927 'section:offset': 0,
2928 'section:size': SECTION_SIZE,
2929 'section:image-pos': 0,
2930 'section/u-boot-dtb:offset': 4,
2931 'section/u-boot-dtb:size': 636,
2932 'section/u-boot-dtb:image-pos': 4,
2933 'u-boot-spl-dtb:offset': SECTION_SIZE,
2934 'u-boot-spl-dtb:size': DTB_SIZE,
2935 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2936 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2937 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2938 'u-boot-tpl-dtb:size': DTB_SIZE,
2939 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2940 'fdtmap:size': FDTMAP_SIZE,
2941 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2944 'section:orig-size': SECTION_SIZE,
2945 'section/u-boot-dtb:orig-offset': 4,
2948 # We expect three device-tree files in the output, with the first one
2949 # within a fixed-size section.
2950 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2951 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2952 # main U-Boot tree. All three should have the same positions and offset
2953 # except that the main tree should include the main_expected properties
2955 for item in ['', 'spl', 'tpl', None]:
2957 start += 16 # Move past fdtmap header
2958 dtb = fdt.Fdt.FromData(data[start:])
2960 props = self._GetPropTree(dtb,
2961 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2962 prefix='/' if item is None else '/binman/')
2963 expected = dict(base_expected)
2967 # Main DTB and fdtdec should include the 'orig-' properties
2968 expected.update(main_expected)
2969 # Helpful for debugging:
2970 #for prop in sorted(props):
2971 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2972 self.assertEqual(expected, props)
2974 start = SECTION_SIZE
2976 start += dtb._fdt_obj.totalsize()
2978 def testFdtmapHeaderMiddle(self):
2979 """Test an FDT map in the middle of an image when it should be at end"""
2980 with self.assertRaises(ValueError) as e:
2981 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2982 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2985 def testFdtmapHeaderStartBad(self):
2986 """Test an FDT map in middle of an image when it should be at start"""
2987 with self.assertRaises(ValueError) as e:
2988 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2989 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2992 def testFdtmapHeaderEndBad(self):
2993 """Test an FDT map at the start of an image when it should be at end"""
2994 with self.assertRaises(ValueError) as e:
2995 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2996 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2999 def testFdtmapHeaderNoSize(self):
3000 """Test an image header at the end of an image with undefined size"""
3001 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3003 def testReplaceResize(self):
3004 """Test replacing a single file in an entry with a larger file"""
3005 expected = U_BOOT_DATA + b'x'
3006 data, _, image = self._RunReplaceCmd('u-boot', expected,
3007 dts='139_replace_repack.dts')
3008 self.assertEqual(expected, data)
3010 entries = image.GetEntries()
3011 dtb_data = entries['u-boot-dtb'].data
3012 dtb = fdt.Fdt.FromData(dtb_data)
3015 # The u-boot section should now be larger in the dtb
3016 node = dtb.GetNode('/binman/u-boot')
3017 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3019 # Same for the fdtmap
3020 fdata = entries['fdtmap'].data
3021 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3023 fnode = fdtb.GetNode('/u-boot')
3024 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3026 def testReplaceResizeNoRepack(self):
3027 """Test replacing an entry with a larger file when not allowed"""
3028 expected = U_BOOT_DATA + b'x'
3029 with self.assertRaises(ValueError) as e:
3030 self._RunReplaceCmd('u-boot', expected)
3031 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3034 def testEntryShrink(self):
3035 """Test contracting an entry after it is packed"""
3037 state.SetAllowEntryContraction(True)
3038 data = self._DoReadFileDtb('140_entry_shrink.dts',
3041 state.SetAllowEntryContraction(False)
3042 self.assertEqual(b'a', data[:1])
3043 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3044 self.assertEqual(b'a', data[-1:])
3046 def testEntryShrinkFail(self):
3047 """Test not being allowed to contract an entry after it is packed"""
3048 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3050 # In this case there is a spare byte at the end of the data. The size of
3051 # the contents is only 1 byte but we still have the size before it
3053 self.assertEqual(b'a\0', data[:2])
3054 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3055 self.assertEqual(b'a\0', data[-2:])
3057 def testDescriptorOffset(self):
3058 """Test that the Intel descriptor is always placed at at the start"""
3059 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3060 image = control.images['image']
3061 entries = image.GetEntries()
3062 desc = entries['intel-descriptor']
3063 self.assertEqual(0xff800000, desc.offset);
3064 self.assertEqual(0xff800000, desc.image_pos);
3066 def testReplaceCbfs(self):
3067 """Test replacing a single file in CBFS without changing the size"""
3069 expected = b'x' * len(U_BOOT_DATA)
3070 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3071 updated_fname = tools.GetOutputFilename('image-updated.bin')
3072 tools.WriteFile(updated_fname, data)
3073 entry_name = 'section/cbfs/u-boot'
3074 control.WriteEntry(updated_fname, entry_name, expected,
3076 data = control.ReadEntry(updated_fname, entry_name)
3077 self.assertEqual(expected, data)
3079 def testReplaceResizeCbfs(self):
3080 """Test replacing a single file in CBFS with one of a different size"""
3082 expected = U_BOOT_DATA + b'x'
3083 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3084 updated_fname = tools.GetOutputFilename('image-updated.bin')
3085 tools.WriteFile(updated_fname, data)
3086 entry_name = 'section/cbfs/u-boot'
3087 control.WriteEntry(updated_fname, entry_name, expected,
3089 data = control.ReadEntry(updated_fname, entry_name)
3090 self.assertEqual(expected, data)
3092 def _SetupForReplace(self):
3093 """Set up some files to use to replace entries
3095 This generates an image, copies it to a new file, extracts all the files
3096 in it and updates some of them
3102 Expected values for updated entries, each a string
3104 data = self._DoReadFileRealDtb('143_replace_all.dts')
3106 updated_fname = tools.GetOutputFilename('image-updated.bin')
3107 tools.WriteFile(updated_fname, data)
3109 outdir = os.path.join(self._indir, 'extract')
3110 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3112 expected1 = b'x' + U_BOOT_DATA + b'y'
3113 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3114 tools.WriteFile(u_boot_fname1, expected1)
3116 expected2 = b'a' + U_BOOT_DATA + b'b'
3117 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3118 tools.WriteFile(u_boot_fname2, expected2)
3120 expected_text = b'not the same text'
3121 text_fname = os.path.join(outdir, 'text')
3122 tools.WriteFile(text_fname, expected_text)
3124 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3125 dtb = fdt.FdtScan(dtb_fname)
3126 node = dtb.GetNode('/binman/text')
3127 node.AddString('my-property', 'the value')
3128 dtb.Sync(auto_resize=True)
3131 return updated_fname, outdir, expected1, expected2, expected_text
3133 def _CheckReplaceMultiple(self, entry_paths):
3134 """Handle replacing the contents of multiple entries
3137 entry_paths: List of entry paths to replace
3141 Dict of entries in the image:
3144 Expected values for updated entries, each a string
3146 updated_fname, outdir, expected1, expected2, expected_text = (
3147 self._SetupForReplace())
3148 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3150 image = Image.FromFile(updated_fname)
3152 return image.GetEntries(), expected1, expected2, expected_text
3154 def testReplaceAll(self):
3155 """Test replacing the contents of all entries"""
3156 entries, expected1, expected2, expected_text = (
3157 self._CheckReplaceMultiple([]))
3158 data = entries['u-boot'].data
3159 self.assertEqual(expected1, data)
3161 data = entries['u-boot2'].data
3162 self.assertEqual(expected2, data)
3164 data = entries['text'].data
3165 self.assertEqual(expected_text, data)
3167 # Check that the device tree is updated
3168 data = entries['u-boot-dtb'].data
3169 dtb = fdt.Fdt.FromData(data)
3171 node = dtb.GetNode('/binman/text')
3172 self.assertEqual('the value', node.props['my-property'].value)
3174 def testReplaceSome(self):
3175 """Test replacing the contents of a few entries"""
3176 entries, expected1, expected2, expected_text = (
3177 self._CheckReplaceMultiple(['u-boot2', 'text']))
3179 # This one should not change
3180 data = entries['u-boot'].data
3181 self.assertEqual(U_BOOT_DATA, data)
3183 data = entries['u-boot2'].data
3184 self.assertEqual(expected2, data)
3186 data = entries['text'].data
3187 self.assertEqual(expected_text, data)
3189 def testReplaceCmd(self):
3190 """Test replacing a file fron an image on the command line"""
3191 self._DoReadFileRealDtb('143_replace_all.dts')
3194 tmpdir, updated_fname = self._SetupImageInTmpdir()
3196 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3197 expected = b'x' * len(U_BOOT_DATA)
3198 tools.WriteFile(fname, expected)
3200 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3201 data = tools.ReadFile(updated_fname)
3202 self.assertEqual(expected, data[:len(expected)])
3203 map_fname = os.path.join(tmpdir, 'image-updated.map')
3204 self.assertFalse(os.path.exists(map_fname))
3206 shutil.rmtree(tmpdir)
3208 def testReplaceCmdSome(self):
3209 """Test replacing some files fron an image on the command line"""
3210 updated_fname, outdir, expected1, expected2, expected_text = (
3211 self._SetupForReplace())
3213 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3216 tools.PrepareOutputDir(None)
3217 image = Image.FromFile(updated_fname)
3219 entries = image.GetEntries()
3221 # This one should not change
3222 data = entries['u-boot'].data
3223 self.assertEqual(U_BOOT_DATA, data)
3225 data = entries['u-boot2'].data
3226 self.assertEqual(expected2, data)
3228 data = entries['text'].data
3229 self.assertEqual(expected_text, data)
3231 def testReplaceMissing(self):
3232 """Test replacing entries where the file is missing"""
3233 updated_fname, outdir, expected1, expected2, expected_text = (
3234 self._SetupForReplace())
3236 # Remove one of the files, to generate a warning
3237 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3238 os.remove(u_boot_fname1)
3240 with test_util.capture_sys_output() as (stdout, stderr):
3241 control.ReplaceEntries(updated_fname, None, outdir, [])
3242 self.assertIn("Skipping entry '/u-boot' from missing file",
3245 def testReplaceCmdMap(self):
3246 """Test replacing a file fron an image on the command line"""
3247 self._DoReadFileRealDtb('143_replace_all.dts')
3250 tmpdir, updated_fname = self._SetupImageInTmpdir()
3252 fname = os.path.join(self._indir, 'update-u-boot.bin')
3253 expected = b'x' * len(U_BOOT_DATA)
3254 tools.WriteFile(fname, expected)
3256 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3258 map_fname = os.path.join(tmpdir, 'image-updated.map')
3259 self.assertTrue(os.path.exists(map_fname))
3261 shutil.rmtree(tmpdir)
3263 def testReplaceNoEntryPaths(self):
3264 """Test replacing an entry without an entry path"""
3265 self._DoReadFileRealDtb('143_replace_all.dts')
3266 image_fname = tools.GetOutputFilename('image.bin')
3267 with self.assertRaises(ValueError) as e:
3268 control.ReplaceEntries(image_fname, 'fname', None, [])
3269 self.assertIn('Must specify an entry path to read with -f',
3272 def testReplaceTooManyEntryPaths(self):
3273 """Test extracting some entries"""
3274 self._DoReadFileRealDtb('143_replace_all.dts')
3275 image_fname = tools.GetOutputFilename('image.bin')
3276 with self.assertRaises(ValueError) as e:
3277 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3278 self.assertIn('Must specify exactly one entry path to write with -f',
3281 def testPackReset16(self):
3282 """Test that an image with an x86 reset16 region can be created"""
3283 data = self._DoReadFile('144_x86_reset16.dts')
3284 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3286 def testPackReset16Spl(self):
3287 """Test that an image with an x86 reset16-spl region can be created"""
3288 data = self._DoReadFile('145_x86_reset16_spl.dts')
3289 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3291 def testPackReset16Tpl(self):
3292 """Test that an image with an x86 reset16-tpl region can be created"""
3293 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3294 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3296 def testPackIntelFit(self):
3297 """Test that an image with an Intel FIT and pointer can be created"""
3298 data = self._DoReadFile('147_intel_fit.dts')
3299 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3301 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3302 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3304 image = control.images['image']
3305 entries = image.GetEntries()
3306 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3307 self.assertEqual(expected_ptr, ptr)
3309 def testPackIntelFitMissing(self):
3310 """Test detection of a FIT pointer with not FIT region"""
3311 with self.assertRaises(ValueError) as e:
3312 self._DoReadFile('148_intel_fit_missing.dts')
3313 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3316 def _CheckSymbolsTplSection(self, dts, expected_vals):
3317 data = self._DoReadFile(dts)
3318 sym_values = struct.pack('<LQLL', *expected_vals)
3319 upto1 = 4 + len(U_BOOT_SPL_DATA)
3320 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3321 self.assertEqual(expected1, data[:upto1])
3323 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3324 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3325 self.assertEqual(expected2, data[upto1:upto2])
3327 upto3 = 0x34 + len(U_BOOT_DATA)
3328 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3329 self.assertEqual(expected3, data[upto2:upto3])
3331 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3332 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3334 def testSymbolsTplSection(self):
3335 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3336 self._SetupSplElf('u_boot_binman_syms')
3337 self._SetupTplElf('u_boot_binman_syms')
3338 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3339 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3341 def testSymbolsTplSectionX86(self):
3342 """Test binman can assign symbols in a section with end-at-4gb"""
3343 self._SetupSplElf('u_boot_binman_syms_x86')
3344 self._SetupTplElf('u_boot_binman_syms_x86')
3345 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3346 [0xffffff04, 0xffffff1c, 0xffffff34,
3349 def testPackX86RomIfwiSectiom(self):
3350 """Test that a section can be placed in an IFWI region"""
3351 self._SetupIfwi('fitimage.bin')
3352 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3353 self._CheckIfwi(data)
3355 def testPackFspM(self):
3356 """Test that an image with a FSP memory-init binary can be created"""
3357 data = self._DoReadFile('152_intel_fsp_m.dts')
3358 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3360 def testPackFspS(self):
3361 """Test that an image with a FSP silicon-init binary can be created"""
3362 data = self._DoReadFile('153_intel_fsp_s.dts')
3363 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3365 def testPackFspT(self):
3366 """Test that an image with a FSP temp-ram-init binary can be created"""
3367 data = self._DoReadFile('154_intel_fsp_t.dts')
3368 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3370 def testMkimage(self):
3371 """Test using mkimage to build an image"""
3372 data = self._DoReadFile('156_mkimage.dts')
3374 # Just check that the data appears in the file somewhere
3375 self.assertIn(U_BOOT_SPL_DATA, data)
3377 def testExtblob(self):
3378 """Test an image with an external blob"""
3379 data = self._DoReadFile('157_blob_ext.dts')
3380 self.assertEqual(REFCODE_DATA, data)
3382 def testExtblobMissing(self):
3383 """Test an image with a missing external blob"""
3384 with self.assertRaises(ValueError) as e:
3385 self._DoReadFile('158_blob_ext_missing.dts')
3386 self.assertIn("Filename 'missing-file' not found in input path",
3389 def testExtblobMissingOk(self):
3390 """Test an image with an missing external blob that is allowed"""
3391 with test_util.capture_sys_output() as (stdout, stderr):
3392 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3393 err = stderr.getvalue()
3394 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3396 def testExtblobMissingOkSect(self):
3397 """Test an image with an missing external blob that is allowed"""
3398 with test_util.capture_sys_output() as (stdout, stderr):
3399 self._DoTestFile('159_blob_ext_missing_sect.dts',
3401 err = stderr.getvalue()
3402 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3403 "blob-ext blob-ext2")
3405 def testPackX86RomMeMissingDesc(self):
3406 """Test that an missing Intel descriptor entry is allowed"""
3407 with test_util.capture_sys_output() as (stdout, stderr):
3408 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
3409 err = stderr.getvalue()
3410 self.assertRegex(err,
3411 "Image 'main-section'.*missing.*: intel-descriptor")
3413 def testPackX86RomMissingIfwi(self):
3414 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3415 self._SetupIfwi('fitimage.bin')
3416 pathname = os.path.join(self._indir, 'fitimage.bin')
3418 with test_util.capture_sys_output() as (stdout, stderr):
3419 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3420 err = stderr.getvalue()
3421 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3423 def testPackOverlap(self):
3424 """Test that zero-size overlapping regions are ignored"""
3425 self._DoTestFile('160_pack_overlap_zero.dts')
3427 def testSimpleFit(self):
3428 """Test an image with a FIT inside"""
3429 data = self._DoReadFile('161_fit.dts')
3430 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3431 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3432 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3434 # The data should be inside the FIT
3435 dtb = fdt.Fdt.FromData(fit_data)
3437 fnode = dtb.GetNode('/images/kernel')
3438 self.assertIn('data', fnode.props)
3440 fname = os.path.join(self._indir, 'fit_data.fit')
3441 tools.WriteFile(fname, fit_data)
3442 out = tools.Run('dumpimage', '-l', fname)
3444 # Check a few features to make sure the plumbing works. We don't need
3445 # to test the operation of mkimage or dumpimage here. First convert the
3446 # output into a dict where the keys are the fields printed by dumpimage
3447 # and the values are a list of values for each field
3448 lines = out.splitlines()
3450 # Converts "Compression: gzip compressed" into two groups:
3451 # 'Compression' and 'gzip compressed'
3452 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3453 vals = collections.defaultdict(list)
3455 mat = re_line.match(line)
3456 vals[mat.group(1)].append(mat.group(2))
3458 self.assertEquals('FIT description: test-desc', lines[0])
3459 self.assertIn('Created:', lines[1])
3460 self.assertIn('Image 0 (kernel)', vals)
3461 self.assertIn('Hash value', vals)
3462 data_sizes = vals.get('Data Size')
3463 self.assertIsNotNone(data_sizes)
3464 self.assertEqual(2, len(data_sizes))
3465 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3466 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3467 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3469 def testFitExternal(self):
3470 """Test an image with an FIT"""
3471 data = self._DoReadFile('162_fit_external.dts')
3472 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3474 # The data should be outside the FIT
3475 dtb = fdt.Fdt.FromData(fit_data)
3477 fnode = dtb.GetNode('/images/kernel')
3478 self.assertNotIn('data', fnode.props)
3480 def testSectionIgnoreHashSignature(self):
3481 """Test that sections ignore hash, signature nodes for its data"""
3482 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3483 expected = (U_BOOT_DATA + U_BOOT_DATA)
3484 self.assertEqual(expected, data)
3486 def testPadInSections(self):
3487 """Test pad-before, pad-after for entries in sections"""
3488 data = self._DoReadFile('166_pad_in_sections.dts')
3489 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3490 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3492 self.assertEqual(expected, data)
3494 def testFitImageSubentryAlignment(self):
3495 """Test relative alignability of FIT image subentries"""
3497 'test-id': TEXT_DATA,
3499 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3500 entry_args=entry_args)
3501 dtb = fdt.Fdt.FromData(data)
3504 node = dtb.GetNode('/images/kernel')
3505 data = dtb.GetProps(node)["data"].bytes
3506 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3507 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3508 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3509 self.assertEqual(expected, data)
3511 node = dtb.GetNode('/images/fdt-1')
3512 data = dtb.GetProps(node)["data"].bytes
3513 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3514 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3516 self.assertEqual(expected, data)
3518 def testFitExtblobMissingOk(self):
3519 """Test a FIT with a missing external blob that is allowed"""
3520 with test_util.capture_sys_output() as (stdout, stderr):
3521 self._DoTestFile('168_fit_missing_blob.dts',
3523 err = stderr.getvalue()
3524 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3526 def testBlobNamedByArgMissing(self):
3527 """Test handling of a missing entry arg"""
3528 with self.assertRaises(ValueError) as e:
3529 self._DoReadFile('068_blob_named_by_arg.dts')
3530 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3533 if __name__ == "__main__":