1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # To run a single test, change to this directory, and:
7 # python -m unittest func_test.TestFunctional.testHelp
9 from __future__ import print_function
12 from optparse import OptionParser
28 from etype import fdtmap
29 from etype import image_header
34 from image import Image
39 # Contents of test files, corresponding to different entry types
41 U_BOOT_IMG_DATA = b'img'
42 U_BOOT_SPL_DATA = b'56780123456789abcde'
43 U_BOOT_TPL_DATA = b'tpl'
47 U_BOOT_DTB_DATA = b'udtb'
48 U_BOOT_SPL_DTB_DATA = b'spldtb'
49 U_BOOT_TPL_DTB_DATA = b'tpldtb'
50 X86_START16_DATA = b'start16'
51 X86_START16_SPL_DATA = b'start16spl'
52 X86_START16_TPL_DATA = b'start16tpl'
53 X86_RESET16_DATA = b'reset16'
54 X86_RESET16_SPL_DATA = b'reset16spl'
55 X86_RESET16_TPL_DATA = b'reset16tpl'
56 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
57 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
58 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
59 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
67 CROS_EC_RW_DATA = b'ecrw'
71 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
72 b"sorry you're alive\n")
73 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
74 REFCODE_DATA = b'refcode'
76 # The expected size for the device tree in some tests
77 EXTRACT_DTB_SIZE = 0x3c9
79 # Properties expected to be in the device tree when update_dtb is used
80 BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
82 # Extra properties expected to be in the device tree when allow-repack is used
83 REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
86 class TestFunctional(unittest.TestCase):
87 """Functional tests for binman
89 Most of these use a sample .dts file to build an image and then check
90 that it looks correct. The sample files are in the test/ subdirectory
93 For each entry type a very small test file is created using fixed
94 string contents. This makes it easy to test that things look right, and
97 In some cases a 'real' file must be used - these are also supplied in
105 # Handle the case where argv[0] is 'python'
106 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
107 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
109 # Create a temporary directory for input files
110 cls._indir = tempfile.mkdtemp(prefix='binmant.')
112 # Create some test files
113 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
114 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
115 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
116 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
117 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
118 TestFunctional._MakeInputFile('me.bin', ME_DATA)
119 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
122 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
124 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
125 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
126 X86_START16_SPL_DATA)
127 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
128 X86_START16_TPL_DATA)
130 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
132 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
133 X86_RESET16_SPL_DATA)
134 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
135 X86_RESET16_TPL_DATA)
137 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
138 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
139 U_BOOT_SPL_NODTB_DATA)
140 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
141 U_BOOT_TPL_NODTB_DATA)
142 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
143 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
144 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
145 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
146 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
147 TestFunctional._MakeInputDir('devkeys')
148 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
149 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
151 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
152 elf_test.BuildElfTestFiles(cls._elf_testdir)
154 # ELF file with a '_dt_ucode_base_size' symbol
155 TestFunctional._MakeInputFile('u-boot',
156 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
158 # Intel flash descriptor file
159 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
160 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
162 shutil.copytree(cls.TestFile('files'),
163 os.path.join(cls._indir, 'files'))
165 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
167 # Travis-CI may have an old lz4
170 tools.Run('lz4', '--no-frame-crc', '-c',
171 os.path.join(cls._indir, 'u-boot.bin'))
176 def tearDownClass(cls):
177 """Remove the temporary input directory and its contents"""
178 if cls.preserve_indir:
179 print('Preserving input dir: %s' % cls._indir)
182 shutil.rmtree(cls._indir)
186 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
187 toolpath=None, verbosity=None):
188 """Accept arguments controlling test execution
191 preserve_indir: Preserve the shared input directory used by all
193 preserve_outdir: Preserve the output directories used by tests. Each
194 test has its own, so this is normally only useful when running a
196 toolpath: ist of paths to use for tools
198 cls.preserve_indir = preserve_indir
199 cls.preserve_outdirs = preserve_outdirs
200 cls.toolpath = toolpath
201 cls.verbosity = verbosity
204 if not self.have_lz4:
205 self.skipTest('lz4 --no-frame-crc not available')
207 def _CleanupOutputDir(self):
208 """Remove the temporary output directory"""
209 if self.preserve_outdirs:
210 print('Preserving output dir: %s' % tools.outdir)
212 tools._FinaliseForTest()
215 # Enable this to turn on debugging output
216 # tout.Init(tout.DEBUG)
217 command.test_result = None
220 """Remove the temporary output directory"""
221 self._CleanupOutputDir()
223 def _SetupImageInTmpdir(self):
224 """Set up the output image in a new temporary directory
226 This is used when an image has been generated in the output directory,
227 but we want to run binman again. This will create a new output
228 directory and fail to delete the original one.
230 This creates a new temporary directory, copies the image to it (with a
231 new name) and removes the old output directory.
235 Temporary directory to use
238 image_fname = tools.GetOutputFilename('image.bin')
239 tmpdir = tempfile.mkdtemp(prefix='binman.')
240 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
241 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
242 self._CleanupOutputDir()
243 return tmpdir, updated_fname
247 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
248 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
249 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
251 def _RunBinman(self, *args, **kwargs):
252 """Run binman using the command line
255 Arguments to pass, as a list of strings
256 kwargs: Arguments to pass to Command.RunPipe()
258 result = command.RunPipe([[self._binman_pathname] + list(args)],
259 capture=True, capture_stderr=True, raise_on_error=False)
260 if result.return_code and kwargs.get('raise_on_error', True):
261 raise Exception("Error running '%s': %s" % (' '.join(args),
262 result.stdout + result.stderr))
265 def _DoBinman(self, *argv):
266 """Run binman using directly (in the same process)
269 Arguments to pass, as a list of strings
271 Return value (0 for success)
274 args = cmdline.ParseArgs(argv)
275 args.pager = 'binman-invalid-pager'
276 args.build_dir = self._indir
278 # For testing, you can force an increase in verbosity here
279 # args.verbosity = tout.DEBUG
280 return control.Binman(args)
282 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
283 entry_args=None, images=None, use_real_dtb=False,
285 """Run binman with a given test file
288 fname: Device-tree source filename to use (e.g. 005_simple.dts)
289 debug: True to enable debugging output
290 map: True to output map files for the images
291 update_dtb: Update the offset and size of each entry in the device
292 tree before packing it into the image
293 entry_args: Dict of entry args to supply to binman
295 value: value of that arg
296 images: List of image names to build
301 if verbosity is not None:
302 args.append('-v%d' % verbosity)
304 args.append('-v%d' % self.verbosity)
306 for path in self.toolpath:
307 args += ['--toolpath', path]
308 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
314 args.append('--fake-dtb')
316 for arg, value in entry_args.items():
317 args.append('-a%s=%s' % (arg, value))
320 args += ['-i', image]
321 return self._DoBinman(*args)
323 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
324 """Set up a new test device-tree file
326 The given file is compiled and set up as the device tree to be used
330 fname: Filename of .dts file to read
331 outfile: Output filename for compiled device-tree binary
334 Contents of device-tree binary
336 tmpdir = tempfile.mkdtemp(prefix='binmant.')
337 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
338 with open(dtb, 'rb') as fd:
340 TestFunctional._MakeInputFile(outfile, data)
341 shutil.rmtree(tmpdir)
344 def _GetDtbContentsForSplTpl(self, dtb_data, name):
345 """Create a version of the main DTB for SPL or SPL
347 For testing we don't actually have different versions of the DTB. With
348 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
349 we don't normally have any unwanted nodes.
351 We still want the DTBs for SPL and TPL to be different though, since
352 otherwise it is confusing to know which one we are looking at. So add
353 an 'spl' or 'tpl' property to the top-level node.
355 dtb = fdt.Fdt.FromData(dtb_data)
357 dtb.GetNode('/binman').AddZeroProp(name)
358 dtb.Sync(auto_resize=True)
360 return dtb.GetContents()
362 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
363 update_dtb=False, entry_args=None, reset_dtbs=True):
364 """Run binman and return the resulting image
366 This runs binman with a given test file and then reads the resulting
367 output file. It is a shortcut function since most tests need to do
370 Raises an assertion failure if binman returns a non-zero exit code.
373 fname: Device-tree source filename to use (e.g. 005_simple.dts)
374 use_real_dtb: True to use the test file as the contents of
375 the u-boot-dtb entry. Normally this is not needed and the
376 test contents (the U_BOOT_DTB_DATA string) can be used.
377 But in some test we need the real contents.
378 map: True to output map files for the images
379 update_dtb: Update the offset and size of each entry in the device
380 tree before packing it into the image
384 Resulting image contents
386 Map data showing contents of image (or None if none)
387 Output device tree binary filename ('u-boot.dtb' path)
390 # Use the compiled test file as the u-boot-dtb input
392 dtb_data = self._SetupDtb(fname)
394 # For testing purposes, make a copy of the DT for SPL and TPL. Add
395 # a node indicating which it is, so aid verification.
396 for name in ['spl', 'tpl']:
397 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
398 outfile = os.path.join(self._indir, dtb_fname)
399 TestFunctional._MakeInputFile(dtb_fname,
400 self._GetDtbContentsForSplTpl(dtb_data, name))
403 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
404 entry_args=entry_args, use_real_dtb=use_real_dtb)
405 self.assertEqual(0, retcode)
406 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
408 # Find the (only) image, read it and return its contents
409 image = control.images['image']
410 image_fname = tools.GetOutputFilename('image.bin')
411 self.assertTrue(os.path.exists(image_fname))
413 map_fname = tools.GetOutputFilename('image.map')
414 with open(map_fname) as fd:
418 with open(image_fname, 'rb') as fd:
419 return fd.read(), dtb_data, map_data, out_dtb_fname
421 # Put the test file back
422 if reset_dtbs and use_real_dtb:
425 def _DoReadFileRealDtb(self, fname):
426 """Run binman with a real .dtb file and return the resulting data
429 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
432 Resulting image contents
434 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
436 def _DoReadFile(self, fname, use_real_dtb=False):
437 """Helper function which discards the device-tree binary
440 fname: Device-tree source filename to use (e.g. 005_simple.dts)
441 use_real_dtb: True to use the test file as the contents of
442 the u-boot-dtb entry. Normally this is not needed and the
443 test contents (the U_BOOT_DTB_DATA string) can be used.
444 But in some test we need the real contents.
447 Resulting image contents
449 return self._DoReadFileDtb(fname, use_real_dtb)[0]
452 def _MakeInputFile(cls, fname, contents):
453 """Create a new test input file, creating directories as needed
456 fname: Filename to create
457 contents: File contents to write in to the file
459 Full pathname of file created
461 pathname = os.path.join(cls._indir, fname)
462 dirname = os.path.dirname(pathname)
463 if dirname and not os.path.exists(dirname):
465 with open(pathname, 'wb') as fd:
470 def _MakeInputDir(cls, dirname):
471 """Create a new test input directory, creating directories as needed
474 dirname: Directory name to create
477 Full pathname of directory created
479 pathname = os.path.join(cls._indir, dirname)
480 if not os.path.exists(pathname):
481 os.makedirs(pathname)
485 def _SetupSplElf(cls, src_fname='bss_data'):
486 """Set up an ELF file with a '_dt_ucode_base_size' symbol
489 Filename of ELF file to use as SPL
491 TestFunctional._MakeInputFile('spl/u-boot-spl',
492 tools.ReadFile(cls.ElfTestFile(src_fname)))
495 def TestFile(cls, fname):
496 return os.path.join(cls._binman_dir, 'test', fname)
499 def ElfTestFile(cls, fname):
500 return os.path.join(cls._elf_testdir, fname)
502 def AssertInList(self, grep_list, target):
503 """Assert that at least one of a list of things is in a target
506 grep_list: List of strings to check
507 target: Target string
509 for grep in grep_list:
512 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
514 def CheckNoGaps(self, entries):
515 """Check that all entries fit together without gaps
518 entries: List of entries to check
521 for entry in entries.values():
522 self.assertEqual(offset, entry.offset)
525 def GetFdtLen(self, dtb):
526 """Get the totalsize field from a device-tree binary
529 dtb: Device-tree binary contents
532 Total size of device-tree binary, from the header
534 return struct.unpack('>L', dtb[4:8])[0]
536 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
537 def AddNode(node, path):
539 path += '/' + node.name
540 for prop in node.props.values():
541 if prop.name in prop_names:
542 prop_path = path + ':' + prop.name
543 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
545 for subnode in node.subnodes:
546 AddNode(subnode, path)
549 AddNode(dtb.GetRoot(), '')
553 """Test a basic run with valid args"""
554 result = self._RunBinman('-h')
556 def testFullHelp(self):
557 """Test that the full help is displayed with -H"""
558 result = self._RunBinman('-H')
559 help_file = os.path.join(self._binman_dir, 'README')
560 # Remove possible extraneous strings
561 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
562 gothelp = result.stdout.replace(extra, '')
563 self.assertEqual(len(gothelp), os.path.getsize(help_file))
564 self.assertEqual(0, len(result.stderr))
565 self.assertEqual(0, result.return_code)
567 def testFullHelpInternal(self):
568 """Test that the full help is displayed with -H"""
570 command.test_result = command.CommandResult()
571 result = self._DoBinman('-H')
572 help_file = os.path.join(self._binman_dir, 'README')
574 command.test_result = None
577 """Test that the basic help is displayed with -h"""
578 result = self._RunBinman('-h')
579 self.assertTrue(len(result.stdout) > 200)
580 self.assertEqual(0, len(result.stderr))
581 self.assertEqual(0, result.return_code)
584 """Test that we can run it with a specific board"""
585 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
586 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
587 result = self._DoBinman('build', '-b', 'sandbox')
588 self.assertEqual(0, result)
590 def testNeedBoard(self):
591 """Test that we get an error when no board ius supplied"""
592 with self.assertRaises(ValueError) as e:
593 result = self._DoBinman('build')
594 self.assertIn("Must provide a board to process (use -b <board>)",
597 def testMissingDt(self):
598 """Test that an invalid device-tree file generates an error"""
599 with self.assertRaises(Exception) as e:
600 self._RunBinman('build', '-d', 'missing_file')
601 # We get one error from libfdt, and a different one from fdtget.
602 self.AssertInList(["Couldn't open blob from 'missing_file'",
603 'No such file or directory'], str(e.exception))
605 def testBrokenDt(self):
606 """Test that an invalid device-tree source file generates an error
608 Since this is a source file it should be compiled and the error
609 will come from the device-tree compiler (dtc).
611 with self.assertRaises(Exception) as e:
612 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
613 self.assertIn("FATAL ERROR: Unable to parse input tree",
616 def testMissingNode(self):
617 """Test that a device tree without a 'binman' node generates an error"""
618 with self.assertRaises(Exception) as e:
619 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
620 self.assertIn("does not have a 'binman' node", str(e.exception))
623 """Test that an empty binman node works OK (i.e. does nothing)"""
624 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
625 self.assertEqual(0, len(result.stderr))
626 self.assertEqual(0, result.return_code)
628 def testInvalidEntry(self):
629 """Test that an invalid entry is flagged"""
630 with self.assertRaises(Exception) as e:
631 result = self._RunBinman('build', '-d',
632 self.TestFile('004_invalid_entry.dts'))
633 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
634 "'/binman/not-a-valid-type'", str(e.exception))
636 def testSimple(self):
637 """Test a simple binman with a single file"""
638 data = self._DoReadFile('005_simple.dts')
639 self.assertEqual(U_BOOT_DATA, data)
641 def testSimpleDebug(self):
642 """Test a simple binman run with debugging enabled"""
643 self._DoTestFile('005_simple.dts', debug=True)
646 """Test that we can handle creating two images
648 This also tests image padding.
650 retcode = self._DoTestFile('006_dual_image.dts')
651 self.assertEqual(0, retcode)
653 image = control.images['image1']
654 self.assertEqual(len(U_BOOT_DATA), image.size)
655 fname = tools.GetOutputFilename('image1.bin')
656 self.assertTrue(os.path.exists(fname))
657 with open(fname, 'rb') as fd:
659 self.assertEqual(U_BOOT_DATA, data)
661 image = control.images['image2']
662 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
663 fname = tools.GetOutputFilename('image2.bin')
664 self.assertTrue(os.path.exists(fname))
665 with open(fname, 'rb') as fd:
667 self.assertEqual(U_BOOT_DATA, data[3:7])
668 self.assertEqual(tools.GetBytes(0, 3), data[:3])
669 self.assertEqual(tools.GetBytes(0, 5), data[7:])
671 def testBadAlign(self):
672 """Test that an invalid alignment value is detected"""
673 with self.assertRaises(ValueError) as e:
674 self._DoTestFile('007_bad_align.dts')
675 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
676 "of two", str(e.exception))
678 def testPackSimple(self):
679 """Test that packing works as expected"""
680 retcode = self._DoTestFile('008_pack.dts')
681 self.assertEqual(0, retcode)
682 self.assertIn('image', control.images)
683 image = control.images['image']
684 entries = image.GetEntries()
685 self.assertEqual(5, len(entries))
688 self.assertIn('u-boot', entries)
689 entry = entries['u-boot']
690 self.assertEqual(0, entry.offset)
691 self.assertEqual(len(U_BOOT_DATA), entry.size)
693 # Second u-boot, aligned to 16-byte boundary
694 self.assertIn('u-boot-align', entries)
695 entry = entries['u-boot-align']
696 self.assertEqual(16, entry.offset)
697 self.assertEqual(len(U_BOOT_DATA), entry.size)
699 # Third u-boot, size 23 bytes
700 self.assertIn('u-boot-size', entries)
701 entry = entries['u-boot-size']
702 self.assertEqual(20, entry.offset)
703 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
704 self.assertEqual(23, entry.size)
706 # Fourth u-boot, placed immediate after the above
707 self.assertIn('u-boot-next', entries)
708 entry = entries['u-boot-next']
709 self.assertEqual(43, entry.offset)
710 self.assertEqual(len(U_BOOT_DATA), entry.size)
712 # Fifth u-boot, placed at a fixed offset
713 self.assertIn('u-boot-fixed', entries)
714 entry = entries['u-boot-fixed']
715 self.assertEqual(61, entry.offset)
716 self.assertEqual(len(U_BOOT_DATA), entry.size)
718 self.assertEqual(65, image.size)
720 def testPackExtra(self):
721 """Test that extra packing feature works as expected"""
722 retcode = self._DoTestFile('009_pack_extra.dts')
724 self.assertEqual(0, retcode)
725 self.assertIn('image', control.images)
726 image = control.images['image']
727 entries = image.GetEntries()
728 self.assertEqual(5, len(entries))
730 # First u-boot with padding before and after
731 self.assertIn('u-boot', entries)
732 entry = entries['u-boot']
733 self.assertEqual(0, entry.offset)
734 self.assertEqual(3, entry.pad_before)
735 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
737 # Second u-boot has an aligned size, but it has no effect
738 self.assertIn('u-boot-align-size-nop', entries)
739 entry = entries['u-boot-align-size-nop']
740 self.assertEqual(12, entry.offset)
741 self.assertEqual(4, entry.size)
743 # Third u-boot has an aligned size too
744 self.assertIn('u-boot-align-size', entries)
745 entry = entries['u-boot-align-size']
746 self.assertEqual(16, entry.offset)
747 self.assertEqual(32, entry.size)
749 # Fourth u-boot has an aligned end
750 self.assertIn('u-boot-align-end', entries)
751 entry = entries['u-boot-align-end']
752 self.assertEqual(48, entry.offset)
753 self.assertEqual(16, entry.size)
755 # Fifth u-boot immediately afterwards
756 self.assertIn('u-boot-align-both', entries)
757 entry = entries['u-boot-align-both']
758 self.assertEqual(64, entry.offset)
759 self.assertEqual(64, entry.size)
761 self.CheckNoGaps(entries)
762 self.assertEqual(128, image.size)
764 def testPackAlignPowerOf2(self):
765 """Test that invalid entry alignment is detected"""
766 with self.assertRaises(ValueError) as e:
767 self._DoTestFile('010_pack_align_power2.dts')
768 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
769 "of two", str(e.exception))
771 def testPackAlignSizePowerOf2(self):
772 """Test that invalid entry size alignment is detected"""
773 with self.assertRaises(ValueError) as e:
774 self._DoTestFile('011_pack_align_size_power2.dts')
775 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
776 "power of two", str(e.exception))
778 def testPackInvalidAlign(self):
779 """Test detection of an offset that does not match its alignment"""
780 with self.assertRaises(ValueError) as e:
781 self._DoTestFile('012_pack_inv_align.dts')
782 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
783 "align 0x4 (4)", str(e.exception))
785 def testPackInvalidSizeAlign(self):
786 """Test that invalid entry size alignment is detected"""
787 with self.assertRaises(ValueError) as e:
788 self._DoTestFile('013_pack_inv_size_align.dts')
789 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
790 "align-size 0x4 (4)", str(e.exception))
792 def testPackOverlap(self):
793 """Test that overlapping regions are detected"""
794 with self.assertRaises(ValueError) as e:
795 self._DoTestFile('014_pack_overlap.dts')
796 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
797 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
800 def testPackEntryOverflow(self):
801 """Test that entries that overflow their size are detected"""
802 with self.assertRaises(ValueError) as e:
803 self._DoTestFile('015_pack_overflow.dts')
804 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
805 "but entry size is 0x3 (3)", str(e.exception))
807 def testPackImageOverflow(self):
808 """Test that entries which overflow the image size are detected"""
809 with self.assertRaises(ValueError) as e:
810 self._DoTestFile('016_pack_image_overflow.dts')
811 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
812 "size 0x3 (3)", str(e.exception))
814 def testPackImageSize(self):
815 """Test that the image size can be set"""
816 retcode = self._DoTestFile('017_pack_image_size.dts')
817 self.assertEqual(0, retcode)
818 self.assertIn('image', control.images)
819 image = control.images['image']
820 self.assertEqual(7, image.size)
822 def testPackImageSizeAlign(self):
823 """Test that image size alignemnt works as expected"""
824 retcode = self._DoTestFile('018_pack_image_align.dts')
825 self.assertEqual(0, retcode)
826 self.assertIn('image', control.images)
827 image = control.images['image']
828 self.assertEqual(16, image.size)
830 def testPackInvalidImageAlign(self):
831 """Test that invalid image alignment is detected"""
832 with self.assertRaises(ValueError) as e:
833 self._DoTestFile('019_pack_inv_image_align.dts')
834 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
835 "align-size 0x8 (8)", str(e.exception))
837 def testPackAlignPowerOf2(self):
838 """Test that invalid image alignment is detected"""
839 with self.assertRaises(ValueError) as e:
840 self._DoTestFile('020_pack_inv_image_align_power2.dts')
841 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
842 "two", str(e.exception))
844 def testImagePadByte(self):
845 """Test that the image pad byte can be specified"""
847 data = self._DoReadFile('021_image_pad.dts')
848 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
851 def testImageName(self):
852 """Test that image files can be named"""
853 retcode = self._DoTestFile('022_image_name.dts')
854 self.assertEqual(0, retcode)
855 image = control.images['image1']
856 fname = tools.GetOutputFilename('test-name')
857 self.assertTrue(os.path.exists(fname))
859 image = control.images['image2']
860 fname = tools.GetOutputFilename('test-name.xx')
861 self.assertTrue(os.path.exists(fname))
863 def testBlobFilename(self):
864 """Test that generic blobs can be provided by filename"""
865 data = self._DoReadFile('023_blob.dts')
866 self.assertEqual(BLOB_DATA, data)
868 def testPackSorted(self):
869 """Test that entries can be sorted"""
871 data = self._DoReadFile('024_sorted.dts')
872 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
873 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
875 def testPackZeroOffset(self):
876 """Test that an entry at offset 0 is not given a new offset"""
877 with self.assertRaises(ValueError) as e:
878 self._DoTestFile('025_pack_zero_size.dts')
879 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
880 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
883 def testPackUbootDtb(self):
884 """Test that a device tree can be added to U-Boot"""
885 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
886 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
888 def testPackX86RomNoSize(self):
889 """Test that the end-at-4gb property requires a size property"""
890 with self.assertRaises(ValueError) as e:
891 self._DoTestFile('027_pack_4gb_no_size.dts')
892 self.assertIn("Image '/binman': Section size must be provided when "
893 "using end-at-4gb", str(e.exception))
895 def test4gbAndSkipAtStartTogether(self):
896 """Test that the end-at-4gb and skip-at-size property can't be used
898 with self.assertRaises(ValueError) as e:
899 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
900 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
901 "'skip-at-start'", str(e.exception))
903 def testPackX86RomOutside(self):
904 """Test that the end-at-4gb property checks for offset boundaries"""
905 with self.assertRaises(ValueError) as e:
906 self._DoTestFile('028_pack_4gb_outside.dts')
907 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
908 "the section starting at 0xffffffe0 (4294967264)",
911 def testPackX86Rom(self):
912 """Test that a basic x86 ROM can be created"""
914 data = self._DoReadFile('029_x86-rom.dts')
915 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
916 tools.GetBytes(0, 2), data)
918 def testPackX86RomMeNoDesc(self):
919 """Test that an invalid Intel descriptor entry is detected"""
920 TestFunctional._MakeInputFile('descriptor.bin', b'')
921 with self.assertRaises(ValueError) as e:
922 self._DoTestFile('031_x86-rom-me.dts')
923 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
926 def testPackX86RomBadDesc(self):
927 """Test that the Intel requires a descriptor entry"""
928 with self.assertRaises(ValueError) as e:
929 self._DoTestFile('030_x86-rom-me-no-desc.dts')
930 self.assertIn("Node '/binman/intel-me': No offset set with "
931 "offset-unset: should another entry provide this correct "
932 "offset?", str(e.exception))
934 def testPackX86RomMe(self):
935 """Test that an x86 ROM with an ME region can be created"""
936 data = self._DoReadFile('031_x86-rom-me.dts')
937 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
938 if data[:0x1000] != expected_desc:
939 self.fail('Expected descriptor binary at start of image')
940 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
942 def testPackVga(self):
943 """Test that an image with a VGA binary can be created"""
944 data = self._DoReadFile('032_intel-vga.dts')
945 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
947 def testPackStart16(self):
948 """Test that an image with an x86 start16 region can be created"""
949 data = self._DoReadFile('033_x86-start16.dts')
950 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
952 def testPackPowerpcMpc85xxBootpgResetvec(self):
953 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
955 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
956 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
958 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
959 """Handle running a test for insertion of microcode
962 dts_fname: Name of test .dts file
963 nodtb_data: Data that we expect in the first section
964 ucode_second: True if the microsecond entry is second instead of
969 Contents of first region (U-Boot or SPL)
970 Offset and size components of microcode pointer, as inserted
971 in the above (two 4-byte words)
973 data = self._DoReadFile(dts_fname, True)
975 # Now check the device tree has no microcode
977 ucode_content = data[len(nodtb_data):]
978 ucode_pos = len(nodtb_data)
979 dtb_with_ucode = ucode_content[16:]
980 fdt_len = self.GetFdtLen(dtb_with_ucode)
982 dtb_with_ucode = data[len(nodtb_data):]
983 fdt_len = self.GetFdtLen(dtb_with_ucode)
984 ucode_content = dtb_with_ucode[fdt_len:]
985 ucode_pos = len(nodtb_data) + fdt_len
986 fname = tools.GetOutputFilename('test.dtb')
987 with open(fname, 'wb') as fd:
988 fd.write(dtb_with_ucode)
989 dtb = fdt.FdtScan(fname)
990 ucode = dtb.GetNode('/microcode')
991 self.assertTrue(ucode)
992 for node in ucode.subnodes:
993 self.assertFalse(node.props.get('data'))
995 # Check that the microcode appears immediately after the Fdt
996 # This matches the concatenation of the data properties in
997 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
998 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1000 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
1002 # Check that the microcode pointer was inserted. It should match the
1003 # expected offset and size
1004 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1006 u_boot = data[:len(nodtb_data)]
1007 return u_boot, pos_and_size
1009 def testPackUbootMicrocode(self):
1010 """Test that x86 microcode can be handled correctly
1012 We expect to see the following in the image, in order:
1013 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1015 u-boot.dtb with the microcode removed
1018 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
1020 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1021 b' somewhere in here', first)
1023 def _RunPackUbootSingleMicrocode(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
1030 an empty microcode region
1032 # We need the libfdt library to run this test since only that allows
1033 # finding the offset of a property. This is required by
1034 # Entry_u_boot_dtb_with_ucode.ObtainContents().
1035 data = self._DoReadFile('035_x86_single_ucode.dts', True)
1037 second = data[len(U_BOOT_NODTB_DATA):]
1039 fdt_len = self.GetFdtLen(second)
1040 third = second[fdt_len:]
1041 second = second[:fdt_len]
1043 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1044 self.assertIn(ucode_data, second)
1045 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
1047 # Check that the microcode pointer was inserted. It should match the
1048 # expected offset and size
1049 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1051 first = data[:len(U_BOOT_NODTB_DATA)]
1052 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1053 b' somewhere in here', first)
1055 def testPackUbootSingleMicrocode(self):
1056 """Test that x86 microcode can be handled correctly with fdt_normal.
1058 self._RunPackUbootSingleMicrocode()
1060 def testUBootImg(self):
1061 """Test that u-boot.img can be put in a file"""
1062 data = self._DoReadFile('036_u_boot_img.dts')
1063 self.assertEqual(U_BOOT_IMG_DATA, data)
1065 def testNoMicrocode(self):
1066 """Test that a missing microcode region is detected"""
1067 with self.assertRaises(ValueError) as e:
1068 self._DoReadFile('037_x86_no_ucode.dts', True)
1069 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1070 "node found in ", str(e.exception))
1072 def testMicrocodeWithoutNode(self):
1073 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1074 with self.assertRaises(ValueError) as e:
1075 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1076 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1077 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1079 def testMicrocodeWithoutNode2(self):
1080 """Test that a missing u-boot-ucode node is detected"""
1081 with self.assertRaises(ValueError) as e:
1082 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1083 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1084 "microcode region u-boot-ucode", str(e.exception))
1086 def testMicrocodeWithoutPtrInElf(self):
1087 """Test that a U-Boot binary without the microcode symbol is detected"""
1088 # ELF file without a '_dt_ucode_base_size' symbol
1090 TestFunctional._MakeInputFile('u-boot',
1091 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1093 with self.assertRaises(ValueError) as e:
1094 self._RunPackUbootSingleMicrocode()
1095 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1096 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1099 # Put the original file back
1100 TestFunctional._MakeInputFile('u-boot',
1101 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1103 def testMicrocodeNotInImage(self):
1104 """Test that microcode must be placed within the image"""
1105 with self.assertRaises(ValueError) as e:
1106 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1107 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1108 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1109 "section ranging from 00000000 to 0000002e", str(e.exception))
1111 def testWithoutMicrocode(self):
1112 """Test that we can cope with an image without microcode (e.g. qemu)"""
1113 TestFunctional._MakeInputFile('u-boot',
1114 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
1115 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1117 # Now check the device tree has no microcode
1118 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1119 second = data[len(U_BOOT_NODTB_DATA):]
1121 fdt_len = self.GetFdtLen(second)
1122 self.assertEqual(dtb, second[:fdt_len])
1124 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1125 third = data[used_len:]
1126 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1128 def testUnknownPosSize(self):
1129 """Test that microcode must be placed within the image"""
1130 with self.assertRaises(ValueError) as e:
1131 self._DoReadFile('041_unknown_pos_size.dts', True)
1132 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1133 "entry 'invalid-entry'", str(e.exception))
1135 def testPackFsp(self):
1136 """Test that an image with a FSP binary can be created"""
1137 data = self._DoReadFile('042_intel-fsp.dts')
1138 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1140 def testPackCmc(self):
1141 """Test that an image with a CMC binary can be created"""
1142 data = self._DoReadFile('043_intel-cmc.dts')
1143 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1145 def testPackVbt(self):
1146 """Test that an image with a VBT binary can be created"""
1147 data = self._DoReadFile('046_intel-vbt.dts')
1148 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1150 def testSplBssPad(self):
1151 """Test that we can pad SPL's BSS with zeros"""
1152 # ELF file with a '__bss_size' symbol
1154 data = self._DoReadFile('047_spl_bss_pad.dts')
1155 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1158 def testSplBssPadMissing(self):
1159 """Test that a missing symbol is detected"""
1160 self._SetupSplElf('u_boot_ucode_ptr')
1161 with self.assertRaises(ValueError) as e:
1162 self._DoReadFile('047_spl_bss_pad.dts')
1163 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1166 def testPackStart16Spl(self):
1167 """Test that an image with an x86 start16 SPL region can be created"""
1168 data = self._DoReadFile('048_x86-start16-spl.dts')
1169 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1171 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1172 """Helper function for microcode tests
1174 We expect to see the following in the image, in order:
1175 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1177 u-boot.dtb with the microcode removed
1181 dts: Device tree file to use for test
1182 ucode_second: True if the microsecond entry is second instead of
1185 self._SetupSplElf('u_boot_ucode_ptr')
1186 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1187 ucode_second=ucode_second)
1188 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1189 b'ter somewhere in here', first)
1191 def testPackUbootSplMicrocode(self):
1192 """Test that x86 microcode can be handled correctly in SPL"""
1193 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1195 def testPackUbootSplMicrocodeReorder(self):
1196 """Test that order doesn't matter for microcode entries
1198 This is the same as testPackUbootSplMicrocode but when we process the
1199 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1200 entry, so we reply on binman to try later.
1202 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1205 def testPackMrc(self):
1206 """Test that an image with an MRC binary can be created"""
1207 data = self._DoReadFile('050_intel_mrc.dts')
1208 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1210 def testSplDtb(self):
1211 """Test that an image with spl/u-boot-spl.dtb can be created"""
1212 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1213 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1215 def testSplNoDtb(self):
1216 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1217 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1218 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1220 def testSymbols(self):
1221 """Test binman can assign symbols embedded in U-Boot"""
1222 elf_fname = self.ElfTestFile('u_boot_binman_syms')
1223 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1224 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1225 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1227 self._SetupSplElf('u_boot_binman_syms')
1228 data = self._DoReadFile('053_symbols.dts')
1229 sym_values = struct.pack('<LQL', 0, 24, 20)
1230 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1231 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1232 U_BOOT_SPL_DATA[16:])
1233 self.assertEqual(expected, data)
1235 def testPackUnitAddress(self):
1236 """Test that we support multiple binaries with the same name"""
1237 data = self._DoReadFile('054_unit_address.dts')
1238 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1240 def testSections(self):
1241 """Basic test of sections"""
1242 data = self._DoReadFile('055_sections.dts')
1243 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1244 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1245 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1246 self.assertEqual(expected, data)
1249 """Tests outputting a map of the images"""
1250 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1251 self.assertEqual('''ImagePos Offset Size Name
1252 00000000 00000000 00000028 main-section
1253 00000000 00000000 00000010 section@0
1254 00000000 00000000 00000004 u-boot
1255 00000010 00000010 00000010 section@1
1256 00000010 00000000 00000004 u-boot
1257 00000020 00000020 00000004 section@2
1258 00000020 00000000 00000004 u-boot
1261 def testNamePrefix(self):
1262 """Tests that name prefixes are used"""
1263 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1264 self.assertEqual('''ImagePos Offset Size Name
1265 00000000 00000000 00000028 main-section
1266 00000000 00000000 00000010 section@0
1267 00000000 00000000 00000004 ro-u-boot
1268 00000010 00000010 00000010 section@1
1269 00000010 00000000 00000004 rw-u-boot
1272 def testUnknownContents(self):
1273 """Test that obtaining the contents works as expected"""
1274 with self.assertRaises(ValueError) as e:
1275 self._DoReadFile('057_unknown_contents.dts', True)
1276 self.assertIn("Image '/binman': Internal error: Could not complete "
1277 "processing of contents: remaining [<_testing.Entry__testing ",
1280 def testBadChangeSize(self):
1281 """Test that trying to change the size of an entry fails"""
1283 state.SetAllowEntryExpansion(False)
1284 with self.assertRaises(ValueError) as e:
1285 self._DoReadFile('059_change_size.dts', True)
1286 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
1289 state.SetAllowEntryExpansion(True)
1291 def testUpdateFdt(self):
1292 """Test that we can update the device tree with offset/size info"""
1293 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1295 dtb = fdt.Fdt(out_dtb_fname)
1297 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
1301 '_testing:offset': 32,
1303 '_testing:image-pos': 32,
1304 'section@0/u-boot:offset': 0,
1305 'section@0/u-boot:size': len(U_BOOT_DATA),
1306 'section@0/u-boot:image-pos': 0,
1307 'section@0:offset': 0,
1308 'section@0:size': 16,
1309 'section@0:image-pos': 0,
1311 'section@1/u-boot:offset': 0,
1312 'section@1/u-boot:size': len(U_BOOT_DATA),
1313 'section@1/u-boot:image-pos': 16,
1314 'section@1:offset': 16,
1315 'section@1:size': 16,
1316 'section@1:image-pos': 16,
1320 def testUpdateFdtBad(self):
1321 """Test that we detect when ProcessFdt never completes"""
1322 with self.assertRaises(ValueError) as e:
1323 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1324 self.assertIn('Could not complete processing of Fdt: remaining '
1325 '[<_testing.Entry__testing', str(e.exception))
1327 def testEntryArgs(self):
1328 """Test passing arguments to entries from the command line"""
1330 'test-str-arg': 'test1',
1331 'test-int-arg': '456',
1333 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1334 self.assertIn('image', control.images)
1335 entry = control.images['image'].GetEntries()['_testing']
1336 self.assertEqual('test0', entry.test_str_fdt)
1337 self.assertEqual('test1', entry.test_str_arg)
1338 self.assertEqual(123, entry.test_int_fdt)
1339 self.assertEqual(456, entry.test_int_arg)
1341 def testEntryArgsMissing(self):
1342 """Test missing arguments and properties"""
1344 'test-int-arg': '456',
1346 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1347 entry = control.images['image'].GetEntries()['_testing']
1348 self.assertEqual('test0', entry.test_str_fdt)
1349 self.assertEqual(None, entry.test_str_arg)
1350 self.assertEqual(None, entry.test_int_fdt)
1351 self.assertEqual(456, entry.test_int_arg)
1353 def testEntryArgsRequired(self):
1354 """Test missing arguments and properties"""
1356 'test-int-arg': '456',
1358 with self.assertRaises(ValueError) as e:
1359 self._DoReadFileDtb('064_entry_args_required.dts')
1360 self.assertIn("Node '/binman/_testing': Missing required "
1361 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1364 def testEntryArgsInvalidFormat(self):
1365 """Test that an invalid entry-argument format is detected"""
1366 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1368 with self.assertRaises(ValueError) as e:
1369 self._DoBinman(*args)
1370 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1372 def testEntryArgsInvalidInteger(self):
1373 """Test that an invalid entry-argument integer is detected"""
1375 'test-int-arg': 'abc',
1377 with self.assertRaises(ValueError) as e:
1378 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1379 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1380 "'test-int-arg' (value 'abc') to integer",
1383 def testEntryArgsInvalidDatatype(self):
1384 """Test that an invalid entry-argument datatype is detected
1386 This test could be written in entry_test.py except that it needs
1387 access to control.entry_args, which seems more than that module should
1391 'test-bad-datatype-arg': '12',
1393 with self.assertRaises(ValueError) as e:
1394 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1395 entry_args=entry_args)
1396 self.assertIn('GetArg() internal error: Unknown data type ',
1400 """Test for a text entry type"""
1402 'test-id': TEXT_DATA,
1403 'test-id2': TEXT_DATA2,
1404 'test-id3': TEXT_DATA3,
1406 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1407 entry_args=entry_args)
1408 expected = (tools.ToBytes(TEXT_DATA) +
1409 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1410 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1411 b'some text' + b'more text')
1412 self.assertEqual(expected, data)
1414 def testEntryDocs(self):
1415 """Test for creation of entry documentation"""
1416 with test_util.capture_sys_output() as (stdout, stderr):
1417 control.WriteEntryDocs(binman.GetEntryModules())
1418 self.assertTrue(len(stdout.getvalue()) > 0)
1420 def testEntryDocsMissing(self):
1421 """Test handling of missing entry documentation"""
1422 with self.assertRaises(ValueError) as e:
1423 with test_util.capture_sys_output() as (stdout, stderr):
1424 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1425 self.assertIn('Documentation is missing for modules: u_boot',
1429 """Basic test of generation of a flashrom fmap"""
1430 data = self._DoReadFile('067_fmap.dts')
1431 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1432 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1433 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1434 self.assertEqual(expected, data[:32])
1435 self.assertEqual(b'__FMAP__', fhdr.signature)
1436 self.assertEqual(1, fhdr.ver_major)
1437 self.assertEqual(0, fhdr.ver_minor)
1438 self.assertEqual(0, fhdr.base)
1439 self.assertEqual(16 + 16 +
1440 fmap_util.FMAP_HEADER_LEN +
1441 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1442 self.assertEqual(b'FMAP', fhdr.name)
1443 self.assertEqual(3, fhdr.nareas)
1444 for fentry in fentries:
1445 self.assertEqual(0, fentry.flags)
1447 self.assertEqual(0, fentries[0].offset)
1448 self.assertEqual(4, fentries[0].size)
1449 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1451 self.assertEqual(16, fentries[1].offset)
1452 self.assertEqual(4, fentries[1].size)
1453 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1455 self.assertEqual(32, fentries[2].offset)
1456 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1457 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1458 self.assertEqual(b'FMAP', fentries[2].name)
1460 def testBlobNamedByArg(self):
1461 """Test we can add a blob with the filename coming from an entry arg"""
1463 'cros-ec-rw-path': 'ecrw.bin',
1465 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1466 entry_args=entry_args)
1469 """Test for an fill entry type"""
1470 data = self._DoReadFile('069_fill.dts')
1471 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1472 self.assertEqual(expected, data)
1474 def testFillNoSize(self):
1475 """Test for an fill entry type with no size"""
1476 with self.assertRaises(ValueError) as e:
1477 self._DoReadFile('070_fill_no_size.dts')
1478 self.assertIn("'fill' entry must have a size property",
1481 def _HandleGbbCommand(self, pipe_list):
1482 """Fake calls to the futility utility"""
1483 if pipe_list[0][0] == 'futility':
1484 fname = pipe_list[0][-1]
1485 # Append our GBB data to the file, which will happen every time the
1486 # futility command is called.
1487 with open(fname, 'ab') as fd:
1489 return command.CommandResult()
1492 """Test for the Chromium OS Google Binary Block"""
1493 command.test_result = self._HandleGbbCommand
1495 'keydir': 'devkeys',
1496 'bmpblk': 'bmpblk.bin',
1498 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1501 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1502 tools.GetBytes(0, 0x2180 - 16))
1503 self.assertEqual(expected, data)
1505 def testGbbTooSmall(self):
1506 """Test for the Chromium OS Google Binary Block being large enough"""
1507 with self.assertRaises(ValueError) as e:
1508 self._DoReadFileDtb('072_gbb_too_small.dts')
1509 self.assertIn("Node '/binman/gbb': GBB is too small",
1512 def testGbbNoSize(self):
1513 """Test for the Chromium OS Google Binary Block having a size"""
1514 with self.assertRaises(ValueError) as e:
1515 self._DoReadFileDtb('073_gbb_no_size.dts')
1516 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1519 def _HandleVblockCommand(self, pipe_list):
1520 """Fake calls to the futility utility"""
1521 if pipe_list[0][0] == 'futility':
1522 fname = pipe_list[0][3]
1523 with open(fname, 'wb') as fd:
1524 fd.write(VBLOCK_DATA)
1525 return command.CommandResult()
1527 def testVblock(self):
1528 """Test for the Chromium OS Verified Boot Block"""
1529 command.test_result = self._HandleVblockCommand
1531 'keydir': 'devkeys',
1533 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1534 entry_args=entry_args)
1535 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1536 self.assertEqual(expected, data)
1538 def testVblockNoContent(self):
1539 """Test we detect a vblock which has no content to sign"""
1540 with self.assertRaises(ValueError) as e:
1541 self._DoReadFile('075_vblock_no_content.dts')
1542 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1543 'property', str(e.exception))
1545 def testVblockBadPhandle(self):
1546 """Test that we detect a vblock with an invalid phandle in contents"""
1547 with self.assertRaises(ValueError) as e:
1548 self._DoReadFile('076_vblock_bad_phandle.dts')
1549 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1550 '1000', str(e.exception))
1552 def testVblockBadEntry(self):
1553 """Test that we detect an entry that points to a non-entry"""
1554 with self.assertRaises(ValueError) as e:
1555 self._DoReadFile('077_vblock_bad_entry.dts')
1556 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1557 "'other'", str(e.exception))
1560 """Test that an image with TPL and ots device tree can be created"""
1561 # ELF file with a '__bss_size' symbol
1562 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1563 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1564 data = self._DoReadFile('078_u_boot_tpl.dts')
1565 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1567 def testUsesPos(self):
1568 """Test that the 'pos' property cannot be used anymore"""
1569 with self.assertRaises(ValueError) as e:
1570 data = self._DoReadFile('079_uses_pos.dts')
1571 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1572 "'pos'", str(e.exception))
1574 def testFillZero(self):
1575 """Test for an fill entry type with a size of 0"""
1576 data = self._DoReadFile('080_fill_empty.dts')
1577 self.assertEqual(tools.GetBytes(0, 16), data)
1579 def testTextMissing(self):
1580 """Test for a text entry type where there is no text"""
1581 with self.assertRaises(ValueError) as e:
1582 self._DoReadFileDtb('066_text.dts',)
1583 self.assertIn("Node '/binman/text': No value provided for text label "
1584 "'test-id'", str(e.exception))
1586 def testPackStart16Tpl(self):
1587 """Test that an image with an x86 start16 TPL region can be created"""
1588 data = self._DoReadFile('081_x86-start16-tpl.dts')
1589 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1591 def testSelectImage(self):
1592 """Test that we can select which images to build"""
1593 expected = 'Skipping images: image1'
1595 # We should only get the expected message in verbose mode
1596 for verbosity in (0, 2):
1597 with test_util.capture_sys_output() as (stdout, stderr):
1598 retcode = self._DoTestFile('006_dual_image.dts',
1599 verbosity=verbosity,
1601 self.assertEqual(0, retcode)
1603 self.assertIn(expected, stdout.getvalue())
1605 self.assertNotIn(expected, stdout.getvalue())
1607 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1608 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1609 self._CleanupOutputDir()
1611 def testUpdateFdtAll(self):
1612 """Test that all device trees are updated with offset/size info"""
1613 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1616 'section:image-pos': 0,
1617 'u-boot-tpl-dtb:size': 513,
1618 'u-boot-spl-dtb:size': 513,
1619 'u-boot-spl-dtb:offset': 493,
1621 'section/u-boot-dtb:image-pos': 0,
1622 'u-boot-spl-dtb:image-pos': 493,
1623 'section/u-boot-dtb:size': 493,
1624 'u-boot-tpl-dtb:image-pos': 1006,
1625 'section/u-boot-dtb:offset': 0,
1626 'section:size': 493,
1628 'section:offset': 0,
1629 'u-boot-tpl-dtb:offset': 1006,
1633 # We expect three device-tree files in the output, one after the other.
1634 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1635 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1636 # main U-Boot tree. All three should have the same postions and offset.
1638 for item in ['', 'spl', 'tpl']:
1639 dtb = fdt.Fdt.FromData(data[start:])
1641 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1643 expected = dict(base_expected)
1646 self.assertEqual(expected, props)
1647 start += dtb._fdt_obj.totalsize()
1649 def testUpdateFdtOutput(self):
1650 """Test that output DTB files are updated"""
1652 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1653 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1655 # Unfortunately, compiling a source file always results in a file
1656 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1657 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1658 # binman as a file called u-boot.dtb. To fix this, copy the file
1659 # over to the expected place.
1660 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1661 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1663 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1664 'tpl/u-boot-tpl.dtb.out']:
1665 dtb = fdt.Fdt.FromData(data[start:])
1666 size = dtb._fdt_obj.totalsize()
1667 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1668 outdata = tools.ReadFile(pathname)
1669 name = os.path.split(fname)[0]
1672 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1674 orig_indata = dtb_data
1675 self.assertNotEqual(outdata, orig_indata,
1676 "Expected output file '%s' be updated" % pathname)
1677 self.assertEqual(outdata, data[start:start + size],
1678 "Expected output file '%s' to match output image" %
1684 def _decompress(self, data):
1685 return tools.Decompress(data, 'lz4')
1687 def testCompress(self):
1688 """Test compression of blobs"""
1690 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1691 use_real_dtb=True, update_dtb=True)
1692 dtb = fdt.Fdt(out_dtb_fname)
1694 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1695 orig = self._decompress(data)
1696 self.assertEquals(COMPRESS_DATA, orig)
1698 'blob:uncomp-size': len(COMPRESS_DATA),
1699 'blob:size': len(data),
1702 self.assertEqual(expected, props)
1704 def testFiles(self):
1705 """Test bringing in multiple files"""
1706 data = self._DoReadFile('084_files.dts')
1707 self.assertEqual(FILES_DATA, data)
1709 def testFilesCompress(self):
1710 """Test bringing in multiple files and compressing them"""
1712 data = self._DoReadFile('085_files_compress.dts')
1714 image = control.images['image']
1715 entries = image.GetEntries()
1716 files = entries['files']
1717 entries = files._entries
1720 for i in range(1, 3):
1722 start = entries[key].image_pos
1723 len = entries[key].size
1724 chunk = data[start:start + len]
1725 orig += self._decompress(chunk)
1727 self.assertEqual(FILES_DATA, orig)
1729 def testFilesMissing(self):
1730 """Test missing files"""
1731 with self.assertRaises(ValueError) as e:
1732 data = self._DoReadFile('086_files_none.dts')
1733 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1734 'no files', str(e.exception))
1736 def testFilesNoPattern(self):
1737 """Test missing files"""
1738 with self.assertRaises(ValueError) as e:
1739 data = self._DoReadFile('087_files_no_pattern.dts')
1740 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1743 def testExpandSize(self):
1744 """Test an expanding entry"""
1745 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1747 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1748 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1749 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1750 tools.GetBytes(ord('d'), 8))
1751 self.assertEqual(expect, data)
1752 self.assertEqual('''ImagePos Offset Size Name
1753 00000000 00000000 00000028 main-section
1754 00000000 00000000 00000008 fill
1755 00000008 00000008 00000004 u-boot
1756 0000000c 0000000c 00000004 section
1757 0000000c 00000000 00000003 intel-mrc
1758 00000010 00000010 00000004 u-boot2
1759 00000014 00000014 0000000c section2
1760 00000014 00000000 00000008 fill
1761 0000001c 00000008 00000004 u-boot
1762 00000020 00000020 00000008 fill2
1765 def testExpandSizeBad(self):
1766 """Test an expanding entry which fails to provide contents"""
1767 with test_util.capture_sys_output() as (stdout, stderr):
1768 with self.assertRaises(ValueError) as e:
1769 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1770 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1771 'expanding entry', str(e.exception))
1774 """Test hashing of the contents of an entry"""
1775 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1776 use_real_dtb=True, update_dtb=True)
1777 dtb = fdt.Fdt(out_dtb_fname)
1779 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1780 m = hashlib.sha256()
1781 m.update(U_BOOT_DATA)
1782 self.assertEqual(m.digest(), b''.join(hash_node.value))
1784 def testHashNoAlgo(self):
1785 with self.assertRaises(ValueError) as e:
1786 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1787 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1788 'hash node', str(e.exception))
1790 def testHashBadAlgo(self):
1791 with self.assertRaises(ValueError) as e:
1792 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1793 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1796 def testHashSection(self):
1797 """Test hashing of the contents of an entry"""
1798 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1799 use_real_dtb=True, update_dtb=True)
1800 dtb = fdt.Fdt(out_dtb_fname)
1802 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1803 m = hashlib.sha256()
1804 m.update(U_BOOT_DATA)
1805 m.update(tools.GetBytes(ord('a'), 16))
1806 self.assertEqual(m.digest(), b''.join(hash_node.value))
1808 def testPackUBootTplMicrocode(self):
1809 """Test that x86 microcode can be handled correctly in TPL
1811 We expect to see the following in the image, in order:
1812 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1814 u-boot-tpl.dtb with the microcode removed
1817 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
1818 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
1819 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1820 U_BOOT_TPL_NODTB_DATA)
1821 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1822 b'ter somewhere in here', first)
1824 def testFmapX86(self):
1825 """Basic test of generation of a flashrom fmap"""
1826 data = self._DoReadFile('094_fmap_x86.dts')
1827 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1828 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1829 self.assertEqual(expected, data[:32])
1830 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1832 self.assertEqual(0x100, fhdr.image_size)
1834 self.assertEqual(0, fentries[0].offset)
1835 self.assertEqual(4, fentries[0].size)
1836 self.assertEqual(b'U_BOOT', fentries[0].name)
1838 self.assertEqual(4, fentries[1].offset)
1839 self.assertEqual(3, fentries[1].size)
1840 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1842 self.assertEqual(32, fentries[2].offset)
1843 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1844 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1845 self.assertEqual(b'FMAP', fentries[2].name)
1847 def testFmapX86Section(self):
1848 """Basic test of generation of a flashrom fmap"""
1849 data = self._DoReadFile('095_fmap_x86_section.dts')
1850 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1851 self.assertEqual(expected, data[:32])
1852 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1854 self.assertEqual(0x100, fhdr.image_size)
1856 self.assertEqual(0, fentries[0].offset)
1857 self.assertEqual(4, fentries[0].size)
1858 self.assertEqual(b'U_BOOT', fentries[0].name)
1860 self.assertEqual(4, fentries[1].offset)
1861 self.assertEqual(3, fentries[1].size)
1862 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1864 self.assertEqual(36, fentries[2].offset)
1865 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1866 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1867 self.assertEqual(b'FMAP', fentries[2].name)
1870 """Basic test of ELF entries"""
1872 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1873 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1874 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1875 TestFunctional._MakeInputFile('-boot', fd.read())
1876 data = self._DoReadFile('096_elf.dts')
1878 def testElfStrip(self):
1879 """Basic test of ELF entries"""
1881 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
1882 TestFunctional._MakeInputFile('-boot', fd.read())
1883 data = self._DoReadFile('097_elf_strip.dts')
1885 def testPackOverlapMap(self):
1886 """Test that overlapping regions are detected"""
1887 with test_util.capture_sys_output() as (stdout, stderr):
1888 with self.assertRaises(ValueError) as e:
1889 self._DoTestFile('014_pack_overlap.dts', map=True)
1890 map_fname = tools.GetOutputFilename('image.map')
1891 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1894 # We should not get an inmage, but there should be a map file
1895 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1896 self.assertTrue(os.path.exists(map_fname))
1897 map_data = tools.ReadFile(map_fname, binary=False)
1898 self.assertEqual('''ImagePos Offset Size Name
1899 <none> 00000000 00000007 main-section
1900 <none> 00000000 00000004 u-boot
1901 <none> 00000003 00000004 u-boot-align
1904 def testPackRefCode(self):
1905 """Test that an image with an Intel Reference code binary works"""
1906 data = self._DoReadFile('100_intel_refcode.dts')
1907 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1909 def testSectionOffset(self):
1910 """Tests use of a section with an offset"""
1911 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1913 self.assertEqual('''ImagePos Offset Size Name
1914 00000000 00000000 00000038 main-section
1915 00000004 00000004 00000010 section@0
1916 00000004 00000000 00000004 u-boot
1917 00000018 00000018 00000010 section@1
1918 00000018 00000000 00000004 u-boot
1919 0000002c 0000002c 00000004 section@2
1920 0000002c 00000000 00000004 u-boot
1922 self.assertEqual(data,
1923 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1924 tools.GetBytes(0x21, 12) +
1925 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1926 tools.GetBytes(0x61, 12) +
1927 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1928 tools.GetBytes(0x26, 8))
1930 def testCbfsRaw(self):
1931 """Test base handling of a Coreboot Filesystem (CBFS)
1933 The exact contents of the CBFS is verified by similar tests in
1934 cbfs_util_test.py. The tests here merely check that the files added to
1935 the CBFS can be found in the final image.
1937 data = self._DoReadFile('102_cbfs_raw.dts')
1940 cbfs = cbfs_util.CbfsReader(data)
1941 self.assertEqual(size, cbfs.rom_size)
1943 self.assertIn('u-boot-dtb', cbfs.files)
1944 cfile = cbfs.files['u-boot-dtb']
1945 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1947 def testCbfsArch(self):
1948 """Test on non-x86 architecture"""
1949 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1952 cbfs = cbfs_util.CbfsReader(data)
1953 self.assertEqual(size, cbfs.rom_size)
1955 self.assertIn('u-boot-dtb', cbfs.files)
1956 cfile = cbfs.files['u-boot-dtb']
1957 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1959 def testCbfsStage(self):
1960 """Tests handling of a Coreboot Filesystem (CBFS)"""
1961 if not elf.ELF_TOOLS:
1962 self.skipTest('Python elftools not available')
1963 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1964 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1967 data = self._DoReadFile('104_cbfs_stage.dts')
1968 cbfs = cbfs_util.CbfsReader(data)
1969 self.assertEqual(size, cbfs.rom_size)
1971 self.assertIn('u-boot', cbfs.files)
1972 cfile = cbfs.files['u-boot']
1973 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1975 def testCbfsRawCompress(self):
1976 """Test handling of compressing raw files"""
1978 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1981 cbfs = cbfs_util.CbfsReader(data)
1982 self.assertIn('u-boot', cbfs.files)
1983 cfile = cbfs.files['u-boot']
1984 self.assertEqual(COMPRESS_DATA, cfile.data)
1986 def testCbfsBadArch(self):
1987 """Test handling of a bad architecture"""
1988 with self.assertRaises(ValueError) as e:
1989 self._DoReadFile('106_cbfs_bad_arch.dts')
1990 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1992 def testCbfsNoSize(self):
1993 """Test handling of a missing size property"""
1994 with self.assertRaises(ValueError) as e:
1995 self._DoReadFile('107_cbfs_no_size.dts')
1996 self.assertIn('entry must have a size property', str(e.exception))
1998 def testCbfsNoCOntents(self):
1999 """Test handling of a CBFS entry which does not provide contentsy"""
2000 with self.assertRaises(ValueError) as e:
2001 self._DoReadFile('108_cbfs_no_contents.dts')
2002 self.assertIn('Could not complete processing of contents',
2005 def testCbfsBadCompress(self):
2006 """Test handling of a bad architecture"""
2007 with self.assertRaises(ValueError) as e:
2008 self._DoReadFile('109_cbfs_bad_compress.dts')
2009 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2012 def testCbfsNamedEntries(self):
2013 """Test handling of named entries"""
2014 data = self._DoReadFile('110_cbfs_name.dts')
2016 cbfs = cbfs_util.CbfsReader(data)
2017 self.assertIn('FRED', cbfs.files)
2018 cfile1 = cbfs.files['FRED']
2019 self.assertEqual(U_BOOT_DATA, cfile1.data)
2021 self.assertIn('hello', cbfs.files)
2022 cfile2 = cbfs.files['hello']
2023 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2025 def _SetupIfwi(self, fname):
2026 """Set up to run an IFWI test
2029 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2033 # Intel Integrated Firmware Image (IFWI) file
2034 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2036 TestFunctional._MakeInputFile(fname,data)
2038 def _CheckIfwi(self, data):
2039 """Check that an image with an IFWI contains the correct output
2042 data: Conents of output file
2044 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2045 if data[:0x1000] != expected_desc:
2046 self.fail('Expected descriptor binary at start of image')
2048 # We expect to find the TPL wil in subpart IBBP entry IBBL
2049 image_fname = tools.GetOutputFilename('image.bin')
2050 tpl_fname = tools.GetOutputFilename('tpl.out')
2051 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2052 subpart='IBBP', entry_name='IBBL')
2054 tpl_data = tools.ReadFile(tpl_fname)
2055 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
2057 def testPackX86RomIfwi(self):
2058 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2059 self._SetupIfwi('fitimage.bin')
2060 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2061 self._CheckIfwi(data)
2063 def testPackX86RomIfwiNoDesc(self):
2064 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2065 self._SetupIfwi('ifwi.bin')
2066 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2067 self._CheckIfwi(data)
2069 def testPackX86RomIfwiNoData(self):
2070 """Test that an x86 ROM with IFWI handles missing data"""
2071 self._SetupIfwi('ifwi.bin')
2072 with self.assertRaises(ValueError) as e:
2073 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2074 self.assertIn('Could not complete processing of contents',
2077 def testCbfsOffset(self):
2078 """Test a CBFS with files at particular offsets
2080 Like all CFBS tests, this is just checking the logic that calls
2081 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2083 data = self._DoReadFile('114_cbfs_offset.dts')
2086 cbfs = cbfs_util.CbfsReader(data)
2087 self.assertEqual(size, cbfs.rom_size)
2089 self.assertIn('u-boot', cbfs.files)
2090 cfile = cbfs.files['u-boot']
2091 self.assertEqual(U_BOOT_DATA, cfile.data)
2092 self.assertEqual(0x40, cfile.cbfs_offset)
2094 self.assertIn('u-boot-dtb', cbfs.files)
2095 cfile2 = cbfs.files['u-boot-dtb']
2096 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2097 self.assertEqual(0x140, cfile2.cbfs_offset)
2099 def testFdtmap(self):
2100 """Test an FDT map can be inserted in the image"""
2101 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2102 fdtmap_data = data[len(U_BOOT_DATA):]
2103 magic = fdtmap_data[:8]
2104 self.assertEqual('_FDTMAP_', magic)
2105 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2107 fdt_data = fdtmap_data[16:]
2108 dtb = fdt.Fdt.FromData(fdt_data)
2110 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
2115 'u-boot:size': len(U_BOOT_DATA),
2116 'u-boot:image-pos': 0,
2117 'fdtmap:image-pos': 4,
2119 'fdtmap:size': len(fdtmap_data),
2123 def testFdtmapNoMatch(self):
2124 """Check handling of an FDT map when the section cannot be found"""
2125 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2127 # Mangle the section name, which should cause a mismatch between the
2128 # correct FDT path and the one expected by the section
2129 image = control.images['image']
2130 image._node.path += '-suffix'
2131 entries = image.GetEntries()
2132 fdtmap = entries['fdtmap']
2133 with self.assertRaises(ValueError) as e:
2135 self.assertIn("Cannot locate node for path '/binman-suffix'",
2138 def testFdtmapHeader(self):
2139 """Test an FDT map and image header can be inserted in the image"""
2140 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2141 fdtmap_pos = len(U_BOOT_DATA)
2142 fdtmap_data = data[fdtmap_pos:]
2143 fdt_data = fdtmap_data[16:]
2144 dtb = fdt.Fdt.FromData(fdt_data)
2145 fdt_size = dtb.GetFdtObj().totalsize()
2146 hdr_data = data[-8:]
2147 self.assertEqual('BinM', hdr_data[:4])
2148 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2149 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2151 def testFdtmapHeaderStart(self):
2152 """Test an image header can be inserted at the image start"""
2153 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2154 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2156 self.assertEqual('BinM', hdr_data[:4])
2157 offset = struct.unpack('<I', hdr_data[4:])[0]
2158 self.assertEqual(fdtmap_pos, offset)
2160 def testFdtmapHeaderPos(self):
2161 """Test an image header can be inserted at a chosen position"""
2162 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2163 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2164 hdr_data = data[0x80:0x88]
2165 self.assertEqual('BinM', hdr_data[:4])
2166 offset = struct.unpack('<I', hdr_data[4:])[0]
2167 self.assertEqual(fdtmap_pos, offset)
2169 def testHeaderMissingFdtmap(self):
2170 """Test an image header requires an fdtmap"""
2171 with self.assertRaises(ValueError) as e:
2172 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2173 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2176 def testHeaderNoLocation(self):
2177 """Test an image header with a no specified location is detected"""
2178 with self.assertRaises(ValueError) as e:
2179 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2180 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2183 def testEntryExpand(self):
2184 """Test expanding an entry after it is packed"""
2185 data = self._DoReadFile('121_entry_expand.dts')
2186 self.assertEqual(b'aaa', data[:3])
2187 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2188 self.assertEqual(b'aaa', data[-3:])
2190 def testEntryExpandBad(self):
2191 """Test expanding an entry after it is packed, twice"""
2192 with self.assertRaises(ValueError) as e:
2193 self._DoReadFile('122_entry_expand_twice.dts')
2194 self.assertIn("Image '/binman': Entries changed size after packing",
2197 def testEntryExpandSection(self):
2198 """Test expanding an entry within a section after it is packed"""
2199 data = self._DoReadFile('123_entry_expand_section.dts')
2200 self.assertEqual(b'aaa', data[:3])
2201 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2202 self.assertEqual(b'aaa', data[-3:])
2204 def testCompressDtb(self):
2205 """Test that compress of device-tree files is supported"""
2207 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2208 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2209 comp_data = data[len(U_BOOT_DATA):]
2210 orig = self._decompress(comp_data)
2211 dtb = fdt.Fdt.FromData(orig)
2213 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2215 'u-boot:size': len(U_BOOT_DATA),
2216 'u-boot-dtb:uncomp-size': len(orig),
2217 'u-boot-dtb:size': len(comp_data),
2220 self.assertEqual(expected, props)
2222 def testCbfsUpdateFdt(self):
2223 """Test that we can update the device tree with CBFS offset/size info"""
2225 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2227 dtb = fdt.Fdt(out_dtb_fname)
2229 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
2230 del props['cbfs/u-boot:size']
2236 'cbfs:size': len(data),
2237 'cbfs:image-pos': 0,
2238 'cbfs/u-boot:offset': 0x38,
2239 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2240 'cbfs/u-boot:image-pos': 0x38,
2241 'cbfs/u-boot-dtb:offset': 0xb8,
2242 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2243 'cbfs/u-boot-dtb:image-pos': 0xb8,
2246 def testCbfsBadType(self):
2247 """Test an image header with a no specified location is detected"""
2248 with self.assertRaises(ValueError) as e:
2249 self._DoReadFile('126_cbfs_bad_type.dts')
2250 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2253 """Test listing the files in an image"""
2255 data = self._DoReadFile('127_list.dts')
2256 image = control.images['image']
2257 entries = image.BuildEntryList()
2258 self.assertEqual(7, len(entries))
2261 self.assertEqual(0, ent.indent)
2262 self.assertEqual('main-section', ent.name)
2263 self.assertEqual('section', ent.etype)
2264 self.assertEqual(len(data), ent.size)
2265 self.assertEqual(0, ent.image_pos)
2266 self.assertEqual(None, ent.uncomp_size)
2267 self.assertEqual(0, ent.offset)
2270 self.assertEqual(1, ent.indent)
2271 self.assertEqual('u-boot', ent.name)
2272 self.assertEqual('u-boot', ent.etype)
2273 self.assertEqual(len(U_BOOT_DATA), ent.size)
2274 self.assertEqual(0, ent.image_pos)
2275 self.assertEqual(None, ent.uncomp_size)
2276 self.assertEqual(0, ent.offset)
2279 self.assertEqual(1, ent.indent)
2280 self.assertEqual('section', ent.name)
2281 self.assertEqual('section', ent.etype)
2282 section_size = ent.size
2283 self.assertEqual(0x100, ent.image_pos)
2284 self.assertEqual(None, ent.uncomp_size)
2285 self.assertEqual(0x100, ent.offset)
2288 self.assertEqual(2, ent.indent)
2289 self.assertEqual('cbfs', ent.name)
2290 self.assertEqual('cbfs', ent.etype)
2291 self.assertEqual(0x400, ent.size)
2292 self.assertEqual(0x100, ent.image_pos)
2293 self.assertEqual(None, ent.uncomp_size)
2294 self.assertEqual(0, ent.offset)
2297 self.assertEqual(3, ent.indent)
2298 self.assertEqual('u-boot', ent.name)
2299 self.assertEqual('u-boot', ent.etype)
2300 self.assertEqual(len(U_BOOT_DATA), ent.size)
2301 self.assertEqual(0x138, ent.image_pos)
2302 self.assertEqual(None, ent.uncomp_size)
2303 self.assertEqual(0x38, ent.offset)
2306 self.assertEqual(3, ent.indent)
2307 self.assertEqual('u-boot-dtb', ent.name)
2308 self.assertEqual('text', ent.etype)
2309 self.assertGreater(len(COMPRESS_DATA), ent.size)
2310 self.assertEqual(0x178, ent.image_pos)
2311 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2312 self.assertEqual(0x78, ent.offset)
2315 self.assertEqual(2, ent.indent)
2316 self.assertEqual('u-boot-dtb', ent.name)
2317 self.assertEqual('u-boot-dtb', ent.etype)
2318 self.assertEqual(0x500, ent.image_pos)
2319 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2321 # Compressing this data expands it since headers are added
2322 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2323 self.assertEqual(0x400, ent.offset)
2325 self.assertEqual(len(data), 0x100 + section_size)
2326 self.assertEqual(section_size, 0x400 + dtb_size)
2328 def testFindFdtmap(self):
2329 """Test locating an FDT map in an image"""
2331 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2332 image = control.images['image']
2333 entries = image.GetEntries()
2334 entry = entries['fdtmap']
2335 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2337 def testFindFdtmapMissing(self):
2338 """Test failing to locate an FDP map"""
2339 data = self._DoReadFile('005_simple.dts')
2340 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2342 def testFindImageHeader(self):
2343 """Test locating a image header"""
2345 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2346 image = control.images['image']
2347 entries = image.GetEntries()
2348 entry = entries['fdtmap']
2349 # The header should point to the FDT map
2350 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2352 def testFindImageHeaderStart(self):
2353 """Test locating a image header located at the start of an image"""
2354 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2355 image = control.images['image']
2356 entries = image.GetEntries()
2357 entry = entries['fdtmap']
2358 # The header should point to the FDT map
2359 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2361 def testFindImageHeaderMissing(self):
2362 """Test failing to locate an image header"""
2363 data = self._DoReadFile('005_simple.dts')
2364 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2366 def testReadImage(self):
2367 """Test reading an image and accessing its FDT map"""
2369 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2370 image_fname = tools.GetOutputFilename('image.bin')
2371 orig_image = control.images['image']
2372 image = Image.FromFile(image_fname)
2373 self.assertEqual(orig_image.GetEntries().keys(),
2374 image.GetEntries().keys())
2376 orig_entry = orig_image.GetEntries()['fdtmap']
2377 entry = image.GetEntries()['fdtmap']
2378 self.assertEquals(orig_entry.offset, entry.offset)
2379 self.assertEquals(orig_entry.size, entry.size)
2380 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2382 def testReadImageNoHeader(self):
2383 """Test accessing an image's FDT map without an image header"""
2385 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2386 image_fname = tools.GetOutputFilename('image.bin')
2387 image = Image.FromFile(image_fname)
2388 self.assertTrue(isinstance(image, Image))
2389 self.assertEqual('image', image.image_name[-5:])
2391 def testReadImageFail(self):
2392 """Test failing to read an image image's FDT map"""
2393 self._DoReadFile('005_simple.dts')
2394 image_fname = tools.GetOutputFilename('image.bin')
2395 with self.assertRaises(ValueError) as e:
2396 image = Image.FromFile(image_fname)
2397 self.assertIn("Cannot find FDT map in image", str(e.exception))
2399 def testListCmd(self):
2400 """Test listing the files in an image using an Fdtmap"""
2402 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2404 # lz4 compression size differs depending on the version
2405 image = control.images['image']
2406 entries = image.GetEntries()
2407 section_size = entries['section'].size
2408 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2409 fdtmap_offset = entries['fdtmap'].offset
2412 tmpdir, updated_fname = self._SetupImageInTmpdir()
2413 with test_util.capture_sys_output() as (stdout, stderr):
2414 self._DoBinman('ls', '-i', updated_fname)
2416 shutil.rmtree(tmpdir)
2417 lines = stdout.getvalue().splitlines()
2419 'Name Image-pos Size Entry-type Offset Uncomp-size',
2420 '----------------------------------------------------------------------',
2421 'main-section 0 c00 section 0',
2422 ' u-boot 0 4 u-boot 0',
2423 ' section 100 %x section 100' % section_size,
2424 ' cbfs 100 400 cbfs 0',
2425 ' u-boot 138 4 u-boot 38',
2426 ' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2427 ' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2428 ' fdtmap %x 3b4 fdtmap %x' %
2429 (fdtmap_offset, fdtmap_offset),
2430 ' image-header bf8 8 image-header bf8',
2432 self.assertEqual(expected, lines)
2434 def testListCmdFail(self):
2435 """Test failing to list an image"""
2436 self._DoReadFile('005_simple.dts')
2438 tmpdir, updated_fname = self._SetupImageInTmpdir()
2439 with self.assertRaises(ValueError) as e:
2440 self._DoBinman('ls', '-i', updated_fname)
2442 shutil.rmtree(tmpdir)
2443 self.assertIn("Cannot find FDT map in image", str(e.exception))
2445 def _RunListCmd(self, paths, expected):
2446 """List out entries and check the result
2449 paths: List of paths to pass to the list command
2450 expected: Expected list of filenames to be returned, in order
2453 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2454 image_fname = tools.GetOutputFilename('image.bin')
2455 image = Image.FromFile(image_fname)
2456 lines = image.GetListEntries(paths)[1]
2457 files = [line[0].strip() for line in lines[1:]]
2458 self.assertEqual(expected, files)
2460 def testListCmdSection(self):
2461 """Test listing the files in a section"""
2462 self._RunListCmd(['section'],
2463 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2465 def testListCmdFile(self):
2466 """Test listing a particular file"""
2467 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2469 def testListCmdWildcard(self):
2470 """Test listing a wildcarded file"""
2471 self._RunListCmd(['*boot*'],
2472 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2474 def testListCmdWildcardMulti(self):
2475 """Test listing a wildcarded file"""
2476 self._RunListCmd(['*cb*', '*head*'],
2477 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2479 def testListCmdEmpty(self):
2480 """Test listing a wildcarded file"""
2481 self._RunListCmd(['nothing'], [])
2483 def testListCmdPath(self):
2484 """Test listing the files in a sub-entry of a section"""
2485 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2487 def _RunExtractCmd(self, entry_name, decomp=True):
2488 """Extract an entry from an image
2491 entry_name: Entry name to extract
2492 decomp: True to decompress the data if compressed, False to leave
2493 it in its raw uncompressed format
2499 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2500 image_fname = tools.GetOutputFilename('image.bin')
2501 return control.ReadEntry(image_fname, entry_name, decomp)
2503 def testExtractSimple(self):
2504 """Test extracting a single file"""
2505 data = self._RunExtractCmd('u-boot')
2506 self.assertEqual(U_BOOT_DATA, data)
2508 def testExtractSection(self):
2509 """Test extracting the files in a section"""
2510 data = self._RunExtractCmd('section')
2511 cbfs_data = data[:0x400]
2512 cbfs = cbfs_util.CbfsReader(cbfs_data)
2513 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2514 dtb_data = data[0x400:]
2515 dtb = self._decompress(dtb_data)
2516 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2518 def testExtractCompressed(self):
2519 """Test extracting compressed data"""
2520 data = self._RunExtractCmd('section/u-boot-dtb')
2521 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2523 def testExtractRaw(self):
2524 """Test extracting compressed data without decompressing it"""
2525 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2526 dtb = self._decompress(data)
2527 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2529 def testExtractCbfs(self):
2530 """Test extracting CBFS data"""
2531 data = self._RunExtractCmd('section/cbfs/u-boot')
2532 self.assertEqual(U_BOOT_DATA, data)
2534 def testExtractCbfsCompressed(self):
2535 """Test extracting CBFS compressed data"""
2536 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2537 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2539 def testExtractCbfsRaw(self):
2540 """Test extracting CBFS compressed data without decompressing it"""
2541 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2542 dtb = tools.Decompress(data, 'lzma', with_header=False)
2543 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2545 def testExtractBadEntry(self):
2546 """Test extracting a bad section path"""
2547 with self.assertRaises(ValueError) as e:
2548 self._RunExtractCmd('section/does-not-exist')
2549 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2552 def testExtractMissingFile(self):
2553 """Test extracting file that does not exist"""
2554 with self.assertRaises(IOError) as e:
2555 control.ReadEntry('missing-file', 'name')
2557 def testExtractBadFile(self):
2558 """Test extracting an invalid file"""
2559 fname = os.path.join(self._indir, 'badfile')
2560 tools.WriteFile(fname, b'')
2561 with self.assertRaises(ValueError) as e:
2562 control.ReadEntry(fname, 'name')
2564 def testExtractCmd(self):
2565 """Test extracting a file fron an image on the command line"""
2567 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2568 fname = os.path.join(self._indir, 'output.extact')
2570 tmpdir, updated_fname = self._SetupImageInTmpdir()
2571 with test_util.capture_sys_output() as (stdout, stderr):
2572 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2575 shutil.rmtree(tmpdir)
2576 data = tools.ReadFile(fname)
2577 self.assertEqual(U_BOOT_DATA, data)
2579 def testExtractOneEntry(self):
2580 """Test extracting a single entry fron an image """
2582 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2583 image_fname = tools.GetOutputFilename('image.bin')
2584 fname = os.path.join(self._indir, 'output.extact')
2585 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2586 data = tools.ReadFile(fname)
2587 self.assertEqual(U_BOOT_DATA, data)
2589 def _CheckExtractOutput(self, decomp):
2590 """Helper to test file output with and without decompression
2593 decomp: True to decompress entry data, False to output it raw
2595 def _CheckPresent(entry_path, expect_data, expect_size=None):
2596 """Check and remove expected file
2598 This checks the data/size of a file and removes the file both from
2599 the outfiles set and from the output directory. Once all files are
2600 processed, both the set and directory should be empty.
2603 entry_path: Entry path
2604 expect_data: Data to expect in file, or None to skip check
2605 expect_size: Size of data to expect in file, or None to skip
2607 path = os.path.join(outdir, entry_path)
2608 data = tools.ReadFile(path)
2611 self.assertEqual(expect_data, data)
2613 self.assertEqual(expect_size, len(data))
2614 outfiles.remove(path)
2616 def _CheckDirPresent(name):
2617 """Remove expected directory
2619 This gives an error if the directory does not exist as expected
2622 name: Name of directory to remove
2624 path = os.path.join(outdir, name)
2627 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2628 image_fname = tools.GetOutputFilename('image.bin')
2629 outdir = os.path.join(self._indir, 'extract')
2630 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2632 # Create a set of all file that were output (should be 9)
2634 for root, dirs, files in os.walk(outdir):
2635 outfiles |= set([os.path.join(root, fname) for fname in files])
2636 self.assertEqual(9, len(outfiles))
2637 self.assertEqual(9, len(einfos))
2639 image = control.images['image']
2640 entries = image.GetEntries()
2642 # Check the 9 files in various ways
2643 section = entries['section']
2644 section_entries = section.GetEntries()
2645 cbfs_entries = section_entries['cbfs'].GetEntries()
2646 _CheckPresent('u-boot', U_BOOT_DATA)
2647 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2648 dtb_len = EXTRACT_DTB_SIZE
2650 dtb_len = cbfs_entries['u-boot-dtb'].size
2651 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2653 dtb_len = section_entries['u-boot-dtb'].size
2654 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2656 fdtmap = entries['fdtmap']
2657 _CheckPresent('fdtmap', fdtmap.data)
2658 hdr = entries['image-header']
2659 _CheckPresent('image-header', hdr.data)
2661 _CheckPresent('section/root', section.data)
2662 cbfs = section_entries['cbfs']
2663 _CheckPresent('section/cbfs/root', cbfs.data)
2664 data = tools.ReadFile(image_fname)
2665 _CheckPresent('root', data)
2667 # There should be no files left. Remove all the directories to check.
2668 # If there are any files/dirs remaining, one of these checks will fail.
2669 self.assertEqual(0, len(outfiles))
2670 _CheckDirPresent('section/cbfs')
2671 _CheckDirPresent('section')
2672 _CheckDirPresent('')
2673 self.assertFalse(os.path.exists(outdir))
2675 def testExtractAllEntries(self):
2676 """Test extracting all entries"""
2678 self._CheckExtractOutput(decomp=True)
2680 def testExtractAllEntriesRaw(self):
2681 """Test extracting all entries without decompressing them"""
2683 self._CheckExtractOutput(decomp=False)
2685 def testExtractSelectedEntries(self):
2686 """Test extracting some entries"""
2688 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2689 image_fname = tools.GetOutputFilename('image.bin')
2690 outdir = os.path.join(self._indir, 'extract')
2691 einfos = control.ExtractEntries(image_fname, None, outdir,
2694 # File output is tested by testExtractAllEntries(), so just check that
2695 # the expected entries are selected
2696 names = [einfo.name for einfo in einfos]
2697 self.assertEqual(names,
2698 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2700 def testExtractNoEntryPaths(self):
2701 """Test extracting some entries"""
2703 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2704 image_fname = tools.GetOutputFilename('image.bin')
2705 with self.assertRaises(ValueError) as e:
2706 control.ExtractEntries(image_fname, 'fname', None, [])
2707 self.assertIn('Must specify an entry path to write with -f',
2710 def testExtractTooManyEntryPaths(self):
2711 """Test extracting some entries"""
2713 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2714 image_fname = tools.GetOutputFilename('image.bin')
2715 with self.assertRaises(ValueError) as e:
2716 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2717 self.assertIn('Must specify exactly one entry path to write with -f',
2720 def testPackAlignSection(self):
2721 """Test that sections can have alignment"""
2722 self._DoReadFile('131_pack_align_section.dts')
2724 self.assertIn('image', control.images)
2725 image = control.images['image']
2726 entries = image.GetEntries()
2727 self.assertEqual(3, len(entries))
2730 self.assertIn('u-boot', entries)
2731 entry = entries['u-boot']
2732 self.assertEqual(0, entry.offset)
2733 self.assertEqual(0, entry.image_pos)
2734 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2735 self.assertEqual(len(U_BOOT_DATA), entry.size)
2738 self.assertIn('section0', entries)
2739 section0 = entries['section0']
2740 self.assertEqual(0x10, section0.offset)
2741 self.assertEqual(0x10, section0.image_pos)
2742 self.assertEqual(len(U_BOOT_DATA), section0.size)
2745 section_entries = section0.GetEntries()
2746 self.assertIn('u-boot', section_entries)
2747 entry = section_entries['u-boot']
2748 self.assertEqual(0, entry.offset)
2749 self.assertEqual(0x10, entry.image_pos)
2750 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2751 self.assertEqual(len(U_BOOT_DATA), entry.size)
2754 self.assertIn('section1', entries)
2755 section1 = entries['section1']
2756 self.assertEqual(0x14, section1.offset)
2757 self.assertEqual(0x14, section1.image_pos)
2758 self.assertEqual(0x20, section1.size)
2761 section_entries = section1.GetEntries()
2762 self.assertIn('u-boot', section_entries)
2763 entry = section_entries['u-boot']
2764 self.assertEqual(0, entry.offset)
2765 self.assertEqual(0x14, entry.image_pos)
2766 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2767 self.assertEqual(len(U_BOOT_DATA), entry.size)
2770 self.assertIn('section2', section_entries)
2771 section2 = section_entries['section2']
2772 self.assertEqual(0x4, section2.offset)
2773 self.assertEqual(0x18, section2.image_pos)
2774 self.assertEqual(4, section2.size)
2777 section_entries = section2.GetEntries()
2778 self.assertIn('u-boot', section_entries)
2779 entry = section_entries['u-boot']
2780 self.assertEqual(0, entry.offset)
2781 self.assertEqual(0x18, entry.image_pos)
2782 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2783 self.assertEqual(len(U_BOOT_DATA), entry.size)
2785 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2786 dts='132_replace.dts'):
2787 """Replace an entry in an image
2789 This writes the entry data to update it, then opens the updated file and
2790 returns the value that it now finds there.
2793 entry_name: Entry name to replace
2794 data: Data to replace it with
2795 decomp: True to compress the data if needed, False if data is
2796 already compressed so should be used as is
2797 allow_resize: True to allow entries to change size, False to raise
2803 data from fdtmap (excluding header)
2804 Image object that was modified
2806 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
2809 self.assertIn('image', control.images)
2810 image = control.images['image']
2811 entries = image.GetEntries()
2812 orig_dtb_data = entries['u-boot-dtb'].data
2813 orig_fdtmap_data = entries['fdtmap'].data
2815 image_fname = tools.GetOutputFilename('image.bin')
2816 updated_fname = tools.GetOutputFilename('image-updated.bin')
2817 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2818 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2820 data = control.ReadEntry(updated_fname, entry_name, decomp)
2822 # The DT data should not change unless resized:
2823 if not allow_resize:
2824 new_dtb_data = entries['u-boot-dtb'].data
2825 self.assertEqual(new_dtb_data, orig_dtb_data)
2826 new_fdtmap_data = entries['fdtmap'].data
2827 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
2829 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
2831 def testReplaceSimple(self):
2832 """Test replacing a single file"""
2833 expected = b'x' * len(U_BOOT_DATA)
2834 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2836 self.assertEqual(expected, data)
2838 # Test that the state looks right. There should be an FDT for the fdtmap
2839 # that we jsut read back in, and it should match what we find in the
2840 # 'control' tables. Checking for an FDT that does not exist should
2842 path, fdtmap = state.GetFdtContents('fdtmap')
2843 self.assertIsNotNone(path)
2844 self.assertEqual(expected_fdtmap, fdtmap)
2846 dtb = state.GetFdtForEtype('fdtmap')
2847 self.assertEqual(dtb.GetContents(), fdtmap)
2849 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2850 self.assertIsNone(missing_path)
2851 self.assertIsNone(missing_fdtmap)
2853 missing_dtb = state.GetFdtForEtype('missing')
2854 self.assertIsNone(missing_dtb)
2856 self.assertEqual('/binman', state.fdt_path_prefix)
2858 def testReplaceResizeFail(self):
2859 """Test replacing a file by something larger"""
2860 expected = U_BOOT_DATA + b'x'
2861 with self.assertRaises(ValueError) as e:
2862 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2863 dts='139_replace_repack.dts')
2864 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2867 def testReplaceMulti(self):
2868 """Test replacing entry data where multiple images are generated"""
2869 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2871 expected = b'x' * len(U_BOOT_DATA)
2872 updated_fname = tools.GetOutputFilename('image-updated.bin')
2873 tools.WriteFile(updated_fname, data)
2874 entry_name = 'u-boot'
2875 control.WriteEntry(updated_fname, entry_name, expected,
2877 data = control.ReadEntry(updated_fname, entry_name)
2878 self.assertEqual(expected, data)
2880 # Check the state looks right.
2881 self.assertEqual('/binman/image', state.fdt_path_prefix)
2883 # Now check we can write the first image
2884 image_fname = tools.GetOutputFilename('first-image.bin')
2885 updated_fname = tools.GetOutputFilename('first-updated.bin')
2886 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2887 entry_name = 'u-boot'
2888 control.WriteEntry(updated_fname, entry_name, expected,
2890 data = control.ReadEntry(updated_fname, entry_name)
2891 self.assertEqual(expected, data)
2893 # Check the state looks right.
2894 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
2896 def testUpdateFdtAllRepack(self):
2897 """Test that all device trees are updated with offset/size info"""
2898 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2899 SECTION_SIZE = 0x300
2904 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2906 'section:offset': 0,
2907 'section:size': SECTION_SIZE,
2908 'section:image-pos': 0,
2909 'section/u-boot-dtb:offset': 4,
2910 'section/u-boot-dtb:size': 636,
2911 'section/u-boot-dtb:image-pos': 4,
2912 'u-boot-spl-dtb:offset': SECTION_SIZE,
2913 'u-boot-spl-dtb:size': DTB_SIZE,
2914 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2915 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2916 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2917 'u-boot-tpl-dtb:size': DTB_SIZE,
2918 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2919 'fdtmap:size': FDTMAP_SIZE,
2920 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2923 'section:orig-size': SECTION_SIZE,
2924 'section/u-boot-dtb:orig-offset': 4,
2927 # We expect three device-tree files in the output, with the first one
2928 # within a fixed-size section.
2929 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2930 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2931 # main U-Boot tree. All three should have the same positions and offset
2932 # except that the main tree should include the main_expected properties
2934 for item in ['', 'spl', 'tpl', None]:
2936 start += 16 # Move past fdtmap header
2937 dtb = fdt.Fdt.FromData(data[start:])
2939 props = self._GetPropTree(dtb,
2940 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2941 prefix='/' if item is None else '/binman/')
2942 expected = dict(base_expected)
2946 # Main DTB and fdtdec should include the 'orig-' properties
2947 expected.update(main_expected)
2948 # Helpful for debugging:
2949 #for prop in sorted(props):
2950 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2951 self.assertEqual(expected, props)
2953 start = SECTION_SIZE
2955 start += dtb._fdt_obj.totalsize()
2957 def testFdtmapHeaderMiddle(self):
2958 """Test an FDT map in the middle of an image when it should be at end"""
2959 with self.assertRaises(ValueError) as e:
2960 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2961 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2964 def testFdtmapHeaderStartBad(self):
2965 """Test an FDT map in middle of an image when it should be at start"""
2966 with self.assertRaises(ValueError) as e:
2967 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2968 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2971 def testFdtmapHeaderEndBad(self):
2972 """Test an FDT map at the start of an image when it should be at end"""
2973 with self.assertRaises(ValueError) as e:
2974 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2975 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2978 def testFdtmapHeaderNoSize(self):
2979 """Test an image header at the end of an image with undefined size"""
2980 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2982 def testReplaceResize(self):
2983 """Test replacing a single file in an entry with a larger file"""
2984 expected = U_BOOT_DATA + b'x'
2985 data, _, image = self._RunReplaceCmd('u-boot', expected,
2986 dts='139_replace_repack.dts')
2987 self.assertEqual(expected, data)
2989 entries = image.GetEntries()
2990 dtb_data = entries['u-boot-dtb'].data
2991 dtb = fdt.Fdt.FromData(dtb_data)
2994 # The u-boot section should now be larger in the dtb
2995 node = dtb.GetNode('/binman/u-boot')
2996 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
2998 # Same for the fdtmap
2999 fdata = entries['fdtmap'].data
3000 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3002 fnode = fdtb.GetNode('/u-boot')
3003 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3005 def testReplaceResizeNoRepack(self):
3006 """Test replacing an entry with a larger file when not allowed"""
3007 expected = U_BOOT_DATA + b'x'
3008 with self.assertRaises(ValueError) as e:
3009 self._RunReplaceCmd('u-boot', expected)
3010 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3013 def testEntryShrink(self):
3014 """Test contracting an entry after it is packed"""
3016 state.SetAllowEntryContraction(True)
3017 data = self._DoReadFileDtb('140_entry_shrink.dts',
3020 state.SetAllowEntryContraction(False)
3021 self.assertEqual(b'a', data[:1])
3022 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3023 self.assertEqual(b'a', data[-1:])
3025 def testEntryShrinkFail(self):
3026 """Test not being allowed to contract an entry after it is packed"""
3027 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3029 # In this case there is a spare byte at the end of the data. The size of
3030 # the contents is only 1 byte but we still have the size before it
3032 self.assertEqual(b'a\0', data[:2])
3033 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3034 self.assertEqual(b'a\0', data[-2:])
3036 def testDescriptorOffset(self):
3037 """Test that the Intel descriptor is always placed at at the start"""
3038 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3039 image = control.images['image']
3040 entries = image.GetEntries()
3041 desc = entries['intel-descriptor']
3042 self.assertEqual(0xff800000, desc.offset);
3043 self.assertEqual(0xff800000, desc.image_pos);
3045 def testReplaceCbfs(self):
3046 """Test replacing a single file in CBFS without changing the size"""
3048 expected = b'x' * len(U_BOOT_DATA)
3049 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3050 updated_fname = tools.GetOutputFilename('image-updated.bin')
3051 tools.WriteFile(updated_fname, data)
3052 entry_name = 'section/cbfs/u-boot'
3053 control.WriteEntry(updated_fname, entry_name, expected,
3055 data = control.ReadEntry(updated_fname, entry_name)
3056 self.assertEqual(expected, data)
3058 def testReplaceResizeCbfs(self):
3059 """Test replacing a single file in CBFS with one of a different size"""
3061 expected = U_BOOT_DATA + b'x'
3062 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3063 updated_fname = tools.GetOutputFilename('image-updated.bin')
3064 tools.WriteFile(updated_fname, data)
3065 entry_name = 'section/cbfs/u-boot'
3066 control.WriteEntry(updated_fname, entry_name, expected,
3068 data = control.ReadEntry(updated_fname, entry_name)
3069 self.assertEqual(expected, data)
3071 def _SetupForReplace(self):
3072 """Set up some files to use to replace entries
3074 This generates an image, copies it to a new file, extracts all the files
3075 in it and updates some of them
3081 Expected values for updated entries, each a string
3083 data = self._DoReadFileRealDtb('143_replace_all.dts')
3085 updated_fname = tools.GetOutputFilename('image-updated.bin')
3086 tools.WriteFile(updated_fname, data)
3088 outdir = os.path.join(self._indir, 'extract')
3089 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3091 expected1 = b'x' + U_BOOT_DATA + b'y'
3092 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3093 tools.WriteFile(u_boot_fname1, expected1)
3095 expected2 = b'a' + U_BOOT_DATA + b'b'
3096 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3097 tools.WriteFile(u_boot_fname2, expected2)
3099 expected_text = b'not the same text'
3100 text_fname = os.path.join(outdir, 'text')
3101 tools.WriteFile(text_fname, expected_text)
3103 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3104 dtb = fdt.FdtScan(dtb_fname)
3105 node = dtb.GetNode('/binman/text')
3106 node.AddString('my-property', 'the value')
3107 dtb.Sync(auto_resize=True)
3110 return updated_fname, outdir, expected1, expected2, expected_text
3112 def _CheckReplaceMultiple(self, entry_paths):
3113 """Handle replacing the contents of multiple entries
3116 entry_paths: List of entry paths to replace
3120 Dict of entries in the image:
3123 Expected values for updated entries, each a string
3125 updated_fname, outdir, expected1, expected2, expected_text = (
3126 self._SetupForReplace())
3127 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3129 image = Image.FromFile(updated_fname)
3131 return image.GetEntries(), expected1, expected2, expected_text
3133 def testReplaceAll(self):
3134 """Test replacing the contents of all entries"""
3135 entries, expected1, expected2, expected_text = (
3136 self._CheckReplaceMultiple([]))
3137 data = entries['u-boot'].data
3138 self.assertEqual(expected1, data)
3140 data = entries['u-boot2'].data
3141 self.assertEqual(expected2, data)
3143 data = entries['text'].data
3144 self.assertEqual(expected_text, data)
3146 # Check that the device tree is updated
3147 data = entries['u-boot-dtb'].data
3148 dtb = fdt.Fdt.FromData(data)
3150 node = dtb.GetNode('/binman/text')
3151 self.assertEqual('the value', node.props['my-property'].value)
3153 def testReplaceSome(self):
3154 """Test replacing the contents of a few entries"""
3155 entries, expected1, expected2, expected_text = (
3156 self._CheckReplaceMultiple(['u-boot2', 'text']))
3158 # This one should not change
3159 data = entries['u-boot'].data
3160 self.assertEqual(U_BOOT_DATA, data)
3162 data = entries['u-boot2'].data
3163 self.assertEqual(expected2, data)
3165 data = entries['text'].data
3166 self.assertEqual(expected_text, data)
3168 def testReplaceCmd(self):
3169 """Test replacing a file fron an image on the command line"""
3170 self._DoReadFileRealDtb('143_replace_all.dts')
3173 tmpdir, updated_fname = self._SetupImageInTmpdir()
3175 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3176 expected = b'x' * len(U_BOOT_DATA)
3177 tools.WriteFile(fname, expected)
3179 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3180 data = tools.ReadFile(updated_fname)
3181 self.assertEqual(expected, data[:len(expected)])
3182 map_fname = os.path.join(tmpdir, 'image-updated.map')
3183 self.assertFalse(os.path.exists(map_fname))
3185 shutil.rmtree(tmpdir)
3187 def testReplaceCmdSome(self):
3188 """Test replacing some files fron an image on the command line"""
3189 updated_fname, outdir, expected1, expected2, expected_text = (
3190 self._SetupForReplace())
3192 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3195 tools.PrepareOutputDir(None)
3196 image = Image.FromFile(updated_fname)
3198 entries = image.GetEntries()
3200 # This one should not change
3201 data = entries['u-boot'].data
3202 self.assertEqual(U_BOOT_DATA, data)
3204 data = entries['u-boot2'].data
3205 self.assertEqual(expected2, data)
3207 data = entries['text'].data
3208 self.assertEqual(expected_text, data)
3210 def testReplaceMissing(self):
3211 """Test replacing entries where the file is missing"""
3212 updated_fname, outdir, expected1, expected2, expected_text = (
3213 self._SetupForReplace())
3215 # Remove one of the files, to generate a warning
3216 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3217 os.remove(u_boot_fname1)
3219 with test_util.capture_sys_output() as (stdout, stderr):
3220 control.ReplaceEntries(updated_fname, None, outdir, [])
3221 self.assertIn("Skipping entry '/u-boot' from missing file",
3224 def testReplaceCmdMap(self):
3225 """Test replacing a file fron an image on the command line"""
3226 self._DoReadFileRealDtb('143_replace_all.dts')
3229 tmpdir, updated_fname = self._SetupImageInTmpdir()
3231 fname = os.path.join(self._indir, 'update-u-boot.bin')
3232 expected = b'x' * len(U_BOOT_DATA)
3233 tools.WriteFile(fname, expected)
3235 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3237 map_fname = os.path.join(tmpdir, 'image-updated.map')
3238 self.assertTrue(os.path.exists(map_fname))
3240 shutil.rmtree(tmpdir)
3242 def testReplaceNoEntryPaths(self):
3243 """Test replacing an entry without an entry path"""
3244 self._DoReadFileRealDtb('143_replace_all.dts')
3245 image_fname = tools.GetOutputFilename('image.bin')
3246 with self.assertRaises(ValueError) as e:
3247 control.ReplaceEntries(image_fname, 'fname', None, [])
3248 self.assertIn('Must specify an entry path to read with -f',
3251 def testReplaceTooManyEntryPaths(self):
3252 """Test extracting some entries"""
3253 self._DoReadFileRealDtb('143_replace_all.dts')
3254 image_fname = tools.GetOutputFilename('image.bin')
3255 with self.assertRaises(ValueError) as e:
3256 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3257 self.assertIn('Must specify exactly one entry path to write with -f',
3260 def testPackReset16(self):
3261 """Test that an image with an x86 reset16 region can be created"""
3262 data = self._DoReadFile('144_x86_reset16.dts')
3263 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3265 def testPackReset16Spl(self):
3266 """Test that an image with an x86 reset16-spl region can be created"""
3267 data = self._DoReadFile('145_x86_reset16_spl.dts')
3268 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3270 def testPackReset16Tpl(self):
3271 """Test that an image with an x86 reset16-tpl region can be created"""
3272 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3273 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3275 def testPackIntelFit(self):
3276 """Test that an image with an Intel FIT and pointer can be created"""
3277 data = self._DoReadFile('147_intel_fit.dts')
3278 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3280 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3281 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3283 image = control.images['image']
3284 entries = image.GetEntries()
3285 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3286 self.assertEqual(expected_ptr, ptr)
3288 def testPackIntelFitMissing(self):
3289 """Test detection of a FIT pointer with not FIT region"""
3290 with self.assertRaises(ValueError) as e:
3291 self._DoReadFile('148_intel_fit_missing.dts')
3292 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3296 if __name__ == "__main__":