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
28 from etype import fdtmap
29 from etype import image_header
34 from image import Image
39 # Contents of test files, corresponding to different entry types
41 U_BOOT_IMG_DATA = b'img'
42 U_BOOT_SPL_DATA = b'56780123456789abcde'
43 U_BOOT_TPL_DATA = b'tpl'
47 U_BOOT_DTB_DATA = b'udtb'
48 U_BOOT_SPL_DTB_DATA = b'spldtb'
49 U_BOOT_TPL_DTB_DATA = b'tpldtb'
50 X86_START16_DATA = b'start16'
51 X86_START16_SPL_DATA = b'start16spl'
52 X86_START16_TPL_DATA = b'start16tpl'
53 X86_RESET16_DATA = b'reset16'
54 X86_RESET16_SPL_DATA = b'reset16spl'
55 X86_RESET16_TPL_DATA = b'reset16tpl'
56 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
57 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
58 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
59 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
67 CROS_EC_RW_DATA = b'ecrw'
71 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
72 b"sorry you're alive\n")
73 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
74 REFCODE_DATA = b'refcode'
76 # The expected size for the device tree in some tests
77 EXTRACT_DTB_SIZE = 0x3c9
79 # Properties expected to be in the device tree when update_dtb is used
80 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
82 # Extra properties expected to be in the device tree when allow-repack is used
83 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
86 class TestFunctional(unittest.TestCase):
87 """Functional tests for binman
89 Most of these use a sample .dts file to build an image and then check
90 that it looks correct. The sample files are in the test/ subdirectory
93 For each entry type a very small test file is created using fixed
94 string contents. This makes it easy to test that things look right, and
97 In some cases a 'real' file must be used - these are also supplied in
105 # Handle the case where argv[0] is 'python'
106 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
107 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
109 # Create a temporary directory for input files
110 cls._indir = tempfile.mkdtemp(prefix='binmant.')
112 # Create some test files
113 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
114 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
115 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
116 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
117 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
118 TestFunctional._MakeInputFile('me.bin', ME_DATA)
119 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
122 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
124 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
125 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
126 X86_START16_SPL_DATA)
127 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
128 X86_START16_TPL_DATA)
130 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
132 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
133 X86_RESET16_SPL_DATA)
134 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
135 X86_RESET16_TPL_DATA)
137 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
138 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
139 U_BOOT_SPL_NODTB_DATA)
140 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
141 U_BOOT_TPL_NODTB_DATA)
142 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
143 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
144 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
145 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
146 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
147 TestFunctional._MakeInputDir('devkeys')
148 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
149 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
151 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
152 elf_test.BuildElfTestFiles(cls._elf_testdir)
154 # ELF file with a '_dt_ucode_base_size' symbol
155 TestFunctional._MakeInputFile('u-boot',
156 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
158 # Intel flash descriptor file
159 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
160 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
162 shutil.copytree(cls.TestFile('files'),
163 os.path.join(cls._indir, 'files'))
165 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
167 # Travis-CI may have an old lz4
170 tools.Run('lz4', '--no-frame-crc', '-c',
171 os.path.join(cls._indir, 'u-boot.bin'))
176 def tearDownClass(cls):
177 """Remove the temporary input directory and its contents"""
178 if cls.preserve_indir:
179 print('Preserving input dir: %s' % cls._indir)
182 shutil.rmtree(cls._indir)
186 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
187 toolpath=None, verbosity=None):
188 """Accept arguments controlling test execution
191 preserve_indir: Preserve the shared input directory used by all
193 preserve_outdir: Preserve the output directories used by tests. Each
194 test has its own, so this is normally only useful when running a
196 toolpath: ist of paths to use for tools
198 cls.preserve_indir = preserve_indir
199 cls.preserve_outdirs = preserve_outdirs
200 cls.toolpath = toolpath
201 cls.verbosity = verbosity
204 if not self.have_lz4:
205 self.skipTest('lz4 --no-frame-crc not available')
207 def _CleanupOutputDir(self):
208 """Remove the temporary output directory"""
209 if self.preserve_outdirs:
210 print('Preserving output dir: %s' % tools.outdir)
212 tools._FinaliseForTest()
215 # Enable this to turn on debugging output
216 # tout.Init(tout.DEBUG)
217 command.test_result = None
220 """Remove the temporary output directory"""
221 self._CleanupOutputDir()
223 def _SetupImageInTmpdir(self):
224 """Set up the output image in a new temporary directory
226 This is used when an image has been generated in the output directory,
227 but we want to run binman again. This will create a new output
228 directory and fail to delete the original one.
230 This creates a new temporary directory, copies the image to it (with a
231 new name) and removes the old output directory.
235 Temporary directory to use
238 image_fname = tools.GetOutputFilename('image.bin')
239 tmpdir = tempfile.mkdtemp(prefix='binman.')
240 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
241 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
242 self._CleanupOutputDir()
243 return tmpdir, updated_fname
247 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
248 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
249 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
251 def _RunBinman(self, *args, **kwargs):
252 """Run binman using the command line
255 Arguments to pass, as a list of strings
256 kwargs: Arguments to pass to Command.RunPipe()
258 result = command.RunPipe([[self._binman_pathname] + list(args)],
259 capture=True, capture_stderr=True, raise_on_error=False)
260 if result.return_code and kwargs.get('raise_on_error', True):
261 raise Exception("Error running '%s': %s" % (' '.join(args),
262 result.stdout + result.stderr))
265 def _DoBinman(self, *argv):
266 """Run binman using directly (in the same process)
269 Arguments to pass, as a list of strings
271 Return value (0 for success)
274 args = cmdline.ParseArgs(argv)
275 args.pager = 'binman-invalid-pager'
276 args.build_dir = self._indir
278 # For testing, you can force an increase in verbosity here
279 # args.verbosity = tout.DEBUG
280 return control.Binman(args)
282 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
283 entry_args=None, images=None, use_real_dtb=False,
285 """Run binman with a given test file
288 fname: Device-tree source filename to use (e.g. 005_simple.dts)
289 debug: True to enable debugging output
290 map: True to output map files for the images
291 update_dtb: Update the offset and size of each entry in the device
292 tree before packing it into the image
293 entry_args: Dict of entry args to supply to binman
295 value: value of that arg
296 images: List of image names to build
301 if verbosity is not None:
302 args.append('-v%d' % verbosity)
304 args.append('-v%d' % self.verbosity)
306 for path in self.toolpath:
307 args += ['--toolpath', path]
308 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
314 args.append('--fake-dtb')
316 for arg, value in entry_args.items():
317 args.append('-a%s=%s' % (arg, value))
320 args += ['-i', image]
321 return self._DoBinman(*args)
323 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
324 """Set up a new test device-tree file
326 The given file is compiled and set up as the device tree to be used
330 fname: Filename of .dts file to read
331 outfile: Output filename for compiled device-tree binary
334 Contents of device-tree binary
336 tmpdir = tempfile.mkdtemp(prefix='binmant.')
337 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
338 with open(dtb, 'rb') as fd:
340 TestFunctional._MakeInputFile(outfile, data)
341 shutil.rmtree(tmpdir)
344 def _GetDtbContentsForSplTpl(self, dtb_data, name):
345 """Create a version of the main DTB for SPL or SPL
347 For testing we don't actually have different versions of the DTB. With
348 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
349 we don't normally have any unwanted nodes.
351 We still want the DTBs for SPL and TPL to be different though, since
352 otherwise it is confusing to know which one we are looking at. So add
353 an 'spl' or 'tpl' property to the top-level node.
355 dtb = fdt.Fdt.FromData(dtb_data)
357 dtb.GetNode('/binman').AddZeroProp(name)
358 dtb.Sync(auto_resize=True)
360 return dtb.GetContents()
362 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
363 update_dtb=False, entry_args=None, reset_dtbs=True):
364 """Run binman and return the resulting image
366 This runs binman with a given test file and then reads the resulting
367 output file. It is a shortcut function since most tests need to do
370 Raises an assertion failure if binman returns a non-zero exit code.
373 fname: Device-tree source filename to use (e.g. 005_simple.dts)
374 use_real_dtb: True to use the test file as the contents of
375 the u-boot-dtb entry. Normally this is not needed and the
376 test contents (the U_BOOT_DTB_DATA string) can be used.
377 But in some test we need the real contents.
378 map: True to output map files for the images
379 update_dtb: Update the offset and size of each entry in the device
380 tree before packing it into the image
384 Resulting image contents
386 Map data showing contents of image (or None if none)
387 Output device tree binary filename ('u-boot.dtb' path)
390 # Use the compiled test file as the u-boot-dtb input
392 dtb_data = self._SetupDtb(fname)
394 # For testing purposes, make a copy of the DT for SPL and TPL. Add
395 # a node indicating which it is, so aid verification.
396 for name in ['spl', 'tpl']:
397 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
398 outfile = os.path.join(self._indir, dtb_fname)
399 TestFunctional._MakeInputFile(dtb_fname,
400 self._GetDtbContentsForSplTpl(dtb_data, name))
403 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
404 entry_args=entry_args, use_real_dtb=use_real_dtb)
405 self.assertEqual(0, retcode)
406 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
408 # Find the (only) image, read it and return its contents
409 image = control.images['image']
410 image_fname = tools.GetOutputFilename('image.bin')
411 self.assertTrue(os.path.exists(image_fname))
413 map_fname = tools.GetOutputFilename('image.map')
414 with open(map_fname) as fd:
418 with open(image_fname, 'rb') as fd:
419 return fd.read(), dtb_data, map_data, out_dtb_fname
421 # Put the test file back
422 if reset_dtbs and use_real_dtb:
425 def _DoReadFileRealDtb(self, fname):
426 """Run binman with a real .dtb file and return the resulting data
429 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
432 Resulting image contents
434 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
436 def _DoReadFile(self, fname, use_real_dtb=False):
437 """Helper function which discards the device-tree binary
440 fname: Device-tree source filename to use (e.g. 005_simple.dts)
441 use_real_dtb: True to use the test file as the contents of
442 the u-boot-dtb entry. Normally this is not needed and the
443 test contents (the U_BOOT_DTB_DATA string) can be used.
444 But in some test we need the real contents.
447 Resulting image contents
449 return self._DoReadFileDtb(fname, use_real_dtb)[0]
452 def _MakeInputFile(cls, fname, contents):
453 """Create a new test input file, creating directories as needed
456 fname: Filename to create
457 contents: File contents to write in to the file
459 Full pathname of file created
461 pathname = os.path.join(cls._indir, fname)
462 dirname = os.path.dirname(pathname)
463 if dirname and not os.path.exists(dirname):
465 with open(pathname, 'wb') as fd:
470 def _MakeInputDir(cls, dirname):
471 """Create a new test input directory, creating directories as needed
474 dirname: Directory name to create
477 Full pathname of directory created
479 pathname = os.path.join(cls._indir, dirname)
480 if not os.path.exists(pathname):
481 os.makedirs(pathname)
485 def _SetupSplElf(cls, src_fname='bss_data'):
486 """Set up an ELF file with a '_dt_ucode_base_size' symbol
489 Filename of ELF file to use as SPL
491 # TODO(sjg@chromium.org): Drop this when all Elf files use ElfTestFile()
492 if src_fname in ['bss_data', 'u_boot_ucode_ptr', 'u_boot_no_ucode_ptr']:
493 fname = cls.ElfTestFile(src_fname)
495 fname = cls.TestFile(src_fname)
496 TestFunctional._MakeInputFile('spl/u-boot-spl', tools.ReadFile(fname))
499 def TestFile(cls, fname):
500 return os.path.join(cls._binman_dir, 'test', fname)
503 def ElfTestFile(cls, fname):
504 return os.path.join(cls._elf_testdir, fname)
506 def AssertInList(self, grep_list, target):
507 """Assert that at least one of a list of things is in a target
510 grep_list: List of strings to check
511 target: Target string
513 for grep in grep_list:
516 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
518 def CheckNoGaps(self, entries):
519 """Check that all entries fit together without gaps
522 entries: List of entries to check
525 for entry in entries.values():
526 self.assertEqual(offset, entry.offset)
529 def GetFdtLen(self, dtb):
530 """Get the totalsize field from a device-tree binary
533 dtb: Device-tree binary contents
536 Total size of device-tree binary, from the header
538 return struct.unpack('>L', dtb[4:8])[0]
540 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
541 def AddNode(node, path):
543 path += '/' + node.name
544 for prop in node.props.values():
545 if prop.name in prop_names:
546 prop_path = path + ':' + prop.name
547 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
549 for subnode in node.subnodes:
550 AddNode(subnode, path)
553 AddNode(dtb.GetRoot(), '')
557 """Test a basic run with valid args"""
558 result = self._RunBinman('-h')
560 def testFullHelp(self):
561 """Test that the full help is displayed with -H"""
562 result = self._RunBinman('-H')
563 help_file = os.path.join(self._binman_dir, 'README')
564 # Remove possible extraneous strings
565 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
566 gothelp = result.stdout.replace(extra, '')
567 self.assertEqual(len(gothelp), os.path.getsize(help_file))
568 self.assertEqual(0, len(result.stderr))
569 self.assertEqual(0, result.return_code)
571 def testFullHelpInternal(self):
572 """Test that the full help is displayed with -H"""
574 command.test_result = command.CommandResult()
575 result = self._DoBinman('-H')
576 help_file = os.path.join(self._binman_dir, 'README')
578 command.test_result = None
581 """Test that the basic help is displayed with -h"""
582 result = self._RunBinman('-h')
583 self.assertTrue(len(result.stdout) > 200)
584 self.assertEqual(0, len(result.stderr))
585 self.assertEqual(0, result.return_code)
588 """Test that we can run it with a specific board"""
589 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
590 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
591 result = self._DoBinman('build', '-b', 'sandbox')
592 self.assertEqual(0, result)
594 def testNeedBoard(self):
595 """Test that we get an error when no board ius supplied"""
596 with self.assertRaises(ValueError) as e:
597 result = self._DoBinman('build')
598 self.assertIn("Must provide a board to process (use -b <board>)",
601 def testMissingDt(self):
602 """Test that an invalid device-tree file generates an error"""
603 with self.assertRaises(Exception) as e:
604 self._RunBinman('build', '-d', 'missing_file')
605 # We get one error from libfdt, and a different one from fdtget.
606 self.AssertInList(["Couldn't open blob from 'missing_file'",
607 'No such file or directory'], str(e.exception))
609 def testBrokenDt(self):
610 """Test that an invalid device-tree source file generates an error
612 Since this is a source file it should be compiled and the error
613 will come from the device-tree compiler (dtc).
615 with self.assertRaises(Exception) as e:
616 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
617 self.assertIn("FATAL ERROR: Unable to parse input tree",
620 def testMissingNode(self):
621 """Test that a device tree without a 'binman' node generates an error"""
622 with self.assertRaises(Exception) as e:
623 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
624 self.assertIn("does not have a 'binman' node", str(e.exception))
627 """Test that an empty binman node works OK (i.e. does nothing)"""
628 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
629 self.assertEqual(0, len(result.stderr))
630 self.assertEqual(0, result.return_code)
632 def testInvalidEntry(self):
633 """Test that an invalid entry is flagged"""
634 with self.assertRaises(Exception) as e:
635 result = self._RunBinman('build', '-d',
636 self.TestFile('004_invalid_entry.dts'))
637 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
638 "'/binman/not-a-valid-type'", str(e.exception))
640 def testSimple(self):
641 """Test a simple binman with a single file"""
642 data = self._DoReadFile('005_simple.dts')
643 self.assertEqual(U_BOOT_DATA, data)
645 def testSimpleDebug(self):
646 """Test a simple binman run with debugging enabled"""
647 self._DoTestFile('005_simple.dts', debug=True)
650 """Test that we can handle creating two images
652 This also tests image padding.
654 retcode = self._DoTestFile('006_dual_image.dts')
655 self.assertEqual(0, retcode)
657 image = control.images['image1']
658 self.assertEqual(len(U_BOOT_DATA), image.size)
659 fname = tools.GetOutputFilename('image1.bin')
660 self.assertTrue(os.path.exists(fname))
661 with open(fname, 'rb') as fd:
663 self.assertEqual(U_BOOT_DATA, data)
665 image = control.images['image2']
666 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
667 fname = tools.GetOutputFilename('image2.bin')
668 self.assertTrue(os.path.exists(fname))
669 with open(fname, 'rb') as fd:
671 self.assertEqual(U_BOOT_DATA, data[3:7])
672 self.assertEqual(tools.GetBytes(0, 3), data[:3])
673 self.assertEqual(tools.GetBytes(0, 5), data[7:])
675 def testBadAlign(self):
676 """Test that an invalid alignment value is detected"""
677 with self.assertRaises(ValueError) as e:
678 self._DoTestFile('007_bad_align.dts')
679 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
680 "of two", str(e.exception))
682 def testPackSimple(self):
683 """Test that packing works as expected"""
684 retcode = self._DoTestFile('008_pack.dts')
685 self.assertEqual(0, retcode)
686 self.assertIn('image', control.images)
687 image = control.images['image']
688 entries = image.GetEntries()
689 self.assertEqual(5, len(entries))
692 self.assertIn('u-boot', entries)
693 entry = entries['u-boot']
694 self.assertEqual(0, entry.offset)
695 self.assertEqual(len(U_BOOT_DATA), entry.size)
697 # Second u-boot, aligned to 16-byte boundary
698 self.assertIn('u-boot-align', entries)
699 entry = entries['u-boot-align']
700 self.assertEqual(16, entry.offset)
701 self.assertEqual(len(U_BOOT_DATA), entry.size)
703 # Third u-boot, size 23 bytes
704 self.assertIn('u-boot-size', entries)
705 entry = entries['u-boot-size']
706 self.assertEqual(20, entry.offset)
707 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
708 self.assertEqual(23, entry.size)
710 # Fourth u-boot, placed immediate after the above
711 self.assertIn('u-boot-next', entries)
712 entry = entries['u-boot-next']
713 self.assertEqual(43, entry.offset)
714 self.assertEqual(len(U_BOOT_DATA), entry.size)
716 # Fifth u-boot, placed at a fixed offset
717 self.assertIn('u-boot-fixed', entries)
718 entry = entries['u-boot-fixed']
719 self.assertEqual(61, entry.offset)
720 self.assertEqual(len(U_BOOT_DATA), entry.size)
722 self.assertEqual(65, image.size)
724 def testPackExtra(self):
725 """Test that extra packing feature works as expected"""
726 retcode = self._DoTestFile('009_pack_extra.dts')
728 self.assertEqual(0, retcode)
729 self.assertIn('image', control.images)
730 image = control.images['image']
731 entries = image.GetEntries()
732 self.assertEqual(5, len(entries))
734 # First u-boot with padding before and after
735 self.assertIn('u-boot', entries)
736 entry = entries['u-boot']
737 self.assertEqual(0, entry.offset)
738 self.assertEqual(3, entry.pad_before)
739 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
741 # Second u-boot has an aligned size, but it has no effect
742 self.assertIn('u-boot-align-size-nop', entries)
743 entry = entries['u-boot-align-size-nop']
744 self.assertEqual(12, entry.offset)
745 self.assertEqual(4, entry.size)
747 # Third u-boot has an aligned size too
748 self.assertIn('u-boot-align-size', entries)
749 entry = entries['u-boot-align-size']
750 self.assertEqual(16, entry.offset)
751 self.assertEqual(32, entry.size)
753 # Fourth u-boot has an aligned end
754 self.assertIn('u-boot-align-end', entries)
755 entry = entries['u-boot-align-end']
756 self.assertEqual(48, entry.offset)
757 self.assertEqual(16, entry.size)
759 # Fifth u-boot immediately afterwards
760 self.assertIn('u-boot-align-both', entries)
761 entry = entries['u-boot-align-both']
762 self.assertEqual(64, entry.offset)
763 self.assertEqual(64, entry.size)
765 self.CheckNoGaps(entries)
766 self.assertEqual(128, image.size)
768 def testPackAlignPowerOf2(self):
769 """Test that invalid entry alignment is detected"""
770 with self.assertRaises(ValueError) as e:
771 self._DoTestFile('010_pack_align_power2.dts')
772 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
773 "of two", str(e.exception))
775 def testPackAlignSizePowerOf2(self):
776 """Test that invalid entry size alignment is detected"""
777 with self.assertRaises(ValueError) as e:
778 self._DoTestFile('011_pack_align_size_power2.dts')
779 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
780 "power of two", str(e.exception))
782 def testPackInvalidAlign(self):
783 """Test detection of an offset that does not match its alignment"""
784 with self.assertRaises(ValueError) as e:
785 self._DoTestFile('012_pack_inv_align.dts')
786 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
787 "align 0x4 (4)", str(e.exception))
789 def testPackInvalidSizeAlign(self):
790 """Test that invalid entry size alignment is detected"""
791 with self.assertRaises(ValueError) as e:
792 self._DoTestFile('013_pack_inv_size_align.dts')
793 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
794 "align-size 0x4 (4)", str(e.exception))
796 def testPackOverlap(self):
797 """Test that overlapping regions are detected"""
798 with self.assertRaises(ValueError) as e:
799 self._DoTestFile('014_pack_overlap.dts')
800 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
801 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
804 def testPackEntryOverflow(self):
805 """Test that entries that overflow their size are detected"""
806 with self.assertRaises(ValueError) as e:
807 self._DoTestFile('015_pack_overflow.dts')
808 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
809 "but entry size is 0x3 (3)", str(e.exception))
811 def testPackImageOverflow(self):
812 """Test that entries which overflow the image size are detected"""
813 with self.assertRaises(ValueError) as e:
814 self._DoTestFile('016_pack_image_overflow.dts')
815 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
816 "size 0x3 (3)", str(e.exception))
818 def testPackImageSize(self):
819 """Test that the image size can be set"""
820 retcode = self._DoTestFile('017_pack_image_size.dts')
821 self.assertEqual(0, retcode)
822 self.assertIn('image', control.images)
823 image = control.images['image']
824 self.assertEqual(7, image.size)
826 def testPackImageSizeAlign(self):
827 """Test that image size alignemnt works as expected"""
828 retcode = self._DoTestFile('018_pack_image_align.dts')
829 self.assertEqual(0, retcode)
830 self.assertIn('image', control.images)
831 image = control.images['image']
832 self.assertEqual(16, image.size)
834 def testPackInvalidImageAlign(self):
835 """Test that invalid image alignment is detected"""
836 with self.assertRaises(ValueError) as e:
837 self._DoTestFile('019_pack_inv_image_align.dts')
838 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
839 "align-size 0x8 (8)", str(e.exception))
841 def testPackAlignPowerOf2(self):
842 """Test that invalid image alignment is detected"""
843 with self.assertRaises(ValueError) as e:
844 self._DoTestFile('020_pack_inv_image_align_power2.dts')
845 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
846 "two", str(e.exception))
848 def testImagePadByte(self):
849 """Test that the image pad byte can be specified"""
851 data = self._DoReadFile('021_image_pad.dts')
852 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
855 def testImageName(self):
856 """Test that image files can be named"""
857 retcode = self._DoTestFile('022_image_name.dts')
858 self.assertEqual(0, retcode)
859 image = control.images['image1']
860 fname = tools.GetOutputFilename('test-name')
861 self.assertTrue(os.path.exists(fname))
863 image = control.images['image2']
864 fname = tools.GetOutputFilename('test-name.xx')
865 self.assertTrue(os.path.exists(fname))
867 def testBlobFilename(self):
868 """Test that generic blobs can be provided by filename"""
869 data = self._DoReadFile('023_blob.dts')
870 self.assertEqual(BLOB_DATA, data)
872 def testPackSorted(self):
873 """Test that entries can be sorted"""
875 data = self._DoReadFile('024_sorted.dts')
876 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
877 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
879 def testPackZeroOffset(self):
880 """Test that an entry at offset 0 is not given a new offset"""
881 with self.assertRaises(ValueError) as e:
882 self._DoTestFile('025_pack_zero_size.dts')
883 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
884 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
887 def testPackUbootDtb(self):
888 """Test that a device tree can be added to U-Boot"""
889 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
890 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
892 def testPackX86RomNoSize(self):
893 """Test that the end-at-4gb property requires a size property"""
894 with self.assertRaises(ValueError) as e:
895 self._DoTestFile('027_pack_4gb_no_size.dts')
896 self.assertIn("Image '/binman': Section size must be provided when "
897 "using end-at-4gb", str(e.exception))
899 def test4gbAndSkipAtStartTogether(self):
900 """Test that the end-at-4gb and skip-at-size property can't be used
902 with self.assertRaises(ValueError) as e:
903 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
904 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
905 "'skip-at-start'", str(e.exception))
907 def testPackX86RomOutside(self):
908 """Test that the end-at-4gb property checks for offset boundaries"""
909 with self.assertRaises(ValueError) as e:
910 self._DoTestFile('028_pack_4gb_outside.dts')
911 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
912 "the section starting at 0xffffffe0 (4294967264)",
915 def testPackX86Rom(self):
916 """Test that a basic x86 ROM can be created"""
918 data = self._DoReadFile('029_x86-rom.dts')
919 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
920 tools.GetBytes(0, 2), data)
922 def testPackX86RomMeNoDesc(self):
923 """Test that an invalid Intel descriptor entry is detected"""
924 TestFunctional._MakeInputFile('descriptor.bin', b'')
925 with self.assertRaises(ValueError) as e:
926 self._DoTestFile('031_x86-rom-me.dts')
927 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
930 def testPackX86RomBadDesc(self):
931 """Test that the Intel requires a descriptor entry"""
932 with self.assertRaises(ValueError) as e:
933 self._DoTestFile('030_x86-rom-me-no-desc.dts')
934 self.assertIn("Node '/binman/intel-me': No offset set with "
935 "offset-unset: should another entry provide this correct "
936 "offset?", str(e.exception))
938 def testPackX86RomMe(self):
939 """Test that an x86 ROM with an ME region can be created"""
940 data = self._DoReadFile('031_x86-rom-me.dts')
941 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
942 if data[:0x1000] != expected_desc:
943 self.fail('Expected descriptor binary at start of image')
944 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
946 def testPackVga(self):
947 """Test that an image with a VGA binary can be created"""
948 data = self._DoReadFile('032_intel-vga.dts')
949 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
951 def testPackStart16(self):
952 """Test that an image with an x86 start16 region can be created"""
953 data = self._DoReadFile('033_x86-start16.dts')
954 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
956 def testPackPowerpcMpc85xxBootpgResetvec(self):
957 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
959 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
960 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
962 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
963 """Handle running a test for insertion of microcode
966 dts_fname: Name of test .dts file
967 nodtb_data: Data that we expect in the first section
968 ucode_second: True if the microsecond entry is second instead of
973 Contents of first region (U-Boot or SPL)
974 Offset and size components of microcode pointer, as inserted
975 in the above (two 4-byte words)
977 data = self._DoReadFile(dts_fname, True)
979 # Now check the device tree has no microcode
981 ucode_content = data[len(nodtb_data):]
982 ucode_pos = len(nodtb_data)
983 dtb_with_ucode = ucode_content[16:]
984 fdt_len = self.GetFdtLen(dtb_with_ucode)
986 dtb_with_ucode = data[len(nodtb_data):]
987 fdt_len = self.GetFdtLen(dtb_with_ucode)
988 ucode_content = dtb_with_ucode[fdt_len:]
989 ucode_pos = len(nodtb_data) + fdt_len
990 fname = tools.GetOutputFilename('test.dtb')
991 with open(fname, 'wb') as fd:
992 fd.write(dtb_with_ucode)
993 dtb = fdt.FdtScan(fname)
994 ucode = dtb.GetNode('/microcode')
995 self.assertTrue(ucode)
996 for node in ucode.subnodes:
997 self.assertFalse(node.props.get('data'))
999 # Check that the microcode appears immediately after the Fdt
1000 # This matches the concatenation of the data properties in
1001 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1002 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1004 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1006 # Check that the microcode pointer was inserted. It should match the
1007 # expected offset and size
1008 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1010 u_boot = data[:len(nodtb_data)]
1011 return u_boot, pos_and_size
1013 def testPackUbootMicrocode(self):
1014 """Test that x86 microcode can be handled correctly
1016 We expect to see the following in the image, in order:
1017 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1019 u-boot.dtb with the microcode removed
1022 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1024 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1025 b' somewhere in here', first)
1027 def _RunPackUbootSingleMicrocode(self):
1028 """Test that x86 microcode can be handled correctly
1030 We expect to see the following in the image, in order:
1031 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1033 u-boot.dtb with the microcode
1034 an empty microcode region
1036 # We need the libfdt library to run this test since only that allows
1037 # finding the offset of a property. This is required by
1038 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1039 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1041 second = data[len(U_BOOT_NODTB_DATA):]
1043 fdt_len = self.GetFdtLen(second)
1044 third = second[fdt_len:]
1045 second = second[:fdt_len]
1047 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1048 self.assertIn(ucode_data, second)
1049 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1051 # Check that the microcode pointer was inserted. It should match the
1052 # expected offset and size
1053 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1055 first = data[:len(U_BOOT_NODTB_DATA)]
1056 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1057 b' somewhere in here', first)
1059 def testPackUbootSingleMicrocode(self):
1060 """Test that x86 microcode can be handled correctly with fdt_normal.
1062 self._RunPackUbootSingleMicrocode()
1064 def testUBootImg(self):
1065 """Test that u-boot.img can be put in a file"""
1066 data = self._DoReadFile('036_u_boot_img.dts')
1067 self.assertEqual(U_BOOT_IMG_DATA, data)
1069 def testNoMicrocode(self):
1070 """Test that a missing microcode region is detected"""
1071 with self.assertRaises(ValueError) as e:
1072 self._DoReadFile('037_x86_no_ucode.dts', True)
1073 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1074 "node found in ", str(e.exception))
1076 def testMicrocodeWithoutNode(self):
1077 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1078 with self.assertRaises(ValueError) as e:
1079 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1080 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1081 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1083 def testMicrocodeWithoutNode2(self):
1084 """Test that a missing u-boot-ucode node is detected"""
1085 with self.assertRaises(ValueError) as e:
1086 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1087 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1088 "microcode region u-boot-ucode", str(e.exception))
1090 def testMicrocodeWithoutPtrInElf(self):
1091 """Test that a U-Boot binary without the microcode symbol is detected"""
1092 # ELF file without a '_dt_ucode_base_size' symbol
1094 TestFunctional._MakeInputFile('u-boot',
1095 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1097 with self.assertRaises(ValueError) as e:
1098 self._RunPackUbootSingleMicrocode()
1099 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1100 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1103 # Put the original file back
1104 TestFunctional._MakeInputFile('u-boot',
1105 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1107 def testMicrocodeNotInImage(self):
1108 """Test that microcode must be placed within the image"""
1109 with self.assertRaises(ValueError) as e:
1110 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1111 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1112 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1113 "section ranging from 00000000 to 0000002e", str(e.exception))
1115 def testWithoutMicrocode(self):
1116 """Test that we can cope with an image without microcode (e.g. qemu)"""
1117 TestFunctional._MakeInputFile('u-boot',
1118 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1119 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1121 # Now check the device tree has no microcode
1122 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1123 second = data[len(U_BOOT_NODTB_DATA):]
1125 fdt_len = self.GetFdtLen(second)
1126 self.assertEqual(dtb, second[:fdt_len])
1128 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1129 third = data[used_len:]
1130 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1132 def testUnknownPosSize(self):
1133 """Test that microcode must be placed within the image"""
1134 with self.assertRaises(ValueError) as e:
1135 self._DoReadFile('041_unknown_pos_size.dts', True)
1136 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1137 "entry 'invalid-entry'", str(e.exception))
1139 def testPackFsp(self):
1140 """Test that an image with a FSP binary can be created"""
1141 data = self._DoReadFile('042_intel-fsp.dts')
1142 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1144 def testPackCmc(self):
1145 """Test that an image with a CMC binary can be created"""
1146 data = self._DoReadFile('043_intel-cmc.dts')
1147 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1149 def testPackVbt(self):
1150 """Test that an image with a VBT binary can be created"""
1151 data = self._DoReadFile('046_intel-vbt.dts')
1152 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1154 def testSplBssPad(self):
1155 """Test that we can pad SPL's BSS with zeros"""
1156 # ELF file with a '__bss_size' symbol
1158 data = self._DoReadFile('047_spl_bss_pad.dts')
1159 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1162 def testSplBssPadMissing(self):
1163 """Test that a missing symbol is detected"""
1164 self._SetupSplElf('u_boot_ucode_ptr')
1165 with self.assertRaises(ValueError) as e:
1166 self._DoReadFile('047_spl_bss_pad.dts')
1167 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1170 def testPackStart16Spl(self):
1171 """Test that an image with an x86 start16 SPL region can be created"""
1172 data = self._DoReadFile('048_x86-start16-spl.dts')
1173 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1175 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1176 """Helper function for microcode tests
1178 We expect to see the following in the image, in order:
1179 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1181 u-boot.dtb with the microcode removed
1185 dts: Device tree file to use for test
1186 ucode_second: True if the microsecond entry is second instead of
1189 self._SetupSplElf('u_boot_ucode_ptr')
1190 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1191 ucode_second=ucode_second)
1192 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1193 b'ter somewhere in here', first)
1195 def testPackUbootSplMicrocode(self):
1196 """Test that x86 microcode can be handled correctly in SPL"""
1197 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1199 def testPackUbootSplMicrocodeReorder(self):
1200 """Test that order doesn't matter for microcode entries
1202 This is the same as testPackUbootSplMicrocode but when we process the
1203 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1204 entry, so we reply on binman to try later.
1206 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1209 def testPackMrc(self):
1210 """Test that an image with an MRC binary can be created"""
1211 data = self._DoReadFile('050_intel_mrc.dts')
1212 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1214 def testSplDtb(self):
1215 """Test that an image with spl/u-boot-spl.dtb can be created"""
1216 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1217 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1219 def testSplNoDtb(self):
1220 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1221 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1222 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1224 def testSymbols(self):
1225 """Test binman can assign symbols embedded in U-Boot"""
1226 elf_fname = self.TestFile('u_boot_binman_syms')
1227 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1228 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1229 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1231 self._SetupSplElf('u_boot_binman_syms')
1232 data = self._DoReadFile('053_symbols.dts')
1233 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1234 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1235 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1236 U_BOOT_SPL_DATA[16:])
1237 self.assertEqual(expected, data)
1239 def testPackUnitAddress(self):
1240 """Test that we support multiple binaries with the same name"""
1241 data = self._DoReadFile('054_unit_address.dts')
1242 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1244 def testSections(self):
1245 """Basic test of sections"""
1246 data = self._DoReadFile('055_sections.dts')
1247 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1248 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1249 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1250 self.assertEqual(expected, data)
1253 """Tests outputting a map of the images"""
1254 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1255 self.assertEqual('''ImagePos Offset Size Name
1256 00000000 00000000 00000028 main-section
1257 00000000 00000000 00000010 section@0
1258 00000000 00000000 00000004 u-boot
1259 00000010 00000010 00000010 section@1
1260 00000010 00000000 00000004 u-boot
1261 00000020 00000020 00000004 section@2
1262 00000020 00000000 00000004 u-boot
1265 def testNamePrefix(self):
1266 """Tests that name prefixes are used"""
1267 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1268 self.assertEqual('''ImagePos Offset Size Name
1269 00000000 00000000 00000028 main-section
1270 00000000 00000000 00000010 section@0
1271 00000000 00000000 00000004 ro-u-boot
1272 00000010 00000010 00000010 section@1
1273 00000010 00000000 00000004 rw-u-boot
1276 def testUnknownContents(self):
1277 """Test that obtaining the contents works as expected"""
1278 with self.assertRaises(ValueError) as e:
1279 self._DoReadFile('057_unknown_contents.dts', True)
1280 self.assertIn("Image '/binman': Internal error: Could not complete "
1281 "processing of contents: remaining [<_testing.Entry__testing ",
1284 def testBadChangeSize(self):
1285 """Test that trying to change the size of an entry fails"""
1287 state.SetAllowEntryExpansion(False)
1288 with self.assertRaises(ValueError) as e:
1289 self._DoReadFile('059_change_size.dts', True)
1290 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1293 state.SetAllowEntryExpansion(True)
1295 def testUpdateFdt(self):
1296 """Test that we can update the device tree with offset/size info"""
1297 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1299 dtb = fdt.Fdt(out_dtb_fname)
1301 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1305 '_testing:offset': 32,
1307 '_testing:image-pos': 32,
1308 'section@0/u-boot:offset': 0,
1309 'section@0/u-boot:size': len(U_BOOT_DATA),
1310 'section@0/u-boot:image-pos': 0,
1311 'section@0:offset': 0,
1312 'section@0:size': 16,
1313 'section@0:image-pos': 0,
1315 'section@1/u-boot:offset': 0,
1316 'section@1/u-boot:size': len(U_BOOT_DATA),
1317 'section@1/u-boot:image-pos': 16,
1318 'section@1:offset': 16,
1319 'section@1:size': 16,
1320 'section@1:image-pos': 16,
1324 def testUpdateFdtBad(self):
1325 """Test that we detect when ProcessFdt never completes"""
1326 with self.assertRaises(ValueError) as e:
1327 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1328 self.assertIn('Could not complete processing of Fdt: remaining '
1329 '[<_testing.Entry__testing', str(e.exception))
1331 def testEntryArgs(self):
1332 """Test passing arguments to entries from the command line"""
1334 'test-str-arg': 'test1',
1335 'test-int-arg': '456',
1337 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1338 self.assertIn('image', control.images)
1339 entry = control.images['image'].GetEntries()['_testing']
1340 self.assertEqual('test0', entry.test_str_fdt)
1341 self.assertEqual('test1', entry.test_str_arg)
1342 self.assertEqual(123, entry.test_int_fdt)
1343 self.assertEqual(456, entry.test_int_arg)
1345 def testEntryArgsMissing(self):
1346 """Test missing arguments and properties"""
1348 'test-int-arg': '456',
1350 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1351 entry = control.images['image'].GetEntries()['_testing']
1352 self.assertEqual('test0', entry.test_str_fdt)
1353 self.assertEqual(None, entry.test_str_arg)
1354 self.assertEqual(None, entry.test_int_fdt)
1355 self.assertEqual(456, entry.test_int_arg)
1357 def testEntryArgsRequired(self):
1358 """Test missing arguments and properties"""
1360 'test-int-arg': '456',
1362 with self.assertRaises(ValueError) as e:
1363 self._DoReadFileDtb('064_entry_args_required.dts')
1364 self.assertIn("Node '/binman/_testing': Missing required "
1365 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1368 def testEntryArgsInvalidFormat(self):
1369 """Test that an invalid entry-argument format is detected"""
1370 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1372 with self.assertRaises(ValueError) as e:
1373 self._DoBinman(*args)
1374 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1376 def testEntryArgsInvalidInteger(self):
1377 """Test that an invalid entry-argument integer is detected"""
1379 'test-int-arg': 'abc',
1381 with self.assertRaises(ValueError) as e:
1382 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1383 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1384 "'test-int-arg' (value 'abc') to integer",
1387 def testEntryArgsInvalidDatatype(self):
1388 """Test that an invalid entry-argument datatype is detected
1390 This test could be written in entry_test.py except that it needs
1391 access to control.entry_args, which seems more than that module should
1395 'test-bad-datatype-arg': '12',
1397 with self.assertRaises(ValueError) as e:
1398 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1399 entry_args=entry_args)
1400 self.assertIn('GetArg() internal error: Unknown data type ',
1404 """Test for a text entry type"""
1406 'test-id': TEXT_DATA,
1407 'test-id2': TEXT_DATA2,
1408 'test-id3': TEXT_DATA3,
1410 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1411 entry_args=entry_args)
1412 expected = (tools.ToBytes(TEXT_DATA) +
1413 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1414 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1415 b'some text' + b'more text')
1416 self.assertEqual(expected, data)
1418 def testEntryDocs(self):
1419 """Test for creation of entry documentation"""
1420 with test_util.capture_sys_output() as (stdout, stderr):
1421 control.WriteEntryDocs(binman.GetEntryModules())
1422 self.assertTrue(len(stdout.getvalue()) > 0)
1424 def testEntryDocsMissing(self):
1425 """Test handling of missing entry documentation"""
1426 with self.assertRaises(ValueError) as e:
1427 with test_util.capture_sys_output() as (stdout, stderr):
1428 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1429 self.assertIn('Documentation is missing for modules: u_boot',
1433 """Basic test of generation of a flashrom fmap"""
1434 data = self._DoReadFile('067_fmap.dts')
1435 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1436 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1437 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1438 self.assertEqual(expected, data[:32])
1439 self.assertEqual(b'__FMAP__', fhdr.signature)
1440 self.assertEqual(1, fhdr.ver_major)
1441 self.assertEqual(0, fhdr.ver_minor)
1442 self.assertEqual(0, fhdr.base)
1443 self.assertEqual(16 + 16 +
1444 fmap_util.FMAP_HEADER_LEN +
1445 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1446 self.assertEqual(b'FMAP', fhdr.name)
1447 self.assertEqual(3, fhdr.nareas)
1448 for fentry in fentries:
1449 self.assertEqual(0, fentry.flags)
1451 self.assertEqual(0, fentries[0].offset)
1452 self.assertEqual(4, fentries[0].size)
1453 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1455 self.assertEqual(16, fentries[1].offset)
1456 self.assertEqual(4, fentries[1].size)
1457 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1459 self.assertEqual(32, fentries[2].offset)
1460 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1461 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1462 self.assertEqual(b'FMAP', fentries[2].name)
1464 def testBlobNamedByArg(self):
1465 """Test we can add a blob with the filename coming from an entry arg"""
1467 'cros-ec-rw-path': 'ecrw.bin',
1469 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1470 entry_args=entry_args)
1473 """Test for an fill entry type"""
1474 data = self._DoReadFile('069_fill.dts')
1475 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1476 self.assertEqual(expected, data)
1478 def testFillNoSize(self):
1479 """Test for an fill entry type with no size"""
1480 with self.assertRaises(ValueError) as e:
1481 self._DoReadFile('070_fill_no_size.dts')
1482 self.assertIn("'fill' entry must have a size property",
1485 def _HandleGbbCommand(self, pipe_list):
1486 """Fake calls to the futility utility"""
1487 if pipe_list[0][0] == 'futility':
1488 fname = pipe_list[0][-1]
1489 # Append our GBB data to the file, which will happen every time the
1490 # futility command is called.
1491 with open(fname, 'ab') as fd:
1493 return command.CommandResult()
1496 """Test for the Chromium OS Google Binary Block"""
1497 command.test_result = self._HandleGbbCommand
1499 'keydir': 'devkeys',
1500 'bmpblk': 'bmpblk.bin',
1502 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1505 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1506 tools.GetBytes(0, 0x2180 - 16))
1507 self.assertEqual(expected, data)
1509 def testGbbTooSmall(self):
1510 """Test for the Chromium OS Google Binary Block being large enough"""
1511 with self.assertRaises(ValueError) as e:
1512 self._DoReadFileDtb('072_gbb_too_small.dts')
1513 self.assertIn("Node '/binman/gbb': GBB is too small",
1516 def testGbbNoSize(self):
1517 """Test for the Chromium OS Google Binary Block having a size"""
1518 with self.assertRaises(ValueError) as e:
1519 self._DoReadFileDtb('073_gbb_no_size.dts')
1520 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1523 def _HandleVblockCommand(self, pipe_list):
1524 """Fake calls to the futility utility"""
1525 if pipe_list[0][0] == 'futility':
1526 fname = pipe_list[0][3]
1527 with open(fname, 'wb') as fd:
1528 fd.write(VBLOCK_DATA)
1529 return command.CommandResult()
1531 def testVblock(self):
1532 """Test for the Chromium OS Verified Boot Block"""
1533 command.test_result = self._HandleVblockCommand
1535 'keydir': 'devkeys',
1537 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1538 entry_args=entry_args)
1539 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1540 self.assertEqual(expected, data)
1542 def testVblockNoContent(self):
1543 """Test we detect a vblock which has no content to sign"""
1544 with self.assertRaises(ValueError) as e:
1545 self._DoReadFile('075_vblock_no_content.dts')
1546 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1547 'property', str(e.exception))
1549 def testVblockBadPhandle(self):
1550 """Test that we detect a vblock with an invalid phandle in contents"""
1551 with self.assertRaises(ValueError) as e:
1552 self._DoReadFile('076_vblock_bad_phandle.dts')
1553 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1554 '1000', str(e.exception))
1556 def testVblockBadEntry(self):
1557 """Test that we detect an entry that points to a non-entry"""
1558 with self.assertRaises(ValueError) as e:
1559 self._DoReadFile('077_vblock_bad_entry.dts')
1560 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1561 "'other'", str(e.exception))
1564 """Test that an image with TPL and ots device tree can be created"""
1565 # ELF file with a '__bss_size' symbol
1566 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1567 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1568 data = self._DoReadFile('078_u_boot_tpl.dts')
1569 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1571 def testUsesPos(self):
1572 """Test that the 'pos' property cannot be used anymore"""
1573 with self.assertRaises(ValueError) as e:
1574 data = self._DoReadFile('079_uses_pos.dts')
1575 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1576 "'pos'", str(e.exception))
1578 def testFillZero(self):
1579 """Test for an fill entry type with a size of 0"""
1580 data = self._DoReadFile('080_fill_empty.dts')
1581 self.assertEqual(tools.GetBytes(0, 16), data)
1583 def testTextMissing(self):
1584 """Test for a text entry type where there is no text"""
1585 with self.assertRaises(ValueError) as e:
1586 self._DoReadFileDtb('066_text.dts',)
1587 self.assertIn("Node '/binman/text': No value provided for text label "
1588 "'test-id'", str(e.exception))
1590 def testPackStart16Tpl(self):
1591 """Test that an image with an x86 start16 TPL region can be created"""
1592 data = self._DoReadFile('081_x86-start16-tpl.dts')
1593 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1595 def testSelectImage(self):
1596 """Test that we can select which images to build"""
1597 expected = 'Skipping images: image1'
1599 # We should only get the expected message in verbose mode
1600 for verbosity in (0, 2):
1601 with test_util.capture_sys_output() as (stdout, stderr):
1602 retcode = self._DoTestFile('006_dual_image.dts',
1603 verbosity=verbosity,
1605 self.assertEqual(0, retcode)
1607 self.assertIn(expected, stdout.getvalue())
1609 self.assertNotIn(expected, stdout.getvalue())
1611 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1612 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1613 self._CleanupOutputDir()
1615 def testUpdateFdtAll(self):
1616 """Test that all device trees are updated with offset/size info"""
1617 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1620 'section:image-pos': 0,
1621 'u-boot-tpl-dtb:size': 513,
1622 'u-boot-spl-dtb:size': 513,
1623 'u-boot-spl-dtb:offset': 493,
1625 'section/u-boot-dtb:image-pos': 0,
1626 'u-boot-spl-dtb:image-pos': 493,
1627 'section/u-boot-dtb:size': 493,
1628 'u-boot-tpl-dtb:image-pos': 1006,
1629 'section/u-boot-dtb:offset': 0,
1630 'section:size': 493,
1632 'section:offset': 0,
1633 'u-boot-tpl-dtb:offset': 1006,
1637 # We expect three device-tree files in the output, one after the other.
1638 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1639 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1640 # main U-Boot tree. All three should have the same postions and offset.
1642 for item in ['', 'spl', 'tpl']:
1643 dtb = fdt.Fdt.FromData(data[start:])
1645 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1647 expected = dict(base_expected)
1650 self.assertEqual(expected, props)
1651 start += dtb._fdt_obj.totalsize()
1653 def testUpdateFdtOutput(self):
1654 """Test that output DTB files are updated"""
1656 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1657 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1659 # Unfortunately, compiling a source file always results in a file
1660 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1661 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1662 # binman as a file called u-boot.dtb. To fix this, copy the file
1663 # over to the expected place.
1664 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1665 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1667 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1668 'tpl/u-boot-tpl.dtb.out']:
1669 dtb = fdt.Fdt.FromData(data[start:])
1670 size = dtb._fdt_obj.totalsize()
1671 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1672 outdata = tools.ReadFile(pathname)
1673 name = os.path.split(fname)[0]
1676 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1678 orig_indata = dtb_data
1679 self.assertNotEqual(outdata, orig_indata,
1680 "Expected output file '%s' be updated" % pathname)
1681 self.assertEqual(outdata, data[start:start + size],
1682 "Expected output file '%s' to match output image" %
1688 def _decompress(self, data):
1689 return tools.Decompress(data, 'lz4')
1691 def testCompress(self):
1692 """Test compression of blobs"""
1694 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1695 use_real_dtb=True, update_dtb=True)
1696 dtb = fdt.Fdt(out_dtb_fname)
1698 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1699 orig = self._decompress(data)
1700 self.assertEquals(COMPRESS_DATA, orig)
1702 'blob:uncomp-size': len(COMPRESS_DATA),
1703 'blob:size': len(data),
1706 self.assertEqual(expected, props)
1708 def testFiles(self):
1709 """Test bringing in multiple files"""
1710 data = self._DoReadFile('084_files.dts')
1711 self.assertEqual(FILES_DATA, data)
1713 def testFilesCompress(self):
1714 """Test bringing in multiple files and compressing them"""
1716 data = self._DoReadFile('085_files_compress.dts')
1718 image = control.images['image']
1719 entries = image.GetEntries()
1720 files = entries['files']
1721 entries = files._entries
1724 for i in range(1, 3):
1726 start = entries[key].image_pos
1727 len = entries[key].size
1728 chunk = data[start:start + len]
1729 orig += self._decompress(chunk)
1731 self.assertEqual(FILES_DATA, orig)
1733 def testFilesMissing(self):
1734 """Test missing files"""
1735 with self.assertRaises(ValueError) as e:
1736 data = self._DoReadFile('086_files_none.dts')
1737 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1738 'no files', str(e.exception))
1740 def testFilesNoPattern(self):
1741 """Test missing files"""
1742 with self.assertRaises(ValueError) as e:
1743 data = self._DoReadFile('087_files_no_pattern.dts')
1744 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1747 def testExpandSize(self):
1748 """Test an expanding entry"""
1749 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1751 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1752 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1753 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1754 tools.GetBytes(ord('d'), 8))
1755 self.assertEqual(expect, data)
1756 self.assertEqual('''ImagePos Offset Size Name
1757 00000000 00000000 00000028 main-section
1758 00000000 00000000 00000008 fill
1759 00000008 00000008 00000004 u-boot
1760 0000000c 0000000c 00000004 section
1761 0000000c 00000000 00000003 intel-mrc
1762 00000010 00000010 00000004 u-boot2
1763 00000014 00000014 0000000c section2
1764 00000014 00000000 00000008 fill
1765 0000001c 00000008 00000004 u-boot
1766 00000020 00000020 00000008 fill2
1769 def testExpandSizeBad(self):
1770 """Test an expanding entry which fails to provide contents"""
1771 with test_util.capture_sys_output() as (stdout, stderr):
1772 with self.assertRaises(ValueError) as e:
1773 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1774 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1775 'expanding entry', str(e.exception))
1778 """Test hashing of the contents of an entry"""
1779 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1780 use_real_dtb=True, update_dtb=True)
1781 dtb = fdt.Fdt(out_dtb_fname)
1783 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1784 m = hashlib.sha256()
1785 m.update(U_BOOT_DATA)
1786 self.assertEqual(m.digest(), b''.join(hash_node.value))
1788 def testHashNoAlgo(self):
1789 with self.assertRaises(ValueError) as e:
1790 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1791 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1792 'hash node', str(e.exception))
1794 def testHashBadAlgo(self):
1795 with self.assertRaises(ValueError) as e:
1796 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1797 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1800 def testHashSection(self):
1801 """Test hashing of the contents of an entry"""
1802 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1803 use_real_dtb=True, update_dtb=True)
1804 dtb = fdt.Fdt(out_dtb_fname)
1806 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1807 m = hashlib.sha256()
1808 m.update(U_BOOT_DATA)
1809 m.update(tools.GetBytes(ord('a'), 16))
1810 self.assertEqual(m.digest(), b''.join(hash_node.value))
1812 def testPackUBootTplMicrocode(self):
1813 """Test that x86 microcode can be handled correctly in TPL
1815 We expect to see the following in the image, in order:
1816 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1818 u-boot-tpl.dtb with the microcode removed
1821 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
1822 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1823 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1824 U_BOOT_TPL_NODTB_DATA)
1825 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1826 b'ter somewhere in here', first)
1828 def testFmapX86(self):
1829 """Basic test of generation of a flashrom fmap"""
1830 data = self._DoReadFile('094_fmap_x86.dts')
1831 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1832 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1833 self.assertEqual(expected, data[:32])
1834 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1836 self.assertEqual(0x100, fhdr.image_size)
1838 self.assertEqual(0, fentries[0].offset)
1839 self.assertEqual(4, fentries[0].size)
1840 self.assertEqual(b'U_BOOT', fentries[0].name)
1842 self.assertEqual(4, fentries[1].offset)
1843 self.assertEqual(3, fentries[1].size)
1844 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1846 self.assertEqual(32, fentries[2].offset)
1847 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1848 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1849 self.assertEqual(b'FMAP', fentries[2].name)
1851 def testFmapX86Section(self):
1852 """Basic test of generation of a flashrom fmap"""
1853 data = self._DoReadFile('095_fmap_x86_section.dts')
1854 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1855 self.assertEqual(expected, data[:32])
1856 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1858 self.assertEqual(0x100, fhdr.image_size)
1860 self.assertEqual(0, fentries[0].offset)
1861 self.assertEqual(4, fentries[0].size)
1862 self.assertEqual(b'U_BOOT', fentries[0].name)
1864 self.assertEqual(4, fentries[1].offset)
1865 self.assertEqual(3, fentries[1].size)
1866 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1868 self.assertEqual(36, fentries[2].offset)
1869 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1870 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1871 self.assertEqual(b'FMAP', fentries[2].name)
1874 """Basic test of ELF entries"""
1876 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1877 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1878 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1879 TestFunctional._MakeInputFile('-boot', fd.read())
1880 data = self._DoReadFile('096_elf.dts')
1882 def testElfStrip(self):
1883 """Basic test of ELF entries"""
1885 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1886 TestFunctional._MakeInputFile('-boot', fd.read())
1887 data = self._DoReadFile('097_elf_strip.dts')
1889 def testPackOverlapMap(self):
1890 """Test that overlapping regions are detected"""
1891 with test_util.capture_sys_output() as (stdout, stderr):
1892 with self.assertRaises(ValueError) as e:
1893 self._DoTestFile('014_pack_overlap.dts', map=True)
1894 map_fname = tools.GetOutputFilename('image.map')
1895 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1898 # We should not get an inmage, but there should be a map file
1899 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1900 self.assertTrue(os.path.exists(map_fname))
1901 map_data = tools.ReadFile(map_fname, binary=False)
1902 self.assertEqual('''ImagePos Offset Size Name
1903 <none> 00000000 00000007 main-section
1904 <none> 00000000 00000004 u-boot
1905 <none> 00000003 00000004 u-boot-align
1908 def testPackRefCode(self):
1909 """Test that an image with an Intel Reference code binary works"""
1910 data = self._DoReadFile('100_intel_refcode.dts')
1911 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1913 def testSectionOffset(self):
1914 """Tests use of a section with an offset"""
1915 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1917 self.assertEqual('''ImagePos Offset Size Name
1918 00000000 00000000 00000038 main-section
1919 00000004 00000004 00000010 section@0
1920 00000004 00000000 00000004 u-boot
1921 00000018 00000018 00000010 section@1
1922 00000018 00000000 00000004 u-boot
1923 0000002c 0000002c 00000004 section@2
1924 0000002c 00000000 00000004 u-boot
1926 self.assertEqual(data,
1927 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1928 tools.GetBytes(0x21, 12) +
1929 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1930 tools.GetBytes(0x61, 12) +
1931 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1932 tools.GetBytes(0x26, 8))
1934 def testCbfsRaw(self):
1935 """Test base handling of a Coreboot Filesystem (CBFS)
1937 The exact contents of the CBFS is verified by similar tests in
1938 cbfs_util_test.py. The tests here merely check that the files added to
1939 the CBFS can be found in the final image.
1941 data = self._DoReadFile('102_cbfs_raw.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 testCbfsArch(self):
1952 """Test on non-x86 architecture"""
1953 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1956 cbfs = cbfs_util.CbfsReader(data)
1957 self.assertEqual(size, cbfs.rom_size)
1959 self.assertIn('u-boot-dtb', cbfs.files)
1960 cfile = cbfs.files['u-boot-dtb']
1961 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1963 def testCbfsStage(self):
1964 """Tests handling of a Coreboot Filesystem (CBFS)"""
1965 if not elf.ELF_TOOLS:
1966 self.skipTest('Python elftools not available')
1967 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1968 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1971 data = self._DoReadFile('104_cbfs_stage.dts')
1972 cbfs = cbfs_util.CbfsReader(data)
1973 self.assertEqual(size, cbfs.rom_size)
1975 self.assertIn('u-boot', cbfs.files)
1976 cfile = cbfs.files['u-boot']
1977 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1979 def testCbfsRawCompress(self):
1980 """Test handling of compressing raw files"""
1982 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1985 cbfs = cbfs_util.CbfsReader(data)
1986 self.assertIn('u-boot', cbfs.files)
1987 cfile = cbfs.files['u-boot']
1988 self.assertEqual(COMPRESS_DATA, cfile.data)
1990 def testCbfsBadArch(self):
1991 """Test handling of a bad architecture"""
1992 with self.assertRaises(ValueError) as e:
1993 self._DoReadFile('106_cbfs_bad_arch.dts')
1994 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1996 def testCbfsNoSize(self):
1997 """Test handling of a missing size property"""
1998 with self.assertRaises(ValueError) as e:
1999 self._DoReadFile('107_cbfs_no_size.dts')
2000 self.assertIn('entry must have a size property', str(e.exception))
2002 def testCbfsNoCOntents(self):
2003 """Test handling of a CBFS entry which does not provide contentsy"""
2004 with self.assertRaises(ValueError) as e:
2005 self._DoReadFile('108_cbfs_no_contents.dts')
2006 self.assertIn('Could not complete processing of contents',
2009 def testCbfsBadCompress(self):
2010 """Test handling of a bad architecture"""
2011 with self.assertRaises(ValueError) as e:
2012 self._DoReadFile('109_cbfs_bad_compress.dts')
2013 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2016 def testCbfsNamedEntries(self):
2017 """Test handling of named entries"""
2018 data = self._DoReadFile('110_cbfs_name.dts')
2020 cbfs = cbfs_util.CbfsReader(data)
2021 self.assertIn('FRED', cbfs.files)
2022 cfile1 = cbfs.files['FRED']
2023 self.assertEqual(U_BOOT_DATA, cfile1.data)
2025 self.assertIn('hello', cbfs.files)
2026 cfile2 = cbfs.files['hello']
2027 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2029 def _SetupIfwi(self, fname):
2030 """Set up to run an IFWI test
2033 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2037 # Intel Integrated Firmware Image (IFWI) file
2038 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2040 TestFunctional._MakeInputFile(fname,data)
2042 def _CheckIfwi(self, data):
2043 """Check that an image with an IFWI contains the correct output
2046 data: Conents of output file
2048 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2049 if data[:0x1000] != expected_desc:
2050 self.fail('Expected descriptor binary at start of image')
2052 # We expect to find the TPL wil in subpart IBBP entry IBBL
2053 image_fname = tools.GetOutputFilename('image.bin')
2054 tpl_fname = tools.GetOutputFilename('tpl.out')
2055 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2056 subpart='IBBP', entry_name='IBBL')
2058 tpl_data = tools.ReadFile(tpl_fname)
2059 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2061 def testPackX86RomIfwi(self):
2062 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2063 self._SetupIfwi('fitimage.bin')
2064 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2065 self._CheckIfwi(data)
2067 def testPackX86RomIfwiNoDesc(self):
2068 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2069 self._SetupIfwi('ifwi.bin')
2070 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2071 self._CheckIfwi(data)
2073 def testPackX86RomIfwiNoData(self):
2074 """Test that an x86 ROM with IFWI handles missing data"""
2075 self._SetupIfwi('ifwi.bin')
2076 with self.assertRaises(ValueError) as e:
2077 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2078 self.assertIn('Could not complete processing of contents',
2081 def testCbfsOffset(self):
2082 """Test a CBFS with files at particular offsets
2084 Like all CFBS tests, this is just checking the logic that calls
2085 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2087 data = self._DoReadFile('114_cbfs_offset.dts')
2090 cbfs = cbfs_util.CbfsReader(data)
2091 self.assertEqual(size, cbfs.rom_size)
2093 self.assertIn('u-boot', cbfs.files)
2094 cfile = cbfs.files['u-boot']
2095 self.assertEqual(U_BOOT_DATA, cfile.data)
2096 self.assertEqual(0x40, cfile.cbfs_offset)
2098 self.assertIn('u-boot-dtb', cbfs.files)
2099 cfile2 = cbfs.files['u-boot-dtb']
2100 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2101 self.assertEqual(0x140, cfile2.cbfs_offset)
2103 def testFdtmap(self):
2104 """Test an FDT map can be inserted in the image"""
2105 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2106 fdtmap_data = data[len(U_BOOT_DATA):]
2107 magic = fdtmap_data[:8]
2108 self.assertEqual('_FDTMAP_', magic)
2109 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2111 fdt_data = fdtmap_data[16:]
2112 dtb = fdt.Fdt.FromData(fdt_data)
2114 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2119 'u-boot:size': len(U_BOOT_DATA),
2120 'u-boot:image-pos': 0,
2121 'fdtmap:image-pos': 4,
2123 'fdtmap:size': len(fdtmap_data),
2127 def testFdtmapNoMatch(self):
2128 """Check handling of an FDT map when the section cannot be found"""
2129 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2131 # Mangle the section name, which should cause a mismatch between the
2132 # correct FDT path and the one expected by the section
2133 image = control.images['image']
2134 image._node.path += '-suffix'
2135 entries = image.GetEntries()
2136 fdtmap = entries['fdtmap']
2137 with self.assertRaises(ValueError) as e:
2139 self.assertIn("Cannot locate node for path '/binman-suffix'",
2142 def testFdtmapHeader(self):
2143 """Test an FDT map and image header can be inserted in the image"""
2144 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2145 fdtmap_pos = len(U_BOOT_DATA)
2146 fdtmap_data = data[fdtmap_pos:]
2147 fdt_data = fdtmap_data[16:]
2148 dtb = fdt.Fdt.FromData(fdt_data)
2149 fdt_size = dtb.GetFdtObj().totalsize()
2150 hdr_data = data[-8:]
2151 self.assertEqual('BinM', hdr_data[:4])
2152 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2153 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2155 def testFdtmapHeaderStart(self):
2156 """Test an image header can be inserted at the image start"""
2157 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2158 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2160 self.assertEqual('BinM', hdr_data[:4])
2161 offset = struct.unpack('<I', hdr_data[4:])[0]
2162 self.assertEqual(fdtmap_pos, offset)
2164 def testFdtmapHeaderPos(self):
2165 """Test an image header can be inserted at a chosen position"""
2166 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2167 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2168 hdr_data = data[0x80:0x88]
2169 self.assertEqual('BinM', hdr_data[:4])
2170 offset = struct.unpack('<I', hdr_data[4:])[0]
2171 self.assertEqual(fdtmap_pos, offset)
2173 def testHeaderMissingFdtmap(self):
2174 """Test an image header requires an fdtmap"""
2175 with self.assertRaises(ValueError) as e:
2176 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2177 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2180 def testHeaderNoLocation(self):
2181 """Test an image header with a no specified location is detected"""
2182 with self.assertRaises(ValueError) as e:
2183 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2184 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2187 def testEntryExpand(self):
2188 """Test expanding an entry after it is packed"""
2189 data = self._DoReadFile('121_entry_expand.dts')
2190 self.assertEqual(b'aaa', data[:3])
2191 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2192 self.assertEqual(b'aaa', data[-3:])
2194 def testEntryExpandBad(self):
2195 """Test expanding an entry after it is packed, twice"""
2196 with self.assertRaises(ValueError) as e:
2197 self._DoReadFile('122_entry_expand_twice.dts')
2198 self.assertIn("Image '/binman': Entries changed size after packing",
2201 def testEntryExpandSection(self):
2202 """Test expanding an entry within a section after it is packed"""
2203 data = self._DoReadFile('123_entry_expand_section.dts')
2204 self.assertEqual(b'aaa', data[:3])
2205 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2206 self.assertEqual(b'aaa', data[-3:])
2208 def testCompressDtb(self):
2209 """Test that compress of device-tree files is supported"""
2211 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2212 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2213 comp_data = data[len(U_BOOT_DATA):]
2214 orig = self._decompress(comp_data)
2215 dtb = fdt.Fdt.FromData(orig)
2217 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2219 'u-boot:size': len(U_BOOT_DATA),
2220 'u-boot-dtb:uncomp-size': len(orig),
2221 'u-boot-dtb:size': len(comp_data),
2224 self.assertEqual(expected, props)
2226 def testCbfsUpdateFdt(self):
2227 """Test that we can update the device tree with CBFS offset/size info"""
2229 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2231 dtb = fdt.Fdt(out_dtb_fname)
2233 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2234 del props['cbfs/u-boot:size']
2240 'cbfs:size': len(data),
2241 'cbfs:image-pos': 0,
2242 'cbfs/u-boot:offset': 0x38,
2243 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2244 'cbfs/u-boot:image-pos': 0x38,
2245 'cbfs/u-boot-dtb:offset': 0xb8,
2246 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2247 'cbfs/u-boot-dtb:image-pos': 0xb8,
2250 def testCbfsBadType(self):
2251 """Test an image header with a no specified location is detected"""
2252 with self.assertRaises(ValueError) as e:
2253 self._DoReadFile('126_cbfs_bad_type.dts')
2254 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2257 """Test listing the files in an image"""
2259 data = self._DoReadFile('127_list.dts')
2260 image = control.images['image']
2261 entries = image.BuildEntryList()
2262 self.assertEqual(7, len(entries))
2265 self.assertEqual(0, ent.indent)
2266 self.assertEqual('main-section', ent.name)
2267 self.assertEqual('section', ent.etype)
2268 self.assertEqual(len(data), ent.size)
2269 self.assertEqual(0, ent.image_pos)
2270 self.assertEqual(None, ent.uncomp_size)
2271 self.assertEqual(0, ent.offset)
2274 self.assertEqual(1, ent.indent)
2275 self.assertEqual('u-boot', ent.name)
2276 self.assertEqual('u-boot', ent.etype)
2277 self.assertEqual(len(U_BOOT_DATA), ent.size)
2278 self.assertEqual(0, ent.image_pos)
2279 self.assertEqual(None, ent.uncomp_size)
2280 self.assertEqual(0, ent.offset)
2283 self.assertEqual(1, ent.indent)
2284 self.assertEqual('section', ent.name)
2285 self.assertEqual('section', ent.etype)
2286 section_size = ent.size
2287 self.assertEqual(0x100, ent.image_pos)
2288 self.assertEqual(None, ent.uncomp_size)
2289 self.assertEqual(0x100, ent.offset)
2292 self.assertEqual(2, ent.indent)
2293 self.assertEqual('cbfs', ent.name)
2294 self.assertEqual('cbfs', ent.etype)
2295 self.assertEqual(0x400, ent.size)
2296 self.assertEqual(0x100, ent.image_pos)
2297 self.assertEqual(None, ent.uncomp_size)
2298 self.assertEqual(0, ent.offset)
2301 self.assertEqual(3, ent.indent)
2302 self.assertEqual('u-boot', ent.name)
2303 self.assertEqual('u-boot', ent.etype)
2304 self.assertEqual(len(U_BOOT_DATA), ent.size)
2305 self.assertEqual(0x138, ent.image_pos)
2306 self.assertEqual(None, ent.uncomp_size)
2307 self.assertEqual(0x38, ent.offset)
2310 self.assertEqual(3, ent.indent)
2311 self.assertEqual('u-boot-dtb', ent.name)
2312 self.assertEqual('text', ent.etype)
2313 self.assertGreater(len(COMPRESS_DATA), ent.size)
2314 self.assertEqual(0x178, ent.image_pos)
2315 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2316 self.assertEqual(0x78, ent.offset)
2319 self.assertEqual(2, ent.indent)
2320 self.assertEqual('u-boot-dtb', ent.name)
2321 self.assertEqual('u-boot-dtb', ent.etype)
2322 self.assertEqual(0x500, ent.image_pos)
2323 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2325 # Compressing this data expands it since headers are added
2326 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2327 self.assertEqual(0x400, ent.offset)
2329 self.assertEqual(len(data), 0x100 + section_size)
2330 self.assertEqual(section_size, 0x400 + dtb_size)
2332 def testFindFdtmap(self):
2333 """Test locating an FDT map in an image"""
2335 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2336 image = control.images['image']
2337 entries = image.GetEntries()
2338 entry = entries['fdtmap']
2339 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2341 def testFindFdtmapMissing(self):
2342 """Test failing to locate an FDP map"""
2343 data = self._DoReadFile('005_simple.dts')
2344 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2346 def testFindImageHeader(self):
2347 """Test locating a image header"""
2349 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2350 image = control.images['image']
2351 entries = image.GetEntries()
2352 entry = entries['fdtmap']
2353 # The header should point to the FDT map
2354 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2356 def testFindImageHeaderStart(self):
2357 """Test locating a image header located at the start of an image"""
2358 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2359 image = control.images['image']
2360 entries = image.GetEntries()
2361 entry = entries['fdtmap']
2362 # The header should point to the FDT map
2363 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2365 def testFindImageHeaderMissing(self):
2366 """Test failing to locate an image header"""
2367 data = self._DoReadFile('005_simple.dts')
2368 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2370 def testReadImage(self):
2371 """Test reading an image and accessing its FDT map"""
2373 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2374 image_fname = tools.GetOutputFilename('image.bin')
2375 orig_image = control.images['image']
2376 image = Image.FromFile(image_fname)
2377 self.assertEqual(orig_image.GetEntries().keys(),
2378 image.GetEntries().keys())
2380 orig_entry = orig_image.GetEntries()['fdtmap']
2381 entry = image.GetEntries()['fdtmap']
2382 self.assertEquals(orig_entry.offset, entry.offset)
2383 self.assertEquals(orig_entry.size, entry.size)
2384 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2386 def testReadImageNoHeader(self):
2387 """Test accessing an image's FDT map without an image header"""
2389 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2390 image_fname = tools.GetOutputFilename('image.bin')
2391 image = Image.FromFile(image_fname)
2392 self.assertTrue(isinstance(image, Image))
2393 self.assertEqual('image', image.image_name[-5:])
2395 def testReadImageFail(self):
2396 """Test failing to read an image image's FDT map"""
2397 self._DoReadFile('005_simple.dts')
2398 image_fname = tools.GetOutputFilename('image.bin')
2399 with self.assertRaises(ValueError) as e:
2400 image = Image.FromFile(image_fname)
2401 self.assertIn("Cannot find FDT map in image", str(e.exception))
2403 def testListCmd(self):
2404 """Test listing the files in an image using an Fdtmap"""
2406 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2408 # lz4 compression size differs depending on the version
2409 image = control.images['image']
2410 entries = image.GetEntries()
2411 section_size = entries['section'].size
2412 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2413 fdtmap_offset = entries['fdtmap'].offset
2416 tmpdir, updated_fname = self._SetupImageInTmpdir()
2417 with test_util.capture_sys_output() as (stdout, stderr):
2418 self._DoBinman('ls', '-i', updated_fname)
2420 shutil.rmtree(tmpdir)
2421 lines = stdout.getvalue().splitlines()
2423 'Name Image-pos Size Entry-type Offset Uncomp-size',
2424 '----------------------------------------------------------------------',
2425 'main-section 0 c00 section 0',
2426 ' u-boot 0 4 u-boot 0',
2427 ' section 100 %x section 100' % section_size,
2428 ' cbfs 100 400 cbfs 0',
2429 ' u-boot 138 4 u-boot 38',
2430 ' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2431 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2432 ' fdtmap %x 3b4 fdtmap %x' %
2433 (fdtmap_offset, fdtmap_offset),
2434 ' image-header bf8 8 image-header bf8',
2436 self.assertEqual(expected, lines)
2438 def testListCmdFail(self):
2439 """Test failing to list an image"""
2440 self._DoReadFile('005_simple.dts')
2442 tmpdir, updated_fname = self._SetupImageInTmpdir()
2443 with self.assertRaises(ValueError) as e:
2444 self._DoBinman('ls', '-i', updated_fname)
2446 shutil.rmtree(tmpdir)
2447 self.assertIn("Cannot find FDT map in image", str(e.exception))
2449 def _RunListCmd(self, paths, expected):
2450 """List out entries and check the result
2453 paths: List of paths to pass to the list command
2454 expected: Expected list of filenames to be returned, in order
2457 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2458 image_fname = tools.GetOutputFilename('image.bin')
2459 image = Image.FromFile(image_fname)
2460 lines = image.GetListEntries(paths)[1]
2461 files = [line[0].strip() for line in lines[1:]]
2462 self.assertEqual(expected, files)
2464 def testListCmdSection(self):
2465 """Test listing the files in a section"""
2466 self._RunListCmd(['section'],
2467 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2469 def testListCmdFile(self):
2470 """Test listing a particular file"""
2471 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2473 def testListCmdWildcard(self):
2474 """Test listing a wildcarded file"""
2475 self._RunListCmd(['*boot*'],
2476 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2478 def testListCmdWildcardMulti(self):
2479 """Test listing a wildcarded file"""
2480 self._RunListCmd(['*cb*', '*head*'],
2481 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2483 def testListCmdEmpty(self):
2484 """Test listing a wildcarded file"""
2485 self._RunListCmd(['nothing'], [])
2487 def testListCmdPath(self):
2488 """Test listing the files in a sub-entry of a section"""
2489 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2491 def _RunExtractCmd(self, entry_name, decomp=True):
2492 """Extract an entry from an image
2495 entry_name: Entry name to extract
2496 decomp: True to decompress the data if compressed, False to leave
2497 it in its raw uncompressed format
2503 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2504 image_fname = tools.GetOutputFilename('image.bin')
2505 return control.ReadEntry(image_fname, entry_name, decomp)
2507 def testExtractSimple(self):
2508 """Test extracting a single file"""
2509 data = self._RunExtractCmd('u-boot')
2510 self.assertEqual(U_BOOT_DATA, data)
2512 def testExtractSection(self):
2513 """Test extracting the files in a section"""
2514 data = self._RunExtractCmd('section')
2515 cbfs_data = data[:0x400]
2516 cbfs = cbfs_util.CbfsReader(cbfs_data)
2517 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2518 dtb_data = data[0x400:]
2519 dtb = self._decompress(dtb_data)
2520 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2522 def testExtractCompressed(self):
2523 """Test extracting compressed data"""
2524 data = self._RunExtractCmd('section/u-boot-dtb')
2525 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2527 def testExtractRaw(self):
2528 """Test extracting compressed data without decompressing it"""
2529 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2530 dtb = self._decompress(data)
2531 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2533 def testExtractCbfs(self):
2534 """Test extracting CBFS data"""
2535 data = self._RunExtractCmd('section/cbfs/u-boot')
2536 self.assertEqual(U_BOOT_DATA, data)
2538 def testExtractCbfsCompressed(self):
2539 """Test extracting CBFS compressed data"""
2540 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2541 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2543 def testExtractCbfsRaw(self):
2544 """Test extracting CBFS compressed data without decompressing it"""
2545 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2546 dtb = tools.Decompress(data, 'lzma', with_header=False)
2547 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2549 def testExtractBadEntry(self):
2550 """Test extracting a bad section path"""
2551 with self.assertRaises(ValueError) as e:
2552 self._RunExtractCmd('section/does-not-exist')
2553 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2556 def testExtractMissingFile(self):
2557 """Test extracting file that does not exist"""
2558 with self.assertRaises(IOError) as e:
2559 control.ReadEntry('missing-file', 'name')
2561 def testExtractBadFile(self):
2562 """Test extracting an invalid file"""
2563 fname = os.path.join(self._indir, 'badfile')
2564 tools.WriteFile(fname, b'')
2565 with self.assertRaises(ValueError) as e:
2566 control.ReadEntry(fname, 'name')
2568 def testExtractCmd(self):
2569 """Test extracting a file fron an image on the command line"""
2571 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2572 fname = os.path.join(self._indir, 'output.extact')
2574 tmpdir, updated_fname = self._SetupImageInTmpdir()
2575 with test_util.capture_sys_output() as (stdout, stderr):
2576 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2579 shutil.rmtree(tmpdir)
2580 data = tools.ReadFile(fname)
2581 self.assertEqual(U_BOOT_DATA, data)
2583 def testExtractOneEntry(self):
2584 """Test extracting a single entry fron an image """
2586 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2587 image_fname = tools.GetOutputFilename('image.bin')
2588 fname = os.path.join(self._indir, 'output.extact')
2589 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2590 data = tools.ReadFile(fname)
2591 self.assertEqual(U_BOOT_DATA, data)
2593 def _CheckExtractOutput(self, decomp):
2594 """Helper to test file output with and without decompression
2597 decomp: True to decompress entry data, False to output it raw
2599 def _CheckPresent(entry_path, expect_data, expect_size=None):
2600 """Check and remove expected file
2602 This checks the data/size of a file and removes the file both from
2603 the outfiles set and from the output directory. Once all files are
2604 processed, both the set and directory should be empty.
2607 entry_path: Entry path
2608 expect_data: Data to expect in file, or None to skip check
2609 expect_size: Size of data to expect in file, or None to skip
2611 path = os.path.join(outdir, entry_path)
2612 data = tools.ReadFile(path)
2615 self.assertEqual(expect_data, data)
2617 self.assertEqual(expect_size, len(data))
2618 outfiles.remove(path)
2620 def _CheckDirPresent(name):
2621 """Remove expected directory
2623 This gives an error if the directory does not exist as expected
2626 name: Name of directory to remove
2628 path = os.path.join(outdir, name)
2631 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2632 image_fname = tools.GetOutputFilename('image.bin')
2633 outdir = os.path.join(self._indir, 'extract')
2634 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2636 # Create a set of all file that were output (should be 9)
2638 for root, dirs, files in os.walk(outdir):
2639 outfiles |= set([os.path.join(root, fname) for fname in files])
2640 self.assertEqual(9, len(outfiles))
2641 self.assertEqual(9, len(einfos))
2643 image = control.images['image']
2644 entries = image.GetEntries()
2646 # Check the 9 files in various ways
2647 section = entries['section']
2648 section_entries = section.GetEntries()
2649 cbfs_entries = section_entries['cbfs'].GetEntries()
2650 _CheckPresent('u-boot', U_BOOT_DATA)
2651 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2652 dtb_len = EXTRACT_DTB_SIZE
2654 dtb_len = cbfs_entries['u-boot-dtb'].size
2655 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2657 dtb_len = section_entries['u-boot-dtb'].size
2658 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2660 fdtmap = entries['fdtmap']
2661 _CheckPresent('fdtmap', fdtmap.data)
2662 hdr = entries['image-header']
2663 _CheckPresent('image-header', hdr.data)
2665 _CheckPresent('section/root', section.data)
2666 cbfs = section_entries['cbfs']
2667 _CheckPresent('section/cbfs/root', cbfs.data)
2668 data = tools.ReadFile(image_fname)
2669 _CheckPresent('root', data)
2671 # There should be no files left. Remove all the directories to check.
2672 # If there are any files/dirs remaining, one of these checks will fail.
2673 self.assertEqual(0, len(outfiles))
2674 _CheckDirPresent('section/cbfs')
2675 _CheckDirPresent('section')
2676 _CheckDirPresent('')
2677 self.assertFalse(os.path.exists(outdir))
2679 def testExtractAllEntries(self):
2680 """Test extracting all entries"""
2682 self._CheckExtractOutput(decomp=True)
2684 def testExtractAllEntriesRaw(self):
2685 """Test extracting all entries without decompressing them"""
2687 self._CheckExtractOutput(decomp=False)
2689 def testExtractSelectedEntries(self):
2690 """Test extracting some entries"""
2692 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2693 image_fname = tools.GetOutputFilename('image.bin')
2694 outdir = os.path.join(self._indir, 'extract')
2695 einfos = control.ExtractEntries(image_fname, None, outdir,
2698 # File output is tested by testExtractAllEntries(), so just check that
2699 # the expected entries are selected
2700 names = [einfo.name for einfo in einfos]
2701 self.assertEqual(names,
2702 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2704 def testExtractNoEntryPaths(self):
2705 """Test extracting some entries"""
2707 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2708 image_fname = tools.GetOutputFilename('image.bin')
2709 with self.assertRaises(ValueError) as e:
2710 control.ExtractEntries(image_fname, 'fname', None, [])
2711 self.assertIn('Must specify an entry path to write with -f',
2714 def testExtractTooManyEntryPaths(self):
2715 """Test extracting some entries"""
2717 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2718 image_fname = tools.GetOutputFilename('image.bin')
2719 with self.assertRaises(ValueError) as e:
2720 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2721 self.assertIn('Must specify exactly one entry path to write with -f',
2724 def testPackAlignSection(self):
2725 """Test that sections can have alignment"""
2726 self._DoReadFile('131_pack_align_section.dts')
2728 self.assertIn('image', control.images)
2729 image = control.images['image']
2730 entries = image.GetEntries()
2731 self.assertEqual(3, len(entries))
2734 self.assertIn('u-boot', entries)
2735 entry = entries['u-boot']
2736 self.assertEqual(0, entry.offset)
2737 self.assertEqual(0, entry.image_pos)
2738 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2739 self.assertEqual(len(U_BOOT_DATA), entry.size)
2742 self.assertIn('section0', entries)
2743 section0 = entries['section0']
2744 self.assertEqual(0x10, section0.offset)
2745 self.assertEqual(0x10, section0.image_pos)
2746 self.assertEqual(len(U_BOOT_DATA), section0.size)
2749 section_entries = section0.GetEntries()
2750 self.assertIn('u-boot', section_entries)
2751 entry = section_entries['u-boot']
2752 self.assertEqual(0, entry.offset)
2753 self.assertEqual(0x10, entry.image_pos)
2754 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2755 self.assertEqual(len(U_BOOT_DATA), entry.size)
2758 self.assertIn('section1', entries)
2759 section1 = entries['section1']
2760 self.assertEqual(0x14, section1.offset)
2761 self.assertEqual(0x14, section1.image_pos)
2762 self.assertEqual(0x20, section1.size)
2765 section_entries = section1.GetEntries()
2766 self.assertIn('u-boot', section_entries)
2767 entry = section_entries['u-boot']
2768 self.assertEqual(0, entry.offset)
2769 self.assertEqual(0x14, entry.image_pos)
2770 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2771 self.assertEqual(len(U_BOOT_DATA), entry.size)
2774 self.assertIn('section2', section_entries)
2775 section2 = section_entries['section2']
2776 self.assertEqual(0x4, section2.offset)
2777 self.assertEqual(0x18, section2.image_pos)
2778 self.assertEqual(4, section2.size)
2781 section_entries = section2.GetEntries()
2782 self.assertIn('u-boot', section_entries)
2783 entry = section_entries['u-boot']
2784 self.assertEqual(0, entry.offset)
2785 self.assertEqual(0x18, entry.image_pos)
2786 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2787 self.assertEqual(len(U_BOOT_DATA), entry.size)
2789 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2790 dts='132_replace.dts'):
2791 """Replace an entry in an image
2793 This writes the entry data to update it, then opens the updated file and
2794 returns the value that it now finds there.
2797 entry_name: Entry name to replace
2798 data: Data to replace it with
2799 decomp: True to compress the data if needed, False if data is
2800 already compressed so should be used as is
2801 allow_resize: True to allow entries to change size, False to raise
2807 data from fdtmap (excluding header)
2808 Image object that was modified
2810 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2813 self.assertIn('image', control.images)
2814 image = control.images['image']
2815 entries = image.GetEntries()
2816 orig_dtb_data = entries['u-boot-dtb'].data
2817 orig_fdtmap_data = entries['fdtmap'].data
2819 image_fname = tools.GetOutputFilename('image.bin')
2820 updated_fname = tools.GetOutputFilename('image-updated.bin')
2821 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2822 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2824 data = control.ReadEntry(updated_fname, entry_name, decomp)
2826 # The DT data should not change unless resized:
2827 if not allow_resize:
2828 new_dtb_data = entries['u-boot-dtb'].data
2829 self.assertEqual(new_dtb_data, orig_dtb_data)
2830 new_fdtmap_data = entries['fdtmap'].data
2831 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2833 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2835 def testReplaceSimple(self):
2836 """Test replacing a single file"""
2837 expected = b'x' * len(U_BOOT_DATA)
2838 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2840 self.assertEqual(expected, data)
2842 # Test that the state looks right. There should be an FDT for the fdtmap
2843 # that we jsut read back in, and it should match what we find in the
2844 # 'control' tables. Checking for an FDT that does not exist should
2846 path, fdtmap = state.GetFdtContents('fdtmap')
2847 self.assertIsNotNone(path)
2848 self.assertEqual(expected_fdtmap, fdtmap)
2850 dtb = state.GetFdtForEtype('fdtmap')
2851 self.assertEqual(dtb.GetContents(), fdtmap)
2853 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2854 self.assertIsNone(missing_path)
2855 self.assertIsNone(missing_fdtmap)
2857 missing_dtb = state.GetFdtForEtype('missing')
2858 self.assertIsNone(missing_dtb)
2860 self.assertEqual('/binman', state.fdt_path_prefix)
2862 def testReplaceResizeFail(self):
2863 """Test replacing a file by something larger"""
2864 expected = U_BOOT_DATA + b'x'
2865 with self.assertRaises(ValueError) as e:
2866 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2867 dts='139_replace_repack.dts')
2868 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2871 def testReplaceMulti(self):
2872 """Test replacing entry data where multiple images are generated"""
2873 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2875 expected = b'x' * len(U_BOOT_DATA)
2876 updated_fname = tools.GetOutputFilename('image-updated.bin')
2877 tools.WriteFile(updated_fname, data)
2878 entry_name = 'u-boot'
2879 control.WriteEntry(updated_fname, entry_name, expected,
2881 data = control.ReadEntry(updated_fname, entry_name)
2882 self.assertEqual(expected, data)
2884 # Check the state looks right.
2885 self.assertEqual('/binman/image', state.fdt_path_prefix)
2887 # Now check we can write the first image
2888 image_fname = tools.GetOutputFilename('first-image.bin')
2889 updated_fname = tools.GetOutputFilename('first-updated.bin')
2890 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2891 entry_name = 'u-boot'
2892 control.WriteEntry(updated_fname, entry_name, expected,
2894 data = control.ReadEntry(updated_fname, entry_name)
2895 self.assertEqual(expected, data)
2897 # Check the state looks right.
2898 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2900 def testUpdateFdtAllRepack(self):
2901 """Test that all device trees are updated with offset/size info"""
2902 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2903 SECTION_SIZE = 0x300
2908 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2910 'section:offset': 0,
2911 'section:size': SECTION_SIZE,
2912 'section:image-pos': 0,
2913 'section/u-boot-dtb:offset': 4,
2914 'section/u-boot-dtb:size': 636,
2915 'section/u-boot-dtb:image-pos': 4,
2916 'u-boot-spl-dtb:offset': SECTION_SIZE,
2917 'u-boot-spl-dtb:size': DTB_SIZE,
2918 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2919 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2920 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2921 'u-boot-tpl-dtb:size': DTB_SIZE,
2922 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2923 'fdtmap:size': FDTMAP_SIZE,
2924 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2927 'section:orig-size': SECTION_SIZE,
2928 'section/u-boot-dtb:orig-offset': 4,
2931 # We expect three device-tree files in the output, with the first one
2932 # within a fixed-size section.
2933 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2934 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2935 # main U-Boot tree. All three should have the same positions and offset
2936 # except that the main tree should include the main_expected properties
2938 for item in ['', 'spl', 'tpl', None]:
2940 start += 16 # Move past fdtmap header
2941 dtb = fdt.Fdt.FromData(data[start:])
2943 props = self._GetPropTree(dtb,
2944 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2945 prefix='/' if item is None else '/binman/')
2946 expected = dict(base_expected)
2950 # Main DTB and fdtdec should include the 'orig-' properties
2951 expected.update(main_expected)
2952 # Helpful for debugging:
2953 #for prop in sorted(props):
2954 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2955 self.assertEqual(expected, props)
2957 start = SECTION_SIZE
2959 start += dtb._fdt_obj.totalsize()
2961 def testFdtmapHeaderMiddle(self):
2962 """Test an FDT map in the middle of an image when it should be at end"""
2963 with self.assertRaises(ValueError) as e:
2964 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2965 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2968 def testFdtmapHeaderStartBad(self):
2969 """Test an FDT map in middle of an image when it should be at start"""
2970 with self.assertRaises(ValueError) as e:
2971 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2972 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2975 def testFdtmapHeaderEndBad(self):
2976 """Test an FDT map at the start of an image when it should be at end"""
2977 with self.assertRaises(ValueError) as e:
2978 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2979 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2982 def testFdtmapHeaderNoSize(self):
2983 """Test an image header at the end of an image with undefined size"""
2984 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2986 def testReplaceResize(self):
2987 """Test replacing a single file in an entry with a larger file"""
2988 expected = U_BOOT_DATA + b'x'
2989 data, _, image = self._RunReplaceCmd('u-boot', expected,
2990 dts='139_replace_repack.dts')
2991 self.assertEqual(expected, data)
2993 entries = image.GetEntries()
2994 dtb_data = entries['u-boot-dtb'].data
2995 dtb = fdt.Fdt.FromData(dtb_data)
2998 # The u-boot section should now be larger in the dtb
2999 node = dtb.GetNode('/binman/u-boot')
3000 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3002 # Same for the fdtmap
3003 fdata = entries['fdtmap'].data
3004 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3006 fnode = fdtb.GetNode('/u-boot')
3007 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3009 def testReplaceResizeNoRepack(self):
3010 """Test replacing an entry with a larger file when not allowed"""
3011 expected = U_BOOT_DATA + b'x'
3012 with self.assertRaises(ValueError) as e:
3013 self._RunReplaceCmd('u-boot', expected)
3014 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3017 def testEntryShrink(self):
3018 """Test contracting an entry after it is packed"""
3020 state.SetAllowEntryContraction(True)
3021 data = self._DoReadFileDtb('140_entry_shrink.dts',
3024 state.SetAllowEntryContraction(False)
3025 self.assertEqual(b'a', data[:1])
3026 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3027 self.assertEqual(b'a', data[-1:])
3029 def testEntryShrinkFail(self):
3030 """Test not being allowed to contract an entry after it is packed"""
3031 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3033 # In this case there is a spare byte at the end of the data. The size of
3034 # the contents is only 1 byte but we still have the size before it
3036 self.assertEqual(b'a\0', data[:2])
3037 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3038 self.assertEqual(b'a\0', data[-2:])
3040 def testDescriptorOffset(self):
3041 """Test that the Intel descriptor is always placed at at the start"""
3042 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3043 image = control.images['image']
3044 entries = image.GetEntries()
3045 desc = entries['intel-descriptor']
3046 self.assertEqual(0xff800000, desc.offset);
3047 self.assertEqual(0xff800000, desc.image_pos);
3049 def testReplaceCbfs(self):
3050 """Test replacing a single file in CBFS without changing the size"""
3052 expected = b'x' * len(U_BOOT_DATA)
3053 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3054 updated_fname = tools.GetOutputFilename('image-updated.bin')
3055 tools.WriteFile(updated_fname, data)
3056 entry_name = 'section/cbfs/u-boot'
3057 control.WriteEntry(updated_fname, entry_name, expected,
3059 data = control.ReadEntry(updated_fname, entry_name)
3060 self.assertEqual(expected, data)
3062 def testReplaceResizeCbfs(self):
3063 """Test replacing a single file in CBFS with one of a different size"""
3065 expected = U_BOOT_DATA + b'x'
3066 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3067 updated_fname = tools.GetOutputFilename('image-updated.bin')
3068 tools.WriteFile(updated_fname, data)
3069 entry_name = 'section/cbfs/u-boot'
3070 control.WriteEntry(updated_fname, entry_name, expected,
3072 data = control.ReadEntry(updated_fname, entry_name)
3073 self.assertEqual(expected, data)
3075 def _SetupForReplace(self):
3076 """Set up some files to use to replace entries
3078 This generates an image, copies it to a new file, extracts all the files
3079 in it and updates some of them
3085 Expected values for updated entries, each a string
3087 data = self._DoReadFileRealDtb('143_replace_all.dts')
3089 updated_fname = tools.GetOutputFilename('image-updated.bin')
3090 tools.WriteFile(updated_fname, data)
3092 outdir = os.path.join(self._indir, 'extract')
3093 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3095 expected1 = b'x' + U_BOOT_DATA + b'y'
3096 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3097 tools.WriteFile(u_boot_fname1, expected1)
3099 expected2 = b'a' + U_BOOT_DATA + b'b'
3100 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3101 tools.WriteFile(u_boot_fname2, expected2)
3103 expected_text = b'not the same text'
3104 text_fname = os.path.join(outdir, 'text')
3105 tools.WriteFile(text_fname, expected_text)
3107 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3108 dtb = fdt.FdtScan(dtb_fname)
3109 node = dtb.GetNode('/binman/text')
3110 node.AddString('my-property', 'the value')
3111 dtb.Sync(auto_resize=True)
3114 return updated_fname, outdir, expected1, expected2, expected_text
3116 def _CheckReplaceMultiple(self, entry_paths):
3117 """Handle replacing the contents of multiple entries
3120 entry_paths: List of entry paths to replace
3124 Dict of entries in the image:
3127 Expected values for updated entries, each a string
3129 updated_fname, outdir, expected1, expected2, expected_text = (
3130 self._SetupForReplace())
3131 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3133 image = Image.FromFile(updated_fname)
3135 return image.GetEntries(), expected1, expected2, expected_text
3137 def testReplaceAll(self):
3138 """Test replacing the contents of all entries"""
3139 entries, expected1, expected2, expected_text = (
3140 self._CheckReplaceMultiple([]))
3141 data = entries['u-boot'].data
3142 self.assertEqual(expected1, data)
3144 data = entries['u-boot2'].data
3145 self.assertEqual(expected2, data)
3147 data = entries['text'].data
3148 self.assertEqual(expected_text, data)
3150 # Check that the device tree is updated
3151 data = entries['u-boot-dtb'].data
3152 dtb = fdt.Fdt.FromData(data)
3154 node = dtb.GetNode('/binman/text')
3155 self.assertEqual('the value', node.props['my-property'].value)
3157 def testReplaceSome(self):
3158 """Test replacing the contents of a few entries"""
3159 entries, expected1, expected2, expected_text = (
3160 self._CheckReplaceMultiple(['u-boot2', 'text']))
3162 # This one should not change
3163 data = entries['u-boot'].data
3164 self.assertEqual(U_BOOT_DATA, data)
3166 data = entries['u-boot2'].data
3167 self.assertEqual(expected2, data)
3169 data = entries['text'].data
3170 self.assertEqual(expected_text, data)
3172 def testReplaceCmd(self):
3173 """Test replacing a file fron an image on the command line"""
3174 self._DoReadFileRealDtb('143_replace_all.dts')
3177 tmpdir, updated_fname = self._SetupImageInTmpdir()
3179 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3180 expected = b'x' * len(U_BOOT_DATA)
3181 tools.WriteFile(fname, expected)
3183 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3184 data = tools.ReadFile(updated_fname)
3185 self.assertEqual(expected, data[:len(expected)])
3186 map_fname = os.path.join(tmpdir, 'image-updated.map')
3187 self.assertFalse(os.path.exists(map_fname))
3189 shutil.rmtree(tmpdir)
3191 def testReplaceCmdSome(self):
3192 """Test replacing some files fron an image on the command line"""
3193 updated_fname, outdir, expected1, expected2, expected_text = (
3194 self._SetupForReplace())
3196 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3199 tools.PrepareOutputDir(None)
3200 image = Image.FromFile(updated_fname)
3202 entries = image.GetEntries()
3204 # This one should not change
3205 data = entries['u-boot'].data
3206 self.assertEqual(U_BOOT_DATA, data)
3208 data = entries['u-boot2'].data
3209 self.assertEqual(expected2, data)
3211 data = entries['text'].data
3212 self.assertEqual(expected_text, data)
3214 def testReplaceMissing(self):
3215 """Test replacing entries where the file is missing"""
3216 updated_fname, outdir, expected1, expected2, expected_text = (
3217 self._SetupForReplace())
3219 # Remove one of the files, to generate a warning
3220 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3221 os.remove(u_boot_fname1)
3223 with test_util.capture_sys_output() as (stdout, stderr):
3224 control.ReplaceEntries(updated_fname, None, outdir, [])
3225 self.assertIn("Skipping entry '/u-boot' from missing file",
3228 def testReplaceCmdMap(self):
3229 """Test replacing a file fron an image on the command line"""
3230 self._DoReadFileRealDtb('143_replace_all.dts')
3233 tmpdir, updated_fname = self._SetupImageInTmpdir()
3235 fname = os.path.join(self._indir, 'update-u-boot.bin')
3236 expected = b'x' * len(U_BOOT_DATA)
3237 tools.WriteFile(fname, expected)
3239 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3241 map_fname = os.path.join(tmpdir, 'image-updated.map')
3242 self.assertTrue(os.path.exists(map_fname))
3244 shutil.rmtree(tmpdir)
3246 def testReplaceNoEntryPaths(self):
3247 """Test replacing an entry without an entry path"""
3248 self._DoReadFileRealDtb('143_replace_all.dts')
3249 image_fname = tools.GetOutputFilename('image.bin')
3250 with self.assertRaises(ValueError) as e:
3251 control.ReplaceEntries(image_fname, 'fname', None, [])
3252 self.assertIn('Must specify an entry path to read with -f',
3255 def testReplaceTooManyEntryPaths(self):
3256 """Test extracting some entries"""
3257 self._DoReadFileRealDtb('143_replace_all.dts')
3258 image_fname = tools.GetOutputFilename('image.bin')
3259 with self.assertRaises(ValueError) as e:
3260 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3261 self.assertIn('Must specify exactly one entry path to write with -f',
3264 def testPackReset16(self):
3265 """Test that an image with an x86 reset16 region can be created"""
3266 data = self._DoReadFile('144_x86_reset16.dts')
3267 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3269 def testPackReset16Spl(self):
3270 """Test that an image with an x86 reset16-spl region can be created"""
3271 data = self._DoReadFile('145_x86_reset16_spl.dts')
3272 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3274 def testPackReset16Tpl(self):
3275 """Test that an image with an x86 reset16-tpl region can be created"""
3276 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3277 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3279 def testPackIntelFit(self):
3280 """Test that an image with an Intel FIT and pointer can be created"""
3281 data = self._DoReadFile('147_intel_fit.dts')
3282 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3284 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3285 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3287 image = control.images['image']
3288 entries = image.GetEntries()
3289 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3290 self.assertEqual(expected_ptr, ptr)
3292 def testPackIntelFitMissing(self):
3293 """Test detection of a FIT pointer with not FIT region"""
3294 with self.assertRaises(ValueError) as e:
3295 self._DoReadFile('148_intel_fit_missing.dts')
3296 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3300 if __name__ == "__main__":