1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # To run a single test, change to this directory, and:
7 # python -m unittest func_test.TestFunctional.testHelp
11 from optparse import OptionParser
19 from binman import cbfs_util
20 from binman import cmdline
21 from binman import control
22 from binman import elf
23 from binman import elf_test
24 from binman import fmap_util
25 from binman import main
26 from binman import state
28 from dtoc import fdt_util
29 from binman.etype import fdtmap
30 from binman.etype import image_header
31 from image import Image
32 from patman import command
33 from patman import test_util
34 from patman import tools
35 from patman import tout
37 # Contents of test files, corresponding to different entry types
39 U_BOOT_IMG_DATA = b'img'
40 U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
41 U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
45 U_BOOT_DTB_DATA = b'udtb'
46 U_BOOT_SPL_DTB_DATA = b'spldtb'
47 U_BOOT_TPL_DTB_DATA = b'tpldtb'
48 X86_START16_DATA = b'start16'
49 X86_START16_SPL_DATA = b'start16spl'
50 X86_START16_TPL_DATA = b'start16tpl'
51 X86_RESET16_DATA = b'reset16'
52 X86_RESET16_SPL_DATA = b'reset16spl'
53 X86_RESET16_TPL_DATA = b'reset16tpl'
54 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
55 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
56 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
57 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
65 CROS_EC_RW_DATA = b'ecrw'
69 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
70 b"sorry you're alive\n")
71 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
72 REFCODE_DATA = b'refcode'
77 # The expected size for the device tree in some tests
78 EXTRACT_DTB_SIZE = 0x3c9
80 # Properties expected to be in the device tree when update_dtb is used
81 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
83 # Extra properties expected to be in the device tree when allow-repack is used
84 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
87 class TestFunctional(unittest.TestCase):
88 """Functional tests for binman
90 Most of these use a sample .dts file to build an image and then check
91 that it looks correct. The sample files are in the test/ subdirectory
94 For each entry type a very small test file is created using fixed
95 string contents. This makes it easy to test that things look right, and
98 In some cases a 'real' file must be used - these are also supplied in
104 from binman import entry
106 # Handle the case where argv[0] is 'python'
107 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
108 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
110 # Create a temporary directory for input files
111 cls._indir = tempfile.mkdtemp(prefix='binmant.')
113 # Create some test files
114 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
115 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
116 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
117 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
118 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
119 TestFunctional._MakeInputFile('me.bin', ME_DATA)
120 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
123 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
125 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
126 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
127 X86_START16_SPL_DATA)
128 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
129 X86_START16_TPL_DATA)
131 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
133 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
134 X86_RESET16_SPL_DATA)
135 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
136 X86_RESET16_TPL_DATA)
138 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
139 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
140 U_BOOT_SPL_NODTB_DATA)
141 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
142 U_BOOT_TPL_NODTB_DATA)
143 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
144 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
145 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
146 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
147 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
148 TestFunctional._MakeInputDir('devkeys')
149 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
150 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
151 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
152 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
153 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
155 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
156 elf_test.BuildElfTestFiles(cls._elf_testdir)
158 # ELF file with a '_dt_ucode_base_size' symbol
159 TestFunctional._MakeInputFile('u-boot',
160 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
162 # Intel flash descriptor file
163 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
164 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
166 shutil.copytree(cls.TestFile('files'),
167 os.path.join(cls._indir, 'files'))
169 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
171 # Travis-CI may have an old lz4
174 tools.Run('lz4', '--no-frame-crc', '-c',
175 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
180 def tearDownClass(cls):
181 """Remove the temporary input directory and its contents"""
182 if cls.preserve_indir:
183 print('Preserving input dir: %s' % cls._indir)
186 shutil.rmtree(cls._indir)
190 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
191 toolpath=None, verbosity=None):
192 """Accept arguments controlling test execution
195 preserve_indir: Preserve the shared input directory used by all
197 preserve_outdir: Preserve the output directories used by tests. Each
198 test has its own, so this is normally only useful when running a
200 toolpath: ist of paths to use for tools
202 cls.preserve_indir = preserve_indir
203 cls.preserve_outdirs = preserve_outdirs
204 cls.toolpath = toolpath
205 cls.verbosity = verbosity
208 if not self.have_lz4:
209 self.skipTest('lz4 --no-frame-crc not available')
211 def _CleanupOutputDir(self):
212 """Remove the temporary output directory"""
213 if self.preserve_outdirs:
214 print('Preserving output dir: %s' % tools.outdir)
216 tools._FinaliseForTest()
219 # Enable this to turn on debugging output
220 # tout.Init(tout.DEBUG)
221 command.test_result = None
224 """Remove the temporary output directory"""
225 self._CleanupOutputDir()
227 def _SetupImageInTmpdir(self):
228 """Set up the output image in a new temporary directory
230 This is used when an image has been generated in the output directory,
231 but we want to run binman again. This will create a new output
232 directory and fail to delete the original one.
234 This creates a new temporary directory, copies the image to it (with a
235 new name) and removes the old output directory.
239 Temporary directory to use
242 image_fname = tools.GetOutputFilename('image.bin')
243 tmpdir = tempfile.mkdtemp(prefix='binman.')
244 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
245 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
246 self._CleanupOutputDir()
247 return tmpdir, updated_fname
251 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
252 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
253 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
255 def _RunBinman(self, *args, **kwargs):
256 """Run binman using the command line
259 Arguments to pass, as a list of strings
260 kwargs: Arguments to pass to Command.RunPipe()
262 result = command.RunPipe([[self._binman_pathname] + list(args)],
263 capture=True, capture_stderr=True, raise_on_error=False)
264 if result.return_code and kwargs.get('raise_on_error', True):
265 raise Exception("Error running '%s': %s" % (' '.join(args),
266 result.stdout + result.stderr))
269 def _DoBinman(self, *argv):
270 """Run binman using directly (in the same process)
273 Arguments to pass, as a list of strings
275 Return value (0 for success)
278 args = cmdline.ParseArgs(argv)
279 args.pager = 'binman-invalid-pager'
280 args.build_dir = self._indir
282 # For testing, you can force an increase in verbosity here
283 # args.verbosity = tout.DEBUG
284 return control.Binman(args)
286 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
287 entry_args=None, images=None, use_real_dtb=False,
289 """Run binman with a given test file
292 fname: Device-tree source filename to use (e.g. 005_simple.dts)
293 debug: True to enable debugging output
294 map: True to output map files for the images
295 update_dtb: Update the offset and size of each entry in the device
296 tree before packing it into the image
297 entry_args: Dict of entry args to supply to binman
299 value: value of that arg
300 images: List of image names to build
305 if verbosity is not None:
306 args.append('-v%d' % verbosity)
308 args.append('-v%d' % self.verbosity)
310 for path in self.toolpath:
311 args += ['--toolpath', path]
312 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
318 args.append('--fake-dtb')
320 for arg, value in entry_args.items():
321 args.append('-a%s=%s' % (arg, value))
324 args += ['-i', image]
325 return self._DoBinman(*args)
327 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
328 """Set up a new test device-tree file
330 The given file is compiled and set up as the device tree to be used
334 fname: Filename of .dts file to read
335 outfile: Output filename for compiled device-tree binary
338 Contents of device-tree binary
340 tmpdir = tempfile.mkdtemp(prefix='binmant.')
341 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
342 with open(dtb, 'rb') as fd:
344 TestFunctional._MakeInputFile(outfile, data)
345 shutil.rmtree(tmpdir)
348 def _GetDtbContentsForSplTpl(self, dtb_data, name):
349 """Create a version of the main DTB for SPL or SPL
351 For testing we don't actually have different versions of the DTB. With
352 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
353 we don't normally have any unwanted nodes.
355 We still want the DTBs for SPL and TPL to be different though, since
356 otherwise it is confusing to know which one we are looking at. So add
357 an 'spl' or 'tpl' property to the top-level node.
359 dtb = fdt.Fdt.FromData(dtb_data)
361 dtb.GetNode('/binman').AddZeroProp(name)
362 dtb.Sync(auto_resize=True)
364 return dtb.GetContents()
366 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
367 update_dtb=False, entry_args=None, reset_dtbs=True):
368 """Run binman and return the resulting image
370 This runs binman with a given test file and then reads the resulting
371 output file. It is a shortcut function since most tests need to do
374 Raises an assertion failure if binman returns a non-zero exit code.
377 fname: Device-tree source filename to use (e.g. 005_simple.dts)
378 use_real_dtb: True to use the test file as the contents of
379 the u-boot-dtb entry. Normally this is not needed and the
380 test contents (the U_BOOT_DTB_DATA string) can be used.
381 But in some test we need the real contents.
382 map: True to output map files for the images
383 update_dtb: Update the offset and size of each entry in the device
384 tree before packing it into the image
388 Resulting image contents
390 Map data showing contents of image (or None if none)
391 Output device tree binary filename ('u-boot.dtb' path)
394 # Use the compiled test file as the u-boot-dtb input
396 dtb_data = self._SetupDtb(fname)
398 # For testing purposes, make a copy of the DT for SPL and TPL. Add
399 # a node indicating which it is, so aid verification.
400 for name in ['spl', 'tpl']:
401 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
402 outfile = os.path.join(self._indir, dtb_fname)
403 TestFunctional._MakeInputFile(dtb_fname,
404 self._GetDtbContentsForSplTpl(dtb_data, name))
407 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
408 entry_args=entry_args, use_real_dtb=use_real_dtb)
409 self.assertEqual(0, retcode)
410 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
412 # Find the (only) image, read it and return its contents
413 image = control.images['image']
414 image_fname = tools.GetOutputFilename('image.bin')
415 self.assertTrue(os.path.exists(image_fname))
417 map_fname = tools.GetOutputFilename('image.map')
418 with open(map_fname) as fd:
422 with open(image_fname, 'rb') as fd:
423 return fd.read(), dtb_data, map_data, out_dtb_fname
425 # Put the test file back
426 if reset_dtbs and use_real_dtb:
429 def _DoReadFileRealDtb(self, fname):
430 """Run binman with a real .dtb file and return the resulting data
433 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
436 Resulting image contents
438 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
440 def _DoReadFile(self, fname, use_real_dtb=False):
441 """Helper function which discards the device-tree binary
444 fname: Device-tree source filename to use (e.g. 005_simple.dts)
445 use_real_dtb: True to use the test file as the contents of
446 the u-boot-dtb entry. Normally this is not needed and the
447 test contents (the U_BOOT_DTB_DATA string) can be used.
448 But in some test we need the real contents.
451 Resulting image contents
453 return self._DoReadFileDtb(fname, use_real_dtb)[0]
456 def _MakeInputFile(cls, fname, contents):
457 """Create a new test input file, creating directories as needed
460 fname: Filename to create
461 contents: File contents to write in to the file
463 Full pathname of file created
465 pathname = os.path.join(cls._indir, fname)
466 dirname = os.path.dirname(pathname)
467 if dirname and not os.path.exists(dirname):
469 with open(pathname, 'wb') as fd:
474 def _MakeInputDir(cls, dirname):
475 """Create a new test input directory, creating directories as needed
478 dirname: Directory name to create
481 Full pathname of directory created
483 pathname = os.path.join(cls._indir, dirname)
484 if not os.path.exists(pathname):
485 os.makedirs(pathname)
489 def _SetupSplElf(cls, src_fname='bss_data'):
490 """Set up an ELF file with a '_dt_ucode_base_size' symbol
493 Filename of ELF file to use as SPL
495 TestFunctional._MakeInputFile('spl/u-boot-spl',
496 tools.ReadFile(cls.ElfTestFile(src_fname)))
499 def _SetupTplElf(cls, src_fname='bss_data'):
500 """Set up an ELF file with a '_dt_ucode_base_size' symbol
503 Filename of ELF file to use as TPL
505 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
506 tools.ReadFile(cls.ElfTestFile(src_fname)))
509 def TestFile(cls, fname):
510 return os.path.join(cls._binman_dir, 'test', fname)
513 def ElfTestFile(cls, fname):
514 return os.path.join(cls._elf_testdir, fname)
516 def AssertInList(self, grep_list, target):
517 """Assert that at least one of a list of things is in a target
520 grep_list: List of strings to check
521 target: Target string
523 for grep in grep_list:
526 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
528 def CheckNoGaps(self, entries):
529 """Check that all entries fit together without gaps
532 entries: List of entries to check
535 for entry in entries.values():
536 self.assertEqual(offset, entry.offset)
539 def GetFdtLen(self, dtb):
540 """Get the totalsize field from a device-tree binary
543 dtb: Device-tree binary contents
546 Total size of device-tree binary, from the header
548 return struct.unpack('>L', dtb[4:8])[0]
550 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
551 def AddNode(node, path):
553 path += '/' + node.name
554 for prop in node.props.values():
555 if prop.name in prop_names:
556 prop_path = path + ':' + prop.name
557 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
559 for subnode in node.subnodes:
560 AddNode(subnode, path)
563 AddNode(dtb.GetRoot(), '')
567 """Test a basic run with valid args"""
568 result = self._RunBinman('-h')
570 def testFullHelp(self):
571 """Test that the full help is displayed with -H"""
572 result = self._RunBinman('-H')
573 help_file = os.path.join(self._binman_dir, 'README')
574 # Remove possible extraneous strings
575 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
576 gothelp = result.stdout.replace(extra, '')
577 self.assertEqual(len(gothelp), os.path.getsize(help_file))
578 self.assertEqual(0, len(result.stderr))
579 self.assertEqual(0, result.return_code)
581 def testFullHelpInternal(self):
582 """Test that the full help is displayed with -H"""
584 command.test_result = command.CommandResult()
585 result = self._DoBinman('-H')
586 help_file = os.path.join(self._binman_dir, 'README')
588 command.test_result = None
591 """Test that the basic help is displayed with -h"""
592 result = self._RunBinman('-h')
593 self.assertTrue(len(result.stdout) > 200)
594 self.assertEqual(0, len(result.stderr))
595 self.assertEqual(0, result.return_code)
598 """Test that we can run it with a specific board"""
599 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
600 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
601 result = self._DoBinman('build', '-b', 'sandbox')
602 self.assertEqual(0, result)
604 def testNeedBoard(self):
605 """Test that we get an error when no board ius supplied"""
606 with self.assertRaises(ValueError) as e:
607 result = self._DoBinman('build')
608 self.assertIn("Must provide a board to process (use -b <board>)",
611 def testMissingDt(self):
612 """Test that an invalid device-tree file generates an error"""
613 with self.assertRaises(Exception) as e:
614 self._RunBinman('build', '-d', 'missing_file')
615 # We get one error from libfdt, and a different one from fdtget.
616 self.AssertInList(["Couldn't open blob from 'missing_file'",
617 'No such file or directory'], str(e.exception))
619 def testBrokenDt(self):
620 """Test that an invalid device-tree source file generates an error
622 Since this is a source file it should be compiled and the error
623 will come from the device-tree compiler (dtc).
625 with self.assertRaises(Exception) as e:
626 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
627 self.assertIn("FATAL ERROR: Unable to parse input tree",
630 def testMissingNode(self):
631 """Test that a device tree without a 'binman' node generates an error"""
632 with self.assertRaises(Exception) as e:
633 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
634 self.assertIn("does not have a 'binman' node", str(e.exception))
637 """Test that an empty binman node works OK (i.e. does nothing)"""
638 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
639 self.assertEqual(0, len(result.stderr))
640 self.assertEqual(0, result.return_code)
642 def testInvalidEntry(self):
643 """Test that an invalid entry is flagged"""
644 with self.assertRaises(Exception) as e:
645 result = self._RunBinman('build', '-d',
646 self.TestFile('004_invalid_entry.dts'))
647 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
648 "'/binman/not-a-valid-type'", str(e.exception))
650 def testSimple(self):
651 """Test a simple binman with a single file"""
652 data = self._DoReadFile('005_simple.dts')
653 self.assertEqual(U_BOOT_DATA, data)
655 def testSimpleDebug(self):
656 """Test a simple binman run with debugging enabled"""
657 self._DoTestFile('005_simple.dts', debug=True)
660 """Test that we can handle creating two images
662 This also tests image padding.
664 retcode = self._DoTestFile('006_dual_image.dts')
665 self.assertEqual(0, retcode)
667 image = control.images['image1']
668 self.assertEqual(len(U_BOOT_DATA), image.size)
669 fname = tools.GetOutputFilename('image1.bin')
670 self.assertTrue(os.path.exists(fname))
671 with open(fname, 'rb') as fd:
673 self.assertEqual(U_BOOT_DATA, data)
675 image = control.images['image2']
676 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
677 fname = tools.GetOutputFilename('image2.bin')
678 self.assertTrue(os.path.exists(fname))
679 with open(fname, 'rb') as fd:
681 self.assertEqual(U_BOOT_DATA, data[3:7])
682 self.assertEqual(tools.GetBytes(0, 3), data[:3])
683 self.assertEqual(tools.GetBytes(0, 5), data[7:])
685 def testBadAlign(self):
686 """Test that an invalid alignment value is detected"""
687 with self.assertRaises(ValueError) as e:
688 self._DoTestFile('007_bad_align.dts')
689 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
690 "of two", str(e.exception))
692 def testPackSimple(self):
693 """Test that packing works as expected"""
694 retcode = self._DoTestFile('008_pack.dts')
695 self.assertEqual(0, retcode)
696 self.assertIn('image', control.images)
697 image = control.images['image']
698 entries = image.GetEntries()
699 self.assertEqual(5, len(entries))
702 self.assertIn('u-boot', entries)
703 entry = entries['u-boot']
704 self.assertEqual(0, entry.offset)
705 self.assertEqual(len(U_BOOT_DATA), entry.size)
707 # Second u-boot, aligned to 16-byte boundary
708 self.assertIn('u-boot-align', entries)
709 entry = entries['u-boot-align']
710 self.assertEqual(16, entry.offset)
711 self.assertEqual(len(U_BOOT_DATA), entry.size)
713 # Third u-boot, size 23 bytes
714 self.assertIn('u-boot-size', entries)
715 entry = entries['u-boot-size']
716 self.assertEqual(20, entry.offset)
717 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
718 self.assertEqual(23, entry.size)
720 # Fourth u-boot, placed immediate after the above
721 self.assertIn('u-boot-next', entries)
722 entry = entries['u-boot-next']
723 self.assertEqual(43, entry.offset)
724 self.assertEqual(len(U_BOOT_DATA), entry.size)
726 # Fifth u-boot, placed at a fixed offset
727 self.assertIn('u-boot-fixed', entries)
728 entry = entries['u-boot-fixed']
729 self.assertEqual(61, entry.offset)
730 self.assertEqual(len(U_BOOT_DATA), entry.size)
732 self.assertEqual(65, image.size)
734 def testPackExtra(self):
735 """Test that extra packing feature works as expected"""
736 retcode = self._DoTestFile('009_pack_extra.dts')
738 self.assertEqual(0, retcode)
739 self.assertIn('image', control.images)
740 image = control.images['image']
741 entries = image.GetEntries()
742 self.assertEqual(5, len(entries))
744 # First u-boot with padding before and after
745 self.assertIn('u-boot', entries)
746 entry = entries['u-boot']
747 self.assertEqual(0, entry.offset)
748 self.assertEqual(3, entry.pad_before)
749 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
751 # Second u-boot has an aligned size, but it has no effect
752 self.assertIn('u-boot-align-size-nop', entries)
753 entry = entries['u-boot-align-size-nop']
754 self.assertEqual(12, entry.offset)
755 self.assertEqual(4, entry.size)
757 # Third u-boot has an aligned size too
758 self.assertIn('u-boot-align-size', entries)
759 entry = entries['u-boot-align-size']
760 self.assertEqual(16, entry.offset)
761 self.assertEqual(32, entry.size)
763 # Fourth u-boot has an aligned end
764 self.assertIn('u-boot-align-end', entries)
765 entry = entries['u-boot-align-end']
766 self.assertEqual(48, entry.offset)
767 self.assertEqual(16, entry.size)
769 # Fifth u-boot immediately afterwards
770 self.assertIn('u-boot-align-both', entries)
771 entry = entries['u-boot-align-both']
772 self.assertEqual(64, entry.offset)
773 self.assertEqual(64, entry.size)
775 self.CheckNoGaps(entries)
776 self.assertEqual(128, image.size)
778 def testPackAlignPowerOf2(self):
779 """Test that invalid entry alignment is detected"""
780 with self.assertRaises(ValueError) as e:
781 self._DoTestFile('010_pack_align_power2.dts')
782 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
783 "of two", str(e.exception))
785 def testPackAlignSizePowerOf2(self):
786 """Test that invalid entry size alignment is detected"""
787 with self.assertRaises(ValueError) as e:
788 self._DoTestFile('011_pack_align_size_power2.dts')
789 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
790 "power of two", str(e.exception))
792 def testPackInvalidAlign(self):
793 """Test detection of an offset that does not match its alignment"""
794 with self.assertRaises(ValueError) as e:
795 self._DoTestFile('012_pack_inv_align.dts')
796 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
797 "align 0x4 (4)", str(e.exception))
799 def testPackInvalidSizeAlign(self):
800 """Test that invalid entry size alignment is detected"""
801 with self.assertRaises(ValueError) as e:
802 self._DoTestFile('013_pack_inv_size_align.dts')
803 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
804 "align-size 0x4 (4)", str(e.exception))
806 def testPackOverlap(self):
807 """Test that overlapping regions are detected"""
808 with self.assertRaises(ValueError) as e:
809 self._DoTestFile('014_pack_overlap.dts')
810 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
811 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
814 def testPackEntryOverflow(self):
815 """Test that entries that overflow their size are detected"""
816 with self.assertRaises(ValueError) as e:
817 self._DoTestFile('015_pack_overflow.dts')
818 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
819 "but entry size is 0x3 (3)", str(e.exception))
821 def testPackImageOverflow(self):
822 """Test that entries which overflow the image size are detected"""
823 with self.assertRaises(ValueError) as e:
824 self._DoTestFile('016_pack_image_overflow.dts')
825 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
826 "size 0x3 (3)", str(e.exception))
828 def testPackImageSize(self):
829 """Test that the image size can be set"""
830 retcode = self._DoTestFile('017_pack_image_size.dts')
831 self.assertEqual(0, retcode)
832 self.assertIn('image', control.images)
833 image = control.images['image']
834 self.assertEqual(7, image.size)
836 def testPackImageSizeAlign(self):
837 """Test that image size alignemnt works as expected"""
838 retcode = self._DoTestFile('018_pack_image_align.dts')
839 self.assertEqual(0, retcode)
840 self.assertIn('image', control.images)
841 image = control.images['image']
842 self.assertEqual(16, image.size)
844 def testPackInvalidImageAlign(self):
845 """Test that invalid image alignment is detected"""
846 with self.assertRaises(ValueError) as e:
847 self._DoTestFile('019_pack_inv_image_align.dts')
848 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
849 "align-size 0x8 (8)", str(e.exception))
851 def testPackAlignPowerOf2(self):
852 """Test that invalid image alignment is detected"""
853 with self.assertRaises(ValueError) as e:
854 self._DoTestFile('020_pack_inv_image_align_power2.dts')
855 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
856 "two", str(e.exception))
858 def testImagePadByte(self):
859 """Test that the image pad byte can be specified"""
861 data = self._DoReadFile('021_image_pad.dts')
862 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
865 def testImageName(self):
866 """Test that image files can be named"""
867 retcode = self._DoTestFile('022_image_name.dts')
868 self.assertEqual(0, retcode)
869 image = control.images['image1']
870 fname = tools.GetOutputFilename('test-name')
871 self.assertTrue(os.path.exists(fname))
873 image = control.images['image2']
874 fname = tools.GetOutputFilename('test-name.xx')
875 self.assertTrue(os.path.exists(fname))
877 def testBlobFilename(self):
878 """Test that generic blobs can be provided by filename"""
879 data = self._DoReadFile('023_blob.dts')
880 self.assertEqual(BLOB_DATA, data)
882 def testPackSorted(self):
883 """Test that entries can be sorted"""
885 data = self._DoReadFile('024_sorted.dts')
886 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
887 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
889 def testPackZeroOffset(self):
890 """Test that an entry at offset 0 is not given a new offset"""
891 with self.assertRaises(ValueError) as e:
892 self._DoTestFile('025_pack_zero_size.dts')
893 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
894 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
897 def testPackUbootDtb(self):
898 """Test that a device tree can be added to U-Boot"""
899 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
900 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
902 def testPackX86RomNoSize(self):
903 """Test that the end-at-4gb property requires a size property"""
904 with self.assertRaises(ValueError) as e:
905 self._DoTestFile('027_pack_4gb_no_size.dts')
906 self.assertIn("Image '/binman': Section size must be provided when "
907 "using end-at-4gb", str(e.exception))
909 def test4gbAndSkipAtStartTogether(self):
910 """Test that the end-at-4gb and skip-at-size property can't be used
912 with self.assertRaises(ValueError) as e:
913 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
914 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
915 "'skip-at-start'", str(e.exception))
917 def testPackX86RomOutside(self):
918 """Test that the end-at-4gb property checks for offset boundaries"""
919 with self.assertRaises(ValueError) as e:
920 self._DoTestFile('028_pack_4gb_outside.dts')
921 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
922 "the section starting at 0xffffffe0 (4294967264)",
925 def testPackX86Rom(self):
926 """Test that a basic x86 ROM can be created"""
928 data = self._DoReadFile('029_x86_rom.dts')
929 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
930 tools.GetBytes(0, 2), data)
932 def testPackX86RomMeNoDesc(self):
933 """Test that an invalid Intel descriptor entry is detected"""
934 TestFunctional._MakeInputFile('descriptor.bin', b'')
935 with self.assertRaises(ValueError) as e:
936 self._DoTestFile('031_x86_rom_me.dts')
937 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
940 def testPackX86RomBadDesc(self):
941 """Test that the Intel requires a descriptor entry"""
942 with self.assertRaises(ValueError) as e:
943 self._DoTestFile('030_x86_rom_me_no_desc.dts')
944 self.assertIn("Node '/binman/intel-me': No offset set with "
945 "offset-unset: should another entry provide this correct "
946 "offset?", str(e.exception))
948 def testPackX86RomMe(self):
949 """Test that an x86 ROM with an ME region can be created"""
950 data = self._DoReadFile('031_x86_rom_me.dts')
951 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
952 if data[:0x1000] != expected_desc:
953 self.fail('Expected descriptor binary at start of image')
954 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
956 def testPackVga(self):
957 """Test that an image with a VGA binary can be created"""
958 data = self._DoReadFile('032_intel_vga.dts')
959 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
961 def testPackStart16(self):
962 """Test that an image with an x86 start16 region can be created"""
963 data = self._DoReadFile('033_x86_start16.dts')
964 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
966 def testPackPowerpcMpc85xxBootpgResetvec(self):
967 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
969 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
970 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
972 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
973 """Handle running a test for insertion of microcode
976 dts_fname: Name of test .dts file
977 nodtb_data: Data that we expect in the first section
978 ucode_second: True if the microsecond entry is second instead of
983 Contents of first region (U-Boot or SPL)
984 Offset and size components of microcode pointer, as inserted
985 in the above (two 4-byte words)
987 data = self._DoReadFile(dts_fname, True)
989 # Now check the device tree has no microcode
991 ucode_content = data[len(nodtb_data):]
992 ucode_pos = len(nodtb_data)
993 dtb_with_ucode = ucode_content[16:]
994 fdt_len = self.GetFdtLen(dtb_with_ucode)
996 dtb_with_ucode = data[len(nodtb_data):]
997 fdt_len = self.GetFdtLen(dtb_with_ucode)
998 ucode_content = dtb_with_ucode[fdt_len:]
999 ucode_pos = len(nodtb_data) + fdt_len
1000 fname = tools.GetOutputFilename('test.dtb')
1001 with open(fname, 'wb') as fd:
1002 fd.write(dtb_with_ucode)
1003 dtb = fdt.FdtScan(fname)
1004 ucode = dtb.GetNode('/microcode')
1005 self.assertTrue(ucode)
1006 for node in ucode.subnodes:
1007 self.assertFalse(node.props.get('data'))
1009 # Check that the microcode appears immediately after the Fdt
1010 # This matches the concatenation of the data properties in
1011 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
1012 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1014 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1016 # Check that the microcode pointer was inserted. It should match the
1017 # expected offset and size
1018 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1020 u_boot = data[:len(nodtb_data)]
1021 return u_boot, pos_and_size
1023 def testPackUbootMicrocode(self):
1024 """Test that x86 microcode can be handled correctly
1026 We expect to see the following in the image, in order:
1027 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1029 u-boot.dtb with the microcode removed
1032 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1034 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1035 b' somewhere in here', first)
1037 def _RunPackUbootSingleMicrocode(self):
1038 """Test that x86 microcode can be handled correctly
1040 We expect to see the following in the image, in order:
1041 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1043 u-boot.dtb with the microcode
1044 an empty microcode region
1046 # We need the libfdt library to run this test since only that allows
1047 # finding the offset of a property. This is required by
1048 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1049 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1051 second = data[len(U_BOOT_NODTB_DATA):]
1053 fdt_len = self.GetFdtLen(second)
1054 third = second[fdt_len:]
1055 second = second[:fdt_len]
1057 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1058 self.assertIn(ucode_data, second)
1059 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1061 # Check that the microcode pointer was inserted. It should match the
1062 # expected offset and size
1063 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1065 first = data[:len(U_BOOT_NODTB_DATA)]
1066 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1067 b' somewhere in here', first)
1069 def testPackUbootSingleMicrocode(self):
1070 """Test that x86 microcode can be handled correctly with fdt_normal.
1072 self._RunPackUbootSingleMicrocode()
1074 def testUBootImg(self):
1075 """Test that u-boot.img can be put in a file"""
1076 data = self._DoReadFile('036_u_boot_img.dts')
1077 self.assertEqual(U_BOOT_IMG_DATA, data)
1079 def testNoMicrocode(self):
1080 """Test that a missing microcode region is detected"""
1081 with self.assertRaises(ValueError) as e:
1082 self._DoReadFile('037_x86_no_ucode.dts', True)
1083 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1084 "node found in ", str(e.exception))
1086 def testMicrocodeWithoutNode(self):
1087 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1088 with self.assertRaises(ValueError) as e:
1089 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1090 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1091 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1093 def testMicrocodeWithoutNode2(self):
1094 """Test that a missing u-boot-ucode node is detected"""
1095 with self.assertRaises(ValueError) as e:
1096 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1097 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1098 "microcode region u-boot-ucode", str(e.exception))
1100 def testMicrocodeWithoutPtrInElf(self):
1101 """Test that a U-Boot binary without the microcode symbol is detected"""
1102 # ELF file without a '_dt_ucode_base_size' symbol
1104 TestFunctional._MakeInputFile('u-boot',
1105 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1107 with self.assertRaises(ValueError) as e:
1108 self._RunPackUbootSingleMicrocode()
1109 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1110 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1113 # Put the original file back
1114 TestFunctional._MakeInputFile('u-boot',
1115 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1117 def testMicrocodeNotInImage(self):
1118 """Test that microcode must be placed within the image"""
1119 with self.assertRaises(ValueError) as e:
1120 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1121 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1122 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1123 "section ranging from 00000000 to 0000002e", str(e.exception))
1125 def testWithoutMicrocode(self):
1126 """Test that we can cope with an image without microcode (e.g. qemu)"""
1127 TestFunctional._MakeInputFile('u-boot',
1128 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1129 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1131 # Now check the device tree has no microcode
1132 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1133 second = data[len(U_BOOT_NODTB_DATA):]
1135 fdt_len = self.GetFdtLen(second)
1136 self.assertEqual(dtb, second[:fdt_len])
1138 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1139 third = data[used_len:]
1140 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1142 def testUnknownPosSize(self):
1143 """Test that microcode must be placed within the image"""
1144 with self.assertRaises(ValueError) as e:
1145 self._DoReadFile('041_unknown_pos_size.dts', True)
1146 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1147 "entry 'invalid-entry'", str(e.exception))
1149 def testPackFsp(self):
1150 """Test that an image with a FSP binary can be created"""
1151 data = self._DoReadFile('042_intel_fsp.dts')
1152 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1154 def testPackCmc(self):
1155 """Test that an image with a CMC binary can be created"""
1156 data = self._DoReadFile('043_intel_cmc.dts')
1157 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1159 def testPackVbt(self):
1160 """Test that an image with a VBT binary can be created"""
1161 data = self._DoReadFile('046_intel_vbt.dts')
1162 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1164 def testSplBssPad(self):
1165 """Test that we can pad SPL's BSS with zeros"""
1166 # ELF file with a '__bss_size' symbol
1168 data = self._DoReadFile('047_spl_bss_pad.dts')
1169 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1172 def testSplBssPadMissing(self):
1173 """Test that a missing symbol is detected"""
1174 self._SetupSplElf('u_boot_ucode_ptr')
1175 with self.assertRaises(ValueError) as e:
1176 self._DoReadFile('047_spl_bss_pad.dts')
1177 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1180 def testPackStart16Spl(self):
1181 """Test that an image with an x86 start16 SPL region can be created"""
1182 data = self._DoReadFile('048_x86_start16_spl.dts')
1183 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1185 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1186 """Helper function for microcode tests
1188 We expect to see the following in the image, in order:
1189 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1191 u-boot.dtb with the microcode removed
1195 dts: Device tree file to use for test
1196 ucode_second: True if the microsecond entry is second instead of
1199 self._SetupSplElf('u_boot_ucode_ptr')
1200 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1201 ucode_second=ucode_second)
1202 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1203 b'ter somewhere in here', first)
1205 def testPackUbootSplMicrocode(self):
1206 """Test that x86 microcode can be handled correctly in SPL"""
1207 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1209 def testPackUbootSplMicrocodeReorder(self):
1210 """Test that order doesn't matter for microcode entries
1212 This is the same as testPackUbootSplMicrocode but when we process the
1213 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1214 entry, so we reply on binman to try later.
1216 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1219 def testPackMrc(self):
1220 """Test that an image with an MRC binary can be created"""
1221 data = self._DoReadFile('050_intel_mrc.dts')
1222 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1224 def testSplDtb(self):
1225 """Test that an image with spl/u-boot-spl.dtb can be created"""
1226 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1227 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1229 def testSplNoDtb(self):
1230 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1231 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1232 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1234 def testSymbols(self):
1235 """Test binman can assign symbols embedded in U-Boot"""
1236 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1237 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1238 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1239 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1241 self._SetupSplElf('u_boot_binman_syms')
1242 data = self._DoReadFile('053_symbols.dts')
1243 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
1244 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
1245 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1246 U_BOOT_SPL_DATA[20:])
1247 self.assertEqual(expected, data)
1249 def testPackUnitAddress(self):
1250 """Test that we support multiple binaries with the same name"""
1251 data = self._DoReadFile('054_unit_address.dts')
1252 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1254 def testSections(self):
1255 """Basic test of sections"""
1256 data = self._DoReadFile('055_sections.dts')
1257 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1258 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1259 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1260 self.assertEqual(expected, data)
1263 """Tests outputting a map of the images"""
1264 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1265 self.assertEqual('''ImagePos Offset Size Name
1266 00000000 00000000 00000028 main-section
1267 00000000 00000000 00000010 section@0
1268 00000000 00000000 00000004 u-boot
1269 00000010 00000010 00000010 section@1
1270 00000010 00000000 00000004 u-boot
1271 00000020 00000020 00000004 section@2
1272 00000020 00000000 00000004 u-boot
1275 def testNamePrefix(self):
1276 """Tests that name prefixes are used"""
1277 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1278 self.assertEqual('''ImagePos Offset Size Name
1279 00000000 00000000 00000028 main-section
1280 00000000 00000000 00000010 section@0
1281 00000000 00000000 00000004 ro-u-boot
1282 00000010 00000010 00000010 section@1
1283 00000010 00000000 00000004 rw-u-boot
1286 def testUnknownContents(self):
1287 """Test that obtaining the contents works as expected"""
1288 with self.assertRaises(ValueError) as e:
1289 self._DoReadFile('057_unknown_contents.dts', True)
1290 self.assertIn("Image '/binman': Internal error: Could not complete "
1291 "processing of contents: remaining ["
1292 "<binman.etype._testing.Entry__testing ", str(e.exception))
1294 def testBadChangeSize(self):
1295 """Test that trying to change the size of an entry fails"""
1297 state.SetAllowEntryExpansion(False)
1298 with self.assertRaises(ValueError) as e:
1299 self._DoReadFile('059_change_size.dts', True)
1300 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1303 state.SetAllowEntryExpansion(True)
1305 def testUpdateFdt(self):
1306 """Test that we can update the device tree with offset/size info"""
1307 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1309 dtb = fdt.Fdt(out_dtb_fname)
1311 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1315 '_testing:offset': 32,
1317 '_testing:image-pos': 32,
1318 'section@0/u-boot:offset': 0,
1319 'section@0/u-boot:size': len(U_BOOT_DATA),
1320 'section@0/u-boot:image-pos': 0,
1321 'section@0:offset': 0,
1322 'section@0:size': 16,
1323 'section@0:image-pos': 0,
1325 'section@1/u-boot:offset': 0,
1326 'section@1/u-boot:size': len(U_BOOT_DATA),
1327 'section@1/u-boot:image-pos': 16,
1328 'section@1:offset': 16,
1329 'section@1:size': 16,
1330 'section@1:image-pos': 16,
1334 def testUpdateFdtBad(self):
1335 """Test that we detect when ProcessFdt never completes"""
1336 with self.assertRaises(ValueError) as e:
1337 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1338 self.assertIn('Could not complete processing of Fdt: remaining '
1339 '[<binman.etype._testing.Entry__testing',
1342 def testEntryArgs(self):
1343 """Test passing arguments to entries from the command line"""
1345 'test-str-arg': 'test1',
1346 'test-int-arg': '456',
1348 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1349 self.assertIn('image', control.images)
1350 entry = control.images['image'].GetEntries()['_testing']
1351 self.assertEqual('test0', entry.test_str_fdt)
1352 self.assertEqual('test1', entry.test_str_arg)
1353 self.assertEqual(123, entry.test_int_fdt)
1354 self.assertEqual(456, entry.test_int_arg)
1356 def testEntryArgsMissing(self):
1357 """Test missing arguments and properties"""
1359 'test-int-arg': '456',
1361 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1362 entry = control.images['image'].GetEntries()['_testing']
1363 self.assertEqual('test0', entry.test_str_fdt)
1364 self.assertEqual(None, entry.test_str_arg)
1365 self.assertEqual(None, entry.test_int_fdt)
1366 self.assertEqual(456, entry.test_int_arg)
1368 def testEntryArgsRequired(self):
1369 """Test missing arguments and properties"""
1371 'test-int-arg': '456',
1373 with self.assertRaises(ValueError) as e:
1374 self._DoReadFileDtb('064_entry_args_required.dts')
1375 self.assertIn("Node '/binman/_testing': Missing required "
1376 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1379 def testEntryArgsInvalidFormat(self):
1380 """Test that an invalid entry-argument format is detected"""
1381 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1383 with self.assertRaises(ValueError) as e:
1384 self._DoBinman(*args)
1385 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1387 def testEntryArgsInvalidInteger(self):
1388 """Test that an invalid entry-argument integer is detected"""
1390 'test-int-arg': 'abc',
1392 with self.assertRaises(ValueError) as e:
1393 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1394 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1395 "'test-int-arg' (value 'abc') to integer",
1398 def testEntryArgsInvalidDatatype(self):
1399 """Test that an invalid entry-argument datatype is detected
1401 This test could be written in entry_test.py except that it needs
1402 access to control.entry_args, which seems more than that module should
1406 'test-bad-datatype-arg': '12',
1408 with self.assertRaises(ValueError) as e:
1409 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1410 entry_args=entry_args)
1411 self.assertIn('GetArg() internal error: Unknown data type ',
1415 """Test for a text entry type"""
1417 'test-id': TEXT_DATA,
1418 'test-id2': TEXT_DATA2,
1419 'test-id3': TEXT_DATA3,
1421 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1422 entry_args=entry_args)
1423 expected = (tools.ToBytes(TEXT_DATA) +
1424 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1425 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1426 b'some text' + b'more text')
1427 self.assertEqual(expected, data)
1429 def testEntryDocs(self):
1430 """Test for creation of entry documentation"""
1431 with test_util.capture_sys_output() as (stdout, stderr):
1432 control.WriteEntryDocs(main.GetEntryModules())
1433 self.assertTrue(len(stdout.getvalue()) > 0)
1435 def testEntryDocsMissing(self):
1436 """Test handling of missing entry documentation"""
1437 with self.assertRaises(ValueError) as e:
1438 with test_util.capture_sys_output() as (stdout, stderr):
1439 control.WriteEntryDocs(main.GetEntryModules(), 'u_boot')
1440 self.assertIn('Documentation is missing for modules: u_boot',
1444 """Basic test of generation of a flashrom fmap"""
1445 data = self._DoReadFile('067_fmap.dts')
1446 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1447 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1448 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1449 self.assertEqual(expected, data[:32])
1450 self.assertEqual(b'__FMAP__', fhdr.signature)
1451 self.assertEqual(1, fhdr.ver_major)
1452 self.assertEqual(0, fhdr.ver_minor)
1453 self.assertEqual(0, fhdr.base)
1454 self.assertEqual(16 + 16 +
1455 fmap_util.FMAP_HEADER_LEN +
1456 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1457 self.assertEqual(b'FMAP', fhdr.name)
1458 self.assertEqual(3, fhdr.nareas)
1459 for fentry in fentries:
1460 self.assertEqual(0, fentry.flags)
1462 self.assertEqual(0, fentries[0].offset)
1463 self.assertEqual(4, fentries[0].size)
1464 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1466 self.assertEqual(16, fentries[1].offset)
1467 self.assertEqual(4, fentries[1].size)
1468 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1470 self.assertEqual(32, fentries[2].offset)
1471 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1472 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1473 self.assertEqual(b'FMAP', fentries[2].name)
1475 def testBlobNamedByArg(self):
1476 """Test we can add a blob with the filename coming from an entry arg"""
1478 'cros-ec-rw-path': 'ecrw.bin',
1480 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1481 entry_args=entry_args)
1484 """Test for an fill entry type"""
1485 data = self._DoReadFile('069_fill.dts')
1486 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1487 self.assertEqual(expected, data)
1489 def testFillNoSize(self):
1490 """Test for an fill entry type with no size"""
1491 with self.assertRaises(ValueError) as e:
1492 self._DoReadFile('070_fill_no_size.dts')
1493 self.assertIn("'fill' entry must have a size property",
1496 def _HandleGbbCommand(self, pipe_list):
1497 """Fake calls to the futility utility"""
1498 if pipe_list[0][0] == 'futility':
1499 fname = pipe_list[0][-1]
1500 # Append our GBB data to the file, which will happen every time the
1501 # futility command is called.
1502 with open(fname, 'ab') as fd:
1504 return command.CommandResult()
1507 """Test for the Chromium OS Google Binary Block"""
1508 command.test_result = self._HandleGbbCommand
1510 'keydir': 'devkeys',
1511 'bmpblk': 'bmpblk.bin',
1513 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1516 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1517 tools.GetBytes(0, 0x2180 - 16))
1518 self.assertEqual(expected, data)
1520 def testGbbTooSmall(self):
1521 """Test for the Chromium OS Google Binary Block being large enough"""
1522 with self.assertRaises(ValueError) as e:
1523 self._DoReadFileDtb('072_gbb_too_small.dts')
1524 self.assertIn("Node '/binman/gbb': GBB is too small",
1527 def testGbbNoSize(self):
1528 """Test for the Chromium OS Google Binary Block having a size"""
1529 with self.assertRaises(ValueError) as e:
1530 self._DoReadFileDtb('073_gbb_no_size.dts')
1531 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1534 def _HandleVblockCommand(self, pipe_list):
1535 """Fake calls to the futility utility"""
1536 if pipe_list[0][0] == 'futility':
1537 fname = pipe_list[0][3]
1538 with open(fname, 'wb') as fd:
1539 fd.write(VBLOCK_DATA)
1540 return command.CommandResult()
1542 def testVblock(self):
1543 """Test for the Chromium OS Verified Boot Block"""
1544 command.test_result = self._HandleVblockCommand
1546 'keydir': 'devkeys',
1548 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1549 entry_args=entry_args)
1550 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1551 self.assertEqual(expected, data)
1553 def testVblockNoContent(self):
1554 """Test we detect a vblock which has no content to sign"""
1555 with self.assertRaises(ValueError) as e:
1556 self._DoReadFile('075_vblock_no_content.dts')
1557 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1558 'property', str(e.exception))
1560 def testVblockBadPhandle(self):
1561 """Test that we detect a vblock with an invalid phandle in contents"""
1562 with self.assertRaises(ValueError) as e:
1563 self._DoReadFile('076_vblock_bad_phandle.dts')
1564 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1565 '1000', str(e.exception))
1567 def testVblockBadEntry(self):
1568 """Test that we detect an entry that points to a non-entry"""
1569 with self.assertRaises(ValueError) as e:
1570 self._DoReadFile('077_vblock_bad_entry.dts')
1571 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1572 "'other'", str(e.exception))
1575 """Test that an image with TPL and its device tree can be created"""
1576 # ELF file with a '__bss_size' symbol
1578 data = self._DoReadFile('078_u_boot_tpl.dts')
1579 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1581 def testUsesPos(self):
1582 """Test that the 'pos' property cannot be used anymore"""
1583 with self.assertRaises(ValueError) as e:
1584 data = self._DoReadFile('079_uses_pos.dts')
1585 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1586 "'pos'", str(e.exception))
1588 def testFillZero(self):
1589 """Test for an fill entry type with a size of 0"""
1590 data = self._DoReadFile('080_fill_empty.dts')
1591 self.assertEqual(tools.GetBytes(0, 16), data)
1593 def testTextMissing(self):
1594 """Test for a text entry type where there is no text"""
1595 with self.assertRaises(ValueError) as e:
1596 self._DoReadFileDtb('066_text.dts',)
1597 self.assertIn("Node '/binman/text': No value provided for text label "
1598 "'test-id'", str(e.exception))
1600 def testPackStart16Tpl(self):
1601 """Test that an image with an x86 start16 TPL region can be created"""
1602 data = self._DoReadFile('081_x86_start16_tpl.dts')
1603 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1605 def testSelectImage(self):
1606 """Test that we can select which images to build"""
1607 expected = 'Skipping images: image1'
1609 # We should only get the expected message in verbose mode
1610 for verbosity in (0, 2):
1611 with test_util.capture_sys_output() as (stdout, stderr):
1612 retcode = self._DoTestFile('006_dual_image.dts',
1613 verbosity=verbosity,
1615 self.assertEqual(0, retcode)
1617 self.assertIn(expected, stdout.getvalue())
1619 self.assertNotIn(expected, stdout.getvalue())
1621 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1622 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1623 self._CleanupOutputDir()
1625 def testUpdateFdtAll(self):
1626 """Test that all device trees are updated with offset/size info"""
1627 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1630 'section:image-pos': 0,
1631 'u-boot-tpl-dtb:size': 513,
1632 'u-boot-spl-dtb:size': 513,
1633 'u-boot-spl-dtb:offset': 493,
1635 'section/u-boot-dtb:image-pos': 0,
1636 'u-boot-spl-dtb:image-pos': 493,
1637 'section/u-boot-dtb:size': 493,
1638 'u-boot-tpl-dtb:image-pos': 1006,
1639 'section/u-boot-dtb:offset': 0,
1640 'section:size': 493,
1642 'section:offset': 0,
1643 'u-boot-tpl-dtb:offset': 1006,
1647 # We expect three device-tree files in the output, one after the other.
1648 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1649 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1650 # main U-Boot tree. All three should have the same postions and offset.
1652 for item in ['', 'spl', 'tpl']:
1653 dtb = fdt.Fdt.FromData(data[start:])
1655 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1657 expected = dict(base_expected)
1660 self.assertEqual(expected, props)
1661 start += dtb._fdt_obj.totalsize()
1663 def testUpdateFdtOutput(self):
1664 """Test that output DTB files are updated"""
1666 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1667 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1669 # Unfortunately, compiling a source file always results in a file
1670 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1671 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1672 # binman as a file called u-boot.dtb. To fix this, copy the file
1673 # over to the expected place.
1675 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1676 'tpl/u-boot-tpl.dtb.out']:
1677 dtb = fdt.Fdt.FromData(data[start:])
1678 size = dtb._fdt_obj.totalsize()
1679 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1680 outdata = tools.ReadFile(pathname)
1681 name = os.path.split(fname)[0]
1684 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1686 orig_indata = dtb_data
1687 self.assertNotEqual(outdata, orig_indata,
1688 "Expected output file '%s' be updated" % pathname)
1689 self.assertEqual(outdata, data[start:start + size],
1690 "Expected output file '%s' to match output image" %
1696 def _decompress(self, data):
1697 return tools.Decompress(data, 'lz4')
1699 def testCompress(self):
1700 """Test compression of blobs"""
1702 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1703 use_real_dtb=True, update_dtb=True)
1704 dtb = fdt.Fdt(out_dtb_fname)
1706 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1707 orig = self._decompress(data)
1708 self.assertEquals(COMPRESS_DATA, orig)
1710 'blob:uncomp-size': len(COMPRESS_DATA),
1711 'blob:size': len(data),
1714 self.assertEqual(expected, props)
1716 def testFiles(self):
1717 """Test bringing in multiple files"""
1718 data = self._DoReadFile('084_files.dts')
1719 self.assertEqual(FILES_DATA, data)
1721 def testFilesCompress(self):
1722 """Test bringing in multiple files and compressing them"""
1724 data = self._DoReadFile('085_files_compress.dts')
1726 image = control.images['image']
1727 entries = image.GetEntries()
1728 files = entries['files']
1729 entries = files._entries
1732 for i in range(1, 3):
1734 start = entries[key].image_pos
1735 len = entries[key].size
1736 chunk = data[start:start + len]
1737 orig += self._decompress(chunk)
1739 self.assertEqual(FILES_DATA, orig)
1741 def testFilesMissing(self):
1742 """Test missing files"""
1743 with self.assertRaises(ValueError) as e:
1744 data = self._DoReadFile('086_files_none.dts')
1745 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1746 'no files', str(e.exception))
1748 def testFilesNoPattern(self):
1749 """Test missing files"""
1750 with self.assertRaises(ValueError) as e:
1751 data = self._DoReadFile('087_files_no_pattern.dts')
1752 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1755 def testExpandSize(self):
1756 """Test an expanding entry"""
1757 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1759 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1760 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1761 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1762 tools.GetBytes(ord('d'), 8))
1763 self.assertEqual(expect, data)
1764 self.assertEqual('''ImagePos Offset Size Name
1765 00000000 00000000 00000028 main-section
1766 00000000 00000000 00000008 fill
1767 00000008 00000008 00000004 u-boot
1768 0000000c 0000000c 00000004 section
1769 0000000c 00000000 00000003 intel-mrc
1770 00000010 00000010 00000004 u-boot2
1771 00000014 00000014 0000000c section2
1772 00000014 00000000 00000008 fill
1773 0000001c 00000008 00000004 u-boot
1774 00000020 00000020 00000008 fill2
1777 def testExpandSizeBad(self):
1778 """Test an expanding entry which fails to provide contents"""
1779 with test_util.capture_sys_output() as (stdout, stderr):
1780 with self.assertRaises(ValueError) as e:
1781 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1782 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1783 'expanding entry', str(e.exception))
1786 """Test hashing of the contents of an entry"""
1787 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1788 use_real_dtb=True, update_dtb=True)
1789 dtb = fdt.Fdt(out_dtb_fname)
1791 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1792 m = hashlib.sha256()
1793 m.update(U_BOOT_DATA)
1794 self.assertEqual(m.digest(), b''.join(hash_node.value))
1796 def testHashNoAlgo(self):
1797 with self.assertRaises(ValueError) as e:
1798 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1799 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1800 'hash node', str(e.exception))
1802 def testHashBadAlgo(self):
1803 with self.assertRaises(ValueError) as e:
1804 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1805 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1808 def testHashSection(self):
1809 """Test hashing of the contents of an entry"""
1810 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1811 use_real_dtb=True, update_dtb=True)
1812 dtb = fdt.Fdt(out_dtb_fname)
1814 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1815 m = hashlib.sha256()
1816 m.update(U_BOOT_DATA)
1817 m.update(tools.GetBytes(ord('a'), 16))
1818 self.assertEqual(m.digest(), b''.join(hash_node.value))
1820 def testPackUBootTplMicrocode(self):
1821 """Test that x86 microcode can be handled correctly in TPL
1823 We expect to see the following in the image, in order:
1824 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1826 u-boot-tpl.dtb with the microcode removed
1829 self._SetupTplElf('u_boot_ucode_ptr')
1830 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1831 U_BOOT_TPL_NODTB_DATA)
1832 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1833 b'ter somewhere in here', first)
1835 def testFmapX86(self):
1836 """Basic test of generation of a flashrom fmap"""
1837 data = self._DoReadFile('094_fmap_x86.dts')
1838 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1839 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1840 self.assertEqual(expected, data[:32])
1841 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1843 self.assertEqual(0x100, fhdr.image_size)
1845 self.assertEqual(0, fentries[0].offset)
1846 self.assertEqual(4, fentries[0].size)
1847 self.assertEqual(b'U_BOOT', fentries[0].name)
1849 self.assertEqual(4, fentries[1].offset)
1850 self.assertEqual(3, fentries[1].size)
1851 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1853 self.assertEqual(32, fentries[2].offset)
1854 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1855 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1856 self.assertEqual(b'FMAP', fentries[2].name)
1858 def testFmapX86Section(self):
1859 """Basic test of generation of a flashrom fmap"""
1860 data = self._DoReadFile('095_fmap_x86_section.dts')
1861 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1862 self.assertEqual(expected, data[:32])
1863 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1865 self.assertEqual(0x100, fhdr.image_size)
1867 self.assertEqual(0, fentries[0].offset)
1868 self.assertEqual(4, fentries[0].size)
1869 self.assertEqual(b'U_BOOT', fentries[0].name)
1871 self.assertEqual(4, fentries[1].offset)
1872 self.assertEqual(3, fentries[1].size)
1873 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1875 self.assertEqual(36, fentries[2].offset)
1876 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1877 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1878 self.assertEqual(b'FMAP', fentries[2].name)
1881 """Basic test of ELF entries"""
1884 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1885 TestFunctional._MakeInputFile('-boot', fd.read())
1886 data = self._DoReadFile('096_elf.dts')
1888 def testElfStrip(self):
1889 """Basic test of ELF entries"""
1891 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1892 TestFunctional._MakeInputFile('-boot', fd.read())
1893 data = self._DoReadFile('097_elf_strip.dts')
1895 def testPackOverlapMap(self):
1896 """Test that overlapping regions are detected"""
1897 with test_util.capture_sys_output() as (stdout, stderr):
1898 with self.assertRaises(ValueError) as e:
1899 self._DoTestFile('014_pack_overlap.dts', map=True)
1900 map_fname = tools.GetOutputFilename('image.map')
1901 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1904 # We should not get an inmage, but there should be a map file
1905 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1906 self.assertTrue(os.path.exists(map_fname))
1907 map_data = tools.ReadFile(map_fname, binary=False)
1908 self.assertEqual('''ImagePos Offset Size Name
1909 <none> 00000000 00000007 main-section
1910 <none> 00000000 00000004 u-boot
1911 <none> 00000003 00000004 u-boot-align
1914 def testPackRefCode(self):
1915 """Test that an image with an Intel Reference code binary works"""
1916 data = self._DoReadFile('100_intel_refcode.dts')
1917 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1919 def testSectionOffset(self):
1920 """Tests use of a section with an offset"""
1921 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1923 self.assertEqual('''ImagePos Offset Size Name
1924 00000000 00000000 00000038 main-section
1925 00000004 00000004 00000010 section@0
1926 00000004 00000000 00000004 u-boot
1927 00000018 00000018 00000010 section@1
1928 00000018 00000000 00000004 u-boot
1929 0000002c 0000002c 00000004 section@2
1930 0000002c 00000000 00000004 u-boot
1932 self.assertEqual(data,
1933 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1934 tools.GetBytes(0x21, 12) +
1935 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1936 tools.GetBytes(0x61, 12) +
1937 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1938 tools.GetBytes(0x26, 8))
1940 def testCbfsRaw(self):
1941 """Test base handling of a Coreboot Filesystem (CBFS)
1943 The exact contents of the CBFS is verified by similar tests in
1944 cbfs_util_test.py. The tests here merely check that the files added to
1945 the CBFS can be found in the final image.
1947 data = self._DoReadFile('102_cbfs_raw.dts')
1950 cbfs = cbfs_util.CbfsReader(data)
1951 self.assertEqual(size, cbfs.rom_size)
1953 self.assertIn('u-boot-dtb', cbfs.files)
1954 cfile = cbfs.files['u-boot-dtb']
1955 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1957 def testCbfsArch(self):
1958 """Test on non-x86 architecture"""
1959 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1962 cbfs = cbfs_util.CbfsReader(data)
1963 self.assertEqual(size, cbfs.rom_size)
1965 self.assertIn('u-boot-dtb', cbfs.files)
1966 cfile = cbfs.files['u-boot-dtb']
1967 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1969 def testCbfsStage(self):
1970 """Tests handling of a Coreboot Filesystem (CBFS)"""
1971 if not elf.ELF_TOOLS:
1972 self.skipTest('Python elftools not available')
1973 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1974 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1977 data = self._DoReadFile('104_cbfs_stage.dts')
1978 cbfs = cbfs_util.CbfsReader(data)
1979 self.assertEqual(size, cbfs.rom_size)
1981 self.assertIn('u-boot', cbfs.files)
1982 cfile = cbfs.files['u-boot']
1983 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1985 def testCbfsRawCompress(self):
1986 """Test handling of compressing raw files"""
1988 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1991 cbfs = cbfs_util.CbfsReader(data)
1992 self.assertIn('u-boot', cbfs.files)
1993 cfile = cbfs.files['u-boot']
1994 self.assertEqual(COMPRESS_DATA, cfile.data)
1996 def testCbfsBadArch(self):
1997 """Test handling of a bad architecture"""
1998 with self.assertRaises(ValueError) as e:
1999 self._DoReadFile('106_cbfs_bad_arch.dts')
2000 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2002 def testCbfsNoSize(self):
2003 """Test handling of a missing size property"""
2004 with self.assertRaises(ValueError) as e:
2005 self._DoReadFile('107_cbfs_no_size.dts')
2006 self.assertIn('entry must have a size property', str(e.exception))
2008 def testCbfsNoCOntents(self):
2009 """Test handling of a CBFS entry which does not provide contentsy"""
2010 with self.assertRaises(ValueError) as e:
2011 self._DoReadFile('108_cbfs_no_contents.dts')
2012 self.assertIn('Could not complete processing of contents',
2015 def testCbfsBadCompress(self):
2016 """Test handling of a bad architecture"""
2017 with self.assertRaises(ValueError) as e:
2018 self._DoReadFile('109_cbfs_bad_compress.dts')
2019 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2022 def testCbfsNamedEntries(self):
2023 """Test handling of named entries"""
2024 data = self._DoReadFile('110_cbfs_name.dts')
2026 cbfs = cbfs_util.CbfsReader(data)
2027 self.assertIn('FRED', cbfs.files)
2028 cfile1 = cbfs.files['FRED']
2029 self.assertEqual(U_BOOT_DATA, cfile1.data)
2031 self.assertIn('hello', cbfs.files)
2032 cfile2 = cbfs.files['hello']
2033 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2035 def _SetupIfwi(self, fname):
2036 """Set up to run an IFWI test
2039 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2044 # Intel Integrated Firmware Image (IFWI) file
2045 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2047 TestFunctional._MakeInputFile(fname,data)
2049 def _CheckIfwi(self, data):
2050 """Check that an image with an IFWI contains the correct output
2053 data: Conents of output file
2055 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2056 if data[:0x1000] != expected_desc:
2057 self.fail('Expected descriptor binary at start of image')
2059 # We expect to find the TPL wil in subpart IBBP entry IBBL
2060 image_fname = tools.GetOutputFilename('image.bin')
2061 tpl_fname = tools.GetOutputFilename('tpl.out')
2062 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2063 subpart='IBBP', entry_name='IBBL')
2065 tpl_data = tools.ReadFile(tpl_fname)
2066 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2068 def testPackX86RomIfwi(self):
2069 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2070 self._SetupIfwi('fitimage.bin')
2071 data = self._DoReadFile('111_x86_rom_ifwi.dts')
2072 self._CheckIfwi(data)
2074 def testPackX86RomIfwiNoDesc(self):
2075 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2076 self._SetupIfwi('ifwi.bin')
2077 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
2078 self._CheckIfwi(data)
2080 def testPackX86RomIfwiNoData(self):
2081 """Test that an x86 ROM with IFWI handles missing data"""
2082 self._SetupIfwi('ifwi.bin')
2083 with self.assertRaises(ValueError) as e:
2084 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
2085 self.assertIn('Could not complete processing of contents',
2088 def testCbfsOffset(self):
2089 """Test a CBFS with files at particular offsets
2091 Like all CFBS tests, this is just checking the logic that calls
2092 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2094 data = self._DoReadFile('114_cbfs_offset.dts')
2097 cbfs = cbfs_util.CbfsReader(data)
2098 self.assertEqual(size, cbfs.rom_size)
2100 self.assertIn('u-boot', cbfs.files)
2101 cfile = cbfs.files['u-boot']
2102 self.assertEqual(U_BOOT_DATA, cfile.data)
2103 self.assertEqual(0x40, cfile.cbfs_offset)
2105 self.assertIn('u-boot-dtb', cbfs.files)
2106 cfile2 = cbfs.files['u-boot-dtb']
2107 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2108 self.assertEqual(0x140, cfile2.cbfs_offset)
2110 def testFdtmap(self):
2111 """Test an FDT map can be inserted in the image"""
2112 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2113 fdtmap_data = data[len(U_BOOT_DATA):]
2114 magic = fdtmap_data[:8]
2115 self.assertEqual(b'_FDTMAP_', magic)
2116 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2118 fdt_data = fdtmap_data[16:]
2119 dtb = fdt.Fdt.FromData(fdt_data)
2121 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2126 'u-boot:size': len(U_BOOT_DATA),
2127 'u-boot:image-pos': 0,
2128 'fdtmap:image-pos': 4,
2130 'fdtmap:size': len(fdtmap_data),
2134 def testFdtmapNoMatch(self):
2135 """Check handling of an FDT map when the section cannot be found"""
2136 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2138 # Mangle the section name, which should cause a mismatch between the
2139 # correct FDT path and the one expected by the section
2140 image = control.images['image']
2141 image._node.path += '-suffix'
2142 entries = image.GetEntries()
2143 fdtmap = entries['fdtmap']
2144 with self.assertRaises(ValueError) as e:
2146 self.assertIn("Cannot locate node for path '/binman-suffix'",
2149 def testFdtmapHeader(self):
2150 """Test an FDT map and image header can be inserted in the image"""
2151 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2152 fdtmap_pos = len(U_BOOT_DATA)
2153 fdtmap_data = data[fdtmap_pos:]
2154 fdt_data = fdtmap_data[16:]
2155 dtb = fdt.Fdt.FromData(fdt_data)
2156 fdt_size = dtb.GetFdtObj().totalsize()
2157 hdr_data = data[-8:]
2158 self.assertEqual(b'BinM', hdr_data[:4])
2159 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2160 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2162 def testFdtmapHeaderStart(self):
2163 """Test an image header can be inserted at the image start"""
2164 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2165 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2167 self.assertEqual(b'BinM', hdr_data[:4])
2168 offset = struct.unpack('<I', hdr_data[4:])[0]
2169 self.assertEqual(fdtmap_pos, offset)
2171 def testFdtmapHeaderPos(self):
2172 """Test an image header can be inserted at a chosen position"""
2173 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2174 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2175 hdr_data = data[0x80:0x88]
2176 self.assertEqual(b'BinM', hdr_data[:4])
2177 offset = struct.unpack('<I', hdr_data[4:])[0]
2178 self.assertEqual(fdtmap_pos, offset)
2180 def testHeaderMissingFdtmap(self):
2181 """Test an image header requires an fdtmap"""
2182 with self.assertRaises(ValueError) as e:
2183 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2184 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2187 def testHeaderNoLocation(self):
2188 """Test an image header with a no specified location is detected"""
2189 with self.assertRaises(ValueError) as e:
2190 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2191 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2194 def testEntryExpand(self):
2195 """Test expanding an entry after it is packed"""
2196 data = self._DoReadFile('121_entry_expand.dts')
2197 self.assertEqual(b'aaa', data[:3])
2198 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2199 self.assertEqual(b'aaa', data[-3:])
2201 def testEntryExpandBad(self):
2202 """Test expanding an entry after it is packed, twice"""
2203 with self.assertRaises(ValueError) as e:
2204 self._DoReadFile('122_entry_expand_twice.dts')
2205 self.assertIn("Image '/binman': Entries changed size after packing",
2208 def testEntryExpandSection(self):
2209 """Test expanding an entry within a section after it is packed"""
2210 data = self._DoReadFile('123_entry_expand_section.dts')
2211 self.assertEqual(b'aaa', data[:3])
2212 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2213 self.assertEqual(b'aaa', data[-3:])
2215 def testCompressDtb(self):
2216 """Test that compress of device-tree files is supported"""
2218 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2219 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2220 comp_data = data[len(U_BOOT_DATA):]
2221 orig = self._decompress(comp_data)
2222 dtb = fdt.Fdt.FromData(orig)
2224 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2226 'u-boot:size': len(U_BOOT_DATA),
2227 'u-boot-dtb:uncomp-size': len(orig),
2228 'u-boot-dtb:size': len(comp_data),
2231 self.assertEqual(expected, props)
2233 def testCbfsUpdateFdt(self):
2234 """Test that we can update the device tree with CBFS offset/size info"""
2236 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2238 dtb = fdt.Fdt(out_dtb_fname)
2240 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2241 del props['cbfs/u-boot:size']
2247 'cbfs:size': len(data),
2248 'cbfs:image-pos': 0,
2249 'cbfs/u-boot:offset': 0x38,
2250 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2251 'cbfs/u-boot:image-pos': 0x38,
2252 'cbfs/u-boot-dtb:offset': 0xb8,
2253 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2254 'cbfs/u-boot-dtb:image-pos': 0xb8,
2257 def testCbfsBadType(self):
2258 """Test an image header with a no specified location is detected"""
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFile('126_cbfs_bad_type.dts')
2261 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2264 """Test listing the files in an image"""
2266 data = self._DoReadFile('127_list.dts')
2267 image = control.images['image']
2268 entries = image.BuildEntryList()
2269 self.assertEqual(7, len(entries))
2272 self.assertEqual(0, ent.indent)
2273 self.assertEqual('main-section', ent.name)
2274 self.assertEqual('section', ent.etype)
2275 self.assertEqual(len(data), ent.size)
2276 self.assertEqual(0, ent.image_pos)
2277 self.assertEqual(None, ent.uncomp_size)
2278 self.assertEqual(0, ent.offset)
2281 self.assertEqual(1, ent.indent)
2282 self.assertEqual('u-boot', ent.name)
2283 self.assertEqual('u-boot', ent.etype)
2284 self.assertEqual(len(U_BOOT_DATA), ent.size)
2285 self.assertEqual(0, ent.image_pos)
2286 self.assertEqual(None, ent.uncomp_size)
2287 self.assertEqual(0, ent.offset)
2290 self.assertEqual(1, ent.indent)
2291 self.assertEqual('section', ent.name)
2292 self.assertEqual('section', ent.etype)
2293 section_size = ent.size
2294 self.assertEqual(0x100, ent.image_pos)
2295 self.assertEqual(None, ent.uncomp_size)
2296 self.assertEqual(0x100, ent.offset)
2299 self.assertEqual(2, ent.indent)
2300 self.assertEqual('cbfs', ent.name)
2301 self.assertEqual('cbfs', ent.etype)
2302 self.assertEqual(0x400, ent.size)
2303 self.assertEqual(0x100, ent.image_pos)
2304 self.assertEqual(None, ent.uncomp_size)
2305 self.assertEqual(0, ent.offset)
2308 self.assertEqual(3, ent.indent)
2309 self.assertEqual('u-boot', ent.name)
2310 self.assertEqual('u-boot', ent.etype)
2311 self.assertEqual(len(U_BOOT_DATA), ent.size)
2312 self.assertEqual(0x138, ent.image_pos)
2313 self.assertEqual(None, ent.uncomp_size)
2314 self.assertEqual(0x38, ent.offset)
2317 self.assertEqual(3, ent.indent)
2318 self.assertEqual('u-boot-dtb', ent.name)
2319 self.assertEqual('text', ent.etype)
2320 self.assertGreater(len(COMPRESS_DATA), ent.size)
2321 self.assertEqual(0x178, ent.image_pos)
2322 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2323 self.assertEqual(0x78, ent.offset)
2326 self.assertEqual(2, ent.indent)
2327 self.assertEqual('u-boot-dtb', ent.name)
2328 self.assertEqual('u-boot-dtb', ent.etype)
2329 self.assertEqual(0x500, ent.image_pos)
2330 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2332 # Compressing this data expands it since headers are added
2333 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2334 self.assertEqual(0x400, ent.offset)
2336 self.assertEqual(len(data), 0x100 + section_size)
2337 self.assertEqual(section_size, 0x400 + dtb_size)
2339 def testFindFdtmap(self):
2340 """Test locating an FDT map in an image"""
2342 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2343 image = control.images['image']
2344 entries = image.GetEntries()
2345 entry = entries['fdtmap']
2346 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2348 def testFindFdtmapMissing(self):
2349 """Test failing to locate an FDP map"""
2350 data = self._DoReadFile('005_simple.dts')
2351 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2353 def testFindImageHeader(self):
2354 """Test locating a image header"""
2356 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2357 image = control.images['image']
2358 entries = image.GetEntries()
2359 entry = entries['fdtmap']
2360 # The header should point to the FDT map
2361 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2363 def testFindImageHeaderStart(self):
2364 """Test locating a image header located at the start of an image"""
2365 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2366 image = control.images['image']
2367 entries = image.GetEntries()
2368 entry = entries['fdtmap']
2369 # The header should point to the FDT map
2370 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2372 def testFindImageHeaderMissing(self):
2373 """Test failing to locate an image header"""
2374 data = self._DoReadFile('005_simple.dts')
2375 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2377 def testReadImage(self):
2378 """Test reading an image and accessing its FDT map"""
2380 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2381 image_fname = tools.GetOutputFilename('image.bin')
2382 orig_image = control.images['image']
2383 image = Image.FromFile(image_fname)
2384 self.assertEqual(orig_image.GetEntries().keys(),
2385 image.GetEntries().keys())
2387 orig_entry = orig_image.GetEntries()['fdtmap']
2388 entry = image.GetEntries()['fdtmap']
2389 self.assertEquals(orig_entry.offset, entry.offset)
2390 self.assertEquals(orig_entry.size, entry.size)
2391 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2393 def testReadImageNoHeader(self):
2394 """Test accessing an image's FDT map without an image header"""
2396 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2397 image_fname = tools.GetOutputFilename('image.bin')
2398 image = Image.FromFile(image_fname)
2399 self.assertTrue(isinstance(image, Image))
2400 self.assertEqual('image', image.image_name[-5:])
2402 def testReadImageFail(self):
2403 """Test failing to read an image image's FDT map"""
2404 self._DoReadFile('005_simple.dts')
2405 image_fname = tools.GetOutputFilename('image.bin')
2406 with self.assertRaises(ValueError) as e:
2407 image = Image.FromFile(image_fname)
2408 self.assertIn("Cannot find FDT map in image", str(e.exception))
2410 def testListCmd(self):
2411 """Test listing the files in an image using an Fdtmap"""
2413 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2415 # lz4 compression size differs depending on the version
2416 image = control.images['image']
2417 entries = image.GetEntries()
2418 section_size = entries['section'].size
2419 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2420 fdtmap_offset = entries['fdtmap'].offset
2423 tmpdir, updated_fname = self._SetupImageInTmpdir()
2424 with test_util.capture_sys_output() as (stdout, stderr):
2425 self._DoBinman('ls', '-i', updated_fname)
2427 shutil.rmtree(tmpdir)
2428 lines = stdout.getvalue().splitlines()
2430 'Name Image-pos Size Entry-type Offset Uncomp-size',
2431 '----------------------------------------------------------------------',
2432 'main-section 0 c00 section 0',
2433 ' u-boot 0 4 u-boot 0',
2434 ' section 100 %x section 100' % section_size,
2435 ' cbfs 100 400 cbfs 0',
2436 ' u-boot 138 4 u-boot 38',
2437 ' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
2438 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2439 ' fdtmap %x 3bd fdtmap %x' %
2440 (fdtmap_offset, fdtmap_offset),
2441 ' image-header bf8 8 image-header bf8',
2443 self.assertEqual(expected, lines)
2445 def testListCmdFail(self):
2446 """Test failing to list an image"""
2447 self._DoReadFile('005_simple.dts')
2449 tmpdir, updated_fname = self._SetupImageInTmpdir()
2450 with self.assertRaises(ValueError) as e:
2451 self._DoBinman('ls', '-i', updated_fname)
2453 shutil.rmtree(tmpdir)
2454 self.assertIn("Cannot find FDT map in image", str(e.exception))
2456 def _RunListCmd(self, paths, expected):
2457 """List out entries and check the result
2460 paths: List of paths to pass to the list command
2461 expected: Expected list of filenames to be returned, in order
2464 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2465 image_fname = tools.GetOutputFilename('image.bin')
2466 image = Image.FromFile(image_fname)
2467 lines = image.GetListEntries(paths)[1]
2468 files = [line[0].strip() for line in lines[1:]]
2469 self.assertEqual(expected, files)
2471 def testListCmdSection(self):
2472 """Test listing the files in a section"""
2473 self._RunListCmd(['section'],
2474 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2476 def testListCmdFile(self):
2477 """Test listing a particular file"""
2478 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2480 def testListCmdWildcard(self):
2481 """Test listing a wildcarded file"""
2482 self._RunListCmd(['*boot*'],
2483 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2485 def testListCmdWildcardMulti(self):
2486 """Test listing a wildcarded file"""
2487 self._RunListCmd(['*cb*', '*head*'],
2488 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2490 def testListCmdEmpty(self):
2491 """Test listing a wildcarded file"""
2492 self._RunListCmd(['nothing'], [])
2494 def testListCmdPath(self):
2495 """Test listing the files in a sub-entry of a section"""
2496 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2498 def _RunExtractCmd(self, entry_name, decomp=True):
2499 """Extract an entry from an image
2502 entry_name: Entry name to extract
2503 decomp: True to decompress the data if compressed, False to leave
2504 it in its raw uncompressed format
2510 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2511 image_fname = tools.GetOutputFilename('image.bin')
2512 return control.ReadEntry(image_fname, entry_name, decomp)
2514 def testExtractSimple(self):
2515 """Test extracting a single file"""
2516 data = self._RunExtractCmd('u-boot')
2517 self.assertEqual(U_BOOT_DATA, data)
2519 def testExtractSection(self):
2520 """Test extracting the files in a section"""
2521 data = self._RunExtractCmd('section')
2522 cbfs_data = data[:0x400]
2523 cbfs = cbfs_util.CbfsReader(cbfs_data)
2524 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
2525 dtb_data = data[0x400:]
2526 dtb = self._decompress(dtb_data)
2527 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2529 def testExtractCompressed(self):
2530 """Test extracting compressed data"""
2531 data = self._RunExtractCmd('section/u-boot-dtb')
2532 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2534 def testExtractRaw(self):
2535 """Test extracting compressed data without decompressing it"""
2536 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2537 dtb = self._decompress(data)
2538 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2540 def testExtractCbfs(self):
2541 """Test extracting CBFS data"""
2542 data = self._RunExtractCmd('section/cbfs/u-boot')
2543 self.assertEqual(U_BOOT_DATA, data)
2545 def testExtractCbfsCompressed(self):
2546 """Test extracting CBFS compressed data"""
2547 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2548 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2550 def testExtractCbfsRaw(self):
2551 """Test extracting CBFS compressed data without decompressing it"""
2552 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2553 dtb = tools.Decompress(data, 'lzma', with_header=False)
2554 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2556 def testExtractBadEntry(self):
2557 """Test extracting a bad section path"""
2558 with self.assertRaises(ValueError) as e:
2559 self._RunExtractCmd('section/does-not-exist')
2560 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2563 def testExtractMissingFile(self):
2564 """Test extracting file that does not exist"""
2565 with self.assertRaises(IOError) as e:
2566 control.ReadEntry('missing-file', 'name')
2568 def testExtractBadFile(self):
2569 """Test extracting an invalid file"""
2570 fname = os.path.join(self._indir, 'badfile')
2571 tools.WriteFile(fname, b'')
2572 with self.assertRaises(ValueError) as e:
2573 control.ReadEntry(fname, 'name')
2575 def testExtractCmd(self):
2576 """Test extracting a file fron an image on the command line"""
2578 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2579 fname = os.path.join(self._indir, 'output.extact')
2581 tmpdir, updated_fname = self._SetupImageInTmpdir()
2582 with test_util.capture_sys_output() as (stdout, stderr):
2583 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2586 shutil.rmtree(tmpdir)
2587 data = tools.ReadFile(fname)
2588 self.assertEqual(U_BOOT_DATA, data)
2590 def testExtractOneEntry(self):
2591 """Test extracting a single entry fron an image """
2593 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2594 image_fname = tools.GetOutputFilename('image.bin')
2595 fname = os.path.join(self._indir, 'output.extact')
2596 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2597 data = tools.ReadFile(fname)
2598 self.assertEqual(U_BOOT_DATA, data)
2600 def _CheckExtractOutput(self, decomp):
2601 """Helper to test file output with and without decompression
2604 decomp: True to decompress entry data, False to output it raw
2606 def _CheckPresent(entry_path, expect_data, expect_size=None):
2607 """Check and remove expected file
2609 This checks the data/size of a file and removes the file both from
2610 the outfiles set and from the output directory. Once all files are
2611 processed, both the set and directory should be empty.
2614 entry_path: Entry path
2615 expect_data: Data to expect in file, or None to skip check
2616 expect_size: Size of data to expect in file, or None to skip
2618 path = os.path.join(outdir, entry_path)
2619 data = tools.ReadFile(path)
2622 self.assertEqual(expect_data, data)
2624 self.assertEqual(expect_size, len(data))
2625 outfiles.remove(path)
2627 def _CheckDirPresent(name):
2628 """Remove expected directory
2630 This gives an error if the directory does not exist as expected
2633 name: Name of directory to remove
2635 path = os.path.join(outdir, name)
2638 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2639 image_fname = tools.GetOutputFilename('image.bin')
2640 outdir = os.path.join(self._indir, 'extract')
2641 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2643 # Create a set of all file that were output (should be 9)
2645 for root, dirs, files in os.walk(outdir):
2646 outfiles |= set([os.path.join(root, fname) for fname in files])
2647 self.assertEqual(9, len(outfiles))
2648 self.assertEqual(9, len(einfos))
2650 image = control.images['image']
2651 entries = image.GetEntries()
2653 # Check the 9 files in various ways
2654 section = entries['section']
2655 section_entries = section.GetEntries()
2656 cbfs_entries = section_entries['cbfs'].GetEntries()
2657 _CheckPresent('u-boot', U_BOOT_DATA)
2658 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2659 dtb_len = EXTRACT_DTB_SIZE
2661 dtb_len = cbfs_entries['u-boot-dtb'].size
2662 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2664 dtb_len = section_entries['u-boot-dtb'].size
2665 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2667 fdtmap = entries['fdtmap']
2668 _CheckPresent('fdtmap', fdtmap.data)
2669 hdr = entries['image-header']
2670 _CheckPresent('image-header', hdr.data)
2672 _CheckPresent('section/root', section.data)
2673 cbfs = section_entries['cbfs']
2674 _CheckPresent('section/cbfs/root', cbfs.data)
2675 data = tools.ReadFile(image_fname)
2676 _CheckPresent('root', data)
2678 # There should be no files left. Remove all the directories to check.
2679 # If there are any files/dirs remaining, one of these checks will fail.
2680 self.assertEqual(0, len(outfiles))
2681 _CheckDirPresent('section/cbfs')
2682 _CheckDirPresent('section')
2683 _CheckDirPresent('')
2684 self.assertFalse(os.path.exists(outdir))
2686 def testExtractAllEntries(self):
2687 """Test extracting all entries"""
2689 self._CheckExtractOutput(decomp=True)
2691 def testExtractAllEntriesRaw(self):
2692 """Test extracting all entries without decompressing them"""
2694 self._CheckExtractOutput(decomp=False)
2696 def testExtractSelectedEntries(self):
2697 """Test extracting some entries"""
2699 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2700 image_fname = tools.GetOutputFilename('image.bin')
2701 outdir = os.path.join(self._indir, 'extract')
2702 einfos = control.ExtractEntries(image_fname, None, outdir,
2705 # File output is tested by testExtractAllEntries(), so just check that
2706 # the expected entries are selected
2707 names = [einfo.name for einfo in einfos]
2708 self.assertEqual(names,
2709 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2711 def testExtractNoEntryPaths(self):
2712 """Test extracting some entries"""
2714 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2715 image_fname = tools.GetOutputFilename('image.bin')
2716 with self.assertRaises(ValueError) as e:
2717 control.ExtractEntries(image_fname, 'fname', None, [])
2718 self.assertIn('Must specify an entry path to write with -f',
2721 def testExtractTooManyEntryPaths(self):
2722 """Test extracting some entries"""
2724 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2725 image_fname = tools.GetOutputFilename('image.bin')
2726 with self.assertRaises(ValueError) as e:
2727 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2728 self.assertIn('Must specify exactly one entry path to write with -f',
2731 def testPackAlignSection(self):
2732 """Test that sections can have alignment"""
2733 self._DoReadFile('131_pack_align_section.dts')
2735 self.assertIn('image', control.images)
2736 image = control.images['image']
2737 entries = image.GetEntries()
2738 self.assertEqual(3, len(entries))
2741 self.assertIn('u-boot', entries)
2742 entry = entries['u-boot']
2743 self.assertEqual(0, entry.offset)
2744 self.assertEqual(0, entry.image_pos)
2745 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2746 self.assertEqual(len(U_BOOT_DATA), entry.size)
2749 self.assertIn('section0', entries)
2750 section0 = entries['section0']
2751 self.assertEqual(0x10, section0.offset)
2752 self.assertEqual(0x10, section0.image_pos)
2753 self.assertEqual(len(U_BOOT_DATA), section0.size)
2756 section_entries = section0.GetEntries()
2757 self.assertIn('u-boot', section_entries)
2758 entry = section_entries['u-boot']
2759 self.assertEqual(0, entry.offset)
2760 self.assertEqual(0x10, entry.image_pos)
2761 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2762 self.assertEqual(len(U_BOOT_DATA), entry.size)
2765 self.assertIn('section1', entries)
2766 section1 = entries['section1']
2767 self.assertEqual(0x14, section1.offset)
2768 self.assertEqual(0x14, section1.image_pos)
2769 self.assertEqual(0x20, section1.size)
2772 section_entries = section1.GetEntries()
2773 self.assertIn('u-boot', section_entries)
2774 entry = section_entries['u-boot']
2775 self.assertEqual(0, entry.offset)
2776 self.assertEqual(0x14, entry.image_pos)
2777 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2778 self.assertEqual(len(U_BOOT_DATA), entry.size)
2781 self.assertIn('section2', section_entries)
2782 section2 = section_entries['section2']
2783 self.assertEqual(0x4, section2.offset)
2784 self.assertEqual(0x18, section2.image_pos)
2785 self.assertEqual(4, section2.size)
2788 section_entries = section2.GetEntries()
2789 self.assertIn('u-boot', section_entries)
2790 entry = section_entries['u-boot']
2791 self.assertEqual(0, entry.offset)
2792 self.assertEqual(0x18, entry.image_pos)
2793 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2794 self.assertEqual(len(U_BOOT_DATA), entry.size)
2796 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2797 dts='132_replace.dts'):
2798 """Replace an entry in an image
2800 This writes the entry data to update it, then opens the updated file and
2801 returns the value that it now finds there.
2804 entry_name: Entry name to replace
2805 data: Data to replace it with
2806 decomp: True to compress the data if needed, False if data is
2807 already compressed so should be used as is
2808 allow_resize: True to allow entries to change size, False to raise
2814 data from fdtmap (excluding header)
2815 Image object that was modified
2817 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2820 self.assertIn('image', control.images)
2821 image = control.images['image']
2822 entries = image.GetEntries()
2823 orig_dtb_data = entries['u-boot-dtb'].data
2824 orig_fdtmap_data = entries['fdtmap'].data
2826 image_fname = tools.GetOutputFilename('image.bin')
2827 updated_fname = tools.GetOutputFilename('image-updated.bin')
2828 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2829 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2831 data = control.ReadEntry(updated_fname, entry_name, decomp)
2833 # The DT data should not change unless resized:
2834 if not allow_resize:
2835 new_dtb_data = entries['u-boot-dtb'].data
2836 self.assertEqual(new_dtb_data, orig_dtb_data)
2837 new_fdtmap_data = entries['fdtmap'].data
2838 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2840 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2842 def testReplaceSimple(self):
2843 """Test replacing a single file"""
2844 expected = b'x' * len(U_BOOT_DATA)
2845 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2847 self.assertEqual(expected, data)
2849 # Test that the state looks right. There should be an FDT for the fdtmap
2850 # that we jsut read back in, and it should match what we find in the
2851 # 'control' tables. Checking for an FDT that does not exist should
2853 path, fdtmap = state.GetFdtContents('fdtmap')
2854 self.assertIsNotNone(path)
2855 self.assertEqual(expected_fdtmap, fdtmap)
2857 dtb = state.GetFdtForEtype('fdtmap')
2858 self.assertEqual(dtb.GetContents(), fdtmap)
2860 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2861 self.assertIsNone(missing_path)
2862 self.assertIsNone(missing_fdtmap)
2864 missing_dtb = state.GetFdtForEtype('missing')
2865 self.assertIsNone(missing_dtb)
2867 self.assertEqual('/binman', state.fdt_path_prefix)
2869 def testReplaceResizeFail(self):
2870 """Test replacing a file by something larger"""
2871 expected = U_BOOT_DATA + b'x'
2872 with self.assertRaises(ValueError) as e:
2873 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2874 dts='139_replace_repack.dts')
2875 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2878 def testReplaceMulti(self):
2879 """Test replacing entry data where multiple images are generated"""
2880 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2882 expected = b'x' * len(U_BOOT_DATA)
2883 updated_fname = tools.GetOutputFilename('image-updated.bin')
2884 tools.WriteFile(updated_fname, data)
2885 entry_name = 'u-boot'
2886 control.WriteEntry(updated_fname, entry_name, expected,
2888 data = control.ReadEntry(updated_fname, entry_name)
2889 self.assertEqual(expected, data)
2891 # Check the state looks right.
2892 self.assertEqual('/binman/image', state.fdt_path_prefix)
2894 # Now check we can write the first image
2895 image_fname = tools.GetOutputFilename('first-image.bin')
2896 updated_fname = tools.GetOutputFilename('first-updated.bin')
2897 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2898 entry_name = 'u-boot'
2899 control.WriteEntry(updated_fname, entry_name, expected,
2901 data = control.ReadEntry(updated_fname, entry_name)
2902 self.assertEqual(expected, data)
2904 # Check the state looks right.
2905 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2907 def testUpdateFdtAllRepack(self):
2908 """Test that all device trees are updated with offset/size info"""
2909 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2910 SECTION_SIZE = 0x300
2915 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2917 'section:offset': 0,
2918 'section:size': SECTION_SIZE,
2919 'section:image-pos': 0,
2920 'section/u-boot-dtb:offset': 4,
2921 'section/u-boot-dtb:size': 636,
2922 'section/u-boot-dtb:image-pos': 4,
2923 'u-boot-spl-dtb:offset': SECTION_SIZE,
2924 'u-boot-spl-dtb:size': DTB_SIZE,
2925 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2926 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2927 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2928 'u-boot-tpl-dtb:size': DTB_SIZE,
2929 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2930 'fdtmap:size': FDTMAP_SIZE,
2931 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2934 'section:orig-size': SECTION_SIZE,
2935 'section/u-boot-dtb:orig-offset': 4,
2938 # We expect three device-tree files in the output, with the first one
2939 # within a fixed-size section.
2940 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2941 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2942 # main U-Boot tree. All three should have the same positions and offset
2943 # except that the main tree should include the main_expected properties
2945 for item in ['', 'spl', 'tpl', None]:
2947 start += 16 # Move past fdtmap header
2948 dtb = fdt.Fdt.FromData(data[start:])
2950 props = self._GetPropTree(dtb,
2951 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2952 prefix='/' if item is None else '/binman/')
2953 expected = dict(base_expected)
2957 # Main DTB and fdtdec should include the 'orig-' properties
2958 expected.update(main_expected)
2959 # Helpful for debugging:
2960 #for prop in sorted(props):
2961 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2962 self.assertEqual(expected, props)
2964 start = SECTION_SIZE
2966 start += dtb._fdt_obj.totalsize()
2968 def testFdtmapHeaderMiddle(self):
2969 """Test an FDT map in the middle of an image when it should be at end"""
2970 with self.assertRaises(ValueError) as e:
2971 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2972 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2975 def testFdtmapHeaderStartBad(self):
2976 """Test an FDT map in middle of an image when it should be at start"""
2977 with self.assertRaises(ValueError) as e:
2978 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2979 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2982 def testFdtmapHeaderEndBad(self):
2983 """Test an FDT map at the start of an image when it should be at end"""
2984 with self.assertRaises(ValueError) as e:
2985 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2986 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2989 def testFdtmapHeaderNoSize(self):
2990 """Test an image header at the end of an image with undefined size"""
2991 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2993 def testReplaceResize(self):
2994 """Test replacing a single file in an entry with a larger file"""
2995 expected = U_BOOT_DATA + b'x'
2996 data, _, image = self._RunReplaceCmd('u-boot', expected,
2997 dts='139_replace_repack.dts')
2998 self.assertEqual(expected, data)
3000 entries = image.GetEntries()
3001 dtb_data = entries['u-boot-dtb'].data
3002 dtb = fdt.Fdt.FromData(dtb_data)
3005 # The u-boot section should now be larger in the dtb
3006 node = dtb.GetNode('/binman/u-boot')
3007 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3009 # Same for the fdtmap
3010 fdata = entries['fdtmap'].data
3011 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3013 fnode = fdtb.GetNode('/u-boot')
3014 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3016 def testReplaceResizeNoRepack(self):
3017 """Test replacing an entry with a larger file when not allowed"""
3018 expected = U_BOOT_DATA + b'x'
3019 with self.assertRaises(ValueError) as e:
3020 self._RunReplaceCmd('u-boot', expected)
3021 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3024 def testEntryShrink(self):
3025 """Test contracting an entry after it is packed"""
3027 state.SetAllowEntryContraction(True)
3028 data = self._DoReadFileDtb('140_entry_shrink.dts',
3031 state.SetAllowEntryContraction(False)
3032 self.assertEqual(b'a', data[:1])
3033 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3034 self.assertEqual(b'a', data[-1:])
3036 def testEntryShrinkFail(self):
3037 """Test not being allowed to contract an entry after it is packed"""
3038 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3040 # In this case there is a spare byte at the end of the data. The size of
3041 # the contents is only 1 byte but we still have the size before it
3043 self.assertEqual(b'a\0', data[:2])
3044 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3045 self.assertEqual(b'a\0', data[-2:])
3047 def testDescriptorOffset(self):
3048 """Test that the Intel descriptor is always placed at at the start"""
3049 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3050 image = control.images['image']
3051 entries = image.GetEntries()
3052 desc = entries['intel-descriptor']
3053 self.assertEqual(0xff800000, desc.offset);
3054 self.assertEqual(0xff800000, desc.image_pos);
3056 def testReplaceCbfs(self):
3057 """Test replacing a single file in CBFS without changing the size"""
3059 expected = b'x' * len(U_BOOT_DATA)
3060 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3061 updated_fname = tools.GetOutputFilename('image-updated.bin')
3062 tools.WriteFile(updated_fname, data)
3063 entry_name = 'section/cbfs/u-boot'
3064 control.WriteEntry(updated_fname, entry_name, expected,
3066 data = control.ReadEntry(updated_fname, entry_name)
3067 self.assertEqual(expected, data)
3069 def testReplaceResizeCbfs(self):
3070 """Test replacing a single file in CBFS with one of a different size"""
3072 expected = U_BOOT_DATA + b'x'
3073 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3074 updated_fname = tools.GetOutputFilename('image-updated.bin')
3075 tools.WriteFile(updated_fname, data)
3076 entry_name = 'section/cbfs/u-boot'
3077 control.WriteEntry(updated_fname, entry_name, expected,
3079 data = control.ReadEntry(updated_fname, entry_name)
3080 self.assertEqual(expected, data)
3082 def _SetupForReplace(self):
3083 """Set up some files to use to replace entries
3085 This generates an image, copies it to a new file, extracts all the files
3086 in it and updates some of them
3092 Expected values for updated entries, each a string
3094 data = self._DoReadFileRealDtb('143_replace_all.dts')
3096 updated_fname = tools.GetOutputFilename('image-updated.bin')
3097 tools.WriteFile(updated_fname, data)
3099 outdir = os.path.join(self._indir, 'extract')
3100 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3102 expected1 = b'x' + U_BOOT_DATA + b'y'
3103 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3104 tools.WriteFile(u_boot_fname1, expected1)
3106 expected2 = b'a' + U_BOOT_DATA + b'b'
3107 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3108 tools.WriteFile(u_boot_fname2, expected2)
3110 expected_text = b'not the same text'
3111 text_fname = os.path.join(outdir, 'text')
3112 tools.WriteFile(text_fname, expected_text)
3114 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3115 dtb = fdt.FdtScan(dtb_fname)
3116 node = dtb.GetNode('/binman/text')
3117 node.AddString('my-property', 'the value')
3118 dtb.Sync(auto_resize=True)
3121 return updated_fname, outdir, expected1, expected2, expected_text
3123 def _CheckReplaceMultiple(self, entry_paths):
3124 """Handle replacing the contents of multiple entries
3127 entry_paths: List of entry paths to replace
3131 Dict of entries in the image:
3134 Expected values for updated entries, each a string
3136 updated_fname, outdir, expected1, expected2, expected_text = (
3137 self._SetupForReplace())
3138 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3140 image = Image.FromFile(updated_fname)
3142 return image.GetEntries(), expected1, expected2, expected_text
3144 def testReplaceAll(self):
3145 """Test replacing the contents of all entries"""
3146 entries, expected1, expected2, expected_text = (
3147 self._CheckReplaceMultiple([]))
3148 data = entries['u-boot'].data
3149 self.assertEqual(expected1, data)
3151 data = entries['u-boot2'].data
3152 self.assertEqual(expected2, data)
3154 data = entries['text'].data
3155 self.assertEqual(expected_text, data)
3157 # Check that the device tree is updated
3158 data = entries['u-boot-dtb'].data
3159 dtb = fdt.Fdt.FromData(data)
3161 node = dtb.GetNode('/binman/text')
3162 self.assertEqual('the value', node.props['my-property'].value)
3164 def testReplaceSome(self):
3165 """Test replacing the contents of a few entries"""
3166 entries, expected1, expected2, expected_text = (
3167 self._CheckReplaceMultiple(['u-boot2', 'text']))
3169 # This one should not change
3170 data = entries['u-boot'].data
3171 self.assertEqual(U_BOOT_DATA, data)
3173 data = entries['u-boot2'].data
3174 self.assertEqual(expected2, data)
3176 data = entries['text'].data
3177 self.assertEqual(expected_text, data)
3179 def testReplaceCmd(self):
3180 """Test replacing a file fron an image on the command line"""
3181 self._DoReadFileRealDtb('143_replace_all.dts')
3184 tmpdir, updated_fname = self._SetupImageInTmpdir()
3186 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3187 expected = b'x' * len(U_BOOT_DATA)
3188 tools.WriteFile(fname, expected)
3190 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3191 data = tools.ReadFile(updated_fname)
3192 self.assertEqual(expected, data[:len(expected)])
3193 map_fname = os.path.join(tmpdir, 'image-updated.map')
3194 self.assertFalse(os.path.exists(map_fname))
3196 shutil.rmtree(tmpdir)
3198 def testReplaceCmdSome(self):
3199 """Test replacing some files fron an image on the command line"""
3200 updated_fname, outdir, expected1, expected2, expected_text = (
3201 self._SetupForReplace())
3203 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3206 tools.PrepareOutputDir(None)
3207 image = Image.FromFile(updated_fname)
3209 entries = image.GetEntries()
3211 # This one should not change
3212 data = entries['u-boot'].data
3213 self.assertEqual(U_BOOT_DATA, data)
3215 data = entries['u-boot2'].data
3216 self.assertEqual(expected2, data)
3218 data = entries['text'].data
3219 self.assertEqual(expected_text, data)
3221 def testReplaceMissing(self):
3222 """Test replacing entries where the file is missing"""
3223 updated_fname, outdir, expected1, expected2, expected_text = (
3224 self._SetupForReplace())
3226 # Remove one of the files, to generate a warning
3227 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3228 os.remove(u_boot_fname1)
3230 with test_util.capture_sys_output() as (stdout, stderr):
3231 control.ReplaceEntries(updated_fname, None, outdir, [])
3232 self.assertIn("Skipping entry '/u-boot' from missing file",
3235 def testReplaceCmdMap(self):
3236 """Test replacing a file fron an image on the command line"""
3237 self._DoReadFileRealDtb('143_replace_all.dts')
3240 tmpdir, updated_fname = self._SetupImageInTmpdir()
3242 fname = os.path.join(self._indir, 'update-u-boot.bin')
3243 expected = b'x' * len(U_BOOT_DATA)
3244 tools.WriteFile(fname, expected)
3246 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3248 map_fname = os.path.join(tmpdir, 'image-updated.map')
3249 self.assertTrue(os.path.exists(map_fname))
3251 shutil.rmtree(tmpdir)
3253 def testReplaceNoEntryPaths(self):
3254 """Test replacing an entry without an entry path"""
3255 self._DoReadFileRealDtb('143_replace_all.dts')
3256 image_fname = tools.GetOutputFilename('image.bin')
3257 with self.assertRaises(ValueError) as e:
3258 control.ReplaceEntries(image_fname, 'fname', None, [])
3259 self.assertIn('Must specify an entry path to read with -f',
3262 def testReplaceTooManyEntryPaths(self):
3263 """Test extracting some entries"""
3264 self._DoReadFileRealDtb('143_replace_all.dts')
3265 image_fname = tools.GetOutputFilename('image.bin')
3266 with self.assertRaises(ValueError) as e:
3267 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3268 self.assertIn('Must specify exactly one entry path to write with -f',
3271 def testPackReset16(self):
3272 """Test that an image with an x86 reset16 region can be created"""
3273 data = self._DoReadFile('144_x86_reset16.dts')
3274 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3276 def testPackReset16Spl(self):
3277 """Test that an image with an x86 reset16-spl region can be created"""
3278 data = self._DoReadFile('145_x86_reset16_spl.dts')
3279 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3281 def testPackReset16Tpl(self):
3282 """Test that an image with an x86 reset16-tpl region can be created"""
3283 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3284 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3286 def testPackIntelFit(self):
3287 """Test that an image with an Intel FIT and pointer can be created"""
3288 data = self._DoReadFile('147_intel_fit.dts')
3289 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3291 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3292 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3294 image = control.images['image']
3295 entries = image.GetEntries()
3296 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3297 self.assertEqual(expected_ptr, ptr)
3299 def testPackIntelFitMissing(self):
3300 """Test detection of a FIT pointer with not FIT region"""
3301 with self.assertRaises(ValueError) as e:
3302 self._DoReadFile('148_intel_fit_missing.dts')
3303 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3306 def _CheckSymbolsTplSection(self, dts, expected_vals):
3307 data = self._DoReadFile(dts)
3308 sym_values = struct.pack('<LQLL', *expected_vals)
3309 upto1 = 4 + len(U_BOOT_SPL_DATA)
3310 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
3311 self.assertEqual(expected1, data[:upto1])
3313 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
3314 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
3315 self.assertEqual(expected2, data[upto1:upto2])
3317 upto3 = 0x34 + len(U_BOOT_DATA)
3318 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
3319 self.assertEqual(expected3, data[upto2:upto3])
3321 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
3322 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3324 def testSymbolsTplSection(self):
3325 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3326 self._SetupSplElf('u_boot_binman_syms')
3327 self._SetupTplElf('u_boot_binman_syms')
3328 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3329 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3331 def testSymbolsTplSectionX86(self):
3332 """Test binman can assign symbols in a section with end-at-4gb"""
3333 self._SetupSplElf('u_boot_binman_syms_x86')
3334 self._SetupTplElf('u_boot_binman_syms_x86')
3335 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3336 [0xffffff04, 0xffffff1c, 0xffffff34,
3339 def testPackX86RomIfwiSectiom(self):
3340 """Test that a section can be placed in an IFWI region"""
3341 self._SetupIfwi('fitimage.bin')
3342 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3343 self._CheckIfwi(data)
3345 def testPackFspM(self):
3346 """Test that an image with a FSP memory-init binary can be created"""
3347 data = self._DoReadFile('152_intel_fsp_m.dts')
3348 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3350 def testPackFspS(self):
3351 """Test that an image with a FSP silicon-init binary can be created"""
3352 data = self._DoReadFile('153_intel_fsp_s.dts')
3353 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
3355 def testPackFspT(self):
3356 """Test that an image with a FSP temp-ram-init binary can be created"""
3357 data = self._DoReadFile('154_intel_fsp_t.dts')
3358 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3361 if __name__ == "__main__":