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
11 from optparse import OptionParser
19 from binman import cbfs_util
20 from binman import cmdline
21 from binman import control
22 from binman import elf
23 from binman import elf_test
24 from binman import fmap_util
25 from binman import main
26 from binman import state
28 from dtoc import fdt_util
29 from binman.etype import fdtmap
30 from binman.etype import image_header
31 from image import Image
32 from patman import command
33 from patman import test_util
34 from patman import tools
35 from patman import tout
37 # Contents of test files, corresponding to different entry types
39 U_BOOT_IMG_DATA = b'img'
40 U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
41 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
45 U_BOOT_DTB_DATA = b'udtb'
46 U_BOOT_SPL_DTB_DATA = b'spldtb'
47 U_BOOT_TPL_DTB_DATA = b'tpldtb'
48 X86_START16_DATA = b'start16'
49 X86_START16_SPL_DATA = b'start16spl'
50 X86_START16_TPL_DATA = b'start16tpl'
51 X86_RESET16_DATA = b'reset16'
52 X86_RESET16_SPL_DATA = b'reset16spl'
53 X86_RESET16_TPL_DATA = b'reset16tpl'
54 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
55 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
56 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
57 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
65 CROS_EC_RW_DATA = b'ecrw'
69 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
70 b"sorry you're alive\n")
71 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
72 REFCODE_DATA = b'refcode'
77 # The expected size for the device tree in some tests
78 EXTRACT_DTB_SIZE = 0x3c9
80 # Properties expected to be in the device tree when update_dtb is used
81 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
83 # Extra properties expected to be in the device tree when allow-repack is used
84 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
87 class TestFunctional(unittest.TestCase):
88 """Functional tests for binman
90 Most of these use a sample .dts file to build an image and then check
91 that it looks correct. The sample files are in the test/ subdirectory
94 For each entry type a very small test file is created using fixed
95 string contents. This makes it easy to test that things look right, and
98 In some cases a 'real' file must be used - these are also supplied in
104 from binman import entry
106 # Handle the case where argv[0] is 'python'
107 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
108 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
110 # Create a temporary directory for input files
111 cls._indir = tempfile.mkdtemp(prefix='binmant.')
113 # Create some test files
114 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
115 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
116 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
117 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
118 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
119 TestFunctional._MakeInputFile('me.bin', ME_DATA)
120 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
123 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
125 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
126 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
127 X86_START16_SPL_DATA)
128 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
129 X86_START16_TPL_DATA)
131 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
133 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
134 X86_RESET16_SPL_DATA)
135 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
136 X86_RESET16_TPL_DATA)
138 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
139 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
140 U_BOOT_SPL_NODTB_DATA)
141 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
142 U_BOOT_TPL_NODTB_DATA)
143 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
144 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
145 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
146 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
147 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
148 TestFunctional._MakeInputDir('devkeys')
149 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
150 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
151 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
152 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
153 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
155 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
156 elf_test.BuildElfTestFiles(cls._elf_testdir)
158 # ELF file with a '_dt_ucode_base_size' symbol
159 TestFunctional._MakeInputFile('u-boot',
160 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
162 # Intel flash descriptor file
163 cls._SetupDescriptor()
165 shutil.copytree(cls.TestFile('files'),
166 os.path.join(cls._indir, 'files'))
168 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
170 # Travis-CI may have an old lz4
173 tools.Run('lz4', '--no-frame-crc', '-c',
174 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
179 def tearDownClass(cls):
180 """Remove the temporary input directory and its contents"""
181 if cls.preserve_indir:
182 print('Preserving input dir: %s' % cls._indir)
185 shutil.rmtree(cls._indir)
189 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
190 toolpath=None, verbosity=None):
191 """Accept arguments controlling test execution
194 preserve_indir: Preserve the shared input directory used by all
196 preserve_outdir: Preserve the output directories used by tests. Each
197 test has its own, so this is normally only useful when running a
199 toolpath: ist of paths to use for tools
201 cls.preserve_indir = preserve_indir
202 cls.preserve_outdirs = preserve_outdirs
203 cls.toolpath = toolpath
204 cls.verbosity = verbosity
207 if not self.have_lz4:
208 self.skipTest('lz4 --no-frame-crc not available')
210 def _CleanupOutputDir(self):
211 """Remove the temporary output directory"""
212 if self.preserve_outdirs:
213 print('Preserving output dir: %s' % tools.outdir)
215 tools._FinaliseForTest()
218 # Enable this to turn on debugging output
219 # tout.Init(tout.DEBUG)
220 command.test_result = None
223 """Remove the temporary output directory"""
224 self._CleanupOutputDir()
226 def _SetupImageInTmpdir(self):
227 """Set up the output image in a new temporary directory
229 This is used when an image has been generated in the output directory,
230 but we want to run binman again. This will create a new output
231 directory and fail to delete the original one.
233 This creates a new temporary directory, copies the image to it (with a
234 new name) and removes the old output directory.
238 Temporary directory to use
241 image_fname = tools.GetOutputFilename('image.bin')
242 tmpdir = tempfile.mkdtemp(prefix='binman.')
243 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
244 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
245 self._CleanupOutputDir()
246 return tmpdir, updated_fname
250 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
251 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
252 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
254 def _RunBinman(self, *args, **kwargs):
255 """Run binman using the command line
258 Arguments to pass, as a list of strings
259 kwargs: Arguments to pass to Command.RunPipe()
261 result = command.RunPipe([[self._binman_pathname] + list(args)],
262 capture=True, capture_stderr=True, raise_on_error=False)
263 if result.return_code and kwargs.get('raise_on_error', True):
264 raise Exception("Error running '%s': %s" % (' '.join(args),
265 result.stdout + result.stderr))
268 def _DoBinman(self, *argv):
269 """Run binman using directly (in the same process)
272 Arguments to pass, as a list of strings
274 Return value (0 for success)
277 args = cmdline.ParseArgs(argv)
278 args.pager = 'binman-invalid-pager'
279 args.build_dir = self._indir
281 # For testing, you can force an increase in verbosity here
282 # args.verbosity = tout.DEBUG
283 return control.Binman(args)
285 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
286 entry_args=None, images=None, use_real_dtb=False,
287 verbosity=None, allow_missing=False):
288 """Run binman with a given test file
291 fname: Device-tree source filename to use (e.g. 005_simple.dts)
292 debug: True to enable debugging output
293 map: True to output map files for the images
294 update_dtb: Update the offset and size of each entry in the device
295 tree before packing it into the image
296 entry_args: Dict of entry args to supply to binman
298 value: value of that arg
299 images: List of image names to build
304 if verbosity is not None:
305 args.append('-v%d' % verbosity)
307 args.append('-v%d' % self.verbosity)
309 for path in self.toolpath:
310 args += ['--toolpath', path]
311 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
317 args.append('--fake-dtb')
319 for arg, value in entry_args.items():
320 args.append('-a%s=%s' % (arg, value))
325 args += ['-i', image]
326 return self._DoBinman(*args)
328 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
329 """Set up a new test device-tree file
331 The given file is compiled and set up as the device tree to be used
335 fname: Filename of .dts file to read
336 outfile: Output filename for compiled device-tree binary
339 Contents of device-tree binary
341 tmpdir = tempfile.mkdtemp(prefix='binmant.')
342 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
343 with open(dtb, 'rb') as fd:
345 TestFunctional._MakeInputFile(outfile, data)
346 shutil.rmtree(tmpdir)
349 def _GetDtbContentsForSplTpl(self, dtb_data, name):
350 """Create a version of the main DTB for SPL or SPL
352 For testing we don't actually have different versions of the DTB. With
353 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
354 we don't normally have any unwanted nodes.
356 We still want the DTBs for SPL and TPL to be different though, since
357 otherwise it is confusing to know which one we are looking at. So add
358 an 'spl' or 'tpl' property to the top-level node.
360 dtb = fdt.Fdt.FromData(dtb_data)
362 dtb.GetNode('/binman').AddZeroProp(name)
363 dtb.Sync(auto_resize=True)
365 return dtb.GetContents()
367 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
368 update_dtb=False, entry_args=None, reset_dtbs=True):
369 """Run binman and return the resulting image
371 This runs binman with a given test file and then reads the resulting
372 output file. It is a shortcut function since most tests need to do
375 Raises an assertion failure if binman returns a non-zero exit code.
378 fname: Device-tree source filename to use (e.g. 005_simple.dts)
379 use_real_dtb: True to use the test file as the contents of
380 the u-boot-dtb entry. Normally this is not needed and the
381 test contents (the U_BOOT_DTB_DATA string) can be used.
382 But in some test we need the real contents.
383 map: True to output map files for the images
384 update_dtb: Update the offset and size of each entry in the device
385 tree before packing it into the image
389 Resulting image contents
391 Map data showing contents of image (or None if none)
392 Output device tree binary filename ('u-boot.dtb' path)
395 # Use the compiled test file as the u-boot-dtb input
397 dtb_data = self._SetupDtb(fname)
399 # For testing purposes, make a copy of the DT for SPL and TPL. Add
400 # a node indicating which it is, so aid verification.
401 for name in ['spl', 'tpl']:
402 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
403 outfile = os.path.join(self._indir, dtb_fname)
404 TestFunctional._MakeInputFile(dtb_fname,
405 self._GetDtbContentsForSplTpl(dtb_data, name))
408 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
409 entry_args=entry_args, use_real_dtb=use_real_dtb)
410 self.assertEqual(0, retcode)
411 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
413 # Find the (only) image, read it and return its contents
414 image = control.images['image']
415 image_fname = tools.GetOutputFilename('image.bin')
416 self.assertTrue(os.path.exists(image_fname))
418 map_fname = tools.GetOutputFilename('image.map')
419 with open(map_fname) as fd:
423 with open(image_fname, 'rb') as fd:
424 return fd.read(), dtb_data, map_data, out_dtb_fname
426 # Put the test file back
427 if reset_dtbs and use_real_dtb:
430 def _DoReadFileRealDtb(self, fname):
431 """Run binman with a real .dtb file and return the resulting data
434 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
437 Resulting image contents
439 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
441 def _DoReadFile(self, fname, use_real_dtb=False):
442 """Helper function which discards the device-tree binary
445 fname: Device-tree source filename to use (e.g. 005_simple.dts)
446 use_real_dtb: True to use the test file as the contents of
447 the u-boot-dtb entry. Normally this is not needed and the
448 test contents (the U_BOOT_DTB_DATA string) can be used.
449 But in some test we need the real contents.
452 Resulting image contents
454 return self._DoReadFileDtb(fname, use_real_dtb)[0]
457 def _MakeInputFile(cls, fname, contents):
458 """Create a new test input file, creating directories as needed
461 fname: Filename to create
462 contents: File contents to write in to the file
464 Full pathname of file created
466 pathname = os.path.join(cls._indir, fname)
467 dirname = os.path.dirname(pathname)
468 if dirname and not os.path.exists(dirname):
470 with open(pathname, 'wb') as fd:
475 def _MakeInputDir(cls, dirname):
476 """Create a new test input directory, creating directories as needed
479 dirname: Directory name to create
482 Full pathname of directory created
484 pathname = os.path.join(cls._indir, dirname)
485 if not os.path.exists(pathname):
486 os.makedirs(pathname)
490 def _SetupSplElf(cls, src_fname='bss_data'):
491 """Set up an ELF file with a '_dt_ucode_base_size' symbol
494 Filename of ELF file to use as SPL
496 TestFunctional._MakeInputFile('spl/u-boot-spl',
497 tools.ReadFile(cls.ElfTestFile(src_fname)))
500 def _SetupTplElf(cls, src_fname='bss_data'):
501 """Set up an ELF file with a '_dt_ucode_base_size' symbol
504 Filename of ELF file to use as TPL
506 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
507 tools.ReadFile(cls.ElfTestFile(src_fname)))
510 def _SetupDescriptor(cls):
511 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
512 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
515 def TestFile(cls, fname):
516 return os.path.join(cls._binman_dir, 'test', fname)
519 def ElfTestFile(cls, fname):
520 return os.path.join(cls._elf_testdir, fname)
522 def AssertInList(self, grep_list, target):
523 """Assert that at least one of a list of things is in a target
526 grep_list: List of strings to check
527 target: Target string
529 for grep in grep_list:
532 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
534 def CheckNoGaps(self, entries):
535 """Check that all entries fit together without gaps
538 entries: List of entries to check
541 for entry in entries.values():
542 self.assertEqual(offset, entry.offset)
545 def GetFdtLen(self, dtb):
546 """Get the totalsize field from a device-tree binary
549 dtb: Device-tree binary contents
552 Total size of device-tree binary, from the header
554 return struct.unpack('>L', dtb[4:8])[0]
556 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
557 def AddNode(node, path):
559 path += '/' + node.name
560 for prop in node.props.values():
561 if prop.name in prop_names:
562 prop_path = path + ':' + prop.name
563 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
565 for subnode in node.subnodes:
566 AddNode(subnode, path)
569 AddNode(dtb.GetRoot(), '')
573 """Test a basic run with valid args"""
574 result = self._RunBinman('-h')
576 def testFullHelp(self):
577 """Test that the full help is displayed with -H"""
578 result = self._RunBinman('-H')
579 help_file = os.path.join(self._binman_dir, 'README')
580 # Remove possible extraneous strings
581 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
582 gothelp = result.stdout.replace(extra, '')
583 self.assertEqual(len(gothelp), os.path.getsize(help_file))
584 self.assertEqual(0, len(result.stderr))
585 self.assertEqual(0, result.return_code)
587 def testFullHelpInternal(self):
588 """Test that the full help is displayed with -H"""
590 command.test_result = command.CommandResult()
591 result = self._DoBinman('-H')
592 help_file = os.path.join(self._binman_dir, 'README')
594 command.test_result = None
597 """Test that the basic help is displayed with -h"""
598 result = self._RunBinman('-h')
599 self.assertTrue(len(result.stdout) > 200)
600 self.assertEqual(0, len(result.stderr))
601 self.assertEqual(0, result.return_code)
604 """Test that we can run it with a specific board"""
605 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
606 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
607 result = self._DoBinman('build', '-b', 'sandbox')
608 self.assertEqual(0, result)
610 def testNeedBoard(self):
611 """Test that we get an error when no board ius supplied"""
612 with self.assertRaises(ValueError) as e:
613 result = self._DoBinman('build')
614 self.assertIn("Must provide a board to process (use -b <board>)",
617 def testMissingDt(self):
618 """Test that an invalid device-tree file generates an error"""
619 with self.assertRaises(Exception) as e:
620 self._RunBinman('build', '-d', 'missing_file')
621 # We get one error from libfdt, and a different one from fdtget.
622 self.AssertInList(["Couldn't open blob from 'missing_file'",
623 'No such file or directory'], str(e.exception))
625 def testBrokenDt(self):
626 """Test that an invalid device-tree source file generates an error
628 Since this is a source file it should be compiled and the error
629 will come from the device-tree compiler (dtc).
631 with self.assertRaises(Exception) as e:
632 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
633 self.assertIn("FATAL ERROR: Unable to parse input tree",
636 def testMissingNode(self):
637 """Test that a device tree without a 'binman' node generates an error"""
638 with self.assertRaises(Exception) as e:
639 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
640 self.assertIn("does not have a 'binman' node", str(e.exception))
643 """Test that an empty binman node works OK (i.e. does nothing)"""
644 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
645 self.assertEqual(0, len(result.stderr))
646 self.assertEqual(0, result.return_code)
648 def testInvalidEntry(self):
649 """Test that an invalid entry is flagged"""
650 with self.assertRaises(Exception) as e:
651 result = self._RunBinman('build', '-d',
652 self.TestFile('004_invalid_entry.dts'))
653 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
654 "'/binman/not-a-valid-type'", str(e.exception))
656 def testSimple(self):
657 """Test a simple binman with a single file"""
658 data = self._DoReadFile('005_simple.dts')
659 self.assertEqual(U_BOOT_DATA, data)
661 def testSimpleDebug(self):
662 """Test a simple binman run with debugging enabled"""
663 self._DoTestFile('005_simple.dts', debug=True)
666 """Test that we can handle creating two images
668 This also tests image padding.
670 retcode = self._DoTestFile('006_dual_image.dts')
671 self.assertEqual(0, retcode)
673 image = control.images['image1']
674 self.assertEqual(len(U_BOOT_DATA), image.size)
675 fname = tools.GetOutputFilename('image1.bin')
676 self.assertTrue(os.path.exists(fname))
677 with open(fname, 'rb') as fd:
679 self.assertEqual(U_BOOT_DATA, data)
681 image = control.images['image2']
682 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
683 fname = tools.GetOutputFilename('image2.bin')
684 self.assertTrue(os.path.exists(fname))
685 with open(fname, 'rb') as fd:
687 self.assertEqual(U_BOOT_DATA, data[3:7])
688 self.assertEqual(tools.GetBytes(0, 3), data[:3])
689 self.assertEqual(tools.GetBytes(0, 5), data[7:])
691 def testBadAlign(self):
692 """Test that an invalid alignment value is detected"""
693 with self.assertRaises(ValueError) as e:
694 self._DoTestFile('007_bad_align.dts')
695 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
696 "of two", str(e.exception))
698 def testPackSimple(self):
699 """Test that packing works as expected"""
700 retcode = self._DoTestFile('008_pack.dts')
701 self.assertEqual(0, retcode)
702 self.assertIn('image', control.images)
703 image = control.images['image']
704 entries = image.GetEntries()
705 self.assertEqual(5, len(entries))
708 self.assertIn('u-boot', entries)
709 entry = entries['u-boot']
710 self.assertEqual(0, entry.offset)
711 self.assertEqual(len(U_BOOT_DATA), entry.size)
713 # Second u-boot, aligned to 16-byte boundary
714 self.assertIn('u-boot-align', entries)
715 entry = entries['u-boot-align']
716 self.assertEqual(16, entry.offset)
717 self.assertEqual(len(U_BOOT_DATA), entry.size)
719 # Third u-boot, size 23 bytes
720 self.assertIn('u-boot-size', entries)
721 entry = entries['u-boot-size']
722 self.assertEqual(20, entry.offset)
723 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
724 self.assertEqual(23, entry.size)
726 # Fourth u-boot, placed immediate after the above
727 self.assertIn('u-boot-next', entries)
728 entry = entries['u-boot-next']
729 self.assertEqual(43, entry.offset)
730 self.assertEqual(len(U_BOOT_DATA), entry.size)
732 # Fifth u-boot, placed at a fixed offset
733 self.assertIn('u-boot-fixed', entries)
734 entry = entries['u-boot-fixed']
735 self.assertEqual(61, entry.offset)
736 self.assertEqual(len(U_BOOT_DATA), entry.size)
738 self.assertEqual(65, image.size)
740 def testPackExtra(self):
741 """Test that extra packing feature works as expected"""
742 retcode = self._DoTestFile('009_pack_extra.dts')
744 self.assertEqual(0, retcode)
745 self.assertIn('image', control.images)
746 image = control.images['image']
747 entries = image.GetEntries()
748 self.assertEqual(5, len(entries))
750 # First u-boot with padding before and after
751 self.assertIn('u-boot', entries)
752 entry = entries['u-boot']
753 self.assertEqual(0, entry.offset)
754 self.assertEqual(3, entry.pad_before)
755 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
757 # Second u-boot has an aligned size, but it has no effect
758 self.assertIn('u-boot-align-size-nop', entries)
759 entry = entries['u-boot-align-size-nop']
760 self.assertEqual(12, entry.offset)
761 self.assertEqual(4, entry.size)
763 # Third u-boot has an aligned size too
764 self.assertIn('u-boot-align-size', entries)
765 entry = entries['u-boot-align-size']
766 self.assertEqual(16, entry.offset)
767 self.assertEqual(32, entry.size)
769 # Fourth u-boot has an aligned end
770 self.assertIn('u-boot-align-end', entries)
771 entry = entries['u-boot-align-end']
772 self.assertEqual(48, entry.offset)
773 self.assertEqual(16, entry.size)
775 # Fifth u-boot immediately afterwards
776 self.assertIn('u-boot-align-both', entries)
777 entry = entries['u-boot-align-both']
778 self.assertEqual(64, entry.offset)
779 self.assertEqual(64, entry.size)
781 self.CheckNoGaps(entries)
782 self.assertEqual(128, image.size)
784 def testPackAlignPowerOf2(self):
785 """Test that invalid entry alignment is detected"""
786 with self.assertRaises(ValueError) as e:
787 self._DoTestFile('010_pack_align_power2.dts')
788 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
789 "of two", str(e.exception))
791 def testPackAlignSizePowerOf2(self):
792 """Test that invalid entry size alignment is detected"""
793 with self.assertRaises(ValueError) as e:
794 self._DoTestFile('011_pack_align_size_power2.dts')
795 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
796 "power of two", str(e.exception))
798 def testPackInvalidAlign(self):
799 """Test detection of an offset that does not match its alignment"""
800 with self.assertRaises(ValueError) as e:
801 self._DoTestFile('012_pack_inv_align.dts')
802 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
803 "align 0x4 (4)", str(e.exception))
805 def testPackInvalidSizeAlign(self):
806 """Test that invalid entry size alignment is detected"""
807 with self.assertRaises(ValueError) as e:
808 self._DoTestFile('013_pack_inv_size_align.dts')
809 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
810 "align-size 0x4 (4)", str(e.exception))
812 def testPackOverlap(self):
813 """Test that overlapping regions are detected"""
814 with self.assertRaises(ValueError) as e:
815 self._DoTestFile('014_pack_overlap.dts')
816 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
817 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
820 def testPackEntryOverflow(self):
821 """Test that entries that overflow their size are detected"""
822 with self.assertRaises(ValueError) as e:
823 self._DoTestFile('015_pack_overflow.dts')
824 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
825 "but entry size is 0x3 (3)", str(e.exception))
827 def testPackImageOverflow(self):
828 """Test that entries which overflow the image size are detected"""
829 with self.assertRaises(ValueError) as e:
830 self._DoTestFile('016_pack_image_overflow.dts')
831 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
832 "size 0x3 (3)", str(e.exception))
834 def testPackImageSize(self):
835 """Test that the image size can be set"""
836 retcode = self._DoTestFile('017_pack_image_size.dts')
837 self.assertEqual(0, retcode)
838 self.assertIn('image', control.images)
839 image = control.images['image']
840 self.assertEqual(7, image.size)
842 def testPackImageSizeAlign(self):
843 """Test that image size alignemnt works as expected"""
844 retcode = self._DoTestFile('018_pack_image_align.dts')
845 self.assertEqual(0, retcode)
846 self.assertIn('image', control.images)
847 image = control.images['image']
848 self.assertEqual(16, image.size)
850 def testPackInvalidImageAlign(self):
851 """Test that invalid image alignment is detected"""
852 with self.assertRaises(ValueError) as e:
853 self._DoTestFile('019_pack_inv_image_align.dts')
854 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
855 "align-size 0x8 (8)", str(e.exception))
857 def testPackAlignPowerOf2(self):
858 """Test that invalid image alignment is detected"""
859 with self.assertRaises(ValueError) as e:
860 self._DoTestFile('020_pack_inv_image_align_power2.dts')
861 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
862 "two", str(e.exception))
864 def testImagePadByte(self):
865 """Test that the image pad byte can be specified"""
867 data = self._DoReadFile('021_image_pad.dts')
868 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
871 def testImageName(self):
872 """Test that image files can be named"""
873 retcode = self._DoTestFile('022_image_name.dts')
874 self.assertEqual(0, retcode)
875 image = control.images['image1']
876 fname = tools.GetOutputFilename('test-name')
877 self.assertTrue(os.path.exists(fname))
879 image = control.images['image2']
880 fname = tools.GetOutputFilename('test-name.xx')
881 self.assertTrue(os.path.exists(fname))
883 def testBlobFilename(self):
884 """Test that generic blobs can be provided by filename"""
885 data = self._DoReadFile('023_blob.dts')
886 self.assertEqual(BLOB_DATA, data)
888 def testPackSorted(self):
889 """Test that entries can be sorted"""
891 data = self._DoReadFile('024_sorted.dts')
892 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
893 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
895 def testPackZeroOffset(self):
896 """Test that an entry at offset 0 is not given a new offset"""
897 with self.assertRaises(ValueError) as e:
898 self._DoTestFile('025_pack_zero_size.dts')
899 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
900 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
903 def testPackUbootDtb(self):
904 """Test that a device tree can be added to U-Boot"""
905 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
906 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
908 def testPackX86RomNoSize(self):
909 """Test that the end-at-4gb property requires a size property"""
910 with self.assertRaises(ValueError) as e:
911 self._DoTestFile('027_pack_4gb_no_size.dts')
912 self.assertIn("Image '/binman': Section size must be provided when "
913 "using end-at-4gb", str(e.exception))
915 def test4gbAndSkipAtStartTogether(self):
916 """Test that the end-at-4gb and skip-at-size property can't be used
918 with self.assertRaises(ValueError) as e:
919 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
920 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
921 "'skip-at-start'", str(e.exception))
923 def testPackX86RomOutside(self):
924 """Test that the end-at-4gb property checks for offset boundaries"""
925 with self.assertRaises(ValueError) as e:
926 self._DoTestFile('028_pack_4gb_outside.dts')
927 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
928 "the section starting at 0xffffffe0 (4294967264)",
931 def testPackX86Rom(self):
932 """Test that a basic x86 ROM can be created"""
934 data = self._DoReadFile('029_x86_rom.dts')
935 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
936 tools.GetBytes(0, 2), data)
938 def testPackX86RomMeNoDesc(self):
939 """Test that an invalid Intel descriptor entry is detected"""
941 TestFunctional._MakeInputFile('descriptor.bin', b'')
942 with self.assertRaises(ValueError) as e:
943 self._DoTestFile('031_x86_rom_me.dts')
944 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
947 self._SetupDescriptor()
949 def testPackX86RomBadDesc(self):
950 """Test that the Intel requires a descriptor entry"""
951 with self.assertRaises(ValueError) as e:
952 self._DoTestFile('030_x86_rom_me_no_desc.dts')
953 self.assertIn("Node '/binman/intel-me': No offset set with "
954 "offset-unset: should another entry provide this correct "
955 "offset?", str(e.exception))
957 def testPackX86RomMe(self):
958 """Test that an x86 ROM with an ME region can be created"""
959 data = self._DoReadFile('031_x86_rom_me.dts')
960 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
961 if data[:0x1000] != expected_desc:
962 self.fail('Expected descriptor binary at start of image')
963 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
965 def testPackVga(self):
966 """Test that an image with a VGA binary can be created"""
967 data = self._DoReadFile('032_intel_vga.dts')
968 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
970 def testPackStart16(self):
971 """Test that an image with an x86 start16 region can be created"""
972 data = self._DoReadFile('033_x86_start16.dts')
973 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
975 def testPackPowerpcMpc85xxBootpgResetvec(self):
976 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
978 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
979 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
981 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
982 """Handle running a test for insertion of microcode
985 dts_fname: Name of test .dts file
986 nodtb_data: Data that we expect in the first section
987 ucode_second: True if the microsecond entry is second instead of
992 Contents of first region (U-Boot or SPL)
993 Offset and size components of microcode pointer, as inserted
994 in the above (two 4-byte words)
996 data = self._DoReadFile(dts_fname, True)
998 # Now check the device tree has no microcode
1000 ucode_content = data[len(nodtb_data):]
1001 ucode_pos = len(nodtb_data)
1002 dtb_with_ucode = ucode_content[16:]
1003 fdt_len = self.GetFdtLen(dtb_with_ucode)
1005 dtb_with_ucode = data[len(nodtb_data):]
1006 fdt_len = self.GetFdtLen(dtb_with_ucode)
1007 ucode_content = dtb_with_ucode[fdt_len:]
1008 ucode_pos = len(nodtb_data) + fdt_len
1009 fname = tools.GetOutputFilename('test.dtb')
1010 with open(fname, 'wb') as fd:
1011 fd.write(dtb_with_ucode)
1012 dtb = fdt.FdtScan(fname)
1013 ucode = dtb.GetNode('/microcode')
1014 self.assertTrue(ucode)
1015 for node in ucode.subnodes:
1016 self.assertFalse(node.props.get('data'))
1018 # Check that the microcode appears immediately after the Fdt
1019 # This matches the concatenation of the data properties in
1020 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1021 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1023 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1025 # Check that the microcode pointer was inserted. It should match the
1026 # expected offset and size
1027 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1029 u_boot = data[:len(nodtb_data)]
1030 return u_boot, pos_and_size
1032 def testPackUbootMicrocode(self):
1033 """Test that x86 microcode can be handled correctly
1035 We expect to see the following in the image, in order:
1036 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1038 u-boot.dtb with the microcode removed
1041 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1043 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1044 b' somewhere in here', first)
1046 def _RunPackUbootSingleMicrocode(self):
1047 """Test that x86 microcode can be handled correctly
1049 We expect to see the following in the image, in order:
1050 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1052 u-boot.dtb with the microcode
1053 an empty microcode region
1055 # We need the libfdt library to run this test since only that allows
1056 # finding the offset of a property. This is required by
1057 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1058 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1060 second = data[len(U_BOOT_NODTB_DATA):]
1062 fdt_len = self.GetFdtLen(second)
1063 third = second[fdt_len:]
1064 second = second[:fdt_len]
1066 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1067 self.assertIn(ucode_data, second)
1068 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1070 # Check that the microcode pointer was inserted. It should match the
1071 # expected offset and size
1072 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1074 first = data[:len(U_BOOT_NODTB_DATA)]
1075 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1076 b' somewhere in here', first)
1078 def testPackUbootSingleMicrocode(self):
1079 """Test that x86 microcode can be handled correctly with fdt_normal.
1081 self._RunPackUbootSingleMicrocode()
1083 def testUBootImg(self):
1084 """Test that u-boot.img can be put in a file"""
1085 data = self._DoReadFile('036_u_boot_img.dts')
1086 self.assertEqual(U_BOOT_IMG_DATA, data)
1088 def testNoMicrocode(self):
1089 """Test that a missing microcode region is detected"""
1090 with self.assertRaises(ValueError) as e:
1091 self._DoReadFile('037_x86_no_ucode.dts', True)
1092 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1093 "node found in ", str(e.exception))
1095 def testMicrocodeWithoutNode(self):
1096 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1097 with self.assertRaises(ValueError) as e:
1098 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1099 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1100 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1102 def testMicrocodeWithoutNode2(self):
1103 """Test that a missing u-boot-ucode node is detected"""
1104 with self.assertRaises(ValueError) as e:
1105 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1106 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1107 "microcode region u-boot-ucode", str(e.exception))
1109 def testMicrocodeWithoutPtrInElf(self):
1110 """Test that a U-Boot binary without the microcode symbol is detected"""
1111 # ELF file without a '_dt_ucode_base_size' symbol
1113 TestFunctional._MakeInputFile('u-boot',
1114 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1116 with self.assertRaises(ValueError) as e:
1117 self._RunPackUbootSingleMicrocode()
1118 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1119 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1122 # Put the original file back
1123 TestFunctional._MakeInputFile('u-boot',
1124 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1126 def testMicrocodeNotInImage(self):
1127 """Test that microcode must be placed within the image"""
1128 with self.assertRaises(ValueError) as e:
1129 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1130 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1131 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1132 "section ranging from 00000000 to 0000002e", str(e.exception))
1134 def testWithoutMicrocode(self):
1135 """Test that we can cope with an image without microcode (e.g. qemu)"""
1136 TestFunctional._MakeInputFile('u-boot',
1137 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1138 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1140 # Now check the device tree has no microcode
1141 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1142 second = data[len(U_BOOT_NODTB_DATA):]
1144 fdt_len = self.GetFdtLen(second)
1145 self.assertEqual(dtb, second[:fdt_len])
1147 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1148 third = data[used_len:]
1149 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1151 def testUnknownPosSize(self):
1152 """Test that microcode must be placed within the image"""
1153 with self.assertRaises(ValueError) as e:
1154 self._DoReadFile('041_unknown_pos_size.dts', True)
1155 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1156 "entry 'invalid-entry'", str(e.exception))
1158 def testPackFsp(self):
1159 """Test that an image with a FSP binary can be created"""
1160 data = self._DoReadFile('042_intel_fsp.dts')
1161 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1163 def testPackCmc(self):
1164 """Test that an image with a CMC binary can be created"""
1165 data = self._DoReadFile('043_intel_cmc.dts')
1166 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1168 def testPackVbt(self):
1169 """Test that an image with a VBT binary can be created"""
1170 data = self._DoReadFile('046_intel_vbt.dts')
1171 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1173 def testSplBssPad(self):
1174 """Test that we can pad SPL's BSS with zeros"""
1175 # ELF file with a '__bss_size' symbol
1177 data = self._DoReadFile('047_spl_bss_pad.dts')
1178 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1181 def testSplBssPadMissing(self):
1182 """Test that a missing symbol is detected"""
1183 self._SetupSplElf('u_boot_ucode_ptr')
1184 with self.assertRaises(ValueError) as e:
1185 self._DoReadFile('047_spl_bss_pad.dts')
1186 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1189 def testPackStart16Spl(self):
1190 """Test that an image with an x86 start16 SPL region can be created"""
1191 data = self._DoReadFile('048_x86_start16_spl.dts')
1192 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1194 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1195 """Helper function for microcode tests
1197 We expect to see the following in the image, in order:
1198 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1200 u-boot.dtb with the microcode removed
1204 dts: Device tree file to use for test
1205 ucode_second: True if the microsecond entry is second instead of
1208 self._SetupSplElf('u_boot_ucode_ptr')
1209 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1210 ucode_second=ucode_second)
1211 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1212 b'ter somewhere in here', first)
1214 def testPackUbootSplMicrocode(self):
1215 """Test that x86 microcode can be handled correctly in SPL"""
1216 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1218 def testPackUbootSplMicrocodeReorder(self):
1219 """Test that order doesn't matter for microcode entries
1221 This is the same as testPackUbootSplMicrocode but when we process the
1222 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1223 entry, so we reply on binman to try later.
1225 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1228 def testPackMrc(self):
1229 """Test that an image with an MRC binary can be created"""
1230 data = self._DoReadFile('050_intel_mrc.dts')
1231 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1233 def testSplDtb(self):
1234 """Test that an image with spl/u-boot-spl.dtb can be created"""
1235 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1236 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1238 def testSplNoDtb(self):
1239 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1240 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1241 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1243 def testSymbols(self):
1244 """Test binman can assign symbols embedded in U-Boot"""
1245 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1246 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1247 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1248 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1250 self._SetupSplElf('u_boot_binman_syms')
1251 data = self._DoReadFile('053_symbols.dts')
1252 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
1253 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
1254 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1255 U_BOOT_SPL_DATA[20:])
1256 self.assertEqual(expected, data)
1258 def testPackUnitAddress(self):
1259 """Test that we support multiple binaries with the same name"""
1260 data = self._DoReadFile('054_unit_address.dts')
1261 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1263 def testSections(self):
1264 """Basic test of sections"""
1265 data = self._DoReadFile('055_sections.dts')
1266 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1267 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1268 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1269 self.assertEqual(expected, data)
1272 """Tests outputting a map of the images"""
1273 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1274 self.assertEqual('''ImagePos Offset Size Name
1275 00000000 00000000 00000028 main-section
1276 00000000 00000000 00000010 section@0
1277 00000000 00000000 00000004 u-boot
1278 00000010 00000010 00000010 section@1
1279 00000010 00000000 00000004 u-boot
1280 00000020 00000020 00000004 section@2
1281 00000020 00000000 00000004 u-boot
1284 def testNamePrefix(self):
1285 """Tests that name prefixes are used"""
1286 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1287 self.assertEqual('''ImagePos Offset Size Name
1288 00000000 00000000 00000028 main-section
1289 00000000 00000000 00000010 section@0
1290 00000000 00000000 00000004 ro-u-boot
1291 00000010 00000010 00000010 section@1
1292 00000010 00000000 00000004 rw-u-boot
1295 def testUnknownContents(self):
1296 """Test that obtaining the contents works as expected"""
1297 with self.assertRaises(ValueError) as e:
1298 self._DoReadFile('057_unknown_contents.dts', True)
1299 self.assertIn("Image '/binman': Internal error: Could not complete "
1300 "processing of contents: remaining ["
1301 "<binman.etype._testing.Entry__testing ", str(e.exception))
1303 def testBadChangeSize(self):
1304 """Test that trying to change the size of an entry fails"""
1306 state.SetAllowEntryExpansion(False)
1307 with self.assertRaises(ValueError) as e:
1308 self._DoReadFile('059_change_size.dts', True)
1309 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1312 state.SetAllowEntryExpansion(True)
1314 def testUpdateFdt(self):
1315 """Test that we can update the device tree with offset/size info"""
1316 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1318 dtb = fdt.Fdt(out_dtb_fname)
1320 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1324 '_testing:offset': 32,
1326 '_testing:image-pos': 32,
1327 'section@0/u-boot:offset': 0,
1328 'section@0/u-boot:size': len(U_BOOT_DATA),
1329 'section@0/u-boot:image-pos': 0,
1330 'section@0:offset': 0,
1331 'section@0:size': 16,
1332 'section@0:image-pos': 0,
1334 'section@1/u-boot:offset': 0,
1335 'section@1/u-boot:size': len(U_BOOT_DATA),
1336 'section@1/u-boot:image-pos': 16,
1337 'section@1:offset': 16,
1338 'section@1:size': 16,
1339 'section@1:image-pos': 16,
1343 def testUpdateFdtBad(self):
1344 """Test that we detect when ProcessFdt never completes"""
1345 with self.assertRaises(ValueError) as e:
1346 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1347 self.assertIn('Could not complete processing of Fdt: remaining '
1348 '[<binman.etype._testing.Entry__testing',
1351 def testEntryArgs(self):
1352 """Test passing arguments to entries from the command line"""
1354 'test-str-arg': 'test1',
1355 'test-int-arg': '456',
1357 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1358 self.assertIn('image', control.images)
1359 entry = control.images['image'].GetEntries()['_testing']
1360 self.assertEqual('test0', entry.test_str_fdt)
1361 self.assertEqual('test1', entry.test_str_arg)
1362 self.assertEqual(123, entry.test_int_fdt)
1363 self.assertEqual(456, entry.test_int_arg)
1365 def testEntryArgsMissing(self):
1366 """Test missing arguments and properties"""
1368 'test-int-arg': '456',
1370 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1371 entry = control.images['image'].GetEntries()['_testing']
1372 self.assertEqual('test0', entry.test_str_fdt)
1373 self.assertEqual(None, entry.test_str_arg)
1374 self.assertEqual(None, entry.test_int_fdt)
1375 self.assertEqual(456, entry.test_int_arg)
1377 def testEntryArgsRequired(self):
1378 """Test missing arguments and properties"""
1380 'test-int-arg': '456',
1382 with self.assertRaises(ValueError) as e:
1383 self._DoReadFileDtb('064_entry_args_required.dts')
1384 self.assertIn("Node '/binman/_testing': Missing required "
1385 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1388 def testEntryArgsInvalidFormat(self):
1389 """Test that an invalid entry-argument format is detected"""
1390 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1392 with self.assertRaises(ValueError) as e:
1393 self._DoBinman(*args)
1394 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1396 def testEntryArgsInvalidInteger(self):
1397 """Test that an invalid entry-argument integer is detected"""
1399 'test-int-arg': 'abc',
1401 with self.assertRaises(ValueError) as e:
1402 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1403 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1404 "'test-int-arg' (value 'abc') to integer",
1407 def testEntryArgsInvalidDatatype(self):
1408 """Test that an invalid entry-argument datatype is detected
1410 This test could be written in entry_test.py except that it needs
1411 access to control.entry_args, which seems more than that module should
1415 'test-bad-datatype-arg': '12',
1417 with self.assertRaises(ValueError) as e:
1418 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1419 entry_args=entry_args)
1420 self.assertIn('GetArg() internal error: Unknown data type ',
1424 """Test for a text entry type"""
1426 'test-id': TEXT_DATA,
1427 'test-id2': TEXT_DATA2,
1428 'test-id3': TEXT_DATA3,
1430 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1431 entry_args=entry_args)
1432 expected = (tools.ToBytes(TEXT_DATA) +
1433 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1434 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1435 b'some text' + b'more text')
1436 self.assertEqual(expected, data)
1438 def testEntryDocs(self):
1439 """Test for creation of entry documentation"""
1440 with test_util.capture_sys_output() as (stdout, stderr):
1441 control.WriteEntryDocs(main.GetEntryModules())
1442 self.assertTrue(len(stdout.getvalue()) > 0)
1444 def testEntryDocsMissing(self):
1445 """Test handling of missing entry documentation"""
1446 with self.assertRaises(ValueError) as e:
1447 with test_util.capture_sys_output() as (stdout, stderr):
1448 control.WriteEntryDocs(main.GetEntryModules(), 'u_boot')
1449 self.assertIn('Documentation is missing for modules: u_boot',
1453 """Basic test of generation of a flashrom fmap"""
1454 data = self._DoReadFile('067_fmap.dts')
1455 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1456 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1457 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1458 self.assertEqual(expected, data[:32])
1459 self.assertEqual(b'__FMAP__', fhdr.signature)
1460 self.assertEqual(1, fhdr.ver_major)
1461 self.assertEqual(0, fhdr.ver_minor)
1462 self.assertEqual(0, fhdr.base)
1463 self.assertEqual(16 + 16 +
1464 fmap_util.FMAP_HEADER_LEN +
1465 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1466 self.assertEqual(b'FMAP', fhdr.name)
1467 self.assertEqual(3, fhdr.nareas)
1468 for fentry in fentries:
1469 self.assertEqual(0, fentry.flags)
1471 self.assertEqual(0, fentries[0].offset)
1472 self.assertEqual(4, fentries[0].size)
1473 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1475 self.assertEqual(16, fentries[1].offset)
1476 self.assertEqual(4, fentries[1].size)
1477 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1479 self.assertEqual(32, fentries[2].offset)
1480 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1481 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1482 self.assertEqual(b'FMAP', fentries[2].name)
1484 def testBlobNamedByArg(self):
1485 """Test we can add a blob with the filename coming from an entry arg"""
1487 'cros-ec-rw-path': 'ecrw.bin',
1489 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1490 entry_args=entry_args)
1493 """Test for an fill entry type"""
1494 data = self._DoReadFile('069_fill.dts')
1495 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1496 self.assertEqual(expected, data)
1498 def testFillNoSize(self):
1499 """Test for an fill entry type with no size"""
1500 with self.assertRaises(ValueError) as e:
1501 self._DoReadFile('070_fill_no_size.dts')
1502 self.assertIn("'fill' entry must have a size property",
1505 def _HandleGbbCommand(self, pipe_list):
1506 """Fake calls to the futility utility"""
1507 if pipe_list[0][0] == 'futility':
1508 fname = pipe_list[0][-1]
1509 # Append our GBB data to the file, which will happen every time the
1510 # futility command is called.
1511 with open(fname, 'ab') as fd:
1513 return command.CommandResult()
1516 """Test for the Chromium OS Google Binary Block"""
1517 command.test_result = self._HandleGbbCommand
1519 'keydir': 'devkeys',
1520 'bmpblk': 'bmpblk.bin',
1522 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1525 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1526 tools.GetBytes(0, 0x2180 - 16))
1527 self.assertEqual(expected, data)
1529 def testGbbTooSmall(self):
1530 """Test for the Chromium OS Google Binary Block being large enough"""
1531 with self.assertRaises(ValueError) as e:
1532 self._DoReadFileDtb('072_gbb_too_small.dts')
1533 self.assertIn("Node '/binman/gbb': GBB is too small",
1536 def testGbbNoSize(self):
1537 """Test for the Chromium OS Google Binary Block having a size"""
1538 with self.assertRaises(ValueError) as e:
1539 self._DoReadFileDtb('073_gbb_no_size.dts')
1540 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1543 def _HandleVblockCommand(self, pipe_list):
1544 """Fake calls to the futility utility"""
1545 if pipe_list[0][0] == 'futility':
1546 fname = pipe_list[0][3]
1547 with open(fname, 'wb') as fd:
1548 fd.write(VBLOCK_DATA)
1549 return command.CommandResult()
1551 def testVblock(self):
1552 """Test for the Chromium OS Verified Boot Block"""
1553 command.test_result = self._HandleVblockCommand
1555 'keydir': 'devkeys',
1557 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1558 entry_args=entry_args)
1559 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1560 self.assertEqual(expected, data)
1562 def testVblockNoContent(self):
1563 """Test we detect a vblock which has no content to sign"""
1564 with self.assertRaises(ValueError) as e:
1565 self._DoReadFile('075_vblock_no_content.dts')
1566 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1567 'property', str(e.exception))
1569 def testVblockBadPhandle(self):
1570 """Test that we detect a vblock with an invalid phandle in contents"""
1571 with self.assertRaises(ValueError) as e:
1572 self._DoReadFile('076_vblock_bad_phandle.dts')
1573 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1574 '1000', str(e.exception))
1576 def testVblockBadEntry(self):
1577 """Test that we detect an entry that points to a non-entry"""
1578 with self.assertRaises(ValueError) as e:
1579 self._DoReadFile('077_vblock_bad_entry.dts')
1580 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1581 "'other'", str(e.exception))
1584 """Test that an image with TPL and its device tree can be created"""
1585 # ELF file with a '__bss_size' symbol
1587 data = self._DoReadFile('078_u_boot_tpl.dts')
1588 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1590 def testUsesPos(self):
1591 """Test that the 'pos' property cannot be used anymore"""
1592 with self.assertRaises(ValueError) as e:
1593 data = self._DoReadFile('079_uses_pos.dts')
1594 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1595 "'pos'", str(e.exception))
1597 def testFillZero(self):
1598 """Test for an fill entry type with a size of 0"""
1599 data = self._DoReadFile('080_fill_empty.dts')
1600 self.assertEqual(tools.GetBytes(0, 16), data)
1602 def testTextMissing(self):
1603 """Test for a text entry type where there is no text"""
1604 with self.assertRaises(ValueError) as e:
1605 self._DoReadFileDtb('066_text.dts',)
1606 self.assertIn("Node '/binman/text': No value provided for text label "
1607 "'test-id'", str(e.exception))
1609 def testPackStart16Tpl(self):
1610 """Test that an image with an x86 start16 TPL region can be created"""
1611 data = self._DoReadFile('081_x86_start16_tpl.dts')
1612 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1614 def testSelectImage(self):
1615 """Test that we can select which images to build"""
1616 expected = 'Skipping images: image1'
1618 # We should only get the expected message in verbose mode
1619 for verbosity in (0, 2):
1620 with test_util.capture_sys_output() as (stdout, stderr):
1621 retcode = self._DoTestFile('006_dual_image.dts',
1622 verbosity=verbosity,
1624 self.assertEqual(0, retcode)
1626 self.assertIn(expected, stdout.getvalue())
1628 self.assertNotIn(expected, stdout.getvalue())
1630 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1631 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1632 self._CleanupOutputDir()
1634 def testUpdateFdtAll(self):
1635 """Test that all device trees are updated with offset/size info"""
1636 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1639 'section:image-pos': 0,
1640 'u-boot-tpl-dtb:size': 513,
1641 'u-boot-spl-dtb:size': 513,
1642 'u-boot-spl-dtb:offset': 493,
1644 'section/u-boot-dtb:image-pos': 0,
1645 'u-boot-spl-dtb:image-pos': 493,
1646 'section/u-boot-dtb:size': 493,
1647 'u-boot-tpl-dtb:image-pos': 1006,
1648 'section/u-boot-dtb:offset': 0,
1649 'section:size': 493,
1651 'section:offset': 0,
1652 'u-boot-tpl-dtb:offset': 1006,
1656 # We expect three device-tree files in the output, one after the other.
1657 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1658 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1659 # main U-Boot tree. All three should have the same postions and offset.
1661 for item in ['', 'spl', 'tpl']:
1662 dtb = fdt.Fdt.FromData(data[start:])
1664 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1666 expected = dict(base_expected)
1669 self.assertEqual(expected, props)
1670 start += dtb._fdt_obj.totalsize()
1672 def testUpdateFdtOutput(self):
1673 """Test that output DTB files are updated"""
1675 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1676 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1678 # Unfortunately, compiling a source file always results in a file
1679 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1680 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1681 # binman as a file called u-boot.dtb. To fix this, copy the file
1682 # over to the expected place.
1684 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1685 'tpl/u-boot-tpl.dtb.out']:
1686 dtb = fdt.Fdt.FromData(data[start:])
1687 size = dtb._fdt_obj.totalsize()
1688 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1689 outdata = tools.ReadFile(pathname)
1690 name = os.path.split(fname)[0]
1693 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1695 orig_indata = dtb_data
1696 self.assertNotEqual(outdata, orig_indata,
1697 "Expected output file '%s' be updated" % pathname)
1698 self.assertEqual(outdata, data[start:start + size],
1699 "Expected output file '%s' to match output image" %
1705 def _decompress(self, data):
1706 return tools.Decompress(data, 'lz4')
1708 def testCompress(self):
1709 """Test compression of blobs"""
1711 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1712 use_real_dtb=True, update_dtb=True)
1713 dtb = fdt.Fdt(out_dtb_fname)
1715 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1716 orig = self._decompress(data)
1717 self.assertEquals(COMPRESS_DATA, orig)
1719 'blob:uncomp-size': len(COMPRESS_DATA),
1720 'blob:size': len(data),
1723 self.assertEqual(expected, props)
1725 def testFiles(self):
1726 """Test bringing in multiple files"""
1727 data = self._DoReadFile('084_files.dts')
1728 self.assertEqual(FILES_DATA, data)
1730 def testFilesCompress(self):
1731 """Test bringing in multiple files and compressing them"""
1733 data = self._DoReadFile('085_files_compress.dts')
1735 image = control.images['image']
1736 entries = image.GetEntries()
1737 files = entries['files']
1738 entries = files._entries
1741 for i in range(1, 3):
1743 start = entries[key].image_pos
1744 len = entries[key].size
1745 chunk = data[start:start + len]
1746 orig += self._decompress(chunk)
1748 self.assertEqual(FILES_DATA, orig)
1750 def testFilesMissing(self):
1751 """Test missing files"""
1752 with self.assertRaises(ValueError) as e:
1753 data = self._DoReadFile('086_files_none.dts')
1754 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1755 'no files', str(e.exception))
1757 def testFilesNoPattern(self):
1758 """Test missing files"""
1759 with self.assertRaises(ValueError) as e:
1760 data = self._DoReadFile('087_files_no_pattern.dts')
1761 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1764 def testExpandSize(self):
1765 """Test an expanding entry"""
1766 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1768 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1769 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1770 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1771 tools.GetBytes(ord('d'), 8))
1772 self.assertEqual(expect, data)
1773 self.assertEqual('''ImagePos Offset Size Name
1774 00000000 00000000 00000028 main-section
1775 00000000 00000000 00000008 fill
1776 00000008 00000008 00000004 u-boot
1777 0000000c 0000000c 00000004 section
1778 0000000c 00000000 00000003 intel-mrc
1779 00000010 00000010 00000004 u-boot2
1780 00000014 00000014 0000000c section2
1781 00000014 00000000 00000008 fill
1782 0000001c 00000008 00000004 u-boot
1783 00000020 00000020 00000008 fill2
1786 def testExpandSizeBad(self):
1787 """Test an expanding entry which fails to provide contents"""
1788 with test_util.capture_sys_output() as (stdout, stderr):
1789 with self.assertRaises(ValueError) as e:
1790 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1791 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1792 'expanding entry', str(e.exception))
1795 """Test hashing of the contents of an entry"""
1796 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1797 use_real_dtb=True, update_dtb=True)
1798 dtb = fdt.Fdt(out_dtb_fname)
1800 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1801 m = hashlib.sha256()
1802 m.update(U_BOOT_DATA)
1803 self.assertEqual(m.digest(), b''.join(hash_node.value))
1805 def testHashNoAlgo(self):
1806 with self.assertRaises(ValueError) as e:
1807 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1808 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1809 'hash node', str(e.exception))
1811 def testHashBadAlgo(self):
1812 with self.assertRaises(ValueError) as e:
1813 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1814 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1817 def testHashSection(self):
1818 """Test hashing of the contents of an entry"""
1819 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1820 use_real_dtb=True, update_dtb=True)
1821 dtb = fdt.Fdt(out_dtb_fname)
1823 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1824 m = hashlib.sha256()
1825 m.update(U_BOOT_DATA)
1826 m.update(tools.GetBytes(ord('a'), 16))
1827 self.assertEqual(m.digest(), b''.join(hash_node.value))
1829 def testPackUBootTplMicrocode(self):
1830 """Test that x86 microcode can be handled correctly in TPL
1832 We expect to see the following in the image, in order:
1833 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1835 u-boot-tpl.dtb with the microcode removed
1838 self._SetupTplElf('u_boot_ucode_ptr')
1839 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1840 U_BOOT_TPL_NODTB_DATA)
1841 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1842 b'ter somewhere in here', first)
1844 def testFmapX86(self):
1845 """Basic test of generation of a flashrom fmap"""
1846 data = self._DoReadFile('094_fmap_x86.dts')
1847 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1848 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1849 self.assertEqual(expected, data[:32])
1850 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1852 self.assertEqual(0x100, fhdr.image_size)
1854 self.assertEqual(0, fentries[0].offset)
1855 self.assertEqual(4, fentries[0].size)
1856 self.assertEqual(b'U_BOOT', fentries[0].name)
1858 self.assertEqual(4, fentries[1].offset)
1859 self.assertEqual(3, fentries[1].size)
1860 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1862 self.assertEqual(32, fentries[2].offset)
1863 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1864 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1865 self.assertEqual(b'FMAP', fentries[2].name)
1867 def testFmapX86Section(self):
1868 """Basic test of generation of a flashrom fmap"""
1869 data = self._DoReadFile('095_fmap_x86_section.dts')
1870 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1871 self.assertEqual(expected, data[:32])
1872 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1874 self.assertEqual(0x100, fhdr.image_size)
1876 self.assertEqual(0, fentries[0].offset)
1877 self.assertEqual(4, fentries[0].size)
1878 self.assertEqual(b'U_BOOT', fentries[0].name)
1880 self.assertEqual(4, fentries[1].offset)
1881 self.assertEqual(3, fentries[1].size)
1882 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1884 self.assertEqual(36, fentries[2].offset)
1885 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1886 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1887 self.assertEqual(b'FMAP', fentries[2].name)
1890 """Basic test of ELF entries"""
1893 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1894 TestFunctional._MakeInputFile('-boot', fd.read())
1895 data = self._DoReadFile('096_elf.dts')
1897 def testElfStrip(self):
1898 """Basic test of ELF entries"""
1900 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1901 TestFunctional._MakeInputFile('-boot', fd.read())
1902 data = self._DoReadFile('097_elf_strip.dts')
1904 def testPackOverlapMap(self):
1905 """Test that overlapping regions are detected"""
1906 with test_util.capture_sys_output() as (stdout, stderr):
1907 with self.assertRaises(ValueError) as e:
1908 self._DoTestFile('014_pack_overlap.dts', map=True)
1909 map_fname = tools.GetOutputFilename('image.map')
1910 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1913 # We should not get an inmage, but there should be a map file
1914 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1915 self.assertTrue(os.path.exists(map_fname))
1916 map_data = tools.ReadFile(map_fname, binary=False)
1917 self.assertEqual('''ImagePos Offset Size Name
1918 <none> 00000000 00000007 main-section
1919 <none> 00000000 00000004 u-boot
1920 <none> 00000003 00000004 u-boot-align
1923 def testPackRefCode(self):
1924 """Test that an image with an Intel Reference code binary works"""
1925 data = self._DoReadFile('100_intel_refcode.dts')
1926 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1928 def testSectionOffset(self):
1929 """Tests use of a section with an offset"""
1930 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1932 self.assertEqual('''ImagePos Offset Size Name
1933 00000000 00000000 00000038 main-section
1934 00000004 00000004 00000010 section@0
1935 00000004 00000000 00000004 u-boot
1936 00000018 00000018 00000010 section@1
1937 00000018 00000000 00000004 u-boot
1938 0000002c 0000002c 00000004 section@2
1939 0000002c 00000000 00000004 u-boot
1941 self.assertEqual(data,
1942 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1943 tools.GetBytes(0x21, 12) +
1944 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1945 tools.GetBytes(0x61, 12) +
1946 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1947 tools.GetBytes(0x26, 8))
1949 def testCbfsRaw(self):
1950 """Test base handling of a Coreboot Filesystem (CBFS)
1952 The exact contents of the CBFS is verified by similar tests in
1953 cbfs_util_test.py. The tests here merely check that the files added to
1954 the CBFS can be found in the final image.
1956 data = self._DoReadFile('102_cbfs_raw.dts')
1959 cbfs = cbfs_util.CbfsReader(data)
1960 self.assertEqual(size, cbfs.rom_size)
1962 self.assertIn('u-boot-dtb', cbfs.files)
1963 cfile = cbfs.files['u-boot-dtb']
1964 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1966 def testCbfsArch(self):
1967 """Test on non-x86 architecture"""
1968 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1971 cbfs = cbfs_util.CbfsReader(data)
1972 self.assertEqual(size, cbfs.rom_size)
1974 self.assertIn('u-boot-dtb', cbfs.files)
1975 cfile = cbfs.files['u-boot-dtb']
1976 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1978 def testCbfsStage(self):
1979 """Tests handling of a Coreboot Filesystem (CBFS)"""
1980 if not elf.ELF_TOOLS:
1981 self.skipTest('Python elftools not available')
1982 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1983 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1986 data = self._DoReadFile('104_cbfs_stage.dts')
1987 cbfs = cbfs_util.CbfsReader(data)
1988 self.assertEqual(size, cbfs.rom_size)
1990 self.assertIn('u-boot', cbfs.files)
1991 cfile = cbfs.files['u-boot']
1992 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1994 def testCbfsRawCompress(self):
1995 """Test handling of compressing raw files"""
1997 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2000 cbfs = cbfs_util.CbfsReader(data)
2001 self.assertIn('u-boot', cbfs.files)
2002 cfile = cbfs.files['u-boot']
2003 self.assertEqual(COMPRESS_DATA, cfile.data)
2005 def testCbfsBadArch(self):
2006 """Test handling of a bad architecture"""
2007 with self.assertRaises(ValueError) as e:
2008 self._DoReadFile('106_cbfs_bad_arch.dts')
2009 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2011 def testCbfsNoSize(self):
2012 """Test handling of a missing size property"""
2013 with self.assertRaises(ValueError) as e:
2014 self._DoReadFile('107_cbfs_no_size.dts')
2015 self.assertIn('entry must have a size property', str(e.exception))
2017 def testCbfsNoCOntents(self):
2018 """Test handling of a CBFS entry which does not provide contentsy"""
2019 with self.assertRaises(ValueError) as e:
2020 self._DoReadFile('108_cbfs_no_contents.dts')
2021 self.assertIn('Could not complete processing of contents',
2024 def testCbfsBadCompress(self):
2025 """Test handling of a bad architecture"""
2026 with self.assertRaises(ValueError) as e:
2027 self._DoReadFile('109_cbfs_bad_compress.dts')
2028 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2031 def testCbfsNamedEntries(self):
2032 """Test handling of named entries"""
2033 data = self._DoReadFile('110_cbfs_name.dts')
2035 cbfs = cbfs_util.CbfsReader(data)
2036 self.assertIn('FRED', cbfs.files)
2037 cfile1 = cbfs.files['FRED']
2038 self.assertEqual(U_BOOT_DATA, cfile1.data)
2040 self.assertIn('hello', cbfs.files)
2041 cfile2 = cbfs.files['hello']
2042 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2044 def _SetupIfwi(self, fname):
2045 """Set up to run an IFWI test
2048 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2053 # Intel Integrated Firmware Image (IFWI) file
2054 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2056 TestFunctional._MakeInputFile(fname,data)
2058 def _CheckIfwi(self, data):
2059 """Check that an image with an IFWI contains the correct output
2062 data: Conents of output file
2064 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2065 if data[:0x1000] != expected_desc:
2066 self.fail('Expected descriptor binary at start of image')
2068 # We expect to find the TPL wil in subpart IBBP entry IBBL
2069 image_fname = tools.GetOutputFilename('image.bin')
2070 tpl_fname = tools.GetOutputFilename('tpl.out')
2071 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2072 subpart='IBBP', entry_name='IBBL')
2074 tpl_data = tools.ReadFile(tpl_fname)
2075 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2077 def testPackX86RomIfwi(self):
2078 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2079 self._SetupIfwi('fitimage.bin')
2080 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2081 self._CheckIfwi(data)
2083 def testPackX86RomIfwiNoDesc(self):
2084 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2085 self._SetupIfwi('ifwi.bin')
2086 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2087 self._CheckIfwi(data)
2089 def testPackX86RomIfwiNoData(self):
2090 """Test that an x86 ROM with IFWI handles missing data"""
2091 self._SetupIfwi('ifwi.bin')
2092 with self.assertRaises(ValueError) as e:
2093 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2094 self.assertIn('Could not complete processing of contents',
2097 def testCbfsOffset(self):
2098 """Test a CBFS with files at particular offsets
2100 Like all CFBS tests, this is just checking the logic that calls
2101 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2103 data = self._DoReadFile('114_cbfs_offset.dts')
2106 cbfs = cbfs_util.CbfsReader(data)
2107 self.assertEqual(size, cbfs.rom_size)
2109 self.assertIn('u-boot', cbfs.files)
2110 cfile = cbfs.files['u-boot']
2111 self.assertEqual(U_BOOT_DATA, cfile.data)
2112 self.assertEqual(0x40, cfile.cbfs_offset)
2114 self.assertIn('u-boot-dtb', cbfs.files)
2115 cfile2 = cbfs.files['u-boot-dtb']
2116 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2117 self.assertEqual(0x140, cfile2.cbfs_offset)
2119 def testFdtmap(self):
2120 """Test an FDT map can be inserted in the image"""
2121 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2122 fdtmap_data = data[len(U_BOOT_DATA):]
2123 magic = fdtmap_data[:8]
2124 self.assertEqual(b'_FDTMAP_', magic)
2125 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2127 fdt_data = fdtmap_data[16:]
2128 dtb = fdt.Fdt.FromData(fdt_data)
2130 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2135 'u-boot:size': len(U_BOOT_DATA),
2136 'u-boot:image-pos': 0,
2137 'fdtmap:image-pos': 4,
2139 'fdtmap:size': len(fdtmap_data),
2143 def testFdtmapNoMatch(self):
2144 """Check handling of an FDT map when the section cannot be found"""
2145 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2147 # Mangle the section name, which should cause a mismatch between the
2148 # correct FDT path and the one expected by the section
2149 image = control.images['image']
2150 image._node.path += '-suffix'
2151 entries = image.GetEntries()
2152 fdtmap = entries['fdtmap']
2153 with self.assertRaises(ValueError) as e:
2155 self.assertIn("Cannot locate node for path '/binman-suffix'",
2158 def testFdtmapHeader(self):
2159 """Test an FDT map and image header can be inserted in the image"""
2160 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2161 fdtmap_pos = len(U_BOOT_DATA)
2162 fdtmap_data = data[fdtmap_pos:]
2163 fdt_data = fdtmap_data[16:]
2164 dtb = fdt.Fdt.FromData(fdt_data)
2165 fdt_size = dtb.GetFdtObj().totalsize()
2166 hdr_data = data[-8:]
2167 self.assertEqual(b'BinM', hdr_data[:4])
2168 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2169 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2171 def testFdtmapHeaderStart(self):
2172 """Test an image header can be inserted at the image start"""
2173 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2174 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2176 self.assertEqual(b'BinM', hdr_data[:4])
2177 offset = struct.unpack('<I', hdr_data[4:])[0]
2178 self.assertEqual(fdtmap_pos, offset)
2180 def testFdtmapHeaderPos(self):
2181 """Test an image header can be inserted at a chosen position"""
2182 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2183 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2184 hdr_data = data[0x80:0x88]
2185 self.assertEqual(b'BinM', hdr_data[:4])
2186 offset = struct.unpack('<I', hdr_data[4:])[0]
2187 self.assertEqual(fdtmap_pos, offset)
2189 def testHeaderMissingFdtmap(self):
2190 """Test an image header requires an fdtmap"""
2191 with self.assertRaises(ValueError) as e:
2192 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2193 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2196 def testHeaderNoLocation(self):
2197 """Test an image header with a no specified location is detected"""
2198 with self.assertRaises(ValueError) as e:
2199 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2200 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2203 def testEntryExpand(self):
2204 """Test expanding an entry after it is packed"""
2205 data = self._DoReadFile('121_entry_expand.dts')
2206 self.assertEqual(b'aaa', data[:3])
2207 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2208 self.assertEqual(b'aaa', data[-3:])
2210 def testEntryExpandBad(self):
2211 """Test expanding an entry after it is packed, twice"""
2212 with self.assertRaises(ValueError) as e:
2213 self._DoReadFile('122_entry_expand_twice.dts')
2214 self.assertIn("Image '/binman': Entries changed size after packing",
2217 def testEntryExpandSection(self):
2218 """Test expanding an entry within a section after it is packed"""
2219 data = self._DoReadFile('123_entry_expand_section.dts')
2220 self.assertEqual(b'aaa', data[:3])
2221 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2222 self.assertEqual(b'aaa', data[-3:])
2224 def testCompressDtb(self):
2225 """Test that compress of device-tree files is supported"""
2227 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2228 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2229 comp_data = data[len(U_BOOT_DATA):]
2230 orig = self._decompress(comp_data)
2231 dtb = fdt.Fdt.FromData(orig)
2233 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2235 'u-boot:size': len(U_BOOT_DATA),
2236 'u-boot-dtb:uncomp-size': len(orig),
2237 'u-boot-dtb:size': len(comp_data),
2240 self.assertEqual(expected, props)
2242 def testCbfsUpdateFdt(self):
2243 """Test that we can update the device tree with CBFS offset/size info"""
2245 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2247 dtb = fdt.Fdt(out_dtb_fname)
2249 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2250 del props['cbfs/u-boot:size']
2256 'cbfs:size': len(data),
2257 'cbfs:image-pos': 0,
2258 'cbfs/u-boot:offset': 0x38,
2259 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2260 'cbfs/u-boot:image-pos': 0x38,
2261 'cbfs/u-boot-dtb:offset': 0xb8,
2262 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2263 'cbfs/u-boot-dtb:image-pos': 0xb8,
2266 def testCbfsBadType(self):
2267 """Test an image header with a no specified location is detected"""
2268 with self.assertRaises(ValueError) as e:
2269 self._DoReadFile('126_cbfs_bad_type.dts')
2270 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2273 """Test listing the files in an image"""
2275 data = self._DoReadFile('127_list.dts')
2276 image = control.images['image']
2277 entries = image.BuildEntryList()
2278 self.assertEqual(7, len(entries))
2281 self.assertEqual(0, ent.indent)
2282 self.assertEqual('main-section', ent.name)
2283 self.assertEqual('section', ent.etype)
2284 self.assertEqual(len(data), ent.size)
2285 self.assertEqual(0, ent.image_pos)
2286 self.assertEqual(None, ent.uncomp_size)
2287 self.assertEqual(0, ent.offset)
2290 self.assertEqual(1, ent.indent)
2291 self.assertEqual('u-boot', ent.name)
2292 self.assertEqual('u-boot', ent.etype)
2293 self.assertEqual(len(U_BOOT_DATA), ent.size)
2294 self.assertEqual(0, ent.image_pos)
2295 self.assertEqual(None, ent.uncomp_size)
2296 self.assertEqual(0, ent.offset)
2299 self.assertEqual(1, ent.indent)
2300 self.assertEqual('section', ent.name)
2301 self.assertEqual('section', ent.etype)
2302 section_size = ent.size
2303 self.assertEqual(0x100, ent.image_pos)
2304 self.assertEqual(None, ent.uncomp_size)
2305 self.assertEqual(0x100, ent.offset)
2308 self.assertEqual(2, ent.indent)
2309 self.assertEqual('cbfs', ent.name)
2310 self.assertEqual('cbfs', ent.etype)
2311 self.assertEqual(0x400, ent.size)
2312 self.assertEqual(0x100, ent.image_pos)
2313 self.assertEqual(None, ent.uncomp_size)
2314 self.assertEqual(0, ent.offset)
2317 self.assertEqual(3, ent.indent)
2318 self.assertEqual('u-boot', ent.name)
2319 self.assertEqual('u-boot', ent.etype)
2320 self.assertEqual(len(U_BOOT_DATA), ent.size)
2321 self.assertEqual(0x138, ent.image_pos)
2322 self.assertEqual(None, ent.uncomp_size)
2323 self.assertEqual(0x38, ent.offset)
2326 self.assertEqual(3, ent.indent)
2327 self.assertEqual('u-boot-dtb', ent.name)
2328 self.assertEqual('text', ent.etype)
2329 self.assertGreater(len(COMPRESS_DATA), ent.size)
2330 self.assertEqual(0x178, ent.image_pos)
2331 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2332 self.assertEqual(0x78, ent.offset)
2335 self.assertEqual(2, ent.indent)
2336 self.assertEqual('u-boot-dtb', ent.name)
2337 self.assertEqual('u-boot-dtb', ent.etype)
2338 self.assertEqual(0x500, ent.image_pos)
2339 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2341 # Compressing this data expands it since headers are added
2342 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2343 self.assertEqual(0x400, ent.offset)
2345 self.assertEqual(len(data), 0x100 + section_size)
2346 self.assertEqual(section_size, 0x400 + dtb_size)
2348 def testFindFdtmap(self):
2349 """Test locating an FDT map in an image"""
2351 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2352 image = control.images['image']
2353 entries = image.GetEntries()
2354 entry = entries['fdtmap']
2355 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2357 def testFindFdtmapMissing(self):
2358 """Test failing to locate an FDP map"""
2359 data = self._DoReadFile('005_simple.dts')
2360 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2362 def testFindImageHeader(self):
2363 """Test locating a image header"""
2365 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2366 image = control.images['image']
2367 entries = image.GetEntries()
2368 entry = entries['fdtmap']
2369 # The header should point to the FDT map
2370 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2372 def testFindImageHeaderStart(self):
2373 """Test locating a image header located at the start of an image"""
2374 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2375 image = control.images['image']
2376 entries = image.GetEntries()
2377 entry = entries['fdtmap']
2378 # The header should point to the FDT map
2379 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2381 def testFindImageHeaderMissing(self):
2382 """Test failing to locate an image header"""
2383 data = self._DoReadFile('005_simple.dts')
2384 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2386 def testReadImage(self):
2387 """Test reading an image and accessing its FDT map"""
2389 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2390 image_fname = tools.GetOutputFilename('image.bin')
2391 orig_image = control.images['image']
2392 image = Image.FromFile(image_fname)
2393 self.assertEqual(orig_image.GetEntries().keys(),
2394 image.GetEntries().keys())
2396 orig_entry = orig_image.GetEntries()['fdtmap']
2397 entry = image.GetEntries()['fdtmap']
2398 self.assertEquals(orig_entry.offset, entry.offset)
2399 self.assertEquals(orig_entry.size, entry.size)
2400 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2402 def testReadImageNoHeader(self):
2403 """Test accessing an image's FDT map without an image header"""
2405 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2406 image_fname = tools.GetOutputFilename('image.bin')
2407 image = Image.FromFile(image_fname)
2408 self.assertTrue(isinstance(image, Image))
2409 self.assertEqual('image', image.image_name[-5:])
2411 def testReadImageFail(self):
2412 """Test failing to read an image image's FDT map"""
2413 self._DoReadFile('005_simple.dts')
2414 image_fname = tools.GetOutputFilename('image.bin')
2415 with self.assertRaises(ValueError) as e:
2416 image = Image.FromFile(image_fname)
2417 self.assertIn("Cannot find FDT map in image", str(e.exception))
2419 def testListCmd(self):
2420 """Test listing the files in an image using an Fdtmap"""
2422 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2424 # lz4 compression size differs depending on the version
2425 image = control.images['image']
2426 entries = image.GetEntries()
2427 section_size = entries['section'].size
2428 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2429 fdtmap_offset = entries['fdtmap'].offset
2432 tmpdir, updated_fname = self._SetupImageInTmpdir()
2433 with test_util.capture_sys_output() as (stdout, stderr):
2434 self._DoBinman('ls', '-i', updated_fname)
2436 shutil.rmtree(tmpdir)
2437 lines = stdout.getvalue().splitlines()
2439 'Name Image-pos Size Entry-type Offset Uncomp-size',
2440 '----------------------------------------------------------------------',
2441 'main-section 0 c00 section 0',
2442 ' u-boot 0 4 u-boot 0',
2443 ' section 100 %x section 100' % section_size,
2444 ' cbfs 100 400 cbfs 0',
2445 ' u-boot 138 4 u-boot 38',
2446 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2447 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2448 ' fdtmap %x 3bd fdtmap %x' %
2449 (fdtmap_offset, fdtmap_offset),
2450 ' image-header bf8 8 image-header bf8',
2452 self.assertEqual(expected, lines)
2454 def testListCmdFail(self):
2455 """Test failing to list an image"""
2456 self._DoReadFile('005_simple.dts')
2458 tmpdir, updated_fname = self._SetupImageInTmpdir()
2459 with self.assertRaises(ValueError) as e:
2460 self._DoBinman('ls', '-i', updated_fname)
2462 shutil.rmtree(tmpdir)
2463 self.assertIn("Cannot find FDT map in image", str(e.exception))
2465 def _RunListCmd(self, paths, expected):
2466 """List out entries and check the result
2469 paths: List of paths to pass to the list command
2470 expected: Expected list of filenames to be returned, in order
2473 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2474 image_fname = tools.GetOutputFilename('image.bin')
2475 image = Image.FromFile(image_fname)
2476 lines = image.GetListEntries(paths)[1]
2477 files = [line[0].strip() for line in lines[1:]]
2478 self.assertEqual(expected, files)
2480 def testListCmdSection(self):
2481 """Test listing the files in a section"""
2482 self._RunListCmd(['section'],
2483 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2485 def testListCmdFile(self):
2486 """Test listing a particular file"""
2487 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2489 def testListCmdWildcard(self):
2490 """Test listing a wildcarded file"""
2491 self._RunListCmd(['*boot*'],
2492 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2494 def testListCmdWildcardMulti(self):
2495 """Test listing a wildcarded file"""
2496 self._RunListCmd(['*cb*', '*head*'],
2497 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2499 def testListCmdEmpty(self):
2500 """Test listing a wildcarded file"""
2501 self._RunListCmd(['nothing'], [])
2503 def testListCmdPath(self):
2504 """Test listing the files in a sub-entry of a section"""
2505 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2507 def _RunExtractCmd(self, entry_name, decomp=True):
2508 """Extract an entry from an image
2511 entry_name: Entry name to extract
2512 decomp: True to decompress the data if compressed, False to leave
2513 it in its raw uncompressed format
2519 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2520 image_fname = tools.GetOutputFilename('image.bin')
2521 return control.ReadEntry(image_fname, entry_name, decomp)
2523 def testExtractSimple(self):
2524 """Test extracting a single file"""
2525 data = self._RunExtractCmd('u-boot')
2526 self.assertEqual(U_BOOT_DATA, data)
2528 def testExtractSection(self):
2529 """Test extracting the files in a section"""
2530 data = self._RunExtractCmd('section')
2531 cbfs_data = data[:0x400]
2532 cbfs = cbfs_util.CbfsReader(cbfs_data)
2533 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2534 dtb_data = data[0x400:]
2535 dtb = self._decompress(dtb_data)
2536 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2538 def testExtractCompressed(self):
2539 """Test extracting compressed data"""
2540 data = self._RunExtractCmd('section/u-boot-dtb')
2541 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2543 def testExtractRaw(self):
2544 """Test extracting compressed data without decompressing it"""
2545 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2546 dtb = self._decompress(data)
2547 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2549 def testExtractCbfs(self):
2550 """Test extracting CBFS data"""
2551 data = self._RunExtractCmd('section/cbfs/u-boot')
2552 self.assertEqual(U_BOOT_DATA, data)
2554 def testExtractCbfsCompressed(self):
2555 """Test extracting CBFS compressed data"""
2556 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2557 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2559 def testExtractCbfsRaw(self):
2560 """Test extracting CBFS compressed data without decompressing it"""
2561 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2562 dtb = tools.Decompress(data, 'lzma', with_header=False)
2563 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2565 def testExtractBadEntry(self):
2566 """Test extracting a bad section path"""
2567 with self.assertRaises(ValueError) as e:
2568 self._RunExtractCmd('section/does-not-exist')
2569 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2572 def testExtractMissingFile(self):
2573 """Test extracting file that does not exist"""
2574 with self.assertRaises(IOError) as e:
2575 control.ReadEntry('missing-file', 'name')
2577 def testExtractBadFile(self):
2578 """Test extracting an invalid file"""
2579 fname = os.path.join(self._indir, 'badfile')
2580 tools.WriteFile(fname, b'')
2581 with self.assertRaises(ValueError) as e:
2582 control.ReadEntry(fname, 'name')
2584 def testExtractCmd(self):
2585 """Test extracting a file fron an image on the command line"""
2587 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2588 fname = os.path.join(self._indir, 'output.extact')
2590 tmpdir, updated_fname = self._SetupImageInTmpdir()
2591 with test_util.capture_sys_output() as (stdout, stderr):
2592 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2595 shutil.rmtree(tmpdir)
2596 data = tools.ReadFile(fname)
2597 self.assertEqual(U_BOOT_DATA, data)
2599 def testExtractOneEntry(self):
2600 """Test extracting a single entry fron an image """
2602 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2603 image_fname = tools.GetOutputFilename('image.bin')
2604 fname = os.path.join(self._indir, 'output.extact')
2605 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2606 data = tools.ReadFile(fname)
2607 self.assertEqual(U_BOOT_DATA, data)
2609 def _CheckExtractOutput(self, decomp):
2610 """Helper to test file output with and without decompression
2613 decomp: True to decompress entry data, False to output it raw
2615 def _CheckPresent(entry_path, expect_data, expect_size=None):
2616 """Check and remove expected file
2618 This checks the data/size of a file and removes the file both from
2619 the outfiles set and from the output directory. Once all files are
2620 processed, both the set and directory should be empty.
2623 entry_path: Entry path
2624 expect_data: Data to expect in file, or None to skip check
2625 expect_size: Size of data to expect in file, or None to skip
2627 path = os.path.join(outdir, entry_path)
2628 data = tools.ReadFile(path)
2631 self.assertEqual(expect_data, data)
2633 self.assertEqual(expect_size, len(data))
2634 outfiles.remove(path)
2636 def _CheckDirPresent(name):
2637 """Remove expected directory
2639 This gives an error if the directory does not exist as expected
2642 name: Name of directory to remove
2644 path = os.path.join(outdir, name)
2647 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2648 image_fname = tools.GetOutputFilename('image.bin')
2649 outdir = os.path.join(self._indir, 'extract')
2650 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2652 # Create a set of all file that were output (should be 9)
2654 for root, dirs, files in os.walk(outdir):
2655 outfiles |= set([os.path.join(root, fname) for fname in files])
2656 self.assertEqual(9, len(outfiles))
2657 self.assertEqual(9, len(einfos))
2659 image = control.images['image']
2660 entries = image.GetEntries()
2662 # Check the 9 files in various ways
2663 section = entries['section']
2664 section_entries = section.GetEntries()
2665 cbfs_entries = section_entries['cbfs'].GetEntries()
2666 _CheckPresent('u-boot', U_BOOT_DATA)
2667 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2668 dtb_len = EXTRACT_DTB_SIZE
2670 dtb_len = cbfs_entries['u-boot-dtb'].size
2671 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2673 dtb_len = section_entries['u-boot-dtb'].size
2674 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2676 fdtmap = entries['fdtmap']
2677 _CheckPresent('fdtmap', fdtmap.data)
2678 hdr = entries['image-header']
2679 _CheckPresent('image-header', hdr.data)
2681 _CheckPresent('section/root', section.data)
2682 cbfs = section_entries['cbfs']
2683 _CheckPresent('section/cbfs/root', cbfs.data)
2684 data = tools.ReadFile(image_fname)
2685 _CheckPresent('root', data)
2687 # There should be no files left. Remove all the directories to check.
2688 # If there are any files/dirs remaining, one of these checks will fail.
2689 self.assertEqual(0, len(outfiles))
2690 _CheckDirPresent('section/cbfs')
2691 _CheckDirPresent('section')
2692 _CheckDirPresent('')
2693 self.assertFalse(os.path.exists(outdir))
2695 def testExtractAllEntries(self):
2696 """Test extracting all entries"""
2698 self._CheckExtractOutput(decomp=True)
2700 def testExtractAllEntriesRaw(self):
2701 """Test extracting all entries without decompressing them"""
2703 self._CheckExtractOutput(decomp=False)
2705 def testExtractSelectedEntries(self):
2706 """Test extracting some entries"""
2708 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2709 image_fname = tools.GetOutputFilename('image.bin')
2710 outdir = os.path.join(self._indir, 'extract')
2711 einfos = control.ExtractEntries(image_fname, None, outdir,
2714 # File output is tested by testExtractAllEntries(), so just check that
2715 # the expected entries are selected
2716 names = [einfo.name for einfo in einfos]
2717 self.assertEqual(names,
2718 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2720 def testExtractNoEntryPaths(self):
2721 """Test extracting some entries"""
2723 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2724 image_fname = tools.GetOutputFilename('image.bin')
2725 with self.assertRaises(ValueError) as e:
2726 control.ExtractEntries(image_fname, 'fname', None, [])
2727 self.assertIn('Must specify an entry path to write with -f',
2730 def testExtractTooManyEntryPaths(self):
2731 """Test extracting some entries"""
2733 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2734 image_fname = tools.GetOutputFilename('image.bin')
2735 with self.assertRaises(ValueError) as e:
2736 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2737 self.assertIn('Must specify exactly one entry path to write with -f',
2740 def testPackAlignSection(self):
2741 """Test that sections can have alignment"""
2742 self._DoReadFile('131_pack_align_section.dts')
2744 self.assertIn('image', control.images)
2745 image = control.images['image']
2746 entries = image.GetEntries()
2747 self.assertEqual(3, len(entries))
2750 self.assertIn('u-boot', entries)
2751 entry = entries['u-boot']
2752 self.assertEqual(0, entry.offset)
2753 self.assertEqual(0, entry.image_pos)
2754 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2755 self.assertEqual(len(U_BOOT_DATA), entry.size)
2758 self.assertIn('section0', entries)
2759 section0 = entries['section0']
2760 self.assertEqual(0x10, section0.offset)
2761 self.assertEqual(0x10, section0.image_pos)
2762 self.assertEqual(len(U_BOOT_DATA), section0.size)
2765 section_entries = section0.GetEntries()
2766 self.assertIn('u-boot', section_entries)
2767 entry = section_entries['u-boot']
2768 self.assertEqual(0, entry.offset)
2769 self.assertEqual(0x10, entry.image_pos)
2770 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2771 self.assertEqual(len(U_BOOT_DATA), entry.size)
2774 self.assertIn('section1', entries)
2775 section1 = entries['section1']
2776 self.assertEqual(0x14, section1.offset)
2777 self.assertEqual(0x14, section1.image_pos)
2778 self.assertEqual(0x20, section1.size)
2781 section_entries = section1.GetEntries()
2782 self.assertIn('u-boot', section_entries)
2783 entry = section_entries['u-boot']
2784 self.assertEqual(0, entry.offset)
2785 self.assertEqual(0x14, entry.image_pos)
2786 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2787 self.assertEqual(len(U_BOOT_DATA), entry.size)
2790 self.assertIn('section2', section_entries)
2791 section2 = section_entries['section2']
2792 self.assertEqual(0x4, section2.offset)
2793 self.assertEqual(0x18, section2.image_pos)
2794 self.assertEqual(4, section2.size)
2797 section_entries = section2.GetEntries()
2798 self.assertIn('u-boot', section_entries)
2799 entry = section_entries['u-boot']
2800 self.assertEqual(0, entry.offset)
2801 self.assertEqual(0x18, entry.image_pos)
2802 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2803 self.assertEqual(len(U_BOOT_DATA), entry.size)
2805 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2806 dts='132_replace.dts'):
2807 """Replace an entry in an image
2809 This writes the entry data to update it, then opens the updated file and
2810 returns the value that it now finds there.
2813 entry_name: Entry name to replace
2814 data: Data to replace it with
2815 decomp: True to compress the data if needed, False if data is
2816 already compressed so should be used as is
2817 allow_resize: True to allow entries to change size, False to raise
2823 data from fdtmap (excluding header)
2824 Image object that was modified
2826 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2829 self.assertIn('image', control.images)
2830 image = control.images['image']
2831 entries = image.GetEntries()
2832 orig_dtb_data = entries['u-boot-dtb'].data
2833 orig_fdtmap_data = entries['fdtmap'].data
2835 image_fname = tools.GetOutputFilename('image.bin')
2836 updated_fname = tools.GetOutputFilename('image-updated.bin')
2837 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2838 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2840 data = control.ReadEntry(updated_fname, entry_name, decomp)
2842 # The DT data should not change unless resized:
2843 if not allow_resize:
2844 new_dtb_data = entries['u-boot-dtb'].data
2845 self.assertEqual(new_dtb_data, orig_dtb_data)
2846 new_fdtmap_data = entries['fdtmap'].data
2847 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2849 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2851 def testReplaceSimple(self):
2852 """Test replacing a single file"""
2853 expected = b'x' * len(U_BOOT_DATA)
2854 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2856 self.assertEqual(expected, data)
2858 # Test that the state looks right. There should be an FDT for the fdtmap
2859 # that we jsut read back in, and it should match what we find in the
2860 # 'control' tables. Checking for an FDT that does not exist should
2862 path, fdtmap = state.GetFdtContents('fdtmap')
2863 self.assertIsNotNone(path)
2864 self.assertEqual(expected_fdtmap, fdtmap)
2866 dtb = state.GetFdtForEtype('fdtmap')
2867 self.assertEqual(dtb.GetContents(), fdtmap)
2869 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2870 self.assertIsNone(missing_path)
2871 self.assertIsNone(missing_fdtmap)
2873 missing_dtb = state.GetFdtForEtype('missing')
2874 self.assertIsNone(missing_dtb)
2876 self.assertEqual('/binman', state.fdt_path_prefix)
2878 def testReplaceResizeFail(self):
2879 """Test replacing a file by something larger"""
2880 expected = U_BOOT_DATA + b'x'
2881 with self.assertRaises(ValueError) as e:
2882 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2883 dts='139_replace_repack.dts')
2884 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2887 def testReplaceMulti(self):
2888 """Test replacing entry data where multiple images are generated"""
2889 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2891 expected = b'x' * len(U_BOOT_DATA)
2892 updated_fname = tools.GetOutputFilename('image-updated.bin')
2893 tools.WriteFile(updated_fname, data)
2894 entry_name = 'u-boot'
2895 control.WriteEntry(updated_fname, entry_name, expected,
2897 data = control.ReadEntry(updated_fname, entry_name)
2898 self.assertEqual(expected, data)
2900 # Check the state looks right.
2901 self.assertEqual('/binman/image', state.fdt_path_prefix)
2903 # Now check we can write the first image
2904 image_fname = tools.GetOutputFilename('first-image.bin')
2905 updated_fname = tools.GetOutputFilename('first-updated.bin')
2906 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2907 entry_name = 'u-boot'
2908 control.WriteEntry(updated_fname, entry_name, expected,
2910 data = control.ReadEntry(updated_fname, entry_name)
2911 self.assertEqual(expected, data)
2913 # Check the state looks right.
2914 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2916 def testUpdateFdtAllRepack(self):
2917 """Test that all device trees are updated with offset/size info"""
2918 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2919 SECTION_SIZE = 0x300
2924 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2926 'section:offset': 0,
2927 'section:size': SECTION_SIZE,
2928 'section:image-pos': 0,
2929 'section/u-boot-dtb:offset': 4,
2930 'section/u-boot-dtb:size': 636,
2931 'section/u-boot-dtb:image-pos': 4,
2932 'u-boot-spl-dtb:offset': SECTION_SIZE,
2933 'u-boot-spl-dtb:size': DTB_SIZE,
2934 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2935 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2936 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2937 'u-boot-tpl-dtb:size': DTB_SIZE,
2938 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2939 'fdtmap:size': FDTMAP_SIZE,
2940 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2943 'section:orig-size': SECTION_SIZE,
2944 'section/u-boot-dtb:orig-offset': 4,
2947 # We expect three device-tree files in the output, with the first one
2948 # within a fixed-size section.
2949 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2950 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2951 # main U-Boot tree. All three should have the same positions and offset
2952 # except that the main tree should include the main_expected properties
2954 for item in ['', 'spl', 'tpl', None]:
2956 start += 16 # Move past fdtmap header
2957 dtb = fdt.Fdt.FromData(data[start:])
2959 props = self._GetPropTree(dtb,
2960 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2961 prefix='/' if item is None else '/binman/')
2962 expected = dict(base_expected)
2966 # Main DTB and fdtdec should include the 'orig-' properties
2967 expected.update(main_expected)
2968 # Helpful for debugging:
2969 #for prop in sorted(props):
2970 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2971 self.assertEqual(expected, props)
2973 start = SECTION_SIZE
2975 start += dtb._fdt_obj.totalsize()
2977 def testFdtmapHeaderMiddle(self):
2978 """Test an FDT map in the middle of an image when it should be at end"""
2979 with self.assertRaises(ValueError) as e:
2980 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2981 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2984 def testFdtmapHeaderStartBad(self):
2985 """Test an FDT map in middle of an image when it should be at start"""
2986 with self.assertRaises(ValueError) as e:
2987 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2988 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2991 def testFdtmapHeaderEndBad(self):
2992 """Test an FDT map at the start of an image when it should be at end"""
2993 with self.assertRaises(ValueError) as e:
2994 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2995 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2998 def testFdtmapHeaderNoSize(self):
2999 """Test an image header at the end of an image with undefined size"""
3000 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3002 def testReplaceResize(self):
3003 """Test replacing a single file in an entry with a larger file"""
3004 expected = U_BOOT_DATA + b'x'
3005 data, _, image = self._RunReplaceCmd('u-boot', expected,
3006 dts='139_replace_repack.dts')
3007 self.assertEqual(expected, data)
3009 entries = image.GetEntries()
3010 dtb_data = entries['u-boot-dtb'].data
3011 dtb = fdt.Fdt.FromData(dtb_data)
3014 # The u-boot section should now be larger in the dtb
3015 node = dtb.GetNode('/binman/u-boot')
3016 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3018 # Same for the fdtmap
3019 fdata = entries['fdtmap'].data
3020 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3022 fnode = fdtb.GetNode('/u-boot')
3023 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3025 def testReplaceResizeNoRepack(self):
3026 """Test replacing an entry with a larger file when not allowed"""
3027 expected = U_BOOT_DATA + b'x'
3028 with self.assertRaises(ValueError) as e:
3029 self._RunReplaceCmd('u-boot', expected)
3030 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3033 def testEntryShrink(self):
3034 """Test contracting an entry after it is packed"""
3036 state.SetAllowEntryContraction(True)
3037 data = self._DoReadFileDtb('140_entry_shrink.dts',
3040 state.SetAllowEntryContraction(False)
3041 self.assertEqual(b'a', data[:1])
3042 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3043 self.assertEqual(b'a', data[-1:])
3045 def testEntryShrinkFail(self):
3046 """Test not being allowed to contract an entry after it is packed"""
3047 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3049 # In this case there is a spare byte at the end of the data. The size of
3050 # the contents is only 1 byte but we still have the size before it
3052 self.assertEqual(b'a\0', data[:2])
3053 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3054 self.assertEqual(b'a\0', data[-2:])
3056 def testDescriptorOffset(self):
3057 """Test that the Intel descriptor is always placed at at the start"""
3058 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3059 image = control.images['image']
3060 entries = image.GetEntries()
3061 desc = entries['intel-descriptor']
3062 self.assertEqual(0xff800000, desc.offset);
3063 self.assertEqual(0xff800000, desc.image_pos);
3065 def testReplaceCbfs(self):
3066 """Test replacing a single file in CBFS without changing the size"""
3068 expected = b'x' * len(U_BOOT_DATA)
3069 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3070 updated_fname = tools.GetOutputFilename('image-updated.bin')
3071 tools.WriteFile(updated_fname, data)
3072 entry_name = 'section/cbfs/u-boot'
3073 control.WriteEntry(updated_fname, entry_name, expected,
3075 data = control.ReadEntry(updated_fname, entry_name)
3076 self.assertEqual(expected, data)
3078 def testReplaceResizeCbfs(self):
3079 """Test replacing a single file in CBFS with one of a different size"""
3081 expected = U_BOOT_DATA + b'x'
3082 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3083 updated_fname = tools.GetOutputFilename('image-updated.bin')
3084 tools.WriteFile(updated_fname, data)
3085 entry_name = 'section/cbfs/u-boot'
3086 control.WriteEntry(updated_fname, entry_name, expected,
3088 data = control.ReadEntry(updated_fname, entry_name)
3089 self.assertEqual(expected, data)
3091 def _SetupForReplace(self):
3092 """Set up some files to use to replace entries
3094 This generates an image, copies it to a new file, extracts all the files
3095 in it and updates some of them
3101 Expected values for updated entries, each a string
3103 data = self._DoReadFileRealDtb('143_replace_all.dts')
3105 updated_fname = tools.GetOutputFilename('image-updated.bin')
3106 tools.WriteFile(updated_fname, data)
3108 outdir = os.path.join(self._indir, 'extract')
3109 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3111 expected1 = b'x' + U_BOOT_DATA + b'y'
3112 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3113 tools.WriteFile(u_boot_fname1, expected1)
3115 expected2 = b'a' + U_BOOT_DATA + b'b'
3116 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3117 tools.WriteFile(u_boot_fname2, expected2)
3119 expected_text = b'not the same text'
3120 text_fname = os.path.join(outdir, 'text')
3121 tools.WriteFile(text_fname, expected_text)
3123 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3124 dtb = fdt.FdtScan(dtb_fname)
3125 node = dtb.GetNode('/binman/text')
3126 node.AddString('my-property', 'the value')
3127 dtb.Sync(auto_resize=True)
3130 return updated_fname, outdir, expected1, expected2, expected_text
3132 def _CheckReplaceMultiple(self, entry_paths):
3133 """Handle replacing the contents of multiple entries
3136 entry_paths: List of entry paths to replace
3140 Dict of entries in the image:
3143 Expected values for updated entries, each a string
3145 updated_fname, outdir, expected1, expected2, expected_text = (
3146 self._SetupForReplace())
3147 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3149 image = Image.FromFile(updated_fname)
3151 return image.GetEntries(), expected1, expected2, expected_text
3153 def testReplaceAll(self):
3154 """Test replacing the contents of all entries"""
3155 entries, expected1, expected2, expected_text = (
3156 self._CheckReplaceMultiple([]))
3157 data = entries['u-boot'].data
3158 self.assertEqual(expected1, data)
3160 data = entries['u-boot2'].data
3161 self.assertEqual(expected2, data)
3163 data = entries['text'].data
3164 self.assertEqual(expected_text, data)
3166 # Check that the device tree is updated
3167 data = entries['u-boot-dtb'].data
3168 dtb = fdt.Fdt.FromData(data)
3170 node = dtb.GetNode('/binman/text')
3171 self.assertEqual('the value', node.props['my-property'].value)
3173 def testReplaceSome(self):
3174 """Test replacing the contents of a few entries"""
3175 entries, expected1, expected2, expected_text = (
3176 self._CheckReplaceMultiple(['u-boot2', 'text']))
3178 # This one should not change
3179 data = entries['u-boot'].data
3180 self.assertEqual(U_BOOT_DATA, data)
3182 data = entries['u-boot2'].data
3183 self.assertEqual(expected2, data)
3185 data = entries['text'].data
3186 self.assertEqual(expected_text, data)
3188 def testReplaceCmd(self):
3189 """Test replacing a file fron an image on the command line"""
3190 self._DoReadFileRealDtb('143_replace_all.dts')
3193 tmpdir, updated_fname = self._SetupImageInTmpdir()
3195 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3196 expected = b'x' * len(U_BOOT_DATA)
3197 tools.WriteFile(fname, expected)
3199 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3200 data = tools.ReadFile(updated_fname)
3201 self.assertEqual(expected, data[:len(expected)])
3202 map_fname = os.path.join(tmpdir, 'image-updated.map')
3203 self.assertFalse(os.path.exists(map_fname))
3205 shutil.rmtree(tmpdir)
3207 def testReplaceCmdSome(self):
3208 """Test replacing some files fron an image on the command line"""
3209 updated_fname, outdir, expected1, expected2, expected_text = (
3210 self._SetupForReplace())
3212 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3215 tools.PrepareOutputDir(None)
3216 image = Image.FromFile(updated_fname)
3218 entries = image.GetEntries()
3220 # This one should not change
3221 data = entries['u-boot'].data
3222 self.assertEqual(U_BOOT_DATA, data)
3224 data = entries['u-boot2'].data
3225 self.assertEqual(expected2, data)
3227 data = entries['text'].data
3228 self.assertEqual(expected_text, data)
3230 def testReplaceMissing(self):
3231 """Test replacing entries where the file is missing"""
3232 updated_fname, outdir, expected1, expected2, expected_text = (
3233 self._SetupForReplace())
3235 # Remove one of the files, to generate a warning
3236 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3237 os.remove(u_boot_fname1)
3239 with test_util.capture_sys_output() as (stdout, stderr):
3240 control.ReplaceEntries(updated_fname, None, outdir, [])
3241 self.assertIn("Skipping entry '/u-boot' from missing file",
3244 def testReplaceCmdMap(self):
3245 """Test replacing a file fron an image on the command line"""
3246 self._DoReadFileRealDtb('143_replace_all.dts')
3249 tmpdir, updated_fname = self._SetupImageInTmpdir()
3251 fname = os.path.join(self._indir, 'update-u-boot.bin')
3252 expected = b'x' * len(U_BOOT_DATA)
3253 tools.WriteFile(fname, expected)
3255 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3257 map_fname = os.path.join(tmpdir, 'image-updated.map')
3258 self.assertTrue(os.path.exists(map_fname))
3260 shutil.rmtree(tmpdir)
3262 def testReplaceNoEntryPaths(self):
3263 """Test replacing an entry without an entry path"""
3264 self._DoReadFileRealDtb('143_replace_all.dts')
3265 image_fname = tools.GetOutputFilename('image.bin')
3266 with self.assertRaises(ValueError) as e:
3267 control.ReplaceEntries(image_fname, 'fname', None, [])
3268 self.assertIn('Must specify an entry path to read with -f',
3271 def testReplaceTooManyEntryPaths(self):
3272 """Test extracting some entries"""
3273 self._DoReadFileRealDtb('143_replace_all.dts')
3274 image_fname = tools.GetOutputFilename('image.bin')
3275 with self.assertRaises(ValueError) as e:
3276 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3277 self.assertIn('Must specify exactly one entry path to write with -f',
3280 def testPackReset16(self):
3281 """Test that an image with an x86 reset16 region can be created"""
3282 data = self._DoReadFile('144_x86_reset16.dts')
3283 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3285 def testPackReset16Spl(self):
3286 """Test that an image with an x86 reset16-spl region can be created"""
3287 data = self._DoReadFile('145_x86_reset16_spl.dts')
3288 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3290 def testPackReset16Tpl(self):
3291 """Test that an image with an x86 reset16-tpl region can be created"""
3292 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3293 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3295 def testPackIntelFit(self):
3296 """Test that an image with an Intel FIT and pointer can be created"""
3297 data = self._DoReadFile('147_intel_fit.dts')
3298 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3300 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3301 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3303 image = control.images['image']
3304 entries = image.GetEntries()
3305 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3306 self.assertEqual(expected_ptr, ptr)
3308 def testPackIntelFitMissing(self):
3309 """Test detection of a FIT pointer with not FIT region"""
3310 with self.assertRaises(ValueError) as e:
3311 self._DoReadFile('148_intel_fit_missing.dts')
3312 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3315 def _CheckSymbolsTplSection(self, dts, expected_vals):
3316 data = self._DoReadFile(dts)
3317 sym_values = struct.pack('<LQLL', *expected_vals)
3318 upto1 = 4 + len(U_BOOT_SPL_DATA)
3319 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3320 self.assertEqual(expected1, data[:upto1])
3322 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3323 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3324 self.assertEqual(expected2, data[upto1:upto2])
3326 upto3 = 0x34 + len(U_BOOT_DATA)
3327 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3328 self.assertEqual(expected3, data[upto2:upto3])
3330 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3331 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3333 def testSymbolsTplSection(self):
3334 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3335 self._SetupSplElf('u_boot_binman_syms')
3336 self._SetupTplElf('u_boot_binman_syms')
3337 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3338 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3340 def testSymbolsTplSectionX86(self):
3341 """Test binman can assign symbols in a section with end-at-4gb"""
3342 self._SetupSplElf('u_boot_binman_syms_x86')
3343 self._SetupTplElf('u_boot_binman_syms_x86')
3344 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3345 [0xffffff04, 0xffffff1c, 0xffffff34,
3348 def testPackX86RomIfwiSectiom(self):
3349 """Test that a section can be placed in an IFWI region"""
3350 self._SetupIfwi('fitimage.bin')
3351 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3352 self._CheckIfwi(data)
3354 def testPackFspM(self):
3355 """Test that an image with a FSP memory-init binary can be created"""
3356 data = self._DoReadFile('152_intel_fsp_m.dts')
3357 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3359 def testPackFspS(self):
3360 """Test that an image with a FSP silicon-init binary can be created"""
3361 data = self._DoReadFile('153_intel_fsp_s.dts')
3362 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3364 def testPackFspT(self):
3365 """Test that an image with a FSP temp-ram-init binary can be created"""
3366 data = self._DoReadFile('154_intel_fsp_t.dts')
3367 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3369 def testMkimage(self):
3370 """Test using mkimage to build an image"""
3371 data = self._DoReadFile('156_mkimage.dts')
3373 # Just check that the data appears in the file somewhere
3374 self.assertIn(U_BOOT_SPL_DATA, data)
3376 def testExtblob(self):
3377 """Test an image with an external blob"""
3378 data = self._DoReadFile('157_blob_ext.dts')
3379 self.assertEqual(REFCODE_DATA, data)
3381 def testExtblobMissing(self):
3382 """Test an image with a missing external blob"""
3383 with self.assertRaises(ValueError) as e:
3384 self._DoReadFile('158_blob_ext_missing.dts')
3385 self.assertIn("Filename 'missing-file' not found in input path",
3388 def testExtblobMissingOk(self):
3389 """Test an image with an missing external blob that is allowed"""
3390 with test_util.capture_sys_output() as (stdout, stderr):
3391 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3392 err = stderr.getvalue()
3393 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3395 def testExtblobMissingOkSect(self):
3396 """Test an image with an missing external blob that is allowed"""
3397 with test_util.capture_sys_output() as (stdout, stderr):
3398 self._DoTestFile('159_blob_ext_missing_sect.dts',
3400 err = stderr.getvalue()
3401 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3402 "blob-ext blob-ext2")
3404 def testPackX86RomMeMissingDesc(self):
3405 """Test that an missing Intel descriptor entry is allowed"""
3406 pathname = os.path.join(self._indir, 'descriptor.bin')
3408 with test_util.capture_sys_output() as (stdout, stderr):
3409 self._DoTestFile('031_x86_rom_me.dts', allow_missing=True)
3410 err = stderr.getvalue()
3411 self.assertRegex(err,
3412 "Image 'main-section'.*missing.*: intel-descriptor")
3414 def testPackX86RomMissingIfwi(self):
3415 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3416 self._SetupIfwi('fitimage.bin')
3417 pathname = os.path.join(self._indir, 'fitimage.bin')
3419 with test_util.capture_sys_output() as (stdout, stderr):
3420 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3421 err = stderr.getvalue()
3422 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3425 if __name__ == "__main__":