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 'u_boot_binman_syms', 'u_boot_binman_syms_size']:
494 fname = cls.ElfTestFile(src_fname)
496 fname = cls.TestFile(src_fname)
497 TestFunctional._MakeInputFile('spl/u-boot-spl', tools.ReadFile(fname))
500 def TestFile(cls, fname):
501 return os.path.join(cls._binman_dir, 'test', fname)
504 def ElfTestFile(cls, fname):
505 return os.path.join(cls._elf_testdir, fname)
507 def AssertInList(self, grep_list, target):
508 """Assert that at least one of a list of things is in a target
511 grep_list: List of strings to check
512 target: Target string
514 for grep in grep_list:
517 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
519 def CheckNoGaps(self, entries):
520 """Check that all entries fit together without gaps
523 entries: List of entries to check
526 for entry in entries.values():
527 self.assertEqual(offset, entry.offset)
530 def GetFdtLen(self, dtb):
531 """Get the totalsize field from a device-tree binary
534 dtb: Device-tree binary contents
537 Total size of device-tree binary, from the header
539 return struct.unpack('>L', dtb[4:8])[0]
541 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
542 def AddNode(node, path):
544 path += '/' + node.name
545 for prop in node.props.values():
546 if prop.name in prop_names:
547 prop_path = path + ':' + prop.name
548 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
550 for subnode in node.subnodes:
551 AddNode(subnode, path)
554 AddNode(dtb.GetRoot(), '')
558 """Test a basic run with valid args"""
559 result = self._RunBinman('-h')
561 def testFullHelp(self):
562 """Test that the full help is displayed with -H"""
563 result = self._RunBinman('-H')
564 help_file = os.path.join(self._binman_dir, 'README')
565 # Remove possible extraneous strings
566 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
567 gothelp = result.stdout.replace(extra, '')
568 self.assertEqual(len(gothelp), os.path.getsize(help_file))
569 self.assertEqual(0, len(result.stderr))
570 self.assertEqual(0, result.return_code)
572 def testFullHelpInternal(self):
573 """Test that the full help is displayed with -H"""
575 command.test_result = command.CommandResult()
576 result = self._DoBinman('-H')
577 help_file = os.path.join(self._binman_dir, 'README')
579 command.test_result = None
582 """Test that the basic help is displayed with -h"""
583 result = self._RunBinman('-h')
584 self.assertTrue(len(result.stdout) > 200)
585 self.assertEqual(0, len(result.stderr))
586 self.assertEqual(0, result.return_code)
589 """Test that we can run it with a specific board"""
590 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
591 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
592 result = self._DoBinman('build', '-b', 'sandbox')
593 self.assertEqual(0, result)
595 def testNeedBoard(self):
596 """Test that we get an error when no board ius supplied"""
597 with self.assertRaises(ValueError) as e:
598 result = self._DoBinman('build')
599 self.assertIn("Must provide a board to process (use -b <board>)",
602 def testMissingDt(self):
603 """Test that an invalid device-tree file generates an error"""
604 with self.assertRaises(Exception) as e:
605 self._RunBinman('build', '-d', 'missing_file')
606 # We get one error from libfdt, and a different one from fdtget.
607 self.AssertInList(["Couldn't open blob from 'missing_file'",
608 'No such file or directory'], str(e.exception))
610 def testBrokenDt(self):
611 """Test that an invalid device-tree source file generates an error
613 Since this is a source file it should be compiled and the error
614 will come from the device-tree compiler (dtc).
616 with self.assertRaises(Exception) as e:
617 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
618 self.assertIn("FATAL ERROR: Unable to parse input tree",
621 def testMissingNode(self):
622 """Test that a device tree without a 'binman' node generates an error"""
623 with self.assertRaises(Exception) as e:
624 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
625 self.assertIn("does not have a 'binman' node", str(e.exception))
628 """Test that an empty binman node works OK (i.e. does nothing)"""
629 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
630 self.assertEqual(0, len(result.stderr))
631 self.assertEqual(0, result.return_code)
633 def testInvalidEntry(self):
634 """Test that an invalid entry is flagged"""
635 with self.assertRaises(Exception) as e:
636 result = self._RunBinman('build', '-d',
637 self.TestFile('004_invalid_entry.dts'))
638 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
639 "'/binman/not-a-valid-type'", str(e.exception))
641 def testSimple(self):
642 """Test a simple binman with a single file"""
643 data = self._DoReadFile('005_simple.dts')
644 self.assertEqual(U_BOOT_DATA, data)
646 def testSimpleDebug(self):
647 """Test a simple binman run with debugging enabled"""
648 self._DoTestFile('005_simple.dts', debug=True)
651 """Test that we can handle creating two images
653 This also tests image padding.
655 retcode = self._DoTestFile('006_dual_image.dts')
656 self.assertEqual(0, retcode)
658 image = control.images['image1']
659 self.assertEqual(len(U_BOOT_DATA), image.size)
660 fname = tools.GetOutputFilename('image1.bin')
661 self.assertTrue(os.path.exists(fname))
662 with open(fname, 'rb') as fd:
664 self.assertEqual(U_BOOT_DATA, data)
666 image = control.images['image2']
667 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
668 fname = tools.GetOutputFilename('image2.bin')
669 self.assertTrue(os.path.exists(fname))
670 with open(fname, 'rb') as fd:
672 self.assertEqual(U_BOOT_DATA, data[3:7])
673 self.assertEqual(tools.GetBytes(0, 3), data[:3])
674 self.assertEqual(tools.GetBytes(0, 5), data[7:])
676 def testBadAlign(self):
677 """Test that an invalid alignment value is detected"""
678 with self.assertRaises(ValueError) as e:
679 self._DoTestFile('007_bad_align.dts')
680 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
681 "of two", str(e.exception))
683 def testPackSimple(self):
684 """Test that packing works as expected"""
685 retcode = self._DoTestFile('008_pack.dts')
686 self.assertEqual(0, retcode)
687 self.assertIn('image', control.images)
688 image = control.images['image']
689 entries = image.GetEntries()
690 self.assertEqual(5, len(entries))
693 self.assertIn('u-boot', entries)
694 entry = entries['u-boot']
695 self.assertEqual(0, entry.offset)
696 self.assertEqual(len(U_BOOT_DATA), entry.size)
698 # Second u-boot, aligned to 16-byte boundary
699 self.assertIn('u-boot-align', entries)
700 entry = entries['u-boot-align']
701 self.assertEqual(16, entry.offset)
702 self.assertEqual(len(U_BOOT_DATA), entry.size)
704 # Third u-boot, size 23 bytes
705 self.assertIn('u-boot-size', entries)
706 entry = entries['u-boot-size']
707 self.assertEqual(20, entry.offset)
708 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
709 self.assertEqual(23, entry.size)
711 # Fourth u-boot, placed immediate after the above
712 self.assertIn('u-boot-next', entries)
713 entry = entries['u-boot-next']
714 self.assertEqual(43, entry.offset)
715 self.assertEqual(len(U_BOOT_DATA), entry.size)
717 # Fifth u-boot, placed at a fixed offset
718 self.assertIn('u-boot-fixed', entries)
719 entry = entries['u-boot-fixed']
720 self.assertEqual(61, entry.offset)
721 self.assertEqual(len(U_BOOT_DATA), entry.size)
723 self.assertEqual(65, image.size)
725 def testPackExtra(self):
726 """Test that extra packing feature works as expected"""
727 retcode = self._DoTestFile('009_pack_extra.dts')
729 self.assertEqual(0, retcode)
730 self.assertIn('image', control.images)
731 image = control.images['image']
732 entries = image.GetEntries()
733 self.assertEqual(5, len(entries))
735 # First u-boot with padding before and after
736 self.assertIn('u-boot', entries)
737 entry = entries['u-boot']
738 self.assertEqual(0, entry.offset)
739 self.assertEqual(3, entry.pad_before)
740 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
742 # Second u-boot has an aligned size, but it has no effect
743 self.assertIn('u-boot-align-size-nop', entries)
744 entry = entries['u-boot-align-size-nop']
745 self.assertEqual(12, entry.offset)
746 self.assertEqual(4, entry.size)
748 # Third u-boot has an aligned size too
749 self.assertIn('u-boot-align-size', entries)
750 entry = entries['u-boot-align-size']
751 self.assertEqual(16, entry.offset)
752 self.assertEqual(32, entry.size)
754 # Fourth u-boot has an aligned end
755 self.assertIn('u-boot-align-end', entries)
756 entry = entries['u-boot-align-end']
757 self.assertEqual(48, entry.offset)
758 self.assertEqual(16, entry.size)
760 # Fifth u-boot immediately afterwards
761 self.assertIn('u-boot-align-both', entries)
762 entry = entries['u-boot-align-both']
763 self.assertEqual(64, entry.offset)
764 self.assertEqual(64, entry.size)
766 self.CheckNoGaps(entries)
767 self.assertEqual(128, image.size)
769 def testPackAlignPowerOf2(self):
770 """Test that invalid entry alignment is detected"""
771 with self.assertRaises(ValueError) as e:
772 self._DoTestFile('010_pack_align_power2.dts')
773 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
774 "of two", str(e.exception))
776 def testPackAlignSizePowerOf2(self):
777 """Test that invalid entry size alignment is detected"""
778 with self.assertRaises(ValueError) as e:
779 self._DoTestFile('011_pack_align_size_power2.dts')
780 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
781 "power of two", str(e.exception))
783 def testPackInvalidAlign(self):
784 """Test detection of an offset that does not match its alignment"""
785 with self.assertRaises(ValueError) as e:
786 self._DoTestFile('012_pack_inv_align.dts')
787 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
788 "align 0x4 (4)", str(e.exception))
790 def testPackInvalidSizeAlign(self):
791 """Test that invalid entry size alignment is detected"""
792 with self.assertRaises(ValueError) as e:
793 self._DoTestFile('013_pack_inv_size_align.dts')
794 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
795 "align-size 0x4 (4)", str(e.exception))
797 def testPackOverlap(self):
798 """Test that overlapping regions are detected"""
799 with self.assertRaises(ValueError) as e:
800 self._DoTestFile('014_pack_overlap.dts')
801 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
802 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
805 def testPackEntryOverflow(self):
806 """Test that entries that overflow their size are detected"""
807 with self.assertRaises(ValueError) as e:
808 self._DoTestFile('015_pack_overflow.dts')
809 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
810 "but entry size is 0x3 (3)", str(e.exception))
812 def testPackImageOverflow(self):
813 """Test that entries which overflow the image size are detected"""
814 with self.assertRaises(ValueError) as e:
815 self._DoTestFile('016_pack_image_overflow.dts')
816 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
817 "size 0x3 (3)", str(e.exception))
819 def testPackImageSize(self):
820 """Test that the image size can be set"""
821 retcode = self._DoTestFile('017_pack_image_size.dts')
822 self.assertEqual(0, retcode)
823 self.assertIn('image', control.images)
824 image = control.images['image']
825 self.assertEqual(7, image.size)
827 def testPackImageSizeAlign(self):
828 """Test that image size alignemnt works as expected"""
829 retcode = self._DoTestFile('018_pack_image_align.dts')
830 self.assertEqual(0, retcode)
831 self.assertIn('image', control.images)
832 image = control.images['image']
833 self.assertEqual(16, image.size)
835 def testPackInvalidImageAlign(self):
836 """Test that invalid image alignment is detected"""
837 with self.assertRaises(ValueError) as e:
838 self._DoTestFile('019_pack_inv_image_align.dts')
839 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
840 "align-size 0x8 (8)", str(e.exception))
842 def testPackAlignPowerOf2(self):
843 """Test that invalid image alignment is detected"""
844 with self.assertRaises(ValueError) as e:
845 self._DoTestFile('020_pack_inv_image_align_power2.dts')
846 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
847 "two", str(e.exception))
849 def testImagePadByte(self):
850 """Test that the image pad byte can be specified"""
852 data = self._DoReadFile('021_image_pad.dts')
853 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
856 def testImageName(self):
857 """Test that image files can be named"""
858 retcode = self._DoTestFile('022_image_name.dts')
859 self.assertEqual(0, retcode)
860 image = control.images['image1']
861 fname = tools.GetOutputFilename('test-name')
862 self.assertTrue(os.path.exists(fname))
864 image = control.images['image2']
865 fname = tools.GetOutputFilename('test-name.xx')
866 self.assertTrue(os.path.exists(fname))
868 def testBlobFilename(self):
869 """Test that generic blobs can be provided by filename"""
870 data = self._DoReadFile('023_blob.dts')
871 self.assertEqual(BLOB_DATA, data)
873 def testPackSorted(self):
874 """Test that entries can be sorted"""
876 data = self._DoReadFile('024_sorted.dts')
877 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
878 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
880 def testPackZeroOffset(self):
881 """Test that an entry at offset 0 is not given a new offset"""
882 with self.assertRaises(ValueError) as e:
883 self._DoTestFile('025_pack_zero_size.dts')
884 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
885 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
888 def testPackUbootDtb(self):
889 """Test that a device tree can be added to U-Boot"""
890 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
891 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
893 def testPackX86RomNoSize(self):
894 """Test that the end-at-4gb property requires a size property"""
895 with self.assertRaises(ValueError) as e:
896 self._DoTestFile('027_pack_4gb_no_size.dts')
897 self.assertIn("Image '/binman': Section size must be provided when "
898 "using end-at-4gb", str(e.exception))
900 def test4gbAndSkipAtStartTogether(self):
901 """Test that the end-at-4gb and skip-at-size property can't be used
903 with self.assertRaises(ValueError) as e:
904 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
905 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
906 "'skip-at-start'", str(e.exception))
908 def testPackX86RomOutside(self):
909 """Test that the end-at-4gb property checks for offset boundaries"""
910 with self.assertRaises(ValueError) as e:
911 self._DoTestFile('028_pack_4gb_outside.dts')
912 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
913 "the section starting at 0xffffffe0 (4294967264)",
916 def testPackX86Rom(self):
917 """Test that a basic x86 ROM can be created"""
919 data = self._DoReadFile('029_x86-rom.dts')
920 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
921 tools.GetBytes(0, 2), data)
923 def testPackX86RomMeNoDesc(self):
924 """Test that an invalid Intel descriptor entry is detected"""
925 TestFunctional._MakeInputFile('descriptor.bin', b'')
926 with self.assertRaises(ValueError) as e:
927 self._DoTestFile('031_x86-rom-me.dts')
928 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
931 def testPackX86RomBadDesc(self):
932 """Test that the Intel requires a descriptor entry"""
933 with self.assertRaises(ValueError) as e:
934 self._DoTestFile('030_x86-rom-me-no-desc.dts')
935 self.assertIn("Node '/binman/intel-me': No offset set with "
936 "offset-unset: should another entry provide this correct "
937 "offset?", str(e.exception))
939 def testPackX86RomMe(self):
940 """Test that an x86 ROM with an ME region can be created"""
941 data = self._DoReadFile('031_x86-rom-me.dts')
942 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
943 if data[:0x1000] != expected_desc:
944 self.fail('Expected descriptor binary at start of image')
945 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
947 def testPackVga(self):
948 """Test that an image with a VGA binary can be created"""
949 data = self._DoReadFile('032_intel-vga.dts')
950 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
952 def testPackStart16(self):
953 """Test that an image with an x86 start16 region can be created"""
954 data = self._DoReadFile('033_x86-start16.dts')
955 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
957 def testPackPowerpcMpc85xxBootpgResetvec(self):
958 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
960 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
961 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
963 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
964 """Handle running a test for insertion of microcode
967 dts_fname: Name of test .dts file
968 nodtb_data: Data that we expect in the first section
969 ucode_second: True if the microsecond entry is second instead of
974 Contents of first region (U-Boot or SPL)
975 Offset and size components of microcode pointer, as inserted
976 in the above (two 4-byte words)
978 data = self._DoReadFile(dts_fname, True)
980 # Now check the device tree has no microcode
982 ucode_content = data[len(nodtb_data):]
983 ucode_pos = len(nodtb_data)
984 dtb_with_ucode = ucode_content[16:]
985 fdt_len = self.GetFdtLen(dtb_with_ucode)
987 dtb_with_ucode = data[len(nodtb_data):]
988 fdt_len = self.GetFdtLen(dtb_with_ucode)
989 ucode_content = dtb_with_ucode[fdt_len:]
990 ucode_pos = len(nodtb_data) + fdt_len
991 fname = tools.GetOutputFilename('test.dtb')
992 with open(fname, 'wb') as fd:
993 fd.write(dtb_with_ucode)
994 dtb = fdt.FdtScan(fname)
995 ucode = dtb.GetNode('/microcode')
996 self.assertTrue(ucode)
997 for node in ucode.subnodes:
998 self.assertFalse(node.props.get('data'))
1000 # Check that the microcode appears immediately after the Fdt
1001 # This matches the concatenation of the data properties in
1002 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1003 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1005 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1007 # Check that the microcode pointer was inserted. It should match the
1008 # expected offset and size
1009 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1011 u_boot = data[:len(nodtb_data)]
1012 return u_boot, pos_and_size
1014 def testPackUbootMicrocode(self):
1015 """Test that x86 microcode can be handled correctly
1017 We expect to see the following in the image, in order:
1018 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1020 u-boot.dtb with the microcode removed
1023 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1025 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1026 b' somewhere in here', first)
1028 def _RunPackUbootSingleMicrocode(self):
1029 """Test that x86 microcode can be handled correctly
1031 We expect to see the following in the image, in order:
1032 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1034 u-boot.dtb with the microcode
1035 an empty microcode region
1037 # We need the libfdt library to run this test since only that allows
1038 # finding the offset of a property. This is required by
1039 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1040 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1042 second = data[len(U_BOOT_NODTB_DATA):]
1044 fdt_len = self.GetFdtLen(second)
1045 third = second[fdt_len:]
1046 second = second[:fdt_len]
1048 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1049 self.assertIn(ucode_data, second)
1050 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1052 # Check that the microcode pointer was inserted. It should match the
1053 # expected offset and size
1054 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1056 first = data[:len(U_BOOT_NODTB_DATA)]
1057 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1058 b' somewhere in here', first)
1060 def testPackUbootSingleMicrocode(self):
1061 """Test that x86 microcode can be handled correctly with fdt_normal.
1063 self._RunPackUbootSingleMicrocode()
1065 def testUBootImg(self):
1066 """Test that u-boot.img can be put in a file"""
1067 data = self._DoReadFile('036_u_boot_img.dts')
1068 self.assertEqual(U_BOOT_IMG_DATA, data)
1070 def testNoMicrocode(self):
1071 """Test that a missing microcode region is detected"""
1072 with self.assertRaises(ValueError) as e:
1073 self._DoReadFile('037_x86_no_ucode.dts', True)
1074 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1075 "node found in ", str(e.exception))
1077 def testMicrocodeWithoutNode(self):
1078 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1079 with self.assertRaises(ValueError) as e:
1080 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1081 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1082 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1084 def testMicrocodeWithoutNode2(self):
1085 """Test that a missing u-boot-ucode node is detected"""
1086 with self.assertRaises(ValueError) as e:
1087 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1088 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1089 "microcode region u-boot-ucode", str(e.exception))
1091 def testMicrocodeWithoutPtrInElf(self):
1092 """Test that a U-Boot binary without the microcode symbol is detected"""
1093 # ELF file without a '_dt_ucode_base_size' symbol
1095 TestFunctional._MakeInputFile('u-boot',
1096 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1098 with self.assertRaises(ValueError) as e:
1099 self._RunPackUbootSingleMicrocode()
1100 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1101 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1104 # Put the original file back
1105 TestFunctional._MakeInputFile('u-boot',
1106 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1108 def testMicrocodeNotInImage(self):
1109 """Test that microcode must be placed within the image"""
1110 with self.assertRaises(ValueError) as e:
1111 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1112 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1113 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1114 "section ranging from 00000000 to 0000002e", str(e.exception))
1116 def testWithoutMicrocode(self):
1117 """Test that we can cope with an image without microcode (e.g. qemu)"""
1118 TestFunctional._MakeInputFile('u-boot',
1119 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1120 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1122 # Now check the device tree has no microcode
1123 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1124 second = data[len(U_BOOT_NODTB_DATA):]
1126 fdt_len = self.GetFdtLen(second)
1127 self.assertEqual(dtb, second[:fdt_len])
1129 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1130 third = data[used_len:]
1131 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1133 def testUnknownPosSize(self):
1134 """Test that microcode must be placed within the image"""
1135 with self.assertRaises(ValueError) as e:
1136 self._DoReadFile('041_unknown_pos_size.dts', True)
1137 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1138 "entry 'invalid-entry'", str(e.exception))
1140 def testPackFsp(self):
1141 """Test that an image with a FSP binary can be created"""
1142 data = self._DoReadFile('042_intel-fsp.dts')
1143 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1145 def testPackCmc(self):
1146 """Test that an image with a CMC binary can be created"""
1147 data = self._DoReadFile('043_intel-cmc.dts')
1148 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1150 def testPackVbt(self):
1151 """Test that an image with a VBT binary can be created"""
1152 data = self._DoReadFile('046_intel-vbt.dts')
1153 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1155 def testSplBssPad(self):
1156 """Test that we can pad SPL's BSS with zeros"""
1157 # ELF file with a '__bss_size' symbol
1159 data = self._DoReadFile('047_spl_bss_pad.dts')
1160 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1163 def testSplBssPadMissing(self):
1164 """Test that a missing symbol is detected"""
1165 self._SetupSplElf('u_boot_ucode_ptr')
1166 with self.assertRaises(ValueError) as e:
1167 self._DoReadFile('047_spl_bss_pad.dts')
1168 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1171 def testPackStart16Spl(self):
1172 """Test that an image with an x86 start16 SPL region can be created"""
1173 data = self._DoReadFile('048_x86-start16-spl.dts')
1174 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1176 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1177 """Helper function for microcode tests
1179 We expect to see the following in the image, in order:
1180 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1182 u-boot.dtb with the microcode removed
1186 dts: Device tree file to use for test
1187 ucode_second: True if the microsecond entry is second instead of
1190 self._SetupSplElf('u_boot_ucode_ptr')
1191 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1192 ucode_second=ucode_second)
1193 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1194 b'ter somewhere in here', first)
1196 def testPackUbootSplMicrocode(self):
1197 """Test that x86 microcode can be handled correctly in SPL"""
1198 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1200 def testPackUbootSplMicrocodeReorder(self):
1201 """Test that order doesn't matter for microcode entries
1203 This is the same as testPackUbootSplMicrocode but when we process the
1204 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1205 entry, so we reply on binman to try later.
1207 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1210 def testPackMrc(self):
1211 """Test that an image with an MRC binary can be created"""
1212 data = self._DoReadFile('050_intel_mrc.dts')
1213 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1215 def testSplDtb(self):
1216 """Test that an image with spl/u-boot-spl.dtb can be created"""
1217 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1218 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1220 def testSplNoDtb(self):
1221 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1222 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1223 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1225 def testSymbols(self):
1226 """Test binman can assign symbols embedded in U-Boot"""
1227 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1228 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1229 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1230 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1232 self._SetupSplElf('u_boot_binman_syms')
1233 data = self._DoReadFile('053_symbols.dts')
1234 sym_values = struct.pack('<LQL', 0, 24, 20)
1235 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1236 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1237 U_BOOT_SPL_DATA[16:])
1238 self.assertEqual(expected, data)
1240 def testPackUnitAddress(self):
1241 """Test that we support multiple binaries with the same name"""
1242 data = self._DoReadFile('054_unit_address.dts')
1243 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1245 def testSections(self):
1246 """Basic test of sections"""
1247 data = self._DoReadFile('055_sections.dts')
1248 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1249 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1250 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1251 self.assertEqual(expected, data)
1254 """Tests outputting a map of the images"""
1255 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1256 self.assertEqual('''ImagePos Offset Size Name
1257 00000000 00000000 00000028 main-section
1258 00000000 00000000 00000010 section@0
1259 00000000 00000000 00000004 u-boot
1260 00000010 00000010 00000010 section@1
1261 00000010 00000000 00000004 u-boot
1262 00000020 00000020 00000004 section@2
1263 00000020 00000000 00000004 u-boot
1266 def testNamePrefix(self):
1267 """Tests that name prefixes are used"""
1268 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1269 self.assertEqual('''ImagePos Offset Size Name
1270 00000000 00000000 00000028 main-section
1271 00000000 00000000 00000010 section@0
1272 00000000 00000000 00000004 ro-u-boot
1273 00000010 00000010 00000010 section@1
1274 00000010 00000000 00000004 rw-u-boot
1277 def testUnknownContents(self):
1278 """Test that obtaining the contents works as expected"""
1279 with self.assertRaises(ValueError) as e:
1280 self._DoReadFile('057_unknown_contents.dts', True)
1281 self.assertIn("Image '/binman': Internal error: Could not complete "
1282 "processing of contents: remaining [<_testing.Entry__testing ",
1285 def testBadChangeSize(self):
1286 """Test that trying to change the size of an entry fails"""
1288 state.SetAllowEntryExpansion(False)
1289 with self.assertRaises(ValueError) as e:
1290 self._DoReadFile('059_change_size.dts', True)
1291 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1294 state.SetAllowEntryExpansion(True)
1296 def testUpdateFdt(self):
1297 """Test that we can update the device tree with offset/size info"""
1298 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1300 dtb = fdt.Fdt(out_dtb_fname)
1302 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1306 '_testing:offset': 32,
1308 '_testing:image-pos': 32,
1309 'section@0/u-boot:offset': 0,
1310 'section@0/u-boot:size': len(U_BOOT_DATA),
1311 'section@0/u-boot:image-pos': 0,
1312 'section@0:offset': 0,
1313 'section@0:size': 16,
1314 'section@0:image-pos': 0,
1316 'section@1/u-boot:offset': 0,
1317 'section@1/u-boot:size': len(U_BOOT_DATA),
1318 'section@1/u-boot:image-pos': 16,
1319 'section@1:offset': 16,
1320 'section@1:size': 16,
1321 'section@1:image-pos': 16,
1325 def testUpdateFdtBad(self):
1326 """Test that we detect when ProcessFdt never completes"""
1327 with self.assertRaises(ValueError) as e:
1328 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1329 self.assertIn('Could not complete processing of Fdt: remaining '
1330 '[<_testing.Entry__testing', str(e.exception))
1332 def testEntryArgs(self):
1333 """Test passing arguments to entries from the command line"""
1335 'test-str-arg': 'test1',
1336 'test-int-arg': '456',
1338 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1339 self.assertIn('image', control.images)
1340 entry = control.images['image'].GetEntries()['_testing']
1341 self.assertEqual('test0', entry.test_str_fdt)
1342 self.assertEqual('test1', entry.test_str_arg)
1343 self.assertEqual(123, entry.test_int_fdt)
1344 self.assertEqual(456, entry.test_int_arg)
1346 def testEntryArgsMissing(self):
1347 """Test missing arguments and properties"""
1349 'test-int-arg': '456',
1351 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1352 entry = control.images['image'].GetEntries()['_testing']
1353 self.assertEqual('test0', entry.test_str_fdt)
1354 self.assertEqual(None, entry.test_str_arg)
1355 self.assertEqual(None, entry.test_int_fdt)
1356 self.assertEqual(456, entry.test_int_arg)
1358 def testEntryArgsRequired(self):
1359 """Test missing arguments and properties"""
1361 'test-int-arg': '456',
1363 with self.assertRaises(ValueError) as e:
1364 self._DoReadFileDtb('064_entry_args_required.dts')
1365 self.assertIn("Node '/binman/_testing': Missing required "
1366 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1369 def testEntryArgsInvalidFormat(self):
1370 """Test that an invalid entry-argument format is detected"""
1371 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1373 with self.assertRaises(ValueError) as e:
1374 self._DoBinman(*args)
1375 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1377 def testEntryArgsInvalidInteger(self):
1378 """Test that an invalid entry-argument integer is detected"""
1380 'test-int-arg': 'abc',
1382 with self.assertRaises(ValueError) as e:
1383 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1384 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1385 "'test-int-arg' (value 'abc') to integer",
1388 def testEntryArgsInvalidDatatype(self):
1389 """Test that an invalid entry-argument datatype is detected
1391 This test could be written in entry_test.py except that it needs
1392 access to control.entry_args, which seems more than that module should
1396 'test-bad-datatype-arg': '12',
1398 with self.assertRaises(ValueError) as e:
1399 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1400 entry_args=entry_args)
1401 self.assertIn('GetArg() internal error: Unknown data type ',
1405 """Test for a text entry type"""
1407 'test-id': TEXT_DATA,
1408 'test-id2': TEXT_DATA2,
1409 'test-id3': TEXT_DATA3,
1411 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1412 entry_args=entry_args)
1413 expected = (tools.ToBytes(TEXT_DATA) +
1414 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1415 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1416 b'some text' + b'more text')
1417 self.assertEqual(expected, data)
1419 def testEntryDocs(self):
1420 """Test for creation of entry documentation"""
1421 with test_util.capture_sys_output() as (stdout, stderr):
1422 control.WriteEntryDocs(binman.GetEntryModules())
1423 self.assertTrue(len(stdout.getvalue()) > 0)
1425 def testEntryDocsMissing(self):
1426 """Test handling of missing entry documentation"""
1427 with self.assertRaises(ValueError) as e:
1428 with test_util.capture_sys_output() as (stdout, stderr):
1429 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1430 self.assertIn('Documentation is missing for modules: u_boot',
1434 """Basic test of generation of a flashrom fmap"""
1435 data = self._DoReadFile('067_fmap.dts')
1436 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1437 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1438 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1439 self.assertEqual(expected, data[:32])
1440 self.assertEqual(b'__FMAP__', fhdr.signature)
1441 self.assertEqual(1, fhdr.ver_major)
1442 self.assertEqual(0, fhdr.ver_minor)
1443 self.assertEqual(0, fhdr.base)
1444 self.assertEqual(16 + 16 +
1445 fmap_util.FMAP_HEADER_LEN +
1446 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1447 self.assertEqual(b'FMAP', fhdr.name)
1448 self.assertEqual(3, fhdr.nareas)
1449 for fentry in fentries:
1450 self.assertEqual(0, fentry.flags)
1452 self.assertEqual(0, fentries[0].offset)
1453 self.assertEqual(4, fentries[0].size)
1454 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1456 self.assertEqual(16, fentries[1].offset)
1457 self.assertEqual(4, fentries[1].size)
1458 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1460 self.assertEqual(32, fentries[2].offset)
1461 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1462 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1463 self.assertEqual(b'FMAP', fentries[2].name)
1465 def testBlobNamedByArg(self):
1466 """Test we can add a blob with the filename coming from an entry arg"""
1468 'cros-ec-rw-path': 'ecrw.bin',
1470 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1471 entry_args=entry_args)
1474 """Test for an fill entry type"""
1475 data = self._DoReadFile('069_fill.dts')
1476 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1477 self.assertEqual(expected, data)
1479 def testFillNoSize(self):
1480 """Test for an fill entry type with no size"""
1481 with self.assertRaises(ValueError) as e:
1482 self._DoReadFile('070_fill_no_size.dts')
1483 self.assertIn("'fill' entry must have a size property",
1486 def _HandleGbbCommand(self, pipe_list):
1487 """Fake calls to the futility utility"""
1488 if pipe_list[0][0] == 'futility':
1489 fname = pipe_list[0][-1]
1490 # Append our GBB data to the file, which will happen every time the
1491 # futility command is called.
1492 with open(fname, 'ab') as fd:
1494 return command.CommandResult()
1497 """Test for the Chromium OS Google Binary Block"""
1498 command.test_result = self._HandleGbbCommand
1500 'keydir': 'devkeys',
1501 'bmpblk': 'bmpblk.bin',
1503 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1506 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1507 tools.GetBytes(0, 0x2180 - 16))
1508 self.assertEqual(expected, data)
1510 def testGbbTooSmall(self):
1511 """Test for the Chromium OS Google Binary Block being large enough"""
1512 with self.assertRaises(ValueError) as e:
1513 self._DoReadFileDtb('072_gbb_too_small.dts')
1514 self.assertIn("Node '/binman/gbb': GBB is too small",
1517 def testGbbNoSize(self):
1518 """Test for the Chromium OS Google Binary Block having a size"""
1519 with self.assertRaises(ValueError) as e:
1520 self._DoReadFileDtb('073_gbb_no_size.dts')
1521 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1524 def _HandleVblockCommand(self, pipe_list):
1525 """Fake calls to the futility utility"""
1526 if pipe_list[0][0] == 'futility':
1527 fname = pipe_list[0][3]
1528 with open(fname, 'wb') as fd:
1529 fd.write(VBLOCK_DATA)
1530 return command.CommandResult()
1532 def testVblock(self):
1533 """Test for the Chromium OS Verified Boot Block"""
1534 command.test_result = self._HandleVblockCommand
1536 'keydir': 'devkeys',
1538 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1539 entry_args=entry_args)
1540 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1541 self.assertEqual(expected, data)
1543 def testVblockNoContent(self):
1544 """Test we detect a vblock which has no content to sign"""
1545 with self.assertRaises(ValueError) as e:
1546 self._DoReadFile('075_vblock_no_content.dts')
1547 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1548 'property', str(e.exception))
1550 def testVblockBadPhandle(self):
1551 """Test that we detect a vblock with an invalid phandle in contents"""
1552 with self.assertRaises(ValueError) as e:
1553 self._DoReadFile('076_vblock_bad_phandle.dts')
1554 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1555 '1000', str(e.exception))
1557 def testVblockBadEntry(self):
1558 """Test that we detect an entry that points to a non-entry"""
1559 with self.assertRaises(ValueError) as e:
1560 self._DoReadFile('077_vblock_bad_entry.dts')
1561 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1562 "'other'", str(e.exception))
1565 """Test that an image with TPL and ots device tree can be created"""
1566 # ELF file with a '__bss_size' symbol
1567 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1568 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1569 data = self._DoReadFile('078_u_boot_tpl.dts')
1570 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1572 def testUsesPos(self):
1573 """Test that the 'pos' property cannot be used anymore"""
1574 with self.assertRaises(ValueError) as e:
1575 data = self._DoReadFile('079_uses_pos.dts')
1576 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1577 "'pos'", str(e.exception))
1579 def testFillZero(self):
1580 """Test for an fill entry type with a size of 0"""
1581 data = self._DoReadFile('080_fill_empty.dts')
1582 self.assertEqual(tools.GetBytes(0, 16), data)
1584 def testTextMissing(self):
1585 """Test for a text entry type where there is no text"""
1586 with self.assertRaises(ValueError) as e:
1587 self._DoReadFileDtb('066_text.dts',)
1588 self.assertIn("Node '/binman/text': No value provided for text label "
1589 "'test-id'", str(e.exception))
1591 def testPackStart16Tpl(self):
1592 """Test that an image with an x86 start16 TPL region can be created"""
1593 data = self._DoReadFile('081_x86-start16-tpl.dts')
1594 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1596 def testSelectImage(self):
1597 """Test that we can select which images to build"""
1598 expected = 'Skipping images: image1'
1600 # We should only get the expected message in verbose mode
1601 for verbosity in (0, 2):
1602 with test_util.capture_sys_output() as (stdout, stderr):
1603 retcode = self._DoTestFile('006_dual_image.dts',
1604 verbosity=verbosity,
1606 self.assertEqual(0, retcode)
1608 self.assertIn(expected, stdout.getvalue())
1610 self.assertNotIn(expected, stdout.getvalue())
1612 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1613 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1614 self._CleanupOutputDir()
1616 def testUpdateFdtAll(self):
1617 """Test that all device trees are updated with offset/size info"""
1618 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1621 'section:image-pos': 0,
1622 'u-boot-tpl-dtb:size': 513,
1623 'u-boot-spl-dtb:size': 513,
1624 'u-boot-spl-dtb:offset': 493,
1626 'section/u-boot-dtb:image-pos': 0,
1627 'u-boot-spl-dtb:image-pos': 493,
1628 'section/u-boot-dtb:size': 493,
1629 'u-boot-tpl-dtb:image-pos': 1006,
1630 'section/u-boot-dtb:offset': 0,
1631 'section:size': 493,
1633 'section:offset': 0,
1634 'u-boot-tpl-dtb:offset': 1006,
1638 # We expect three device-tree files in the output, one after the other.
1639 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1640 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1641 # main U-Boot tree. All three should have the same postions and offset.
1643 for item in ['', 'spl', 'tpl']:
1644 dtb = fdt.Fdt.FromData(data[start:])
1646 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1648 expected = dict(base_expected)
1651 self.assertEqual(expected, props)
1652 start += dtb._fdt_obj.totalsize()
1654 def testUpdateFdtOutput(self):
1655 """Test that output DTB files are updated"""
1657 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1658 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1660 # Unfortunately, compiling a source file always results in a file
1661 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1662 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1663 # binman as a file called u-boot.dtb. To fix this, copy the file
1664 # over to the expected place.
1665 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1666 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1668 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1669 'tpl/u-boot-tpl.dtb.out']:
1670 dtb = fdt.Fdt.FromData(data[start:])
1671 size = dtb._fdt_obj.totalsize()
1672 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1673 outdata = tools.ReadFile(pathname)
1674 name = os.path.split(fname)[0]
1677 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1679 orig_indata = dtb_data
1680 self.assertNotEqual(outdata, orig_indata,
1681 "Expected output file '%s' be updated" % pathname)
1682 self.assertEqual(outdata, data[start:start + size],
1683 "Expected output file '%s' to match output image" %
1689 def _decompress(self, data):
1690 return tools.Decompress(data, 'lz4')
1692 def testCompress(self):
1693 """Test compression of blobs"""
1695 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1696 use_real_dtb=True, update_dtb=True)
1697 dtb = fdt.Fdt(out_dtb_fname)
1699 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1700 orig = self._decompress(data)
1701 self.assertEquals(COMPRESS_DATA, orig)
1703 'blob:uncomp-size': len(COMPRESS_DATA),
1704 'blob:size': len(data),
1707 self.assertEqual(expected, props)
1709 def testFiles(self):
1710 """Test bringing in multiple files"""
1711 data = self._DoReadFile('084_files.dts')
1712 self.assertEqual(FILES_DATA, data)
1714 def testFilesCompress(self):
1715 """Test bringing in multiple files and compressing them"""
1717 data = self._DoReadFile('085_files_compress.dts')
1719 image = control.images['image']
1720 entries = image.GetEntries()
1721 files = entries['files']
1722 entries = files._entries
1725 for i in range(1, 3):
1727 start = entries[key].image_pos
1728 len = entries[key].size
1729 chunk = data[start:start + len]
1730 orig += self._decompress(chunk)
1732 self.assertEqual(FILES_DATA, orig)
1734 def testFilesMissing(self):
1735 """Test missing files"""
1736 with self.assertRaises(ValueError) as e:
1737 data = self._DoReadFile('086_files_none.dts')
1738 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1739 'no files', str(e.exception))
1741 def testFilesNoPattern(self):
1742 """Test missing files"""
1743 with self.assertRaises(ValueError) as e:
1744 data = self._DoReadFile('087_files_no_pattern.dts')
1745 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1748 def testExpandSize(self):
1749 """Test an expanding entry"""
1750 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1752 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1753 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1754 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1755 tools.GetBytes(ord('d'), 8))
1756 self.assertEqual(expect, data)
1757 self.assertEqual('''ImagePos Offset Size Name
1758 00000000 00000000 00000028 main-section
1759 00000000 00000000 00000008 fill
1760 00000008 00000008 00000004 u-boot
1761 0000000c 0000000c 00000004 section
1762 0000000c 00000000 00000003 intel-mrc
1763 00000010 00000010 00000004 u-boot2
1764 00000014 00000014 0000000c section2
1765 00000014 00000000 00000008 fill
1766 0000001c 00000008 00000004 u-boot
1767 00000020 00000020 00000008 fill2
1770 def testExpandSizeBad(self):
1771 """Test an expanding entry which fails to provide contents"""
1772 with test_util.capture_sys_output() as (stdout, stderr):
1773 with self.assertRaises(ValueError) as e:
1774 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1775 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1776 'expanding entry', str(e.exception))
1779 """Test hashing of the contents of an entry"""
1780 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1781 use_real_dtb=True, update_dtb=True)
1782 dtb = fdt.Fdt(out_dtb_fname)
1784 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1785 m = hashlib.sha256()
1786 m.update(U_BOOT_DATA)
1787 self.assertEqual(m.digest(), b''.join(hash_node.value))
1789 def testHashNoAlgo(self):
1790 with self.assertRaises(ValueError) as e:
1791 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1792 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1793 'hash node', str(e.exception))
1795 def testHashBadAlgo(self):
1796 with self.assertRaises(ValueError) as e:
1797 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1798 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1801 def testHashSection(self):
1802 """Test hashing of the contents of an entry"""
1803 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1804 use_real_dtb=True, update_dtb=True)
1805 dtb = fdt.Fdt(out_dtb_fname)
1807 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1808 m = hashlib.sha256()
1809 m.update(U_BOOT_DATA)
1810 m.update(tools.GetBytes(ord('a'), 16))
1811 self.assertEqual(m.digest(), b''.join(hash_node.value))
1813 def testPackUBootTplMicrocode(self):
1814 """Test that x86 microcode can be handled correctly in TPL
1816 We expect to see the following in the image, in order:
1817 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1819 u-boot-tpl.dtb with the microcode removed
1822 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
1823 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1824 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1825 U_BOOT_TPL_NODTB_DATA)
1826 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1827 b'ter somewhere in here', first)
1829 def testFmapX86(self):
1830 """Basic test of generation of a flashrom fmap"""
1831 data = self._DoReadFile('094_fmap_x86.dts')
1832 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1833 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1834 self.assertEqual(expected, data[:32])
1835 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1837 self.assertEqual(0x100, fhdr.image_size)
1839 self.assertEqual(0, fentries[0].offset)
1840 self.assertEqual(4, fentries[0].size)
1841 self.assertEqual(b'U_BOOT', fentries[0].name)
1843 self.assertEqual(4, fentries[1].offset)
1844 self.assertEqual(3, fentries[1].size)
1845 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1847 self.assertEqual(32, fentries[2].offset)
1848 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1849 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1850 self.assertEqual(b'FMAP', fentries[2].name)
1852 def testFmapX86Section(self):
1853 """Basic test of generation of a flashrom fmap"""
1854 data = self._DoReadFile('095_fmap_x86_section.dts')
1855 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1856 self.assertEqual(expected, data[:32])
1857 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1859 self.assertEqual(0x100, fhdr.image_size)
1861 self.assertEqual(0, fentries[0].offset)
1862 self.assertEqual(4, fentries[0].size)
1863 self.assertEqual(b'U_BOOT', fentries[0].name)
1865 self.assertEqual(4, fentries[1].offset)
1866 self.assertEqual(3, fentries[1].size)
1867 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1869 self.assertEqual(36, fentries[2].offset)
1870 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1871 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1872 self.assertEqual(b'FMAP', fentries[2].name)
1875 """Basic test of ELF entries"""
1877 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1878 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1879 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1880 TestFunctional._MakeInputFile('-boot', fd.read())
1881 data = self._DoReadFile('096_elf.dts')
1883 def testElfStrip(self):
1884 """Basic test of ELF entries"""
1886 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1887 TestFunctional._MakeInputFile('-boot', fd.read())
1888 data = self._DoReadFile('097_elf_strip.dts')
1890 def testPackOverlapMap(self):
1891 """Test that overlapping regions are detected"""
1892 with test_util.capture_sys_output() as (stdout, stderr):
1893 with self.assertRaises(ValueError) as e:
1894 self._DoTestFile('014_pack_overlap.dts', map=True)
1895 map_fname = tools.GetOutputFilename('image.map')
1896 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1899 # We should not get an inmage, but there should be a map file
1900 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1901 self.assertTrue(os.path.exists(map_fname))
1902 map_data = tools.ReadFile(map_fname, binary=False)
1903 self.assertEqual('''ImagePos Offset Size Name
1904 <none> 00000000 00000007 main-section
1905 <none> 00000000 00000004 u-boot
1906 <none> 00000003 00000004 u-boot-align
1909 def testPackRefCode(self):
1910 """Test that an image with an Intel Reference code binary works"""
1911 data = self._DoReadFile('100_intel_refcode.dts')
1912 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1914 def testSectionOffset(self):
1915 """Tests use of a section with an offset"""
1916 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1918 self.assertEqual('''ImagePos Offset Size Name
1919 00000000 00000000 00000038 main-section
1920 00000004 00000004 00000010 section@0
1921 00000004 00000000 00000004 u-boot
1922 00000018 00000018 00000010 section@1
1923 00000018 00000000 00000004 u-boot
1924 0000002c 0000002c 00000004 section@2
1925 0000002c 00000000 00000004 u-boot
1927 self.assertEqual(data,
1928 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1929 tools.GetBytes(0x21, 12) +
1930 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1931 tools.GetBytes(0x61, 12) +
1932 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1933 tools.GetBytes(0x26, 8))
1935 def testCbfsRaw(self):
1936 """Test base handling of a Coreboot Filesystem (CBFS)
1938 The exact contents of the CBFS is verified by similar tests in
1939 cbfs_util_test.py. The tests here merely check that the files added to
1940 the CBFS can be found in the final image.
1942 data = self._DoReadFile('102_cbfs_raw.dts')
1945 cbfs = cbfs_util.CbfsReader(data)
1946 self.assertEqual(size, cbfs.rom_size)
1948 self.assertIn('u-boot-dtb', cbfs.files)
1949 cfile = cbfs.files['u-boot-dtb']
1950 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1952 def testCbfsArch(self):
1953 """Test on non-x86 architecture"""
1954 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1957 cbfs = cbfs_util.CbfsReader(data)
1958 self.assertEqual(size, cbfs.rom_size)
1960 self.assertIn('u-boot-dtb', cbfs.files)
1961 cfile = cbfs.files['u-boot-dtb']
1962 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1964 def testCbfsStage(self):
1965 """Tests handling of a Coreboot Filesystem (CBFS)"""
1966 if not elf.ELF_TOOLS:
1967 self.skipTest('Python elftools not available')
1968 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1969 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1972 data = self._DoReadFile('104_cbfs_stage.dts')
1973 cbfs = cbfs_util.CbfsReader(data)
1974 self.assertEqual(size, cbfs.rom_size)
1976 self.assertIn('u-boot', cbfs.files)
1977 cfile = cbfs.files['u-boot']
1978 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1980 def testCbfsRawCompress(self):
1981 """Test handling of compressing raw files"""
1983 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1986 cbfs = cbfs_util.CbfsReader(data)
1987 self.assertIn('u-boot', cbfs.files)
1988 cfile = cbfs.files['u-boot']
1989 self.assertEqual(COMPRESS_DATA, cfile.data)
1991 def testCbfsBadArch(self):
1992 """Test handling of a bad architecture"""
1993 with self.assertRaises(ValueError) as e:
1994 self._DoReadFile('106_cbfs_bad_arch.dts')
1995 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1997 def testCbfsNoSize(self):
1998 """Test handling of a missing size property"""
1999 with self.assertRaises(ValueError) as e:
2000 self._DoReadFile('107_cbfs_no_size.dts')
2001 self.assertIn('entry must have a size property', str(e.exception))
2003 def testCbfsNoCOntents(self):
2004 """Test handling of a CBFS entry which does not provide contentsy"""
2005 with self.assertRaises(ValueError) as e:
2006 self._DoReadFile('108_cbfs_no_contents.dts')
2007 self.assertIn('Could not complete processing of contents',
2010 def testCbfsBadCompress(self):
2011 """Test handling of a bad architecture"""
2012 with self.assertRaises(ValueError) as e:
2013 self._DoReadFile('109_cbfs_bad_compress.dts')
2014 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2017 def testCbfsNamedEntries(self):
2018 """Test handling of named entries"""
2019 data = self._DoReadFile('110_cbfs_name.dts')
2021 cbfs = cbfs_util.CbfsReader(data)
2022 self.assertIn('FRED', cbfs.files)
2023 cfile1 = cbfs.files['FRED']
2024 self.assertEqual(U_BOOT_DATA, cfile1.data)
2026 self.assertIn('hello', cbfs.files)
2027 cfile2 = cbfs.files['hello']
2028 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2030 def _SetupIfwi(self, fname):
2031 """Set up to run an IFWI test
2034 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2038 # Intel Integrated Firmware Image (IFWI) file
2039 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2041 TestFunctional._MakeInputFile(fname,data)
2043 def _CheckIfwi(self, data):
2044 """Check that an image with an IFWI contains the correct output
2047 data: Conents of output file
2049 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2050 if data[:0x1000] != expected_desc:
2051 self.fail('Expected descriptor binary at start of image')
2053 # We expect to find the TPL wil in subpart IBBP entry IBBL
2054 image_fname = tools.GetOutputFilename('image.bin')
2055 tpl_fname = tools.GetOutputFilename('tpl.out')
2056 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2057 subpart='IBBP', entry_name='IBBL')
2059 tpl_data = tools.ReadFile(tpl_fname)
2060 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2062 def testPackX86RomIfwi(self):
2063 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2064 self._SetupIfwi('fitimage.bin')
2065 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2066 self._CheckIfwi(data)
2068 def testPackX86RomIfwiNoDesc(self):
2069 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2070 self._SetupIfwi('ifwi.bin')
2071 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2072 self._CheckIfwi(data)
2074 def testPackX86RomIfwiNoData(self):
2075 """Test that an x86 ROM with IFWI handles missing data"""
2076 self._SetupIfwi('ifwi.bin')
2077 with self.assertRaises(ValueError) as e:
2078 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2079 self.assertIn('Could not complete processing of contents',
2082 def testCbfsOffset(self):
2083 """Test a CBFS with files at particular offsets
2085 Like all CFBS tests, this is just checking the logic that calls
2086 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2088 data = self._DoReadFile('114_cbfs_offset.dts')
2091 cbfs = cbfs_util.CbfsReader(data)
2092 self.assertEqual(size, cbfs.rom_size)
2094 self.assertIn('u-boot', cbfs.files)
2095 cfile = cbfs.files['u-boot']
2096 self.assertEqual(U_BOOT_DATA, cfile.data)
2097 self.assertEqual(0x40, cfile.cbfs_offset)
2099 self.assertIn('u-boot-dtb', cbfs.files)
2100 cfile2 = cbfs.files['u-boot-dtb']
2101 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2102 self.assertEqual(0x140, cfile2.cbfs_offset)
2104 def testFdtmap(self):
2105 """Test an FDT map can be inserted in the image"""
2106 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2107 fdtmap_data = data[len(U_BOOT_DATA):]
2108 magic = fdtmap_data[:8]
2109 self.assertEqual('_FDTMAP_', magic)
2110 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2112 fdt_data = fdtmap_data[16:]
2113 dtb = fdt.Fdt.FromData(fdt_data)
2115 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2120 'u-boot:size': len(U_BOOT_DATA),
2121 'u-boot:image-pos': 0,
2122 'fdtmap:image-pos': 4,
2124 'fdtmap:size': len(fdtmap_data),
2128 def testFdtmapNoMatch(self):
2129 """Check handling of an FDT map when the section cannot be found"""
2130 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2132 # Mangle the section name, which should cause a mismatch between the
2133 # correct FDT path and the one expected by the section
2134 image = control.images['image']
2135 image._node.path += '-suffix'
2136 entries = image.GetEntries()
2137 fdtmap = entries['fdtmap']
2138 with self.assertRaises(ValueError) as e:
2140 self.assertIn("Cannot locate node for path '/binman-suffix'",
2143 def testFdtmapHeader(self):
2144 """Test an FDT map and image header can be inserted in the image"""
2145 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2146 fdtmap_pos = len(U_BOOT_DATA)
2147 fdtmap_data = data[fdtmap_pos:]
2148 fdt_data = fdtmap_data[16:]
2149 dtb = fdt.Fdt.FromData(fdt_data)
2150 fdt_size = dtb.GetFdtObj().totalsize()
2151 hdr_data = data[-8:]
2152 self.assertEqual('BinM', hdr_data[:4])
2153 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2154 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2156 def testFdtmapHeaderStart(self):
2157 """Test an image header can be inserted at the image start"""
2158 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2159 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2161 self.assertEqual('BinM', hdr_data[:4])
2162 offset = struct.unpack('<I', hdr_data[4:])[0]
2163 self.assertEqual(fdtmap_pos, offset)
2165 def testFdtmapHeaderPos(self):
2166 """Test an image header can be inserted at a chosen position"""
2167 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2168 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2169 hdr_data = data[0x80:0x88]
2170 self.assertEqual('BinM', hdr_data[:4])
2171 offset = struct.unpack('<I', hdr_data[4:])[0]
2172 self.assertEqual(fdtmap_pos, offset)
2174 def testHeaderMissingFdtmap(self):
2175 """Test an image header requires an fdtmap"""
2176 with self.assertRaises(ValueError) as e:
2177 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2178 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2181 def testHeaderNoLocation(self):
2182 """Test an image header with a no specified location is detected"""
2183 with self.assertRaises(ValueError) as e:
2184 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2185 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2188 def testEntryExpand(self):
2189 """Test expanding an entry after it is packed"""
2190 data = self._DoReadFile('121_entry_expand.dts')
2191 self.assertEqual(b'aaa', data[:3])
2192 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2193 self.assertEqual(b'aaa', data[-3:])
2195 def testEntryExpandBad(self):
2196 """Test expanding an entry after it is packed, twice"""
2197 with self.assertRaises(ValueError) as e:
2198 self._DoReadFile('122_entry_expand_twice.dts')
2199 self.assertIn("Image '/binman': Entries changed size after packing",
2202 def testEntryExpandSection(self):
2203 """Test expanding an entry within a section after it is packed"""
2204 data = self._DoReadFile('123_entry_expand_section.dts')
2205 self.assertEqual(b'aaa', data[:3])
2206 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2207 self.assertEqual(b'aaa', data[-3:])
2209 def testCompressDtb(self):
2210 """Test that compress of device-tree files is supported"""
2212 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2213 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2214 comp_data = data[len(U_BOOT_DATA):]
2215 orig = self._decompress(comp_data)
2216 dtb = fdt.Fdt.FromData(orig)
2218 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2220 'u-boot:size': len(U_BOOT_DATA),
2221 'u-boot-dtb:uncomp-size': len(orig),
2222 'u-boot-dtb:size': len(comp_data),
2225 self.assertEqual(expected, props)
2227 def testCbfsUpdateFdt(self):
2228 """Test that we can update the device tree with CBFS offset/size info"""
2230 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2232 dtb = fdt.Fdt(out_dtb_fname)
2234 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2235 del props['cbfs/u-boot:size']
2241 'cbfs:size': len(data),
2242 'cbfs:image-pos': 0,
2243 'cbfs/u-boot:offset': 0x38,
2244 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2245 'cbfs/u-boot:image-pos': 0x38,
2246 'cbfs/u-boot-dtb:offset': 0xb8,
2247 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2248 'cbfs/u-boot-dtb:image-pos': 0xb8,
2251 def testCbfsBadType(self):
2252 """Test an image header with a no specified location is detected"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('126_cbfs_bad_type.dts')
2255 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2258 """Test listing the files in an image"""
2260 data = self._DoReadFile('127_list.dts')
2261 image = control.images['image']
2262 entries = image.BuildEntryList()
2263 self.assertEqual(7, len(entries))
2266 self.assertEqual(0, ent.indent)
2267 self.assertEqual('main-section', ent.name)
2268 self.assertEqual('section', ent.etype)
2269 self.assertEqual(len(data), ent.size)
2270 self.assertEqual(0, ent.image_pos)
2271 self.assertEqual(None, ent.uncomp_size)
2272 self.assertEqual(0, ent.offset)
2275 self.assertEqual(1, ent.indent)
2276 self.assertEqual('u-boot', ent.name)
2277 self.assertEqual('u-boot', ent.etype)
2278 self.assertEqual(len(U_BOOT_DATA), ent.size)
2279 self.assertEqual(0, ent.image_pos)
2280 self.assertEqual(None, ent.uncomp_size)
2281 self.assertEqual(0, ent.offset)
2284 self.assertEqual(1, ent.indent)
2285 self.assertEqual('section', ent.name)
2286 self.assertEqual('section', ent.etype)
2287 section_size = ent.size
2288 self.assertEqual(0x100, ent.image_pos)
2289 self.assertEqual(None, ent.uncomp_size)
2290 self.assertEqual(0x100, ent.offset)
2293 self.assertEqual(2, ent.indent)
2294 self.assertEqual('cbfs', ent.name)
2295 self.assertEqual('cbfs', ent.etype)
2296 self.assertEqual(0x400, ent.size)
2297 self.assertEqual(0x100, ent.image_pos)
2298 self.assertEqual(None, ent.uncomp_size)
2299 self.assertEqual(0, ent.offset)
2302 self.assertEqual(3, ent.indent)
2303 self.assertEqual('u-boot', ent.name)
2304 self.assertEqual('u-boot', ent.etype)
2305 self.assertEqual(len(U_BOOT_DATA), ent.size)
2306 self.assertEqual(0x138, ent.image_pos)
2307 self.assertEqual(None, ent.uncomp_size)
2308 self.assertEqual(0x38, ent.offset)
2311 self.assertEqual(3, ent.indent)
2312 self.assertEqual('u-boot-dtb', ent.name)
2313 self.assertEqual('text', ent.etype)
2314 self.assertGreater(len(COMPRESS_DATA), ent.size)
2315 self.assertEqual(0x178, ent.image_pos)
2316 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2317 self.assertEqual(0x78, ent.offset)
2320 self.assertEqual(2, ent.indent)
2321 self.assertEqual('u-boot-dtb', ent.name)
2322 self.assertEqual('u-boot-dtb', ent.etype)
2323 self.assertEqual(0x500, ent.image_pos)
2324 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2326 # Compressing this data expands it since headers are added
2327 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2328 self.assertEqual(0x400, ent.offset)
2330 self.assertEqual(len(data), 0x100 + section_size)
2331 self.assertEqual(section_size, 0x400 + dtb_size)
2333 def testFindFdtmap(self):
2334 """Test locating an FDT map in an image"""
2336 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2337 image = control.images['image']
2338 entries = image.GetEntries()
2339 entry = entries['fdtmap']
2340 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2342 def testFindFdtmapMissing(self):
2343 """Test failing to locate an FDP map"""
2344 data = self._DoReadFile('005_simple.dts')
2345 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2347 def testFindImageHeader(self):
2348 """Test locating a image header"""
2350 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2351 image = control.images['image']
2352 entries = image.GetEntries()
2353 entry = entries['fdtmap']
2354 # The header should point to the FDT map
2355 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2357 def testFindImageHeaderStart(self):
2358 """Test locating a image header located at the start of an image"""
2359 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2360 image = control.images['image']
2361 entries = image.GetEntries()
2362 entry = entries['fdtmap']
2363 # The header should point to the FDT map
2364 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2366 def testFindImageHeaderMissing(self):
2367 """Test failing to locate an image header"""
2368 data = self._DoReadFile('005_simple.dts')
2369 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2371 def testReadImage(self):
2372 """Test reading an image and accessing its FDT map"""
2374 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2375 image_fname = tools.GetOutputFilename('image.bin')
2376 orig_image = control.images['image']
2377 image = Image.FromFile(image_fname)
2378 self.assertEqual(orig_image.GetEntries().keys(),
2379 image.GetEntries().keys())
2381 orig_entry = orig_image.GetEntries()['fdtmap']
2382 entry = image.GetEntries()['fdtmap']
2383 self.assertEquals(orig_entry.offset, entry.offset)
2384 self.assertEquals(orig_entry.size, entry.size)
2385 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2387 def testReadImageNoHeader(self):
2388 """Test accessing an image's FDT map without an image header"""
2390 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2391 image_fname = tools.GetOutputFilename('image.bin')
2392 image = Image.FromFile(image_fname)
2393 self.assertTrue(isinstance(image, Image))
2394 self.assertEqual('image', image.image_name[-5:])
2396 def testReadImageFail(self):
2397 """Test failing to read an image image's FDT map"""
2398 self._DoReadFile('005_simple.dts')
2399 image_fname = tools.GetOutputFilename('image.bin')
2400 with self.assertRaises(ValueError) as e:
2401 image = Image.FromFile(image_fname)
2402 self.assertIn("Cannot find FDT map in image", str(e.exception))
2404 def testListCmd(self):
2405 """Test listing the files in an image using an Fdtmap"""
2407 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2409 # lz4 compression size differs depending on the version
2410 image = control.images['image']
2411 entries = image.GetEntries()
2412 section_size = entries['section'].size
2413 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2414 fdtmap_offset = entries['fdtmap'].offset
2417 tmpdir, updated_fname = self._SetupImageInTmpdir()
2418 with test_util.capture_sys_output() as (stdout, stderr):
2419 self._DoBinman('ls', '-i', updated_fname)
2421 shutil.rmtree(tmpdir)
2422 lines = stdout.getvalue().splitlines()
2424 'Name Image-pos Size Entry-type Offset Uncomp-size',
2425 '----------------------------------------------------------------------',
2426 'main-section 0 c00 section 0',
2427 ' u-boot 0 4 u-boot 0',
2428 ' section 100 %x section 100' % section_size,
2429 ' cbfs 100 400 cbfs 0',
2430 ' u-boot 138 4 u-boot 38',
2431 ' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2432 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2433 ' fdtmap %x 3b4 fdtmap %x' %
2434 (fdtmap_offset, fdtmap_offset),
2435 ' image-header bf8 8 image-header bf8',
2437 self.assertEqual(expected, lines)
2439 def testListCmdFail(self):
2440 """Test failing to list an image"""
2441 self._DoReadFile('005_simple.dts')
2443 tmpdir, updated_fname = self._SetupImageInTmpdir()
2444 with self.assertRaises(ValueError) as e:
2445 self._DoBinman('ls', '-i', updated_fname)
2447 shutil.rmtree(tmpdir)
2448 self.assertIn("Cannot find FDT map in image", str(e.exception))
2450 def _RunListCmd(self, paths, expected):
2451 """List out entries and check the result
2454 paths: List of paths to pass to the list command
2455 expected: Expected list of filenames to be returned, in order
2458 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2459 image_fname = tools.GetOutputFilename('image.bin')
2460 image = Image.FromFile(image_fname)
2461 lines = image.GetListEntries(paths)[1]
2462 files = [line[0].strip() for line in lines[1:]]
2463 self.assertEqual(expected, files)
2465 def testListCmdSection(self):
2466 """Test listing the files in a section"""
2467 self._RunListCmd(['section'],
2468 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2470 def testListCmdFile(self):
2471 """Test listing a particular file"""
2472 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2474 def testListCmdWildcard(self):
2475 """Test listing a wildcarded file"""
2476 self._RunListCmd(['*boot*'],
2477 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2479 def testListCmdWildcardMulti(self):
2480 """Test listing a wildcarded file"""
2481 self._RunListCmd(['*cb*', '*head*'],
2482 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2484 def testListCmdEmpty(self):
2485 """Test listing a wildcarded file"""
2486 self._RunListCmd(['nothing'], [])
2488 def testListCmdPath(self):
2489 """Test listing the files in a sub-entry of a section"""
2490 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2492 def _RunExtractCmd(self, entry_name, decomp=True):
2493 """Extract an entry from an image
2496 entry_name: Entry name to extract
2497 decomp: True to decompress the data if compressed, False to leave
2498 it in its raw uncompressed format
2504 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2505 image_fname = tools.GetOutputFilename('image.bin')
2506 return control.ReadEntry(image_fname, entry_name, decomp)
2508 def testExtractSimple(self):
2509 """Test extracting a single file"""
2510 data = self._RunExtractCmd('u-boot')
2511 self.assertEqual(U_BOOT_DATA, data)
2513 def testExtractSection(self):
2514 """Test extracting the files in a section"""
2515 data = self._RunExtractCmd('section')
2516 cbfs_data = data[:0x400]
2517 cbfs = cbfs_util.CbfsReader(cbfs_data)
2518 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2519 dtb_data = data[0x400:]
2520 dtb = self._decompress(dtb_data)
2521 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2523 def testExtractCompressed(self):
2524 """Test extracting compressed data"""
2525 data = self._RunExtractCmd('section/u-boot-dtb')
2526 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2528 def testExtractRaw(self):
2529 """Test extracting compressed data without decompressing it"""
2530 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2531 dtb = self._decompress(data)
2532 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2534 def testExtractCbfs(self):
2535 """Test extracting CBFS data"""
2536 data = self._RunExtractCmd('section/cbfs/u-boot')
2537 self.assertEqual(U_BOOT_DATA, data)
2539 def testExtractCbfsCompressed(self):
2540 """Test extracting CBFS compressed data"""
2541 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2542 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2544 def testExtractCbfsRaw(self):
2545 """Test extracting CBFS compressed data without decompressing it"""
2546 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2547 dtb = tools.Decompress(data, 'lzma', with_header=False)
2548 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2550 def testExtractBadEntry(self):
2551 """Test extracting a bad section path"""
2552 with self.assertRaises(ValueError) as e:
2553 self._RunExtractCmd('section/does-not-exist')
2554 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2557 def testExtractMissingFile(self):
2558 """Test extracting file that does not exist"""
2559 with self.assertRaises(IOError) as e:
2560 control.ReadEntry('missing-file', 'name')
2562 def testExtractBadFile(self):
2563 """Test extracting an invalid file"""
2564 fname = os.path.join(self._indir, 'badfile')
2565 tools.WriteFile(fname, b'')
2566 with self.assertRaises(ValueError) as e:
2567 control.ReadEntry(fname, 'name')
2569 def testExtractCmd(self):
2570 """Test extracting a file fron an image on the command line"""
2572 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2573 fname = os.path.join(self._indir, 'output.extact')
2575 tmpdir, updated_fname = self._SetupImageInTmpdir()
2576 with test_util.capture_sys_output() as (stdout, stderr):
2577 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2580 shutil.rmtree(tmpdir)
2581 data = tools.ReadFile(fname)
2582 self.assertEqual(U_BOOT_DATA, data)
2584 def testExtractOneEntry(self):
2585 """Test extracting a single entry fron an image """
2587 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2588 image_fname = tools.GetOutputFilename('image.bin')
2589 fname = os.path.join(self._indir, 'output.extact')
2590 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2591 data = tools.ReadFile(fname)
2592 self.assertEqual(U_BOOT_DATA, data)
2594 def _CheckExtractOutput(self, decomp):
2595 """Helper to test file output with and without decompression
2598 decomp: True to decompress entry data, False to output it raw
2600 def _CheckPresent(entry_path, expect_data, expect_size=None):
2601 """Check and remove expected file
2603 This checks the data/size of a file and removes the file both from
2604 the outfiles set and from the output directory. Once all files are
2605 processed, both the set and directory should be empty.
2608 entry_path: Entry path
2609 expect_data: Data to expect in file, or None to skip check
2610 expect_size: Size of data to expect in file, or None to skip
2612 path = os.path.join(outdir, entry_path)
2613 data = tools.ReadFile(path)
2616 self.assertEqual(expect_data, data)
2618 self.assertEqual(expect_size, len(data))
2619 outfiles.remove(path)
2621 def _CheckDirPresent(name):
2622 """Remove expected directory
2624 This gives an error if the directory does not exist as expected
2627 name: Name of directory to remove
2629 path = os.path.join(outdir, name)
2632 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2633 image_fname = tools.GetOutputFilename('image.bin')
2634 outdir = os.path.join(self._indir, 'extract')
2635 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2637 # Create a set of all file that were output (should be 9)
2639 for root, dirs, files in os.walk(outdir):
2640 outfiles |= set([os.path.join(root, fname) for fname in files])
2641 self.assertEqual(9, len(outfiles))
2642 self.assertEqual(9, len(einfos))
2644 image = control.images['image']
2645 entries = image.GetEntries()
2647 # Check the 9 files in various ways
2648 section = entries['section']
2649 section_entries = section.GetEntries()
2650 cbfs_entries = section_entries['cbfs'].GetEntries()
2651 _CheckPresent('u-boot', U_BOOT_DATA)
2652 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2653 dtb_len = EXTRACT_DTB_SIZE
2655 dtb_len = cbfs_entries['u-boot-dtb'].size
2656 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2658 dtb_len = section_entries['u-boot-dtb'].size
2659 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2661 fdtmap = entries['fdtmap']
2662 _CheckPresent('fdtmap', fdtmap.data)
2663 hdr = entries['image-header']
2664 _CheckPresent('image-header', hdr.data)
2666 _CheckPresent('section/root', section.data)
2667 cbfs = section_entries['cbfs']
2668 _CheckPresent('section/cbfs/root', cbfs.data)
2669 data = tools.ReadFile(image_fname)
2670 _CheckPresent('root', data)
2672 # There should be no files left. Remove all the directories to check.
2673 # If there are any files/dirs remaining, one of these checks will fail.
2674 self.assertEqual(0, len(outfiles))
2675 _CheckDirPresent('section/cbfs')
2676 _CheckDirPresent('section')
2677 _CheckDirPresent('')
2678 self.assertFalse(os.path.exists(outdir))
2680 def testExtractAllEntries(self):
2681 """Test extracting all entries"""
2683 self._CheckExtractOutput(decomp=True)
2685 def testExtractAllEntriesRaw(self):
2686 """Test extracting all entries without decompressing them"""
2688 self._CheckExtractOutput(decomp=False)
2690 def testExtractSelectedEntries(self):
2691 """Test extracting some entries"""
2693 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2694 image_fname = tools.GetOutputFilename('image.bin')
2695 outdir = os.path.join(self._indir, 'extract')
2696 einfos = control.ExtractEntries(image_fname, None, outdir,
2699 # File output is tested by testExtractAllEntries(), so just check that
2700 # the expected entries are selected
2701 names = [einfo.name for einfo in einfos]
2702 self.assertEqual(names,
2703 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2705 def testExtractNoEntryPaths(self):
2706 """Test extracting some entries"""
2708 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2709 image_fname = tools.GetOutputFilename('image.bin')
2710 with self.assertRaises(ValueError) as e:
2711 control.ExtractEntries(image_fname, 'fname', None, [])
2712 self.assertIn('Must specify an entry path to write with -f',
2715 def testExtractTooManyEntryPaths(self):
2716 """Test extracting some entries"""
2718 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2719 image_fname = tools.GetOutputFilename('image.bin')
2720 with self.assertRaises(ValueError) as e:
2721 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2722 self.assertIn('Must specify exactly one entry path to write with -f',
2725 def testPackAlignSection(self):
2726 """Test that sections can have alignment"""
2727 self._DoReadFile('131_pack_align_section.dts')
2729 self.assertIn('image', control.images)
2730 image = control.images['image']
2731 entries = image.GetEntries()
2732 self.assertEqual(3, len(entries))
2735 self.assertIn('u-boot', entries)
2736 entry = entries['u-boot']
2737 self.assertEqual(0, entry.offset)
2738 self.assertEqual(0, entry.image_pos)
2739 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2740 self.assertEqual(len(U_BOOT_DATA), entry.size)
2743 self.assertIn('section0', entries)
2744 section0 = entries['section0']
2745 self.assertEqual(0x10, section0.offset)
2746 self.assertEqual(0x10, section0.image_pos)
2747 self.assertEqual(len(U_BOOT_DATA), section0.size)
2750 section_entries = section0.GetEntries()
2751 self.assertIn('u-boot', section_entries)
2752 entry = section_entries['u-boot']
2753 self.assertEqual(0, entry.offset)
2754 self.assertEqual(0x10, entry.image_pos)
2755 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2756 self.assertEqual(len(U_BOOT_DATA), entry.size)
2759 self.assertIn('section1', entries)
2760 section1 = entries['section1']
2761 self.assertEqual(0x14, section1.offset)
2762 self.assertEqual(0x14, section1.image_pos)
2763 self.assertEqual(0x20, section1.size)
2766 section_entries = section1.GetEntries()
2767 self.assertIn('u-boot', section_entries)
2768 entry = section_entries['u-boot']
2769 self.assertEqual(0, entry.offset)
2770 self.assertEqual(0x14, entry.image_pos)
2771 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2772 self.assertEqual(len(U_BOOT_DATA), entry.size)
2775 self.assertIn('section2', section_entries)
2776 section2 = section_entries['section2']
2777 self.assertEqual(0x4, section2.offset)
2778 self.assertEqual(0x18, section2.image_pos)
2779 self.assertEqual(4, section2.size)
2782 section_entries = section2.GetEntries()
2783 self.assertIn('u-boot', section_entries)
2784 entry = section_entries['u-boot']
2785 self.assertEqual(0, entry.offset)
2786 self.assertEqual(0x18, entry.image_pos)
2787 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2788 self.assertEqual(len(U_BOOT_DATA), entry.size)
2790 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2791 dts='132_replace.dts'):
2792 """Replace an entry in an image
2794 This writes the entry data to update it, then opens the updated file and
2795 returns the value that it now finds there.
2798 entry_name: Entry name to replace
2799 data: Data to replace it with
2800 decomp: True to compress the data if needed, False if data is
2801 already compressed so should be used as is
2802 allow_resize: True to allow entries to change size, False to raise
2808 data from fdtmap (excluding header)
2809 Image object that was modified
2811 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2814 self.assertIn('image', control.images)
2815 image = control.images['image']
2816 entries = image.GetEntries()
2817 orig_dtb_data = entries['u-boot-dtb'].data
2818 orig_fdtmap_data = entries['fdtmap'].data
2820 image_fname = tools.GetOutputFilename('image.bin')
2821 updated_fname = tools.GetOutputFilename('image-updated.bin')
2822 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2823 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2825 data = control.ReadEntry(updated_fname, entry_name, decomp)
2827 # The DT data should not change unless resized:
2828 if not allow_resize:
2829 new_dtb_data = entries['u-boot-dtb'].data
2830 self.assertEqual(new_dtb_data, orig_dtb_data)
2831 new_fdtmap_data = entries['fdtmap'].data
2832 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2834 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2836 def testReplaceSimple(self):
2837 """Test replacing a single file"""
2838 expected = b'x' * len(U_BOOT_DATA)
2839 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2841 self.assertEqual(expected, data)
2843 # Test that the state looks right. There should be an FDT for the fdtmap
2844 # that we jsut read back in, and it should match what we find in the
2845 # 'control' tables. Checking for an FDT that does not exist should
2847 path, fdtmap = state.GetFdtContents('fdtmap')
2848 self.assertIsNotNone(path)
2849 self.assertEqual(expected_fdtmap, fdtmap)
2851 dtb = state.GetFdtForEtype('fdtmap')
2852 self.assertEqual(dtb.GetContents(), fdtmap)
2854 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2855 self.assertIsNone(missing_path)
2856 self.assertIsNone(missing_fdtmap)
2858 missing_dtb = state.GetFdtForEtype('missing')
2859 self.assertIsNone(missing_dtb)
2861 self.assertEqual('/binman', state.fdt_path_prefix)
2863 def testReplaceResizeFail(self):
2864 """Test replacing a file by something larger"""
2865 expected = U_BOOT_DATA + b'x'
2866 with self.assertRaises(ValueError) as e:
2867 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2868 dts='139_replace_repack.dts')
2869 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2872 def testReplaceMulti(self):
2873 """Test replacing entry data where multiple images are generated"""
2874 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2876 expected = b'x' * len(U_BOOT_DATA)
2877 updated_fname = tools.GetOutputFilename('image-updated.bin')
2878 tools.WriteFile(updated_fname, data)
2879 entry_name = 'u-boot'
2880 control.WriteEntry(updated_fname, entry_name, expected,
2882 data = control.ReadEntry(updated_fname, entry_name)
2883 self.assertEqual(expected, data)
2885 # Check the state looks right.
2886 self.assertEqual('/binman/image', state.fdt_path_prefix)
2888 # Now check we can write the first image
2889 image_fname = tools.GetOutputFilename('first-image.bin')
2890 updated_fname = tools.GetOutputFilename('first-updated.bin')
2891 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2892 entry_name = 'u-boot'
2893 control.WriteEntry(updated_fname, entry_name, expected,
2895 data = control.ReadEntry(updated_fname, entry_name)
2896 self.assertEqual(expected, data)
2898 # Check the state looks right.
2899 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2901 def testUpdateFdtAllRepack(self):
2902 """Test that all device trees are updated with offset/size info"""
2903 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2904 SECTION_SIZE = 0x300
2909 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2911 'section:offset': 0,
2912 'section:size': SECTION_SIZE,
2913 'section:image-pos': 0,
2914 'section/u-boot-dtb:offset': 4,
2915 'section/u-boot-dtb:size': 636,
2916 'section/u-boot-dtb:image-pos': 4,
2917 'u-boot-spl-dtb:offset': SECTION_SIZE,
2918 'u-boot-spl-dtb:size': DTB_SIZE,
2919 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2920 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2921 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2922 'u-boot-tpl-dtb:size': DTB_SIZE,
2923 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2924 'fdtmap:size': FDTMAP_SIZE,
2925 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2928 'section:orig-size': SECTION_SIZE,
2929 'section/u-boot-dtb:orig-offset': 4,
2932 # We expect three device-tree files in the output, with the first one
2933 # within a fixed-size section.
2934 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2935 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2936 # main U-Boot tree. All three should have the same positions and offset
2937 # except that the main tree should include the main_expected properties
2939 for item in ['', 'spl', 'tpl', None]:
2941 start += 16 # Move past fdtmap header
2942 dtb = fdt.Fdt.FromData(data[start:])
2944 props = self._GetPropTree(dtb,
2945 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2946 prefix='/' if item is None else '/binman/')
2947 expected = dict(base_expected)
2951 # Main DTB and fdtdec should include the 'orig-' properties
2952 expected.update(main_expected)
2953 # Helpful for debugging:
2954 #for prop in sorted(props):
2955 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2956 self.assertEqual(expected, props)
2958 start = SECTION_SIZE
2960 start += dtb._fdt_obj.totalsize()
2962 def testFdtmapHeaderMiddle(self):
2963 """Test an FDT map in the middle of an image when it should be at end"""
2964 with self.assertRaises(ValueError) as e:
2965 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2966 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2969 def testFdtmapHeaderStartBad(self):
2970 """Test an FDT map in middle of an image when it should be at start"""
2971 with self.assertRaises(ValueError) as e:
2972 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2973 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2976 def testFdtmapHeaderEndBad(self):
2977 """Test an FDT map at the start of an image when it should be at end"""
2978 with self.assertRaises(ValueError) as e:
2979 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2980 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2983 def testFdtmapHeaderNoSize(self):
2984 """Test an image header at the end of an image with undefined size"""
2985 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2987 def testReplaceResize(self):
2988 """Test replacing a single file in an entry with a larger file"""
2989 expected = U_BOOT_DATA + b'x'
2990 data, _, image = self._RunReplaceCmd('u-boot', expected,
2991 dts='139_replace_repack.dts')
2992 self.assertEqual(expected, data)
2994 entries = image.GetEntries()
2995 dtb_data = entries['u-boot-dtb'].data
2996 dtb = fdt.Fdt.FromData(dtb_data)
2999 # The u-boot section should now be larger in the dtb
3000 node = dtb.GetNode('/binman/u-boot')
3001 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3003 # Same for the fdtmap
3004 fdata = entries['fdtmap'].data
3005 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3007 fnode = fdtb.GetNode('/u-boot')
3008 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3010 def testReplaceResizeNoRepack(self):
3011 """Test replacing an entry with a larger file when not allowed"""
3012 expected = U_BOOT_DATA + b'x'
3013 with self.assertRaises(ValueError) as e:
3014 self._RunReplaceCmd('u-boot', expected)
3015 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3018 def testEntryShrink(self):
3019 """Test contracting an entry after it is packed"""
3021 state.SetAllowEntryContraction(True)
3022 data = self._DoReadFileDtb('140_entry_shrink.dts',
3025 state.SetAllowEntryContraction(False)
3026 self.assertEqual(b'a', data[:1])
3027 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3028 self.assertEqual(b'a', data[-1:])
3030 def testEntryShrinkFail(self):
3031 """Test not being allowed to contract an entry after it is packed"""
3032 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3034 # In this case there is a spare byte at the end of the data. The size of
3035 # the contents is only 1 byte but we still have the size before it
3037 self.assertEqual(b'a\0', data[:2])
3038 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3039 self.assertEqual(b'a\0', data[-2:])
3041 def testDescriptorOffset(self):
3042 """Test that the Intel descriptor is always placed at at the start"""
3043 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3044 image = control.images['image']
3045 entries = image.GetEntries()
3046 desc = entries['intel-descriptor']
3047 self.assertEqual(0xff800000, desc.offset);
3048 self.assertEqual(0xff800000, desc.image_pos);
3050 def testReplaceCbfs(self):
3051 """Test replacing a single file in CBFS without changing the size"""
3053 expected = b'x' * len(U_BOOT_DATA)
3054 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3055 updated_fname = tools.GetOutputFilename('image-updated.bin')
3056 tools.WriteFile(updated_fname, data)
3057 entry_name = 'section/cbfs/u-boot'
3058 control.WriteEntry(updated_fname, entry_name, expected,
3060 data = control.ReadEntry(updated_fname, entry_name)
3061 self.assertEqual(expected, data)
3063 def testReplaceResizeCbfs(self):
3064 """Test replacing a single file in CBFS with one of a different size"""
3066 expected = U_BOOT_DATA + b'x'
3067 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3068 updated_fname = tools.GetOutputFilename('image-updated.bin')
3069 tools.WriteFile(updated_fname, data)
3070 entry_name = 'section/cbfs/u-boot'
3071 control.WriteEntry(updated_fname, entry_name, expected,
3073 data = control.ReadEntry(updated_fname, entry_name)
3074 self.assertEqual(expected, data)
3076 def _SetupForReplace(self):
3077 """Set up some files to use to replace entries
3079 This generates an image, copies it to a new file, extracts all the files
3080 in it and updates some of them
3086 Expected values for updated entries, each a string
3088 data = self._DoReadFileRealDtb('143_replace_all.dts')
3090 updated_fname = tools.GetOutputFilename('image-updated.bin')
3091 tools.WriteFile(updated_fname, data)
3093 outdir = os.path.join(self._indir, 'extract')
3094 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3096 expected1 = b'x' + U_BOOT_DATA + b'y'
3097 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3098 tools.WriteFile(u_boot_fname1, expected1)
3100 expected2 = b'a' + U_BOOT_DATA + b'b'
3101 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3102 tools.WriteFile(u_boot_fname2, expected2)
3104 expected_text = b'not the same text'
3105 text_fname = os.path.join(outdir, 'text')
3106 tools.WriteFile(text_fname, expected_text)
3108 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3109 dtb = fdt.FdtScan(dtb_fname)
3110 node = dtb.GetNode('/binman/text')
3111 node.AddString('my-property', 'the value')
3112 dtb.Sync(auto_resize=True)
3115 return updated_fname, outdir, expected1, expected2, expected_text
3117 def _CheckReplaceMultiple(self, entry_paths):
3118 """Handle replacing the contents of multiple entries
3121 entry_paths: List of entry paths to replace
3125 Dict of entries in the image:
3128 Expected values for updated entries, each a string
3130 updated_fname, outdir, expected1, expected2, expected_text = (
3131 self._SetupForReplace())
3132 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3134 image = Image.FromFile(updated_fname)
3136 return image.GetEntries(), expected1, expected2, expected_text
3138 def testReplaceAll(self):
3139 """Test replacing the contents of all entries"""
3140 entries, expected1, expected2, expected_text = (
3141 self._CheckReplaceMultiple([]))
3142 data = entries['u-boot'].data
3143 self.assertEqual(expected1, data)
3145 data = entries['u-boot2'].data
3146 self.assertEqual(expected2, data)
3148 data = entries['text'].data
3149 self.assertEqual(expected_text, data)
3151 # Check that the device tree is updated
3152 data = entries['u-boot-dtb'].data
3153 dtb = fdt.Fdt.FromData(data)
3155 node = dtb.GetNode('/binman/text')
3156 self.assertEqual('the value', node.props['my-property'].value)
3158 def testReplaceSome(self):
3159 """Test replacing the contents of a few entries"""
3160 entries, expected1, expected2, expected_text = (
3161 self._CheckReplaceMultiple(['u-boot2', 'text']))
3163 # This one should not change
3164 data = entries['u-boot'].data
3165 self.assertEqual(U_BOOT_DATA, data)
3167 data = entries['u-boot2'].data
3168 self.assertEqual(expected2, data)
3170 data = entries['text'].data
3171 self.assertEqual(expected_text, data)
3173 def testReplaceCmd(self):
3174 """Test replacing a file fron an image on the command line"""
3175 self._DoReadFileRealDtb('143_replace_all.dts')
3178 tmpdir, updated_fname = self._SetupImageInTmpdir()
3180 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3181 expected = b'x' * len(U_BOOT_DATA)
3182 tools.WriteFile(fname, expected)
3184 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3185 data = tools.ReadFile(updated_fname)
3186 self.assertEqual(expected, data[:len(expected)])
3187 map_fname = os.path.join(tmpdir, 'image-updated.map')
3188 self.assertFalse(os.path.exists(map_fname))
3190 shutil.rmtree(tmpdir)
3192 def testReplaceCmdSome(self):
3193 """Test replacing some files fron an image on the command line"""
3194 updated_fname, outdir, expected1, expected2, expected_text = (
3195 self._SetupForReplace())
3197 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3200 tools.PrepareOutputDir(None)
3201 image = Image.FromFile(updated_fname)
3203 entries = image.GetEntries()
3205 # This one should not change
3206 data = entries['u-boot'].data
3207 self.assertEqual(U_BOOT_DATA, data)
3209 data = entries['u-boot2'].data
3210 self.assertEqual(expected2, data)
3212 data = entries['text'].data
3213 self.assertEqual(expected_text, data)
3215 def testReplaceMissing(self):
3216 """Test replacing entries where the file is missing"""
3217 updated_fname, outdir, expected1, expected2, expected_text = (
3218 self._SetupForReplace())
3220 # Remove one of the files, to generate a warning
3221 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3222 os.remove(u_boot_fname1)
3224 with test_util.capture_sys_output() as (stdout, stderr):
3225 control.ReplaceEntries(updated_fname, None, outdir, [])
3226 self.assertIn("Skipping entry '/u-boot' from missing file",
3229 def testReplaceCmdMap(self):
3230 """Test replacing a file fron an image on the command line"""
3231 self._DoReadFileRealDtb('143_replace_all.dts')
3234 tmpdir, updated_fname = self._SetupImageInTmpdir()
3236 fname = os.path.join(self._indir, 'update-u-boot.bin')
3237 expected = b'x' * len(U_BOOT_DATA)
3238 tools.WriteFile(fname, expected)
3240 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3242 map_fname = os.path.join(tmpdir, 'image-updated.map')
3243 self.assertTrue(os.path.exists(map_fname))
3245 shutil.rmtree(tmpdir)
3247 def testReplaceNoEntryPaths(self):
3248 """Test replacing an entry without an entry path"""
3249 self._DoReadFileRealDtb('143_replace_all.dts')
3250 image_fname = tools.GetOutputFilename('image.bin')
3251 with self.assertRaises(ValueError) as e:
3252 control.ReplaceEntries(image_fname, 'fname', None, [])
3253 self.assertIn('Must specify an entry path to read with -f',
3256 def testReplaceTooManyEntryPaths(self):
3257 """Test extracting some entries"""
3258 self._DoReadFileRealDtb('143_replace_all.dts')
3259 image_fname = tools.GetOutputFilename('image.bin')
3260 with self.assertRaises(ValueError) as e:
3261 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3262 self.assertIn('Must specify exactly one entry path to write with -f',
3265 def testPackReset16(self):
3266 """Test that an image with an x86 reset16 region can be created"""
3267 data = self._DoReadFile('144_x86_reset16.dts')
3268 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3270 def testPackReset16Spl(self):
3271 """Test that an image with an x86 reset16-spl region can be created"""
3272 data = self._DoReadFile('145_x86_reset16_spl.dts')
3273 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3275 def testPackReset16Tpl(self):
3276 """Test that an image with an x86 reset16-tpl region can be created"""
3277 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3278 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3280 def testPackIntelFit(self):
3281 """Test that an image with an Intel FIT and pointer can be created"""
3282 data = self._DoReadFile('147_intel_fit.dts')
3283 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3285 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3286 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3288 image = control.images['image']
3289 entries = image.GetEntries()
3290 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3291 self.assertEqual(expected_ptr, ptr)
3293 def testPackIntelFitMissing(self):
3294 """Test detection of a FIT pointer with not FIT region"""
3295 with self.assertRaises(ValueError) as e:
3296 self._DoReadFile('148_intel_fit_missing.dts')
3297 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3301 if __name__ == "__main__":