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
9 from __future__ import print_function
12 from optparse import OptionParser
27 from etype import fdtmap
28 from etype import image_header
33 from image import Image
38 # Contents of test files, corresponding to different entry types
40 U_BOOT_IMG_DATA = b'img'
41 U_BOOT_SPL_DATA = b'56780123456789abcde'
42 U_BOOT_TPL_DATA = b'tpl'
46 U_BOOT_DTB_DATA = b'udtb'
47 U_BOOT_SPL_DTB_DATA = b'spldtb'
48 U_BOOT_TPL_DTB_DATA = b'tpldtb'
49 X86_START16_DATA = b'start16'
50 X86_START16_SPL_DATA = b'start16spl'
51 X86_START16_TPL_DATA = b'start16tpl'
52 X86_RESET16_DATA = b'reset16'
53 X86_RESET16_SPL_DATA = b'reset16spl'
54 X86_RESET16_TPL_DATA = b'reset16tpl'
55 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
66 CROS_EC_RW_DATA = b'ecrw'
70 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
72 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
73 REFCODE_DATA = b'refcode'
75 # The expected size for the device tree in some tests
76 EXTRACT_DTB_SIZE = 0x3c9
78 # Properties expected to be in the device tree when update_dtb is used
79 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
81 # Extra properties expected to be in the device tree when allow-repack is used
82 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
85 class TestFunctional(unittest.TestCase):
86 """Functional tests for binman
88 Most of these use a sample .dts file to build an image and then check
89 that it looks correct. The sample files are in the test/ subdirectory
92 For each entry type a very small test file is created using fixed
93 string contents. This makes it easy to test that things look right, and
96 In some cases a 'real' file must be used - these are also supplied in
104 # Handle the case where argv[0] is 'python'
105 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
106 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
108 # Create a temporary directory for input files
109 cls._indir = tempfile.mkdtemp(prefix='binmant.')
111 # Create some test files
112 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
113 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
114 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
115 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
116 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
117 TestFunctional._MakeInputFile('me.bin', ME_DATA)
118 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
121 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
123 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
124 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
125 X86_START16_SPL_DATA)
126 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
127 X86_START16_TPL_DATA)
129 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
131 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
132 X86_RESET16_SPL_DATA)
133 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
134 X86_RESET16_TPL_DATA)
136 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
138 U_BOOT_SPL_NODTB_DATA)
139 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
140 U_BOOT_TPL_NODTB_DATA)
141 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
142 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
143 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
144 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
145 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
146 TestFunctional._MakeInputDir('devkeys')
147 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
148 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
150 # ELF file with a '_dt_ucode_base_size' symbol
151 with open(cls.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
152 TestFunctional._MakeInputFile('u-boot', fd.read())
154 # Intel flash descriptor file
155 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
156 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
158 shutil.copytree(cls.TestFile('files'),
159 os.path.join(cls._indir, 'files'))
161 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
163 # Travis-CI may have an old lz4
166 tools.Run('lz4', '--no-frame-crc', '-c',
167 os.path.join(cls._indir, 'u-boot.bin'))
172 def tearDownClass(cls):
173 """Remove the temporary input directory and its contents"""
174 if cls.preserve_indir:
175 print('Preserving input dir: %s' % cls._indir)
178 shutil.rmtree(cls._indir)
182 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
183 toolpath=None, verbosity=None):
184 """Accept arguments controlling test execution
187 preserve_indir: Preserve the shared input directory used by all
189 preserve_outdir: Preserve the output directories used by tests. Each
190 test has its own, so this is normally only useful when running a
192 toolpath: ist of paths to use for tools
194 cls.preserve_indir = preserve_indir
195 cls.preserve_outdirs = preserve_outdirs
196 cls.toolpath = toolpath
197 cls.verbosity = verbosity
200 if not self.have_lz4:
201 self.skipTest('lz4 --no-frame-crc not available')
203 def _CleanupOutputDir(self):
204 """Remove the temporary output directory"""
205 if self.preserve_outdirs:
206 print('Preserving output dir: %s' % tools.outdir)
208 tools._FinaliseForTest()
211 # Enable this to turn on debugging output
212 # tout.Init(tout.DEBUG)
213 command.test_result = None
216 """Remove the temporary output directory"""
217 self._CleanupOutputDir()
219 def _SetupImageInTmpdir(self):
220 """Set up the output image in a new temporary directory
222 This is used when an image has been generated in the output directory,
223 but we want to run binman again. This will create a new output
224 directory and fail to delete the original one.
226 This creates a new temporary directory, copies the image to it (with a
227 new name) and removes the old output directory.
231 Temporary directory to use
234 image_fname = tools.GetOutputFilename('image.bin')
235 tmpdir = tempfile.mkdtemp(prefix='binman.')
236 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
237 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
238 self._CleanupOutputDir()
239 return tmpdir, updated_fname
243 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
244 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
245 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
247 def _RunBinman(self, *args, **kwargs):
248 """Run binman using the command line
251 Arguments to pass, as a list of strings
252 kwargs: Arguments to pass to Command.RunPipe()
254 result = command.RunPipe([[self._binman_pathname] + list(args)],
255 capture=True, capture_stderr=True, raise_on_error=False)
256 if result.return_code and kwargs.get('raise_on_error', True):
257 raise Exception("Error running '%s': %s" % (' '.join(args),
258 result.stdout + result.stderr))
261 def _DoBinman(self, *argv):
262 """Run binman using directly (in the same process)
265 Arguments to pass, as a list of strings
267 Return value (0 for success)
270 args = cmdline.ParseArgs(argv)
271 args.pager = 'binman-invalid-pager'
272 args.build_dir = self._indir
274 # For testing, you can force an increase in verbosity here
275 # args.verbosity = tout.DEBUG
276 return control.Binman(args)
278 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
279 entry_args=None, images=None, use_real_dtb=False,
281 """Run binman with a given test file
284 fname: Device-tree source filename to use (e.g. 005_simple.dts)
285 debug: True to enable debugging output
286 map: True to output map files for the images
287 update_dtb: Update the offset and size of each entry in the device
288 tree before packing it into the image
289 entry_args: Dict of entry args to supply to binman
291 value: value of that arg
292 images: List of image names to build
297 if verbosity is not None:
298 args.append('-v%d' % verbosity)
300 args.append('-v%d' % self.verbosity)
302 for path in self.toolpath:
303 args += ['--toolpath', path]
304 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
310 args.append('--fake-dtb')
312 for arg, value in entry_args.items():
313 args.append('-a%s=%s' % (arg, value))
316 args += ['-i', image]
317 return self._DoBinman(*args)
319 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
320 """Set up a new test device-tree file
322 The given file is compiled and set up as the device tree to be used
326 fname: Filename of .dts file to read
327 outfile: Output filename for compiled device-tree binary
330 Contents of device-tree binary
332 tmpdir = tempfile.mkdtemp(prefix='binmant.')
333 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
334 with open(dtb, 'rb') as fd:
336 TestFunctional._MakeInputFile(outfile, data)
337 shutil.rmtree(tmpdir)
340 def _GetDtbContentsForSplTpl(self, dtb_data, name):
341 """Create a version of the main DTB for SPL or SPL
343 For testing we don't actually have different versions of the DTB. With
344 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
345 we don't normally have any unwanted nodes.
347 We still want the DTBs for SPL and TPL to be different though, since
348 otherwise it is confusing to know which one we are looking at. So add
349 an 'spl' or 'tpl' property to the top-level node.
351 dtb = fdt.Fdt.FromData(dtb_data)
353 dtb.GetNode('/binman').AddZeroProp(name)
354 dtb.Sync(auto_resize=True)
356 return dtb.GetContents()
358 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
359 update_dtb=False, entry_args=None, reset_dtbs=True):
360 """Run binman and return the resulting image
362 This runs binman with a given test file and then reads the resulting
363 output file. It is a shortcut function since most tests need to do
366 Raises an assertion failure if binman returns a non-zero exit code.
369 fname: Device-tree source filename to use (e.g. 005_simple.dts)
370 use_real_dtb: True to use the test file as the contents of
371 the u-boot-dtb entry. Normally this is not needed and the
372 test contents (the U_BOOT_DTB_DATA string) can be used.
373 But in some test we need the real contents.
374 map: True to output map files for the images
375 update_dtb: Update the offset and size of each entry in the device
376 tree before packing it into the image
380 Resulting image contents
382 Map data showing contents of image (or None if none)
383 Output device tree binary filename ('u-boot.dtb' path)
386 # Use the compiled test file as the u-boot-dtb input
388 dtb_data = self._SetupDtb(fname)
390 # For testing purposes, make a copy of the DT for SPL and TPL. Add
391 # a node indicating which it is, so aid verification.
392 for name in ['spl', 'tpl']:
393 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
394 outfile = os.path.join(self._indir, dtb_fname)
395 TestFunctional._MakeInputFile(dtb_fname,
396 self._GetDtbContentsForSplTpl(dtb_data, name))
399 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
400 entry_args=entry_args, use_real_dtb=use_real_dtb)
401 self.assertEqual(0, retcode)
402 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
404 # Find the (only) image, read it and return its contents
405 image = control.images['image']
406 image_fname = tools.GetOutputFilename('image.bin')
407 self.assertTrue(os.path.exists(image_fname))
409 map_fname = tools.GetOutputFilename('image.map')
410 with open(map_fname) as fd:
414 with open(image_fname, 'rb') as fd:
415 return fd.read(), dtb_data, map_data, out_dtb_fname
417 # Put the test file back
418 if reset_dtbs and use_real_dtb:
421 def _DoReadFileRealDtb(self, fname):
422 """Run binman with a real .dtb file and return the resulting data
425 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
428 Resulting image contents
430 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
432 def _DoReadFile(self, fname, use_real_dtb=False):
433 """Helper function which discards the device-tree binary
436 fname: Device-tree source filename to use (e.g. 005_simple.dts)
437 use_real_dtb: True to use the test file as the contents of
438 the u-boot-dtb entry. Normally this is not needed and the
439 test contents (the U_BOOT_DTB_DATA string) can be used.
440 But in some test we need the real contents.
443 Resulting image contents
445 return self._DoReadFileDtb(fname, use_real_dtb)[0]
448 def _MakeInputFile(cls, fname, contents):
449 """Create a new test input file, creating directories as needed
452 fname: Filename to create
453 contents: File contents to write in to the file
455 Full pathname of file created
457 pathname = os.path.join(cls._indir, fname)
458 dirname = os.path.dirname(pathname)
459 if dirname and not os.path.exists(dirname):
461 with open(pathname, 'wb') as fd:
466 def _MakeInputDir(cls, dirname):
467 """Create a new test input directory, creating directories as needed
470 dirname: Directory name to create
473 Full pathname of directory created
475 pathname = os.path.join(cls._indir, dirname)
476 if not os.path.exists(pathname):
477 os.makedirs(pathname)
481 def _SetupSplElf(cls, src_fname='bss_data'):
482 """Set up an ELF file with a '_dt_ucode_base_size' symbol
485 Filename of ELF file to use as SPL
487 with open(cls.TestFile(src_fname), 'rb') as fd:
488 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
491 def TestFile(cls, fname):
492 return os.path.join(cls._binman_dir, 'test', fname)
494 def AssertInList(self, grep_list, target):
495 """Assert that at least one of a list of things is in a target
498 grep_list: List of strings to check
499 target: Target string
501 for grep in grep_list:
504 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
506 def CheckNoGaps(self, entries):
507 """Check that all entries fit together without gaps
510 entries: List of entries to check
513 for entry in entries.values():
514 self.assertEqual(offset, entry.offset)
517 def GetFdtLen(self, dtb):
518 """Get the totalsize field from a device-tree binary
521 dtb: Device-tree binary contents
524 Total size of device-tree binary, from the header
526 return struct.unpack('>L', dtb[4:8])[0]
528 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
529 def AddNode(node, path):
531 path += '/' + node.name
532 for prop in node.props.values():
533 if prop.name in prop_names:
534 prop_path = path + ':' + prop.name
535 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
537 for subnode in node.subnodes:
538 AddNode(subnode, path)
541 AddNode(dtb.GetRoot(), '')
545 """Test a basic run with valid args"""
546 result = self._RunBinman('-h')
548 def testFullHelp(self):
549 """Test that the full help is displayed with -H"""
550 result = self._RunBinman('-H')
551 help_file = os.path.join(self._binman_dir, 'README')
552 # Remove possible extraneous strings
553 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
554 gothelp = result.stdout.replace(extra, '')
555 self.assertEqual(len(gothelp), os.path.getsize(help_file))
556 self.assertEqual(0, len(result.stderr))
557 self.assertEqual(0, result.return_code)
559 def testFullHelpInternal(self):
560 """Test that the full help is displayed with -H"""
562 command.test_result = command.CommandResult()
563 result = self._DoBinman('-H')
564 help_file = os.path.join(self._binman_dir, 'README')
566 command.test_result = None
569 """Test that the basic help is displayed with -h"""
570 result = self._RunBinman('-h')
571 self.assertTrue(len(result.stdout) > 200)
572 self.assertEqual(0, len(result.stderr))
573 self.assertEqual(0, result.return_code)
576 """Test that we can run it with a specific board"""
577 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
578 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
579 result = self._DoBinman('build', '-b', 'sandbox')
580 self.assertEqual(0, result)
582 def testNeedBoard(self):
583 """Test that we get an error when no board ius supplied"""
584 with self.assertRaises(ValueError) as e:
585 result = self._DoBinman('build')
586 self.assertIn("Must provide a board to process (use -b <board>)",
589 def testMissingDt(self):
590 """Test that an invalid device-tree file generates an error"""
591 with self.assertRaises(Exception) as e:
592 self._RunBinman('build', '-d', 'missing_file')
593 # We get one error from libfdt, and a different one from fdtget.
594 self.AssertInList(["Couldn't open blob from 'missing_file'",
595 'No such file or directory'], str(e.exception))
597 def testBrokenDt(self):
598 """Test that an invalid device-tree source file generates an error
600 Since this is a source file it should be compiled and the error
601 will come from the device-tree compiler (dtc).
603 with self.assertRaises(Exception) as e:
604 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
605 self.assertIn("FATAL ERROR: Unable to parse input tree",
608 def testMissingNode(self):
609 """Test that a device tree without a 'binman' node generates an error"""
610 with self.assertRaises(Exception) as e:
611 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
612 self.assertIn("does not have a 'binman' node", str(e.exception))
615 """Test that an empty binman node works OK (i.e. does nothing)"""
616 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
617 self.assertEqual(0, len(result.stderr))
618 self.assertEqual(0, result.return_code)
620 def testInvalidEntry(self):
621 """Test that an invalid entry is flagged"""
622 with self.assertRaises(Exception) as e:
623 result = self._RunBinman('build', '-d',
624 self.TestFile('004_invalid_entry.dts'))
625 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
626 "'/binman/not-a-valid-type'", str(e.exception))
628 def testSimple(self):
629 """Test a simple binman with a single file"""
630 data = self._DoReadFile('005_simple.dts')
631 self.assertEqual(U_BOOT_DATA, data)
633 def testSimpleDebug(self):
634 """Test a simple binman run with debugging enabled"""
635 self._DoTestFile('005_simple.dts', debug=True)
638 """Test that we can handle creating two images
640 This also tests image padding.
642 retcode = self._DoTestFile('006_dual_image.dts')
643 self.assertEqual(0, retcode)
645 image = control.images['image1']
646 self.assertEqual(len(U_BOOT_DATA), image.size)
647 fname = tools.GetOutputFilename('image1.bin')
648 self.assertTrue(os.path.exists(fname))
649 with open(fname, 'rb') as fd:
651 self.assertEqual(U_BOOT_DATA, data)
653 image = control.images['image2']
654 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
655 fname = tools.GetOutputFilename('image2.bin')
656 self.assertTrue(os.path.exists(fname))
657 with open(fname, 'rb') as fd:
659 self.assertEqual(U_BOOT_DATA, data[3:7])
660 self.assertEqual(tools.GetBytes(0, 3), data[:3])
661 self.assertEqual(tools.GetBytes(0, 5), data[7:])
663 def testBadAlign(self):
664 """Test that an invalid alignment value is detected"""
665 with self.assertRaises(ValueError) as e:
666 self._DoTestFile('007_bad_align.dts')
667 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
668 "of two", str(e.exception))
670 def testPackSimple(self):
671 """Test that packing works as expected"""
672 retcode = self._DoTestFile('008_pack.dts')
673 self.assertEqual(0, retcode)
674 self.assertIn('image', control.images)
675 image = control.images['image']
676 entries = image.GetEntries()
677 self.assertEqual(5, len(entries))
680 self.assertIn('u-boot', entries)
681 entry = entries['u-boot']
682 self.assertEqual(0, entry.offset)
683 self.assertEqual(len(U_BOOT_DATA), entry.size)
685 # Second u-boot, aligned to 16-byte boundary
686 self.assertIn('u-boot-align', entries)
687 entry = entries['u-boot-align']
688 self.assertEqual(16, entry.offset)
689 self.assertEqual(len(U_BOOT_DATA), entry.size)
691 # Third u-boot, size 23 bytes
692 self.assertIn('u-boot-size', entries)
693 entry = entries['u-boot-size']
694 self.assertEqual(20, entry.offset)
695 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
696 self.assertEqual(23, entry.size)
698 # Fourth u-boot, placed immediate after the above
699 self.assertIn('u-boot-next', entries)
700 entry = entries['u-boot-next']
701 self.assertEqual(43, entry.offset)
702 self.assertEqual(len(U_BOOT_DATA), entry.size)
704 # Fifth u-boot, placed at a fixed offset
705 self.assertIn('u-boot-fixed', entries)
706 entry = entries['u-boot-fixed']
707 self.assertEqual(61, entry.offset)
708 self.assertEqual(len(U_BOOT_DATA), entry.size)
710 self.assertEqual(65, image.size)
712 def testPackExtra(self):
713 """Test that extra packing feature works as expected"""
714 retcode = self._DoTestFile('009_pack_extra.dts')
716 self.assertEqual(0, retcode)
717 self.assertIn('image', control.images)
718 image = control.images['image']
719 entries = image.GetEntries()
720 self.assertEqual(5, len(entries))
722 # First u-boot with padding before and after
723 self.assertIn('u-boot', entries)
724 entry = entries['u-boot']
725 self.assertEqual(0, entry.offset)
726 self.assertEqual(3, entry.pad_before)
727 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
729 # Second u-boot has an aligned size, but it has no effect
730 self.assertIn('u-boot-align-size-nop', entries)
731 entry = entries['u-boot-align-size-nop']
732 self.assertEqual(12, entry.offset)
733 self.assertEqual(4, entry.size)
735 # Third u-boot has an aligned size too
736 self.assertIn('u-boot-align-size', entries)
737 entry = entries['u-boot-align-size']
738 self.assertEqual(16, entry.offset)
739 self.assertEqual(32, entry.size)
741 # Fourth u-boot has an aligned end
742 self.assertIn('u-boot-align-end', entries)
743 entry = entries['u-boot-align-end']
744 self.assertEqual(48, entry.offset)
745 self.assertEqual(16, entry.size)
747 # Fifth u-boot immediately afterwards
748 self.assertIn('u-boot-align-both', entries)
749 entry = entries['u-boot-align-both']
750 self.assertEqual(64, entry.offset)
751 self.assertEqual(64, entry.size)
753 self.CheckNoGaps(entries)
754 self.assertEqual(128, image.size)
756 def testPackAlignPowerOf2(self):
757 """Test that invalid entry alignment is detected"""
758 with self.assertRaises(ValueError) as e:
759 self._DoTestFile('010_pack_align_power2.dts')
760 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
761 "of two", str(e.exception))
763 def testPackAlignSizePowerOf2(self):
764 """Test that invalid entry size alignment is detected"""
765 with self.assertRaises(ValueError) as e:
766 self._DoTestFile('011_pack_align_size_power2.dts')
767 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
768 "power of two", str(e.exception))
770 def testPackInvalidAlign(self):
771 """Test detection of an offset that does not match its alignment"""
772 with self.assertRaises(ValueError) as e:
773 self._DoTestFile('012_pack_inv_align.dts')
774 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
775 "align 0x4 (4)", str(e.exception))
777 def testPackInvalidSizeAlign(self):
778 """Test that invalid entry size alignment is detected"""
779 with self.assertRaises(ValueError) as e:
780 self._DoTestFile('013_pack_inv_size_align.dts')
781 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
782 "align-size 0x4 (4)", str(e.exception))
784 def testPackOverlap(self):
785 """Test that overlapping regions are detected"""
786 with self.assertRaises(ValueError) as e:
787 self._DoTestFile('014_pack_overlap.dts')
788 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
789 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
792 def testPackEntryOverflow(self):
793 """Test that entries that overflow their size are detected"""
794 with self.assertRaises(ValueError) as e:
795 self._DoTestFile('015_pack_overflow.dts')
796 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
797 "but entry size is 0x3 (3)", str(e.exception))
799 def testPackImageOverflow(self):
800 """Test that entries which overflow the image size are detected"""
801 with self.assertRaises(ValueError) as e:
802 self._DoTestFile('016_pack_image_overflow.dts')
803 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
804 "size 0x3 (3)", str(e.exception))
806 def testPackImageSize(self):
807 """Test that the image size can be set"""
808 retcode = self._DoTestFile('017_pack_image_size.dts')
809 self.assertEqual(0, retcode)
810 self.assertIn('image', control.images)
811 image = control.images['image']
812 self.assertEqual(7, image.size)
814 def testPackImageSizeAlign(self):
815 """Test that image size alignemnt works as expected"""
816 retcode = self._DoTestFile('018_pack_image_align.dts')
817 self.assertEqual(0, retcode)
818 self.assertIn('image', control.images)
819 image = control.images['image']
820 self.assertEqual(16, image.size)
822 def testPackInvalidImageAlign(self):
823 """Test that invalid image alignment is detected"""
824 with self.assertRaises(ValueError) as e:
825 self._DoTestFile('019_pack_inv_image_align.dts')
826 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
827 "align-size 0x8 (8)", str(e.exception))
829 def testPackAlignPowerOf2(self):
830 """Test that invalid image alignment is detected"""
831 with self.assertRaises(ValueError) as e:
832 self._DoTestFile('020_pack_inv_image_align_power2.dts')
833 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
834 "two", str(e.exception))
836 def testImagePadByte(self):
837 """Test that the image pad byte can be specified"""
839 data = self._DoReadFile('021_image_pad.dts')
840 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
843 def testImageName(self):
844 """Test that image files can be named"""
845 retcode = self._DoTestFile('022_image_name.dts')
846 self.assertEqual(0, retcode)
847 image = control.images['image1']
848 fname = tools.GetOutputFilename('test-name')
849 self.assertTrue(os.path.exists(fname))
851 image = control.images['image2']
852 fname = tools.GetOutputFilename('test-name.xx')
853 self.assertTrue(os.path.exists(fname))
855 def testBlobFilename(self):
856 """Test that generic blobs can be provided by filename"""
857 data = self._DoReadFile('023_blob.dts')
858 self.assertEqual(BLOB_DATA, data)
860 def testPackSorted(self):
861 """Test that entries can be sorted"""
863 data = self._DoReadFile('024_sorted.dts')
864 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
865 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
867 def testPackZeroOffset(self):
868 """Test that an entry at offset 0 is not given a new offset"""
869 with self.assertRaises(ValueError) as e:
870 self._DoTestFile('025_pack_zero_size.dts')
871 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
872 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
875 def testPackUbootDtb(self):
876 """Test that a device tree can be added to U-Boot"""
877 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
878 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
880 def testPackX86RomNoSize(self):
881 """Test that the end-at-4gb property requires a size property"""
882 with self.assertRaises(ValueError) as e:
883 self._DoTestFile('027_pack_4gb_no_size.dts')
884 self.assertIn("Image '/binman': Section size must be provided when "
885 "using end-at-4gb", str(e.exception))
887 def test4gbAndSkipAtStartTogether(self):
888 """Test that the end-at-4gb and skip-at-size property can't be used
890 with self.assertRaises(ValueError) as e:
891 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
892 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
893 "'skip-at-start'", str(e.exception))
895 def testPackX86RomOutside(self):
896 """Test that the end-at-4gb property checks for offset boundaries"""
897 with self.assertRaises(ValueError) as e:
898 self._DoTestFile('028_pack_4gb_outside.dts')
899 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
900 "the section starting at 0xffffffe0 (4294967264)",
903 def testPackX86Rom(self):
904 """Test that a basic x86 ROM can be created"""
906 data = self._DoReadFile('029_x86-rom.dts')
907 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
908 tools.GetBytes(0, 2), data)
910 def testPackX86RomMeNoDesc(self):
911 """Test that an invalid Intel descriptor entry is detected"""
912 TestFunctional._MakeInputFile('descriptor.bin', b'')
913 with self.assertRaises(ValueError) as e:
914 self._DoTestFile('031_x86-rom-me.dts')
915 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
918 def testPackX86RomBadDesc(self):
919 """Test that the Intel requires a descriptor entry"""
920 with self.assertRaises(ValueError) as e:
921 self._DoTestFile('030_x86-rom-me-no-desc.dts')
922 self.assertIn("Node '/binman/intel-me': No offset set with "
923 "offset-unset: should another entry provide this correct "
924 "offset?", str(e.exception))
926 def testPackX86RomMe(self):
927 """Test that an x86 ROM with an ME region can be created"""
928 data = self._DoReadFile('031_x86-rom-me.dts')
929 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
930 if data[:0x1000] != expected_desc:
931 self.fail('Expected descriptor binary at start of image')
932 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
934 def testPackVga(self):
935 """Test that an image with a VGA binary can be created"""
936 data = self._DoReadFile('032_intel-vga.dts')
937 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
939 def testPackStart16(self):
940 """Test that an image with an x86 start16 region can be created"""
941 data = self._DoReadFile('033_x86-start16.dts')
942 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
944 def testPackPowerpcMpc85xxBootpgResetvec(self):
945 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
947 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
948 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
950 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
951 """Handle running a test for insertion of microcode
954 dts_fname: Name of test .dts file
955 nodtb_data: Data that we expect in the first section
956 ucode_second: True if the microsecond entry is second instead of
961 Contents of first region (U-Boot or SPL)
962 Offset and size components of microcode pointer, as inserted
963 in the above (two 4-byte words)
965 data = self._DoReadFile(dts_fname, True)
967 # Now check the device tree has no microcode
969 ucode_content = data[len(nodtb_data):]
970 ucode_pos = len(nodtb_data)
971 dtb_with_ucode = ucode_content[16:]
972 fdt_len = self.GetFdtLen(dtb_with_ucode)
974 dtb_with_ucode = data[len(nodtb_data):]
975 fdt_len = self.GetFdtLen(dtb_with_ucode)
976 ucode_content = dtb_with_ucode[fdt_len:]
977 ucode_pos = len(nodtb_data) + fdt_len
978 fname = tools.GetOutputFilename('test.dtb')
979 with open(fname, 'wb') as fd:
980 fd.write(dtb_with_ucode)
981 dtb = fdt.FdtScan(fname)
982 ucode = dtb.GetNode('/microcode')
983 self.assertTrue(ucode)
984 for node in ucode.subnodes:
985 self.assertFalse(node.props.get('data'))
987 # Check that the microcode appears immediately after the Fdt
988 # This matches the concatenation of the data properties in
989 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
990 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
992 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
994 # Check that the microcode pointer was inserted. It should match the
995 # expected offset and size
996 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
998 u_boot = data[:len(nodtb_data)]
999 return u_boot, pos_and_size
1001 def testPackUbootMicrocode(self):
1002 """Test that x86 microcode can be handled correctly
1004 We expect to see the following in the image, in order:
1005 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1007 u-boot.dtb with the microcode removed
1010 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1012 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1013 b' somewhere in here', first)
1015 def _RunPackUbootSingleMicrocode(self):
1016 """Test that x86 microcode can be handled correctly
1018 We expect to see the following in the image, in order:
1019 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1021 u-boot.dtb with the microcode
1022 an empty microcode region
1024 # We need the libfdt library to run this test since only that allows
1025 # finding the offset of a property. This is required by
1026 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1027 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1029 second = data[len(U_BOOT_NODTB_DATA):]
1031 fdt_len = self.GetFdtLen(second)
1032 third = second[fdt_len:]
1033 second = second[:fdt_len]
1035 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1036 self.assertIn(ucode_data, second)
1037 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1039 # Check that the microcode pointer was inserted. It should match the
1040 # expected offset and size
1041 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1043 first = data[:len(U_BOOT_NODTB_DATA)]
1044 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1045 b' somewhere in here', first)
1047 def testPackUbootSingleMicrocode(self):
1048 """Test that x86 microcode can be handled correctly with fdt_normal.
1050 self._RunPackUbootSingleMicrocode()
1052 def testUBootImg(self):
1053 """Test that u-boot.img can be put in a file"""
1054 data = self._DoReadFile('036_u_boot_img.dts')
1055 self.assertEqual(U_BOOT_IMG_DATA, data)
1057 def testNoMicrocode(self):
1058 """Test that a missing microcode region is detected"""
1059 with self.assertRaises(ValueError) as e:
1060 self._DoReadFile('037_x86_no_ucode.dts', True)
1061 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1062 "node found in ", str(e.exception))
1064 def testMicrocodeWithoutNode(self):
1065 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1066 with self.assertRaises(ValueError) as e:
1067 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1068 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1069 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1071 def testMicrocodeWithoutNode2(self):
1072 """Test that a missing u-boot-ucode node is detected"""
1073 with self.assertRaises(ValueError) as e:
1074 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1075 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1076 "microcode region u-boot-ucode", str(e.exception))
1078 def testMicrocodeWithoutPtrInElf(self):
1079 """Test that a U-Boot binary without the microcode symbol is detected"""
1080 # ELF file without a '_dt_ucode_base_size' symbol
1082 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1083 TestFunctional._MakeInputFile('u-boot', fd.read())
1085 with self.assertRaises(ValueError) as e:
1086 self._RunPackUbootSingleMicrocode()
1087 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1088 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1091 # Put the original file back
1092 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1093 TestFunctional._MakeInputFile('u-boot', fd.read())
1095 def testMicrocodeNotInImage(self):
1096 """Test that microcode must be placed within the image"""
1097 with self.assertRaises(ValueError) as e:
1098 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1099 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1100 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1101 "section ranging from 00000000 to 0000002e", str(e.exception))
1103 def testWithoutMicrocode(self):
1104 """Test that we can cope with an image without microcode (e.g. qemu)"""
1105 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1106 TestFunctional._MakeInputFile('u-boot', fd.read())
1107 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1109 # Now check the device tree has no microcode
1110 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1111 second = data[len(U_BOOT_NODTB_DATA):]
1113 fdt_len = self.GetFdtLen(second)
1114 self.assertEqual(dtb, second[:fdt_len])
1116 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1117 third = data[used_len:]
1118 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1120 def testUnknownPosSize(self):
1121 """Test that microcode must be placed within the image"""
1122 with self.assertRaises(ValueError) as e:
1123 self._DoReadFile('041_unknown_pos_size.dts', True)
1124 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1125 "entry 'invalid-entry'", str(e.exception))
1127 def testPackFsp(self):
1128 """Test that an image with a FSP binary can be created"""
1129 data = self._DoReadFile('042_intel-fsp.dts')
1130 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1132 def testPackCmc(self):
1133 """Test that an image with a CMC binary can be created"""
1134 data = self._DoReadFile('043_intel-cmc.dts')
1135 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1137 def testPackVbt(self):
1138 """Test that an image with a VBT binary can be created"""
1139 data = self._DoReadFile('046_intel-vbt.dts')
1140 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1142 def testSplBssPad(self):
1143 """Test that we can pad SPL's BSS with zeros"""
1144 # ELF file with a '__bss_size' symbol
1146 data = self._DoReadFile('047_spl_bss_pad.dts')
1147 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1150 def testSplBssPadMissing(self):
1151 """Test that a missing symbol is detected"""
1152 self._SetupSplElf('u_boot_ucode_ptr')
1153 with self.assertRaises(ValueError) as e:
1154 self._DoReadFile('047_spl_bss_pad.dts')
1155 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1158 def testPackStart16Spl(self):
1159 """Test that an image with an x86 start16 SPL region can be created"""
1160 data = self._DoReadFile('048_x86-start16-spl.dts')
1161 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1163 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1164 """Helper function for microcode tests
1166 We expect to see the following in the image, in order:
1167 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1169 u-boot.dtb with the microcode removed
1173 dts: Device tree file to use for test
1174 ucode_second: True if the microsecond entry is second instead of
1177 self._SetupSplElf('u_boot_ucode_ptr')
1178 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1179 ucode_second=ucode_second)
1180 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1181 b'ter somewhere in here', first)
1183 def testPackUbootSplMicrocode(self):
1184 """Test that x86 microcode can be handled correctly in SPL"""
1185 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1187 def testPackUbootSplMicrocodeReorder(self):
1188 """Test that order doesn't matter for microcode entries
1190 This is the same as testPackUbootSplMicrocode but when we process the
1191 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1192 entry, so we reply on binman to try later.
1194 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1197 def testPackMrc(self):
1198 """Test that an image with an MRC binary can be created"""
1199 data = self._DoReadFile('050_intel_mrc.dts')
1200 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1202 def testSplDtb(self):
1203 """Test that an image with spl/u-boot-spl.dtb can be created"""
1204 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1205 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1207 def testSplNoDtb(self):
1208 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1209 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1210 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1212 def testSymbols(self):
1213 """Test binman can assign symbols embedded in U-Boot"""
1214 elf_fname = self.TestFile('u_boot_binman_syms')
1215 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1216 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1217 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1219 self._SetupSplElf('u_boot_binman_syms')
1220 data = self._DoReadFile('053_symbols.dts')
1221 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1222 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1223 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1224 U_BOOT_SPL_DATA[16:])
1225 self.assertEqual(expected, data)
1227 def testPackUnitAddress(self):
1228 """Test that we support multiple binaries with the same name"""
1229 data = self._DoReadFile('054_unit_address.dts')
1230 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1232 def testSections(self):
1233 """Basic test of sections"""
1234 data = self._DoReadFile('055_sections.dts')
1235 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1236 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1237 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1238 self.assertEqual(expected, data)
1241 """Tests outputting a map of the images"""
1242 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1243 self.assertEqual('''ImagePos Offset Size Name
1244 00000000 00000000 00000028 main-section
1245 00000000 00000000 00000010 section@0
1246 00000000 00000000 00000004 u-boot
1247 00000010 00000010 00000010 section@1
1248 00000010 00000000 00000004 u-boot
1249 00000020 00000020 00000004 section@2
1250 00000020 00000000 00000004 u-boot
1253 def testNamePrefix(self):
1254 """Tests that name prefixes are used"""
1255 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1256 self.assertEqual('''ImagePos Offset Size Name
1257 00000000 00000000 00000028 main-section
1258 00000000 00000000 00000010 section@0
1259 00000000 00000000 00000004 ro-u-boot
1260 00000010 00000010 00000010 section@1
1261 00000010 00000000 00000004 rw-u-boot
1264 def testUnknownContents(self):
1265 """Test that obtaining the contents works as expected"""
1266 with self.assertRaises(ValueError) as e:
1267 self._DoReadFile('057_unknown_contents.dts', True)
1268 self.assertIn("Image '/binman': Internal error: Could not complete "
1269 "processing of contents: remaining [<_testing.Entry__testing ",
1272 def testBadChangeSize(self):
1273 """Test that trying to change the size of an entry fails"""
1275 state.SetAllowEntryExpansion(False)
1276 with self.assertRaises(ValueError) as e:
1277 self._DoReadFile('059_change_size.dts', True)
1278 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1281 state.SetAllowEntryExpansion(True)
1283 def testUpdateFdt(self):
1284 """Test that we can update the device tree with offset/size info"""
1285 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1287 dtb = fdt.Fdt(out_dtb_fname)
1289 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1293 '_testing:offset': 32,
1295 '_testing:image-pos': 32,
1296 'section@0/u-boot:offset': 0,
1297 'section@0/u-boot:size': len(U_BOOT_DATA),
1298 'section@0/u-boot:image-pos': 0,
1299 'section@0:offset': 0,
1300 'section@0:size': 16,
1301 'section@0:image-pos': 0,
1303 'section@1/u-boot:offset': 0,
1304 'section@1/u-boot:size': len(U_BOOT_DATA),
1305 'section@1/u-boot:image-pos': 16,
1306 'section@1:offset': 16,
1307 'section@1:size': 16,
1308 'section@1:image-pos': 16,
1312 def testUpdateFdtBad(self):
1313 """Test that we detect when ProcessFdt never completes"""
1314 with self.assertRaises(ValueError) as e:
1315 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1316 self.assertIn('Could not complete processing of Fdt: remaining '
1317 '[<_testing.Entry__testing', str(e.exception))
1319 def testEntryArgs(self):
1320 """Test passing arguments to entries from the command line"""
1322 'test-str-arg': 'test1',
1323 'test-int-arg': '456',
1325 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1326 self.assertIn('image', control.images)
1327 entry = control.images['image'].GetEntries()['_testing']
1328 self.assertEqual('test0', entry.test_str_fdt)
1329 self.assertEqual('test1', entry.test_str_arg)
1330 self.assertEqual(123, entry.test_int_fdt)
1331 self.assertEqual(456, entry.test_int_arg)
1333 def testEntryArgsMissing(self):
1334 """Test missing arguments and properties"""
1336 'test-int-arg': '456',
1338 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1339 entry = control.images['image'].GetEntries()['_testing']
1340 self.assertEqual('test0', entry.test_str_fdt)
1341 self.assertEqual(None, entry.test_str_arg)
1342 self.assertEqual(None, entry.test_int_fdt)
1343 self.assertEqual(456, entry.test_int_arg)
1345 def testEntryArgsRequired(self):
1346 """Test missing arguments and properties"""
1348 'test-int-arg': '456',
1350 with self.assertRaises(ValueError) as e:
1351 self._DoReadFileDtb('064_entry_args_required.dts')
1352 self.assertIn("Node '/binman/_testing': Missing required "
1353 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1356 def testEntryArgsInvalidFormat(self):
1357 """Test that an invalid entry-argument format is detected"""
1358 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1360 with self.assertRaises(ValueError) as e:
1361 self._DoBinman(*args)
1362 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1364 def testEntryArgsInvalidInteger(self):
1365 """Test that an invalid entry-argument integer is detected"""
1367 'test-int-arg': 'abc',
1369 with self.assertRaises(ValueError) as e:
1370 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1371 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1372 "'test-int-arg' (value 'abc') to integer",
1375 def testEntryArgsInvalidDatatype(self):
1376 """Test that an invalid entry-argument datatype is detected
1378 This test could be written in entry_test.py except that it needs
1379 access to control.entry_args, which seems more than that module should
1383 'test-bad-datatype-arg': '12',
1385 with self.assertRaises(ValueError) as e:
1386 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1387 entry_args=entry_args)
1388 self.assertIn('GetArg() internal error: Unknown data type ',
1392 """Test for a text entry type"""
1394 'test-id': TEXT_DATA,
1395 'test-id2': TEXT_DATA2,
1396 'test-id3': TEXT_DATA3,
1398 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1399 entry_args=entry_args)
1400 expected = (tools.ToBytes(TEXT_DATA) +
1401 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1402 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1403 b'some text' + b'more text')
1404 self.assertEqual(expected, data)
1406 def testEntryDocs(self):
1407 """Test for creation of entry documentation"""
1408 with test_util.capture_sys_output() as (stdout, stderr):
1409 control.WriteEntryDocs(binman.GetEntryModules())
1410 self.assertTrue(len(stdout.getvalue()) > 0)
1412 def testEntryDocsMissing(self):
1413 """Test handling of missing entry documentation"""
1414 with self.assertRaises(ValueError) as e:
1415 with test_util.capture_sys_output() as (stdout, stderr):
1416 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1417 self.assertIn('Documentation is missing for modules: u_boot',
1421 """Basic test of generation of a flashrom fmap"""
1422 data = self._DoReadFile('067_fmap.dts')
1423 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1424 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1425 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1426 self.assertEqual(expected, data[:32])
1427 self.assertEqual(b'__FMAP__', fhdr.signature)
1428 self.assertEqual(1, fhdr.ver_major)
1429 self.assertEqual(0, fhdr.ver_minor)
1430 self.assertEqual(0, fhdr.base)
1431 self.assertEqual(16 + 16 +
1432 fmap_util.FMAP_HEADER_LEN +
1433 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1434 self.assertEqual(b'FMAP', fhdr.name)
1435 self.assertEqual(3, fhdr.nareas)
1436 for fentry in fentries:
1437 self.assertEqual(0, fentry.flags)
1439 self.assertEqual(0, fentries[0].offset)
1440 self.assertEqual(4, fentries[0].size)
1441 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1443 self.assertEqual(16, fentries[1].offset)
1444 self.assertEqual(4, fentries[1].size)
1445 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1447 self.assertEqual(32, fentries[2].offset)
1448 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1449 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1450 self.assertEqual(b'FMAP', fentries[2].name)
1452 def testBlobNamedByArg(self):
1453 """Test we can add a blob with the filename coming from an entry arg"""
1455 'cros-ec-rw-path': 'ecrw.bin',
1457 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1458 entry_args=entry_args)
1461 """Test for an fill entry type"""
1462 data = self._DoReadFile('069_fill.dts')
1463 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1464 self.assertEqual(expected, data)
1466 def testFillNoSize(self):
1467 """Test for an fill entry type with no size"""
1468 with self.assertRaises(ValueError) as e:
1469 self._DoReadFile('070_fill_no_size.dts')
1470 self.assertIn("'fill' entry must have a size property",
1473 def _HandleGbbCommand(self, pipe_list):
1474 """Fake calls to the futility utility"""
1475 if pipe_list[0][0] == 'futility':
1476 fname = pipe_list[0][-1]
1477 # Append our GBB data to the file, which will happen every time the
1478 # futility command is called.
1479 with open(fname, 'ab') as fd:
1481 return command.CommandResult()
1484 """Test for the Chromium OS Google Binary Block"""
1485 command.test_result = self._HandleGbbCommand
1487 'keydir': 'devkeys',
1488 'bmpblk': 'bmpblk.bin',
1490 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1493 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1494 tools.GetBytes(0, 0x2180 - 16))
1495 self.assertEqual(expected, data)
1497 def testGbbTooSmall(self):
1498 """Test for the Chromium OS Google Binary Block being large enough"""
1499 with self.assertRaises(ValueError) as e:
1500 self._DoReadFileDtb('072_gbb_too_small.dts')
1501 self.assertIn("Node '/binman/gbb': GBB is too small",
1504 def testGbbNoSize(self):
1505 """Test for the Chromium OS Google Binary Block having a size"""
1506 with self.assertRaises(ValueError) as e:
1507 self._DoReadFileDtb('073_gbb_no_size.dts')
1508 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1511 def _HandleVblockCommand(self, pipe_list):
1512 """Fake calls to the futility utility"""
1513 if pipe_list[0][0] == 'futility':
1514 fname = pipe_list[0][3]
1515 with open(fname, 'wb') as fd:
1516 fd.write(VBLOCK_DATA)
1517 return command.CommandResult()
1519 def testVblock(self):
1520 """Test for the Chromium OS Verified Boot Block"""
1521 command.test_result = self._HandleVblockCommand
1523 'keydir': 'devkeys',
1525 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1526 entry_args=entry_args)
1527 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1528 self.assertEqual(expected, data)
1530 def testVblockNoContent(self):
1531 """Test we detect a vblock which has no content to sign"""
1532 with self.assertRaises(ValueError) as e:
1533 self._DoReadFile('075_vblock_no_content.dts')
1534 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1535 'property', str(e.exception))
1537 def testVblockBadPhandle(self):
1538 """Test that we detect a vblock with an invalid phandle in contents"""
1539 with self.assertRaises(ValueError) as e:
1540 self._DoReadFile('076_vblock_bad_phandle.dts')
1541 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1542 '1000', str(e.exception))
1544 def testVblockBadEntry(self):
1545 """Test that we detect an entry that points to a non-entry"""
1546 with self.assertRaises(ValueError) as e:
1547 self._DoReadFile('077_vblock_bad_entry.dts')
1548 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1549 "'other'", str(e.exception))
1552 """Test that an image with TPL and ots device tree can be created"""
1553 # ELF file with a '__bss_size' symbol
1554 with open(self.TestFile('bss_data'), 'rb') as fd:
1555 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1556 data = self._DoReadFile('078_u_boot_tpl.dts')
1557 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1559 def testUsesPos(self):
1560 """Test that the 'pos' property cannot be used anymore"""
1561 with self.assertRaises(ValueError) as e:
1562 data = self._DoReadFile('079_uses_pos.dts')
1563 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1564 "'pos'", str(e.exception))
1566 def testFillZero(self):
1567 """Test for an fill entry type with a size of 0"""
1568 data = self._DoReadFile('080_fill_empty.dts')
1569 self.assertEqual(tools.GetBytes(0, 16), data)
1571 def testTextMissing(self):
1572 """Test for a text entry type where there is no text"""
1573 with self.assertRaises(ValueError) as e:
1574 self._DoReadFileDtb('066_text.dts',)
1575 self.assertIn("Node '/binman/text': No value provided for text label "
1576 "'test-id'", str(e.exception))
1578 def testPackStart16Tpl(self):
1579 """Test that an image with an x86 start16 TPL region can be created"""
1580 data = self._DoReadFile('081_x86-start16-tpl.dts')
1581 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1583 def testSelectImage(self):
1584 """Test that we can select which images to build"""
1585 expected = 'Skipping images: image1'
1587 # We should only get the expected message in verbose mode
1588 for verbosity in (0, 2):
1589 with test_util.capture_sys_output() as (stdout, stderr):
1590 retcode = self._DoTestFile('006_dual_image.dts',
1591 verbosity=verbosity,
1593 self.assertEqual(0, retcode)
1595 self.assertIn(expected, stdout.getvalue())
1597 self.assertNotIn(expected, stdout.getvalue())
1599 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1600 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1601 self._CleanupOutputDir()
1603 def testUpdateFdtAll(self):
1604 """Test that all device trees are updated with offset/size info"""
1605 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1608 'section:image-pos': 0,
1609 'u-boot-tpl-dtb:size': 513,
1610 'u-boot-spl-dtb:size': 513,
1611 'u-boot-spl-dtb:offset': 493,
1613 'section/u-boot-dtb:image-pos': 0,
1614 'u-boot-spl-dtb:image-pos': 493,
1615 'section/u-boot-dtb:size': 493,
1616 'u-boot-tpl-dtb:image-pos': 1006,
1617 'section/u-boot-dtb:offset': 0,
1618 'section:size': 493,
1620 'section:offset': 0,
1621 'u-boot-tpl-dtb:offset': 1006,
1625 # We expect three device-tree files in the output, one after the other.
1626 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1627 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1628 # main U-Boot tree. All three should have the same postions and offset.
1630 for item in ['', 'spl', 'tpl']:
1631 dtb = fdt.Fdt.FromData(data[start:])
1633 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1635 expected = dict(base_expected)
1638 self.assertEqual(expected, props)
1639 start += dtb._fdt_obj.totalsize()
1641 def testUpdateFdtOutput(self):
1642 """Test that output DTB files are updated"""
1644 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1645 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1647 # Unfortunately, compiling a source file always results in a file
1648 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1649 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1650 # binman as a file called u-boot.dtb. To fix this, copy the file
1651 # over to the expected place.
1652 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1653 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1655 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1656 'tpl/u-boot-tpl.dtb.out']:
1657 dtb = fdt.Fdt.FromData(data[start:])
1658 size = dtb._fdt_obj.totalsize()
1659 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1660 outdata = tools.ReadFile(pathname)
1661 name = os.path.split(fname)[0]
1664 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1666 orig_indata = dtb_data
1667 self.assertNotEqual(outdata, orig_indata,
1668 "Expected output file '%s' be updated" % pathname)
1669 self.assertEqual(outdata, data[start:start + size],
1670 "Expected output file '%s' to match output image" %
1676 def _decompress(self, data):
1677 return tools.Decompress(data, 'lz4')
1679 def testCompress(self):
1680 """Test compression of blobs"""
1682 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1683 use_real_dtb=True, update_dtb=True)
1684 dtb = fdt.Fdt(out_dtb_fname)
1686 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1687 orig = self._decompress(data)
1688 self.assertEquals(COMPRESS_DATA, orig)
1690 'blob:uncomp-size': len(COMPRESS_DATA),
1691 'blob:size': len(data),
1694 self.assertEqual(expected, props)
1696 def testFiles(self):
1697 """Test bringing in multiple files"""
1698 data = self._DoReadFile('084_files.dts')
1699 self.assertEqual(FILES_DATA, data)
1701 def testFilesCompress(self):
1702 """Test bringing in multiple files and compressing them"""
1704 data = self._DoReadFile('085_files_compress.dts')
1706 image = control.images['image']
1707 entries = image.GetEntries()
1708 files = entries['files']
1709 entries = files._entries
1712 for i in range(1, 3):
1714 start = entries[key].image_pos
1715 len = entries[key].size
1716 chunk = data[start:start + len]
1717 orig += self._decompress(chunk)
1719 self.assertEqual(FILES_DATA, orig)
1721 def testFilesMissing(self):
1722 """Test missing files"""
1723 with self.assertRaises(ValueError) as e:
1724 data = self._DoReadFile('086_files_none.dts')
1725 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1726 'no files', str(e.exception))
1728 def testFilesNoPattern(self):
1729 """Test missing files"""
1730 with self.assertRaises(ValueError) as e:
1731 data = self._DoReadFile('087_files_no_pattern.dts')
1732 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1735 def testExpandSize(self):
1736 """Test an expanding entry"""
1737 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1739 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1740 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1741 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1742 tools.GetBytes(ord('d'), 8))
1743 self.assertEqual(expect, data)
1744 self.assertEqual('''ImagePos Offset Size Name
1745 00000000 00000000 00000028 main-section
1746 00000000 00000000 00000008 fill
1747 00000008 00000008 00000004 u-boot
1748 0000000c 0000000c 00000004 section
1749 0000000c 00000000 00000003 intel-mrc
1750 00000010 00000010 00000004 u-boot2
1751 00000014 00000014 0000000c section2
1752 00000014 00000000 00000008 fill
1753 0000001c 00000008 00000004 u-boot
1754 00000020 00000020 00000008 fill2
1757 def testExpandSizeBad(self):
1758 """Test an expanding entry which fails to provide contents"""
1759 with test_util.capture_sys_output() as (stdout, stderr):
1760 with self.assertRaises(ValueError) as e:
1761 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1762 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1763 'expanding entry', str(e.exception))
1766 """Test hashing of the contents of an entry"""
1767 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1768 use_real_dtb=True, update_dtb=True)
1769 dtb = fdt.Fdt(out_dtb_fname)
1771 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1772 m = hashlib.sha256()
1773 m.update(U_BOOT_DATA)
1774 self.assertEqual(m.digest(), b''.join(hash_node.value))
1776 def testHashNoAlgo(self):
1777 with self.assertRaises(ValueError) as e:
1778 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1779 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1780 'hash node', str(e.exception))
1782 def testHashBadAlgo(self):
1783 with self.assertRaises(ValueError) as e:
1784 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1785 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1788 def testHashSection(self):
1789 """Test hashing of the contents of an entry"""
1790 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1791 use_real_dtb=True, update_dtb=True)
1792 dtb = fdt.Fdt(out_dtb_fname)
1794 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1795 m = hashlib.sha256()
1796 m.update(U_BOOT_DATA)
1797 m.update(tools.GetBytes(ord('a'), 16))
1798 self.assertEqual(m.digest(), b''.join(hash_node.value))
1800 def testPackUBootTplMicrocode(self):
1801 """Test that x86 microcode can be handled correctly in TPL
1803 We expect to see the following in the image, in order:
1804 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1806 u-boot-tpl.dtb with the microcode removed
1809 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1810 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1811 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1812 U_BOOT_TPL_NODTB_DATA)
1813 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1814 b'ter somewhere in here', first)
1816 def testFmapX86(self):
1817 """Basic test of generation of a flashrom fmap"""
1818 data = self._DoReadFile('094_fmap_x86.dts')
1819 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1820 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1821 self.assertEqual(expected, data[:32])
1822 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1824 self.assertEqual(0x100, fhdr.image_size)
1826 self.assertEqual(0, fentries[0].offset)
1827 self.assertEqual(4, fentries[0].size)
1828 self.assertEqual(b'U_BOOT', fentries[0].name)
1830 self.assertEqual(4, fentries[1].offset)
1831 self.assertEqual(3, fentries[1].size)
1832 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1834 self.assertEqual(32, fentries[2].offset)
1835 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1836 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1837 self.assertEqual(b'FMAP', fentries[2].name)
1839 def testFmapX86Section(self):
1840 """Basic test of generation of a flashrom fmap"""
1841 data = self._DoReadFile('095_fmap_x86_section.dts')
1842 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1843 self.assertEqual(expected, data[:32])
1844 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1846 self.assertEqual(0x100, fhdr.image_size)
1848 self.assertEqual(0, fentries[0].offset)
1849 self.assertEqual(4, fentries[0].size)
1850 self.assertEqual(b'U_BOOT', fentries[0].name)
1852 self.assertEqual(4, fentries[1].offset)
1853 self.assertEqual(3, fentries[1].size)
1854 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1856 self.assertEqual(36, fentries[2].offset)
1857 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1858 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1859 self.assertEqual(b'FMAP', fentries[2].name)
1862 """Basic test of ELF entries"""
1864 with open(self.TestFile('bss_data'), 'rb') as fd:
1865 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1866 with open(self.TestFile('bss_data'), 'rb') as fd:
1867 TestFunctional._MakeInputFile('-boot', fd.read())
1868 data = self._DoReadFile('096_elf.dts')
1870 def testElfStrip(self):
1871 """Basic test of ELF entries"""
1873 with open(self.TestFile('bss_data'), 'rb') as fd:
1874 TestFunctional._MakeInputFile('-boot', fd.read())
1875 data = self._DoReadFile('097_elf_strip.dts')
1877 def testPackOverlapMap(self):
1878 """Test that overlapping regions are detected"""
1879 with test_util.capture_sys_output() as (stdout, stderr):
1880 with self.assertRaises(ValueError) as e:
1881 self._DoTestFile('014_pack_overlap.dts', map=True)
1882 map_fname = tools.GetOutputFilename('image.map')
1883 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1886 # We should not get an inmage, but there should be a map file
1887 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1888 self.assertTrue(os.path.exists(map_fname))
1889 map_data = tools.ReadFile(map_fname, binary=False)
1890 self.assertEqual('''ImagePos Offset Size Name
1891 <none> 00000000 00000007 main-section
1892 <none> 00000000 00000004 u-boot
1893 <none> 00000003 00000004 u-boot-align
1896 def testPackRefCode(self):
1897 """Test that an image with an Intel Reference code binary works"""
1898 data = self._DoReadFile('100_intel_refcode.dts')
1899 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1901 def testSectionOffset(self):
1902 """Tests use of a section with an offset"""
1903 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1905 self.assertEqual('''ImagePos Offset Size Name
1906 00000000 00000000 00000038 main-section
1907 00000004 00000004 00000010 section@0
1908 00000004 00000000 00000004 u-boot
1909 00000018 00000018 00000010 section@1
1910 00000018 00000000 00000004 u-boot
1911 0000002c 0000002c 00000004 section@2
1912 0000002c 00000000 00000004 u-boot
1914 self.assertEqual(data,
1915 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1916 tools.GetBytes(0x21, 12) +
1917 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1918 tools.GetBytes(0x61, 12) +
1919 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1920 tools.GetBytes(0x26, 8))
1922 def testCbfsRaw(self):
1923 """Test base handling of a Coreboot Filesystem (CBFS)
1925 The exact contents of the CBFS is verified by similar tests in
1926 cbfs_util_test.py. The tests here merely check that the files added to
1927 the CBFS can be found in the final image.
1929 data = self._DoReadFile('102_cbfs_raw.dts')
1932 cbfs = cbfs_util.CbfsReader(data)
1933 self.assertEqual(size, cbfs.rom_size)
1935 self.assertIn('u-boot-dtb', cbfs.files)
1936 cfile = cbfs.files['u-boot-dtb']
1937 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1939 def testCbfsArch(self):
1940 """Test on non-x86 architecture"""
1941 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1944 cbfs = cbfs_util.CbfsReader(data)
1945 self.assertEqual(size, cbfs.rom_size)
1947 self.assertIn('u-boot-dtb', cbfs.files)
1948 cfile = cbfs.files['u-boot-dtb']
1949 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1951 def testCbfsStage(self):
1952 """Tests handling of a Coreboot Filesystem (CBFS)"""
1953 if not elf.ELF_TOOLS:
1954 self.skipTest('Python elftools not available')
1955 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1956 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1959 data = self._DoReadFile('104_cbfs_stage.dts')
1960 cbfs = cbfs_util.CbfsReader(data)
1961 self.assertEqual(size, cbfs.rom_size)
1963 self.assertIn('u-boot', cbfs.files)
1964 cfile = cbfs.files['u-boot']
1965 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1967 def testCbfsRawCompress(self):
1968 """Test handling of compressing raw files"""
1970 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1973 cbfs = cbfs_util.CbfsReader(data)
1974 self.assertIn('u-boot', cbfs.files)
1975 cfile = cbfs.files['u-boot']
1976 self.assertEqual(COMPRESS_DATA, cfile.data)
1978 def testCbfsBadArch(self):
1979 """Test handling of a bad architecture"""
1980 with self.assertRaises(ValueError) as e:
1981 self._DoReadFile('106_cbfs_bad_arch.dts')
1982 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1984 def testCbfsNoSize(self):
1985 """Test handling of a missing size property"""
1986 with self.assertRaises(ValueError) as e:
1987 self._DoReadFile('107_cbfs_no_size.dts')
1988 self.assertIn('entry must have a size property', str(e.exception))
1990 def testCbfsNoCOntents(self):
1991 """Test handling of a CBFS entry which does not provide contentsy"""
1992 with self.assertRaises(ValueError) as e:
1993 self._DoReadFile('108_cbfs_no_contents.dts')
1994 self.assertIn('Could not complete processing of contents',
1997 def testCbfsBadCompress(self):
1998 """Test handling of a bad architecture"""
1999 with self.assertRaises(ValueError) as e:
2000 self._DoReadFile('109_cbfs_bad_compress.dts')
2001 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2004 def testCbfsNamedEntries(self):
2005 """Test handling of named entries"""
2006 data = self._DoReadFile('110_cbfs_name.dts')
2008 cbfs = cbfs_util.CbfsReader(data)
2009 self.assertIn('FRED', cbfs.files)
2010 cfile1 = cbfs.files['FRED']
2011 self.assertEqual(U_BOOT_DATA, cfile1.data)
2013 self.assertIn('hello', cbfs.files)
2014 cfile2 = cbfs.files['hello']
2015 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2017 def _SetupIfwi(self, fname):
2018 """Set up to run an IFWI test
2021 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2025 # Intel Integrated Firmware Image (IFWI) file
2026 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2028 TestFunctional._MakeInputFile(fname,data)
2030 def _CheckIfwi(self, data):
2031 """Check that an image with an IFWI contains the correct output
2034 data: Conents of output file
2036 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2037 if data[:0x1000] != expected_desc:
2038 self.fail('Expected descriptor binary at start of image')
2040 # We expect to find the TPL wil in subpart IBBP entry IBBL
2041 image_fname = tools.GetOutputFilename('image.bin')
2042 tpl_fname = tools.GetOutputFilename('tpl.out')
2043 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2044 subpart='IBBP', entry_name='IBBL')
2046 tpl_data = tools.ReadFile(tpl_fname)
2047 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2049 def testPackX86RomIfwi(self):
2050 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2051 self._SetupIfwi('fitimage.bin')
2052 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2053 self._CheckIfwi(data)
2055 def testPackX86RomIfwiNoDesc(self):
2056 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2057 self._SetupIfwi('ifwi.bin')
2058 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2059 self._CheckIfwi(data)
2061 def testPackX86RomIfwiNoData(self):
2062 """Test that an x86 ROM with IFWI handles missing data"""
2063 self._SetupIfwi('ifwi.bin')
2064 with self.assertRaises(ValueError) as e:
2065 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2066 self.assertIn('Could not complete processing of contents',
2069 def testCbfsOffset(self):
2070 """Test a CBFS with files at particular offsets
2072 Like all CFBS tests, this is just checking the logic that calls
2073 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2075 data = self._DoReadFile('114_cbfs_offset.dts')
2078 cbfs = cbfs_util.CbfsReader(data)
2079 self.assertEqual(size, cbfs.rom_size)
2081 self.assertIn('u-boot', cbfs.files)
2082 cfile = cbfs.files['u-boot']
2083 self.assertEqual(U_BOOT_DATA, cfile.data)
2084 self.assertEqual(0x40, cfile.cbfs_offset)
2086 self.assertIn('u-boot-dtb', cbfs.files)
2087 cfile2 = cbfs.files['u-boot-dtb']
2088 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2089 self.assertEqual(0x140, cfile2.cbfs_offset)
2091 def testFdtmap(self):
2092 """Test an FDT map can be inserted in the image"""
2093 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2094 fdtmap_data = data[len(U_BOOT_DATA):]
2095 magic = fdtmap_data[:8]
2096 self.assertEqual('_FDTMAP_', magic)
2097 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2099 fdt_data = fdtmap_data[16:]
2100 dtb = fdt.Fdt.FromData(fdt_data)
2102 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2107 'u-boot:size': len(U_BOOT_DATA),
2108 'u-boot:image-pos': 0,
2109 'fdtmap:image-pos': 4,
2111 'fdtmap:size': len(fdtmap_data),
2115 def testFdtmapNoMatch(self):
2116 """Check handling of an FDT map when the section cannot be found"""
2117 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2119 # Mangle the section name, which should cause a mismatch between the
2120 # correct FDT path and the one expected by the section
2121 image = control.images['image']
2122 image._node.path += '-suffix'
2123 entries = image.GetEntries()
2124 fdtmap = entries['fdtmap']
2125 with self.assertRaises(ValueError) as e:
2127 self.assertIn("Cannot locate node for path '/binman-suffix'",
2130 def testFdtmapHeader(self):
2131 """Test an FDT map and image header can be inserted in the image"""
2132 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2133 fdtmap_pos = len(U_BOOT_DATA)
2134 fdtmap_data = data[fdtmap_pos:]
2135 fdt_data = fdtmap_data[16:]
2136 dtb = fdt.Fdt.FromData(fdt_data)
2137 fdt_size = dtb.GetFdtObj().totalsize()
2138 hdr_data = data[-8:]
2139 self.assertEqual('BinM', hdr_data[:4])
2140 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2141 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2143 def testFdtmapHeaderStart(self):
2144 """Test an image header can be inserted at the image start"""
2145 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2146 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2148 self.assertEqual('BinM', hdr_data[:4])
2149 offset = struct.unpack('<I', hdr_data[4:])[0]
2150 self.assertEqual(fdtmap_pos, offset)
2152 def testFdtmapHeaderPos(self):
2153 """Test an image header can be inserted at a chosen position"""
2154 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2155 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2156 hdr_data = data[0x80:0x88]
2157 self.assertEqual('BinM', hdr_data[:4])
2158 offset = struct.unpack('<I', hdr_data[4:])[0]
2159 self.assertEqual(fdtmap_pos, offset)
2161 def testHeaderMissingFdtmap(self):
2162 """Test an image header requires an fdtmap"""
2163 with self.assertRaises(ValueError) as e:
2164 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2165 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2168 def testHeaderNoLocation(self):
2169 """Test an image header with a no specified location is detected"""
2170 with self.assertRaises(ValueError) as e:
2171 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2172 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2175 def testEntryExpand(self):
2176 """Test expanding an entry after it is packed"""
2177 data = self._DoReadFile('121_entry_expand.dts')
2178 self.assertEqual(b'aaa', data[:3])
2179 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2180 self.assertEqual(b'aaa', data[-3:])
2182 def testEntryExpandBad(self):
2183 """Test expanding an entry after it is packed, twice"""
2184 with self.assertRaises(ValueError) as e:
2185 self._DoReadFile('122_entry_expand_twice.dts')
2186 self.assertIn("Image '/binman': Entries changed size after packing",
2189 def testEntryExpandSection(self):
2190 """Test expanding an entry within a section after it is packed"""
2191 data = self._DoReadFile('123_entry_expand_section.dts')
2192 self.assertEqual(b'aaa', data[:3])
2193 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2194 self.assertEqual(b'aaa', data[-3:])
2196 def testCompressDtb(self):
2197 """Test that compress of device-tree files is supported"""
2199 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2200 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2201 comp_data = data[len(U_BOOT_DATA):]
2202 orig = self._decompress(comp_data)
2203 dtb = fdt.Fdt.FromData(orig)
2205 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2207 'u-boot:size': len(U_BOOT_DATA),
2208 'u-boot-dtb:uncomp-size': len(orig),
2209 'u-boot-dtb:size': len(comp_data),
2212 self.assertEqual(expected, props)
2214 def testCbfsUpdateFdt(self):
2215 """Test that we can update the device tree with CBFS offset/size info"""
2217 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2219 dtb = fdt.Fdt(out_dtb_fname)
2221 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2222 del props['cbfs/u-boot:size']
2228 'cbfs:size': len(data),
2229 'cbfs:image-pos': 0,
2230 'cbfs/u-boot:offset': 0x38,
2231 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2232 'cbfs/u-boot:image-pos': 0x38,
2233 'cbfs/u-boot-dtb:offset': 0xb8,
2234 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2235 'cbfs/u-boot-dtb:image-pos': 0xb8,
2238 def testCbfsBadType(self):
2239 """Test an image header with a no specified location is detected"""
2240 with self.assertRaises(ValueError) as e:
2241 self._DoReadFile('126_cbfs_bad_type.dts')
2242 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2245 """Test listing the files in an image"""
2247 data = self._DoReadFile('127_list.dts')
2248 image = control.images['image']
2249 entries = image.BuildEntryList()
2250 self.assertEqual(7, len(entries))
2253 self.assertEqual(0, ent.indent)
2254 self.assertEqual('main-section', ent.name)
2255 self.assertEqual('section', ent.etype)
2256 self.assertEqual(len(data), ent.size)
2257 self.assertEqual(0, ent.image_pos)
2258 self.assertEqual(None, ent.uncomp_size)
2259 self.assertEqual(0, ent.offset)
2262 self.assertEqual(1, ent.indent)
2263 self.assertEqual('u-boot', ent.name)
2264 self.assertEqual('u-boot', ent.etype)
2265 self.assertEqual(len(U_BOOT_DATA), ent.size)
2266 self.assertEqual(0, ent.image_pos)
2267 self.assertEqual(None, ent.uncomp_size)
2268 self.assertEqual(0, ent.offset)
2271 self.assertEqual(1, ent.indent)
2272 self.assertEqual('section', ent.name)
2273 self.assertEqual('section', ent.etype)
2274 section_size = ent.size
2275 self.assertEqual(0x100, ent.image_pos)
2276 self.assertEqual(None, ent.uncomp_size)
2277 self.assertEqual(0x100, ent.offset)
2280 self.assertEqual(2, ent.indent)
2281 self.assertEqual('cbfs', ent.name)
2282 self.assertEqual('cbfs', ent.etype)
2283 self.assertEqual(0x400, ent.size)
2284 self.assertEqual(0x100, ent.image_pos)
2285 self.assertEqual(None, ent.uncomp_size)
2286 self.assertEqual(0, ent.offset)
2289 self.assertEqual(3, ent.indent)
2290 self.assertEqual('u-boot', ent.name)
2291 self.assertEqual('u-boot', ent.etype)
2292 self.assertEqual(len(U_BOOT_DATA), ent.size)
2293 self.assertEqual(0x138, ent.image_pos)
2294 self.assertEqual(None, ent.uncomp_size)
2295 self.assertEqual(0x38, ent.offset)
2298 self.assertEqual(3, ent.indent)
2299 self.assertEqual('u-boot-dtb', ent.name)
2300 self.assertEqual('text', ent.etype)
2301 self.assertGreater(len(COMPRESS_DATA), ent.size)
2302 self.assertEqual(0x178, ent.image_pos)
2303 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2304 self.assertEqual(0x78, ent.offset)
2307 self.assertEqual(2, ent.indent)
2308 self.assertEqual('u-boot-dtb', ent.name)
2309 self.assertEqual('u-boot-dtb', ent.etype)
2310 self.assertEqual(0x500, ent.image_pos)
2311 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2313 # Compressing this data expands it since headers are added
2314 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2315 self.assertEqual(0x400, ent.offset)
2317 self.assertEqual(len(data), 0x100 + section_size)
2318 self.assertEqual(section_size, 0x400 + dtb_size)
2320 def testFindFdtmap(self):
2321 """Test locating an FDT map in an image"""
2323 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2324 image = control.images['image']
2325 entries = image.GetEntries()
2326 entry = entries['fdtmap']
2327 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2329 def testFindFdtmapMissing(self):
2330 """Test failing to locate an FDP map"""
2331 data = self._DoReadFile('005_simple.dts')
2332 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2334 def testFindImageHeader(self):
2335 """Test locating a image header"""
2337 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2338 image = control.images['image']
2339 entries = image.GetEntries()
2340 entry = entries['fdtmap']
2341 # The header should point to the FDT map
2342 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2344 def testFindImageHeaderStart(self):
2345 """Test locating a image header located at the start of an image"""
2346 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2347 image = control.images['image']
2348 entries = image.GetEntries()
2349 entry = entries['fdtmap']
2350 # The header should point to the FDT map
2351 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2353 def testFindImageHeaderMissing(self):
2354 """Test failing to locate an image header"""
2355 data = self._DoReadFile('005_simple.dts')
2356 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2358 def testReadImage(self):
2359 """Test reading an image and accessing its FDT map"""
2361 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2362 image_fname = tools.GetOutputFilename('image.bin')
2363 orig_image = control.images['image']
2364 image = Image.FromFile(image_fname)
2365 self.assertEqual(orig_image.GetEntries().keys(),
2366 image.GetEntries().keys())
2368 orig_entry = orig_image.GetEntries()['fdtmap']
2369 entry = image.GetEntries()['fdtmap']
2370 self.assertEquals(orig_entry.offset, entry.offset)
2371 self.assertEquals(orig_entry.size, entry.size)
2372 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2374 def testReadImageNoHeader(self):
2375 """Test accessing an image's FDT map without an image header"""
2377 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2378 image_fname = tools.GetOutputFilename('image.bin')
2379 image = Image.FromFile(image_fname)
2380 self.assertTrue(isinstance(image, Image))
2381 self.assertEqual('image', image.image_name[-5:])
2383 def testReadImageFail(self):
2384 """Test failing to read an image image's FDT map"""
2385 self._DoReadFile('005_simple.dts')
2386 image_fname = tools.GetOutputFilename('image.bin')
2387 with self.assertRaises(ValueError) as e:
2388 image = Image.FromFile(image_fname)
2389 self.assertIn("Cannot find FDT map in image", str(e.exception))
2391 def testListCmd(self):
2392 """Test listing the files in an image using an Fdtmap"""
2394 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2396 # lz4 compression size differs depending on the version
2397 image = control.images['image']
2398 entries = image.GetEntries()
2399 section_size = entries['section'].size
2400 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2401 fdtmap_offset = entries['fdtmap'].offset
2404 tmpdir, updated_fname = self._SetupImageInTmpdir()
2405 with test_util.capture_sys_output() as (stdout, stderr):
2406 self._DoBinman('ls', '-i', updated_fname)
2408 shutil.rmtree(tmpdir)
2409 lines = stdout.getvalue().splitlines()
2411 'Name Image-pos Size Entry-type Offset Uncomp-size',
2412 '----------------------------------------------------------------------',
2413 'main-section 0 c00 section 0',
2414 ' u-boot 0 4 u-boot 0',
2415 ' section 100 %x section 100' % section_size,
2416 ' cbfs 100 400 cbfs 0',
2417 ' u-boot 138 4 u-boot 38',
2418 ' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2419 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2420 ' fdtmap %x 3b4 fdtmap %x' %
2421 (fdtmap_offset, fdtmap_offset),
2422 ' image-header bf8 8 image-header bf8',
2424 self.assertEqual(expected, lines)
2426 def testListCmdFail(self):
2427 """Test failing to list an image"""
2428 self._DoReadFile('005_simple.dts')
2430 tmpdir, updated_fname = self._SetupImageInTmpdir()
2431 with self.assertRaises(ValueError) as e:
2432 self._DoBinman('ls', '-i', updated_fname)
2434 shutil.rmtree(tmpdir)
2435 self.assertIn("Cannot find FDT map in image", str(e.exception))
2437 def _RunListCmd(self, paths, expected):
2438 """List out entries and check the result
2441 paths: List of paths to pass to the list command
2442 expected: Expected list of filenames to be returned, in order
2445 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2446 image_fname = tools.GetOutputFilename('image.bin')
2447 image = Image.FromFile(image_fname)
2448 lines = image.GetListEntries(paths)[1]
2449 files = [line[0].strip() for line in lines[1:]]
2450 self.assertEqual(expected, files)
2452 def testListCmdSection(self):
2453 """Test listing the files in a section"""
2454 self._RunListCmd(['section'],
2455 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2457 def testListCmdFile(self):
2458 """Test listing a particular file"""
2459 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2461 def testListCmdWildcard(self):
2462 """Test listing a wildcarded file"""
2463 self._RunListCmd(['*boot*'],
2464 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2466 def testListCmdWildcardMulti(self):
2467 """Test listing a wildcarded file"""
2468 self._RunListCmd(['*cb*', '*head*'],
2469 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2471 def testListCmdEmpty(self):
2472 """Test listing a wildcarded file"""
2473 self._RunListCmd(['nothing'], [])
2475 def testListCmdPath(self):
2476 """Test listing the files in a sub-entry of a section"""
2477 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2479 def _RunExtractCmd(self, entry_name, decomp=True):
2480 """Extract an entry from an image
2483 entry_name: Entry name to extract
2484 decomp: True to decompress the data if compressed, False to leave
2485 it in its raw uncompressed format
2491 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2492 image_fname = tools.GetOutputFilename('image.bin')
2493 return control.ReadEntry(image_fname, entry_name, decomp)
2495 def testExtractSimple(self):
2496 """Test extracting a single file"""
2497 data = self._RunExtractCmd('u-boot')
2498 self.assertEqual(U_BOOT_DATA, data)
2500 def testExtractSection(self):
2501 """Test extracting the files in a section"""
2502 data = self._RunExtractCmd('section')
2503 cbfs_data = data[:0x400]
2504 cbfs = cbfs_util.CbfsReader(cbfs_data)
2505 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2506 dtb_data = data[0x400:]
2507 dtb = self._decompress(dtb_data)
2508 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2510 def testExtractCompressed(self):
2511 """Test extracting compressed data"""
2512 data = self._RunExtractCmd('section/u-boot-dtb')
2513 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2515 def testExtractRaw(self):
2516 """Test extracting compressed data without decompressing it"""
2517 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2518 dtb = self._decompress(data)
2519 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2521 def testExtractCbfs(self):
2522 """Test extracting CBFS data"""
2523 data = self._RunExtractCmd('section/cbfs/u-boot')
2524 self.assertEqual(U_BOOT_DATA, data)
2526 def testExtractCbfsCompressed(self):
2527 """Test extracting CBFS compressed data"""
2528 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2529 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2531 def testExtractCbfsRaw(self):
2532 """Test extracting CBFS compressed data without decompressing it"""
2533 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2534 dtb = tools.Decompress(data, 'lzma', with_header=False)
2535 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2537 def testExtractBadEntry(self):
2538 """Test extracting a bad section path"""
2539 with self.assertRaises(ValueError) as e:
2540 self._RunExtractCmd('section/does-not-exist')
2541 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2544 def testExtractMissingFile(self):
2545 """Test extracting file that does not exist"""
2546 with self.assertRaises(IOError) as e:
2547 control.ReadEntry('missing-file', 'name')
2549 def testExtractBadFile(self):
2550 """Test extracting an invalid file"""
2551 fname = os.path.join(self._indir, 'badfile')
2552 tools.WriteFile(fname, b'')
2553 with self.assertRaises(ValueError) as e:
2554 control.ReadEntry(fname, 'name')
2556 def testExtractCmd(self):
2557 """Test extracting a file fron an image on the command line"""
2559 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2560 fname = os.path.join(self._indir, 'output.extact')
2562 tmpdir, updated_fname = self._SetupImageInTmpdir()
2563 with test_util.capture_sys_output() as (stdout, stderr):
2564 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2567 shutil.rmtree(tmpdir)
2568 data = tools.ReadFile(fname)
2569 self.assertEqual(U_BOOT_DATA, data)
2571 def testExtractOneEntry(self):
2572 """Test extracting a single entry fron an image """
2574 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2575 image_fname = tools.GetOutputFilename('image.bin')
2576 fname = os.path.join(self._indir, 'output.extact')
2577 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2578 data = tools.ReadFile(fname)
2579 self.assertEqual(U_BOOT_DATA, data)
2581 def _CheckExtractOutput(self, decomp):
2582 """Helper to test file output with and without decompression
2585 decomp: True to decompress entry data, False to output it raw
2587 def _CheckPresent(entry_path, expect_data, expect_size=None):
2588 """Check and remove expected file
2590 This checks the data/size of a file and removes the file both from
2591 the outfiles set and from the output directory. Once all files are
2592 processed, both the set and directory should be empty.
2595 entry_path: Entry path
2596 expect_data: Data to expect in file, or None to skip check
2597 expect_size: Size of data to expect in file, or None to skip
2599 path = os.path.join(outdir, entry_path)
2600 data = tools.ReadFile(path)
2603 self.assertEqual(expect_data, data)
2605 self.assertEqual(expect_size, len(data))
2606 outfiles.remove(path)
2608 def _CheckDirPresent(name):
2609 """Remove expected directory
2611 This gives an error if the directory does not exist as expected
2614 name: Name of directory to remove
2616 path = os.path.join(outdir, name)
2619 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2620 image_fname = tools.GetOutputFilename('image.bin')
2621 outdir = os.path.join(self._indir, 'extract')
2622 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2624 # Create a set of all file that were output (should be 9)
2626 for root, dirs, files in os.walk(outdir):
2627 outfiles |= set([os.path.join(root, fname) for fname in files])
2628 self.assertEqual(9, len(outfiles))
2629 self.assertEqual(9, len(einfos))
2631 image = control.images['image']
2632 entries = image.GetEntries()
2634 # Check the 9 files in various ways
2635 section = entries['section']
2636 section_entries = section.GetEntries()
2637 cbfs_entries = section_entries['cbfs'].GetEntries()
2638 _CheckPresent('u-boot', U_BOOT_DATA)
2639 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2640 dtb_len = EXTRACT_DTB_SIZE
2642 dtb_len = cbfs_entries['u-boot-dtb'].size
2643 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2645 dtb_len = section_entries['u-boot-dtb'].size
2646 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2648 fdtmap = entries['fdtmap']
2649 _CheckPresent('fdtmap', fdtmap.data)
2650 hdr = entries['image-header']
2651 _CheckPresent('image-header', hdr.data)
2653 _CheckPresent('section/root', section.data)
2654 cbfs = section_entries['cbfs']
2655 _CheckPresent('section/cbfs/root', cbfs.data)
2656 data = tools.ReadFile(image_fname)
2657 _CheckPresent('root', data)
2659 # There should be no files left. Remove all the directories to check.
2660 # If there are any files/dirs remaining, one of these checks will fail.
2661 self.assertEqual(0, len(outfiles))
2662 _CheckDirPresent('section/cbfs')
2663 _CheckDirPresent('section')
2664 _CheckDirPresent('')
2665 self.assertFalse(os.path.exists(outdir))
2667 def testExtractAllEntries(self):
2668 """Test extracting all entries"""
2670 self._CheckExtractOutput(decomp=True)
2672 def testExtractAllEntriesRaw(self):
2673 """Test extracting all entries without decompressing them"""
2675 self._CheckExtractOutput(decomp=False)
2677 def testExtractSelectedEntries(self):
2678 """Test extracting some entries"""
2680 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2681 image_fname = tools.GetOutputFilename('image.bin')
2682 outdir = os.path.join(self._indir, 'extract')
2683 einfos = control.ExtractEntries(image_fname, None, outdir,
2686 # File output is tested by testExtractAllEntries(), so just check that
2687 # the expected entries are selected
2688 names = [einfo.name for einfo in einfos]
2689 self.assertEqual(names,
2690 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2692 def testExtractNoEntryPaths(self):
2693 """Test extracting some entries"""
2695 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2696 image_fname = tools.GetOutputFilename('image.bin')
2697 with self.assertRaises(ValueError) as e:
2698 control.ExtractEntries(image_fname, 'fname', None, [])
2699 self.assertIn('Must specify an entry path to write with -f',
2702 def testExtractTooManyEntryPaths(self):
2703 """Test extracting some entries"""
2705 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2706 image_fname = tools.GetOutputFilename('image.bin')
2707 with self.assertRaises(ValueError) as e:
2708 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2709 self.assertIn('Must specify exactly one entry path to write with -f',
2712 def testPackAlignSection(self):
2713 """Test that sections can have alignment"""
2714 self._DoReadFile('131_pack_align_section.dts')
2716 self.assertIn('image', control.images)
2717 image = control.images['image']
2718 entries = image.GetEntries()
2719 self.assertEqual(3, len(entries))
2722 self.assertIn('u-boot', entries)
2723 entry = entries['u-boot']
2724 self.assertEqual(0, entry.offset)
2725 self.assertEqual(0, entry.image_pos)
2726 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2727 self.assertEqual(len(U_BOOT_DATA), entry.size)
2730 self.assertIn('section0', entries)
2731 section0 = entries['section0']
2732 self.assertEqual(0x10, section0.offset)
2733 self.assertEqual(0x10, section0.image_pos)
2734 self.assertEqual(len(U_BOOT_DATA), section0.size)
2737 section_entries = section0.GetEntries()
2738 self.assertIn('u-boot', section_entries)
2739 entry = section_entries['u-boot']
2740 self.assertEqual(0, entry.offset)
2741 self.assertEqual(0x10, entry.image_pos)
2742 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2743 self.assertEqual(len(U_BOOT_DATA), entry.size)
2746 self.assertIn('section1', entries)
2747 section1 = entries['section1']
2748 self.assertEqual(0x14, section1.offset)
2749 self.assertEqual(0x14, section1.image_pos)
2750 self.assertEqual(0x20, section1.size)
2753 section_entries = section1.GetEntries()
2754 self.assertIn('u-boot', section_entries)
2755 entry = section_entries['u-boot']
2756 self.assertEqual(0, entry.offset)
2757 self.assertEqual(0x14, entry.image_pos)
2758 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2759 self.assertEqual(len(U_BOOT_DATA), entry.size)
2762 self.assertIn('section2', section_entries)
2763 section2 = section_entries['section2']
2764 self.assertEqual(0x4, section2.offset)
2765 self.assertEqual(0x18, section2.image_pos)
2766 self.assertEqual(4, section2.size)
2769 section_entries = section2.GetEntries()
2770 self.assertIn('u-boot', section_entries)
2771 entry = section_entries['u-boot']
2772 self.assertEqual(0, entry.offset)
2773 self.assertEqual(0x18, entry.image_pos)
2774 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2775 self.assertEqual(len(U_BOOT_DATA), entry.size)
2777 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2778 dts='132_replace.dts'):
2779 """Replace an entry in an image
2781 This writes the entry data to update it, then opens the updated file and
2782 returns the value that it now finds there.
2785 entry_name: Entry name to replace
2786 data: Data to replace it with
2787 decomp: True to compress the data if needed, False if data is
2788 already compressed so should be used as is
2789 allow_resize: True to allow entries to change size, False to raise
2795 data from fdtmap (excluding header)
2796 Image object that was modified
2798 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2801 self.assertIn('image', control.images)
2802 image = control.images['image']
2803 entries = image.GetEntries()
2804 orig_dtb_data = entries['u-boot-dtb'].data
2805 orig_fdtmap_data = entries['fdtmap'].data
2807 image_fname = tools.GetOutputFilename('image.bin')
2808 updated_fname = tools.GetOutputFilename('image-updated.bin')
2809 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2810 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2812 data = control.ReadEntry(updated_fname, entry_name, decomp)
2814 # The DT data should not change unless resized:
2815 if not allow_resize:
2816 new_dtb_data = entries['u-boot-dtb'].data
2817 self.assertEqual(new_dtb_data, orig_dtb_data)
2818 new_fdtmap_data = entries['fdtmap'].data
2819 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2821 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2823 def testReplaceSimple(self):
2824 """Test replacing a single file"""
2825 expected = b'x' * len(U_BOOT_DATA)
2826 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2828 self.assertEqual(expected, data)
2830 # Test that the state looks right. There should be an FDT for the fdtmap
2831 # that we jsut read back in, and it should match what we find in the
2832 # 'control' tables. Checking for an FDT that does not exist should
2834 path, fdtmap = state.GetFdtContents('fdtmap')
2835 self.assertIsNotNone(path)
2836 self.assertEqual(expected_fdtmap, fdtmap)
2838 dtb = state.GetFdtForEtype('fdtmap')
2839 self.assertEqual(dtb.GetContents(), fdtmap)
2841 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2842 self.assertIsNone(missing_path)
2843 self.assertIsNone(missing_fdtmap)
2845 missing_dtb = state.GetFdtForEtype('missing')
2846 self.assertIsNone(missing_dtb)
2848 self.assertEqual('/binman', state.fdt_path_prefix)
2850 def testReplaceResizeFail(self):
2851 """Test replacing a file by something larger"""
2852 expected = U_BOOT_DATA + b'x'
2853 with self.assertRaises(ValueError) as e:
2854 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2855 dts='139_replace_repack.dts')
2856 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2859 def testReplaceMulti(self):
2860 """Test replacing entry data where multiple images are generated"""
2861 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2863 expected = b'x' * len(U_BOOT_DATA)
2864 updated_fname = tools.GetOutputFilename('image-updated.bin')
2865 tools.WriteFile(updated_fname, data)
2866 entry_name = 'u-boot'
2867 control.WriteEntry(updated_fname, entry_name, expected,
2869 data = control.ReadEntry(updated_fname, entry_name)
2870 self.assertEqual(expected, data)
2872 # Check the state looks right.
2873 self.assertEqual('/binman/image', state.fdt_path_prefix)
2875 # Now check we can write the first image
2876 image_fname = tools.GetOutputFilename('first-image.bin')
2877 updated_fname = tools.GetOutputFilename('first-updated.bin')
2878 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2879 entry_name = 'u-boot'
2880 control.WriteEntry(updated_fname, entry_name, expected,
2882 data = control.ReadEntry(updated_fname, entry_name)
2883 self.assertEqual(expected, data)
2885 # Check the state looks right.
2886 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2888 def testUpdateFdtAllRepack(self):
2889 """Test that all device trees are updated with offset/size info"""
2890 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2891 SECTION_SIZE = 0x300
2896 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2898 'section:offset': 0,
2899 'section:size': SECTION_SIZE,
2900 'section:image-pos': 0,
2901 'section/u-boot-dtb:offset': 4,
2902 'section/u-boot-dtb:size': 636,
2903 'section/u-boot-dtb:image-pos': 4,
2904 'u-boot-spl-dtb:offset': SECTION_SIZE,
2905 'u-boot-spl-dtb:size': DTB_SIZE,
2906 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2907 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2908 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2909 'u-boot-tpl-dtb:size': DTB_SIZE,
2910 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2911 'fdtmap:size': FDTMAP_SIZE,
2912 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2915 'section:orig-size': SECTION_SIZE,
2916 'section/u-boot-dtb:orig-offset': 4,
2919 # We expect three device-tree files in the output, with the first one
2920 # within a fixed-size section.
2921 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2922 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2923 # main U-Boot tree. All three should have the same positions and offset
2924 # except that the main tree should include the main_expected properties
2926 for item in ['', 'spl', 'tpl', None]:
2928 start += 16 # Move past fdtmap header
2929 dtb = fdt.Fdt.FromData(data[start:])
2931 props = self._GetPropTree(dtb,
2932 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2933 prefix='/' if item is None else '/binman/')
2934 expected = dict(base_expected)
2938 # Main DTB and fdtdec should include the 'orig-' properties
2939 expected.update(main_expected)
2940 # Helpful for debugging:
2941 #for prop in sorted(props):
2942 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2943 self.assertEqual(expected, props)
2945 start = SECTION_SIZE
2947 start += dtb._fdt_obj.totalsize()
2949 def testFdtmapHeaderMiddle(self):
2950 """Test an FDT map in the middle of an image when it should be at end"""
2951 with self.assertRaises(ValueError) as e:
2952 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2953 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2956 def testFdtmapHeaderStartBad(self):
2957 """Test an FDT map in middle of an image when it should be at start"""
2958 with self.assertRaises(ValueError) as e:
2959 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2960 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2963 def testFdtmapHeaderEndBad(self):
2964 """Test an FDT map at the start of an image when it should be at end"""
2965 with self.assertRaises(ValueError) as e:
2966 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2967 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2970 def testFdtmapHeaderNoSize(self):
2971 """Test an image header at the end of an image with undefined size"""
2972 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2974 def testReplaceResize(self):
2975 """Test replacing a single file in an entry with a larger file"""
2976 expected = U_BOOT_DATA + b'x'
2977 data, _, image = self._RunReplaceCmd('u-boot', expected,
2978 dts='139_replace_repack.dts')
2979 self.assertEqual(expected, data)
2981 entries = image.GetEntries()
2982 dtb_data = entries['u-boot-dtb'].data
2983 dtb = fdt.Fdt.FromData(dtb_data)
2986 # The u-boot section should now be larger in the dtb
2987 node = dtb.GetNode('/binman/u-boot')
2988 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
2990 # Same for the fdtmap
2991 fdata = entries['fdtmap'].data
2992 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
2994 fnode = fdtb.GetNode('/u-boot')
2995 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
2997 def testReplaceResizeNoRepack(self):
2998 """Test replacing an entry with a larger file when not allowed"""
2999 expected = U_BOOT_DATA + b'x'
3000 with self.assertRaises(ValueError) as e:
3001 self._RunReplaceCmd('u-boot', expected)
3002 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3005 def testEntryShrink(self):
3006 """Test contracting an entry after it is packed"""
3008 state.SetAllowEntryContraction(True)
3009 data = self._DoReadFileDtb('140_entry_shrink.dts',
3012 state.SetAllowEntryContraction(False)
3013 self.assertEqual(b'a', data[:1])
3014 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3015 self.assertEqual(b'a', data[-1:])
3017 def testEntryShrinkFail(self):
3018 """Test not being allowed to contract an entry after it is packed"""
3019 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3021 # In this case there is a spare byte at the end of the data. The size of
3022 # the contents is only 1 byte but we still have the size before it
3024 self.assertEqual(b'a\0', data[:2])
3025 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3026 self.assertEqual(b'a\0', data[-2:])
3028 def testDescriptorOffset(self):
3029 """Test that the Intel descriptor is always placed at at the start"""
3030 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3031 image = control.images['image']
3032 entries = image.GetEntries()
3033 desc = entries['intel-descriptor']
3034 self.assertEqual(0xff800000, desc.offset);
3035 self.assertEqual(0xff800000, desc.image_pos);
3037 def testReplaceCbfs(self):
3038 """Test replacing a single file in CBFS without changing the size"""
3040 expected = b'x' * len(U_BOOT_DATA)
3041 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3042 updated_fname = tools.GetOutputFilename('image-updated.bin')
3043 tools.WriteFile(updated_fname, data)
3044 entry_name = 'section/cbfs/u-boot'
3045 control.WriteEntry(updated_fname, entry_name, expected,
3047 data = control.ReadEntry(updated_fname, entry_name)
3048 self.assertEqual(expected, data)
3050 def testReplaceResizeCbfs(self):
3051 """Test replacing a single file in CBFS with one of a different size"""
3053 expected = U_BOOT_DATA + b'x'
3054 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3055 updated_fname = tools.GetOutputFilename('image-updated.bin')
3056 tools.WriteFile(updated_fname, data)
3057 entry_name = 'section/cbfs/u-boot'
3058 control.WriteEntry(updated_fname, entry_name, expected,
3060 data = control.ReadEntry(updated_fname, entry_name)
3061 self.assertEqual(expected, data)
3063 def _SetupForReplace(self):
3064 """Set up some files to use to replace entries
3066 This generates an image, copies it to a new file, extracts all the files
3067 in it and updates some of them
3073 Expected values for updated entries, each a string
3075 data = self._DoReadFileRealDtb('143_replace_all.dts')
3077 updated_fname = tools.GetOutputFilename('image-updated.bin')
3078 tools.WriteFile(updated_fname, data)
3080 outdir = os.path.join(self._indir, 'extract')
3081 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3083 expected1 = b'x' + U_BOOT_DATA + b'y'
3084 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3085 tools.WriteFile(u_boot_fname1, expected1)
3087 expected2 = b'a' + U_BOOT_DATA + b'b'
3088 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3089 tools.WriteFile(u_boot_fname2, expected2)
3091 expected_text = b'not the same text'
3092 text_fname = os.path.join(outdir, 'text')
3093 tools.WriteFile(text_fname, expected_text)
3095 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3096 dtb = fdt.FdtScan(dtb_fname)
3097 node = dtb.GetNode('/binman/text')
3098 node.AddString('my-property', 'the value')
3099 dtb.Sync(auto_resize=True)
3102 return updated_fname, outdir, expected1, expected2, expected_text
3104 def _CheckReplaceMultiple(self, entry_paths):
3105 """Handle replacing the contents of multiple entries
3108 entry_paths: List of entry paths to replace
3112 Dict of entries in the image:
3115 Expected values for updated entries, each a string
3117 updated_fname, outdir, expected1, expected2, expected_text = (
3118 self._SetupForReplace())
3119 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3121 image = Image.FromFile(updated_fname)
3123 return image.GetEntries(), expected1, expected2, expected_text
3125 def testReplaceAll(self):
3126 """Test replacing the contents of all entries"""
3127 entries, expected1, expected2, expected_text = (
3128 self._CheckReplaceMultiple([]))
3129 data = entries['u-boot'].data
3130 self.assertEqual(expected1, data)
3132 data = entries['u-boot2'].data
3133 self.assertEqual(expected2, data)
3135 data = entries['text'].data
3136 self.assertEqual(expected_text, data)
3138 # Check that the device tree is updated
3139 data = entries['u-boot-dtb'].data
3140 dtb = fdt.Fdt.FromData(data)
3142 node = dtb.GetNode('/binman/text')
3143 self.assertEqual('the value', node.props['my-property'].value)
3145 def testReplaceSome(self):
3146 """Test replacing the contents of a few entries"""
3147 entries, expected1, expected2, expected_text = (
3148 self._CheckReplaceMultiple(['u-boot2', 'text']))
3150 # This one should not change
3151 data = entries['u-boot'].data
3152 self.assertEqual(U_BOOT_DATA, data)
3154 data = entries['u-boot2'].data
3155 self.assertEqual(expected2, data)
3157 data = entries['text'].data
3158 self.assertEqual(expected_text, data)
3160 def testReplaceCmd(self):
3161 """Test replacing a file fron an image on the command line"""
3162 self._DoReadFileRealDtb('143_replace_all.dts')
3165 tmpdir, updated_fname = self._SetupImageInTmpdir()
3167 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3168 expected = b'x' * len(U_BOOT_DATA)
3169 tools.WriteFile(fname, expected)
3171 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3172 data = tools.ReadFile(updated_fname)
3173 self.assertEqual(expected, data[:len(expected)])
3174 map_fname = os.path.join(tmpdir, 'image-updated.map')
3175 self.assertFalse(os.path.exists(map_fname))
3177 shutil.rmtree(tmpdir)
3179 def testReplaceCmdSome(self):
3180 """Test replacing some files fron an image on the command line"""
3181 updated_fname, outdir, expected1, expected2, expected_text = (
3182 self._SetupForReplace())
3184 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3187 tools.PrepareOutputDir(None)
3188 image = Image.FromFile(updated_fname)
3190 entries = image.GetEntries()
3192 # This one should not change
3193 data = entries['u-boot'].data
3194 self.assertEqual(U_BOOT_DATA, data)
3196 data = entries['u-boot2'].data
3197 self.assertEqual(expected2, data)
3199 data = entries['text'].data
3200 self.assertEqual(expected_text, data)
3202 def testReplaceMissing(self):
3203 """Test replacing entries where the file is missing"""
3204 updated_fname, outdir, expected1, expected2, expected_text = (
3205 self._SetupForReplace())
3207 # Remove one of the files, to generate a warning
3208 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3209 os.remove(u_boot_fname1)
3211 with test_util.capture_sys_output() as (stdout, stderr):
3212 control.ReplaceEntries(updated_fname, None, outdir, [])
3213 self.assertIn("Skipping entry '/u-boot' from missing file",
3216 def testReplaceCmdMap(self):
3217 """Test replacing a file fron an image on the command line"""
3218 self._DoReadFileRealDtb('143_replace_all.dts')
3221 tmpdir, updated_fname = self._SetupImageInTmpdir()
3223 fname = os.path.join(self._indir, 'update-u-boot.bin')
3224 expected = b'x' * len(U_BOOT_DATA)
3225 tools.WriteFile(fname, expected)
3227 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3229 map_fname = os.path.join(tmpdir, 'image-updated.map')
3230 self.assertTrue(os.path.exists(map_fname))
3232 shutil.rmtree(tmpdir)
3234 def testReplaceNoEntryPaths(self):
3235 """Test replacing an entry without an entry path"""
3236 self._DoReadFileRealDtb('143_replace_all.dts')
3237 image_fname = tools.GetOutputFilename('image.bin')
3238 with self.assertRaises(ValueError) as e:
3239 control.ReplaceEntries(image_fname, 'fname', None, [])
3240 self.assertIn('Must specify an entry path to read with -f',
3243 def testReplaceTooManyEntryPaths(self):
3244 """Test extracting some entries"""
3245 self._DoReadFileRealDtb('143_replace_all.dts')
3246 image_fname = tools.GetOutputFilename('image.bin')
3247 with self.assertRaises(ValueError) as e:
3248 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3249 self.assertIn('Must specify exactly one entry path to write with -f',
3252 def testPackReset16(self):
3253 """Test that an image with an x86 reset16 region can be created"""
3254 data = self._DoReadFile('144_x86_reset16.dts')
3255 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3257 def testPackReset16Spl(self):
3258 """Test that an image with an x86 reset16-spl region can be created"""
3259 data = self._DoReadFile('145_x86_reset16_spl.dts')
3260 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3262 def testPackReset16Tpl(self):
3263 """Test that an image with an x86 reset16-tpl region can be created"""
3264 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3265 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3267 def testPackIntelFit(self):
3268 """Test that an image with an Intel FIT and pointer can be created"""
3269 data = self._DoReadFile('147_intel_fit.dts')
3270 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3272 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3273 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3275 image = control.images['image']
3276 entries = image.GetEntries()
3277 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3278 self.assertEqual(expected_ptr, ptr)
3280 def testPackIntelFitMissing(self):
3281 """Test detection of a FIT pointer with not FIT region"""
3282 with self.assertRaises(ValueError) as e:
3283 self._DoReadFile('148_intel_fit_missing.dts')
3284 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3288 if __name__ == "__main__":