1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2016 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # To run a single test, change to this directory, and:
7 # python -m unittest func_test.TestFunctional.testHelp
9 from __future__ import print_function
12 from optparse import OptionParser
27 from etype import fdtmap
28 from etype import image_header
33 from image import Image
38 # Contents of test files, corresponding to different entry types
40 U_BOOT_IMG_DATA = b'img'
41 U_BOOT_SPL_DATA = b'56780123456789abcde'
42 U_BOOT_TPL_DATA = b'tpl'
46 U_BOOT_DTB_DATA = b'udtb'
47 U_BOOT_SPL_DTB_DATA = b'spldtb'
48 U_BOOT_TPL_DTB_DATA = b'tpldtb'
49 X86_START16_DATA = b'start16'
50 X86_START16_SPL_DATA = b'start16spl'
51 X86_START16_TPL_DATA = b'start16tpl'
52 PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
53 U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
54 U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
55 U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
63 CROS_EC_RW_DATA = b'ecrw'
67 FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
68 b"sorry you're alive\n")
69 COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
70 REFCODE_DATA = b'refcode'
73 class TestFunctional(unittest.TestCase):
74 """Functional tests for binman
76 Most of these use a sample .dts file to build an image and then check
77 that it looks correct. The sample files are in the test/ subdirectory
80 For each entry type a very small test file is created using fixed
81 string contents. This makes it easy to test that things look right, and
84 In some cases a 'real' file must be used - these are also supplied in
92 # Handle the case where argv[0] is 'python'
93 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
94 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
96 # Create a temporary directory for input files
97 self._indir = tempfile.mkdtemp(prefix='binmant.')
99 # Create some test files
100 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
101 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
102 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
103 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
104 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
105 TestFunctional._MakeInputFile('me.bin', ME_DATA)
106 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
108 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
109 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
110 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
111 X86_START16_SPL_DATA)
112 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
113 X86_START16_TPL_DATA)
114 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
115 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
116 U_BOOT_SPL_NODTB_DATA)
117 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
118 U_BOOT_TPL_NODTB_DATA)
119 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
120 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
121 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
122 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
123 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
124 TestFunctional._MakeInputDir('devkeys')
125 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
126 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
128 # ELF file with a '_dt_ucode_base_size' symbol
129 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
130 TestFunctional._MakeInputFile('u-boot', fd.read())
132 # Intel flash descriptor file
133 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
134 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
136 shutil.copytree(self.TestFile('files'),
137 os.path.join(self._indir, 'files'))
139 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
141 # Travis-CI may have an old lz4
144 tools.Run('lz4', '--no-frame-crc', '-c',
145 os.path.join(self._indir, 'u-boot.bin'))
147 self.have_lz4 = False
150 def tearDownClass(self):
151 """Remove the temporary input directory and its contents"""
152 if self.preserve_indir:
153 print('Preserving input dir: %s' % self._indir)
156 shutil.rmtree(self._indir)
160 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
161 toolpath=None, verbosity=None):
162 """Accept arguments controlling test execution
165 preserve_indir: Preserve the shared input directory used by all
167 preserve_outdir: Preserve the output directories used by tests. Each
168 test has its own, so this is normally only useful when running a
170 toolpath: ist of paths to use for tools
172 cls.preserve_indir = preserve_indir
173 cls.preserve_outdirs = preserve_outdirs
174 cls.toolpath = toolpath
175 cls.verbosity = verbosity
178 if not self.have_lz4:
179 self.skipTest('lz4 --no-frame-crc not available')
182 # Enable this to turn on debugging output
183 # tout.Init(tout.DEBUG)
184 command.test_result = None
187 """Remove the temporary output directory"""
188 if self.preserve_outdirs:
189 print('Preserving output dir: %s' % tools.outdir)
191 tools._FinaliseForTest()
194 def _ResetDtbs(self):
195 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
196 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
197 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
199 def _RunBinman(self, *args, **kwargs):
200 """Run binman using the command line
203 Arguments to pass, as a list of strings
204 kwargs: Arguments to pass to Command.RunPipe()
206 result = command.RunPipe([[self._binman_pathname] + list(args)],
207 capture=True, capture_stderr=True, raise_on_error=False)
208 if result.return_code and kwargs.get('raise_on_error', True):
209 raise Exception("Error running '%s': %s" % (' '.join(args),
210 result.stdout + result.stderr))
213 def _DoBinman(self, *argv):
214 """Run binman using directly (in the same process)
217 Arguments to pass, as a list of strings
219 Return value (0 for success)
222 args = cmdline.ParseArgs(argv)
223 args.pager = 'binman-invalid-pager'
224 args.build_dir = self._indir
226 # For testing, you can force an increase in verbosity here
227 # args.verbosity = tout.DEBUG
228 return control.Binman(args)
230 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
231 entry_args=None, images=None, use_real_dtb=False,
233 """Run binman with a given test file
236 fname: Device-tree source filename to use (e.g. 005_simple.dts)
237 debug: True to enable debugging output
238 map: True to output map files for the images
239 update_dtb: Update the offset and size of each entry in the device
240 tree before packing it into the image
241 entry_args: Dict of entry args to supply to binman
243 value: value of that arg
244 images: List of image names to build
249 if verbosity is not None:
250 args.append('-v%d' % verbosity)
252 args.append('-v%d' % self.verbosity)
254 for path in self.toolpath:
255 args += ['--toolpath', path]
256 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
262 args.append('--fake-dtb')
264 for arg, value in entry_args.items():
265 args.append('-a%s=%s' % (arg, value))
268 args += ['-i', image]
269 return self._DoBinman(*args)
271 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
272 """Set up a new test device-tree file
274 The given file is compiled and set up as the device tree to be used
278 fname: Filename of .dts file to read
279 outfile: Output filename for compiled device-tree binary
282 Contents of device-tree binary
284 tools.PrepareOutputDir(None)
285 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
286 with open(dtb, 'rb') as fd:
288 TestFunctional._MakeInputFile(outfile, data)
289 tools.FinaliseOutputDir()
292 def _GetDtbContentsForSplTpl(self, dtb_data, name):
293 """Create a version of the main DTB for SPL or SPL
295 For testing we don't actually have different versions of the DTB. With
296 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
297 we don't normally have any unwanted nodes.
299 We still want the DTBs for SPL and TPL to be different though, since
300 otherwise it is confusing to know which one we are looking at. So add
301 an 'spl' or 'tpl' property to the top-level node.
303 dtb = fdt.Fdt.FromData(dtb_data)
305 dtb.GetNode('/binman').AddZeroProp(name)
306 dtb.Sync(auto_resize=True)
308 return dtb.GetContents()
310 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
311 update_dtb=False, entry_args=None, reset_dtbs=True):
312 """Run binman and return the resulting image
314 This runs binman with a given test file and then reads the resulting
315 output file. It is a shortcut function since most tests need to do
318 Raises an assertion failure if binman returns a non-zero exit code.
321 fname: Device-tree source filename to use (e.g. 005_simple.dts)
322 use_real_dtb: True to use the test file as the contents of
323 the u-boot-dtb entry. Normally this is not needed and the
324 test contents (the U_BOOT_DTB_DATA string) can be used.
325 But in some test we need the real contents.
326 map: True to output map files for the images
327 update_dtb: Update the offset and size of each entry in the device
328 tree before packing it into the image
332 Resulting image contents
334 Map data showing contents of image (or None if none)
335 Output device tree binary filename ('u-boot.dtb' path)
338 # Use the compiled test file as the u-boot-dtb input
340 dtb_data = self._SetupDtb(fname)
342 # For testing purposes, make a copy of the DT for SPL and TPL. Add
343 # a node indicating which it is, so aid verification.
344 for name in ['spl', 'tpl']:
345 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
346 outfile = os.path.join(self._indir, dtb_fname)
347 TestFunctional._MakeInputFile(dtb_fname,
348 self._GetDtbContentsForSplTpl(dtb_data, name))
351 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
352 entry_args=entry_args, use_real_dtb=use_real_dtb)
353 self.assertEqual(0, retcode)
354 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
356 # Find the (only) image, read it and return its contents
357 image = control.images['image']
358 image_fname = tools.GetOutputFilename('image.bin')
359 self.assertTrue(os.path.exists(image_fname))
361 map_fname = tools.GetOutputFilename('image.map')
362 with open(map_fname) as fd:
366 with open(image_fname, 'rb') as fd:
367 return fd.read(), dtb_data, map_data, out_dtb_fname
369 # Put the test file back
370 if reset_dtbs and use_real_dtb:
373 def _DoReadFileRealDtb(self, fname):
374 """Run binman with a real .dtb file and return the resulting data
377 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
380 Resulting image contents
382 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
384 def _DoReadFile(self, fname, use_real_dtb=False):
385 """Helper function which discards the device-tree binary
388 fname: Device-tree source filename to use (e.g. 005_simple.dts)
389 use_real_dtb: True to use the test file as the contents of
390 the u-boot-dtb entry. Normally this is not needed and the
391 test contents (the U_BOOT_DTB_DATA string) can be used.
392 But in some test we need the real contents.
395 Resulting image contents
397 return self._DoReadFileDtb(fname, use_real_dtb)[0]
400 def _MakeInputFile(self, fname, contents):
401 """Create a new test input file, creating directories as needed
404 fname: Filename to create
405 contents: File contents to write in to the file
407 Full pathname of file created
409 pathname = os.path.join(self._indir, fname)
410 dirname = os.path.dirname(pathname)
411 if dirname and not os.path.exists(dirname):
413 with open(pathname, 'wb') as fd:
418 def _MakeInputDir(self, dirname):
419 """Create a new test input directory, creating directories as needed
422 dirname: Directory name to create
425 Full pathname of directory created
427 pathname = os.path.join(self._indir, dirname)
428 if not os.path.exists(pathname):
429 os.makedirs(pathname)
433 def _SetupSplElf(self, src_fname='bss_data'):
434 """Set up an ELF file with a '_dt_ucode_base_size' symbol
437 Filename of ELF file to use as SPL
439 with open(self.TestFile(src_fname), 'rb') as fd:
440 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
443 def TestFile(self, fname):
444 return os.path.join(self._binman_dir, 'test', fname)
446 def AssertInList(self, grep_list, target):
447 """Assert that at least one of a list of things is in a target
450 grep_list: List of strings to check
451 target: Target string
453 for grep in grep_list:
456 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
458 def CheckNoGaps(self, entries):
459 """Check that all entries fit together without gaps
462 entries: List of entries to check
465 for entry in entries.values():
466 self.assertEqual(offset, entry.offset)
469 def GetFdtLen(self, dtb):
470 """Get the totalsize field from a device-tree binary
473 dtb: Device-tree binary contents
476 Total size of device-tree binary, from the header
478 return struct.unpack('>L', dtb[4:8])[0]
480 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
481 def AddNode(node, path):
483 path += '/' + node.name
484 for prop in node.props.values():
485 if prop.name in prop_names:
486 prop_path = path + ':' + prop.name
487 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
489 for subnode in node.subnodes:
490 AddNode(subnode, path)
493 AddNode(dtb.GetRoot(), '')
497 """Test a basic run with valid args"""
498 result = self._RunBinman('-h')
500 def testFullHelp(self):
501 """Test that the full help is displayed with -H"""
502 result = self._RunBinman('-H')
503 help_file = os.path.join(self._binman_dir, 'README')
504 # Remove possible extraneous strings
505 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
506 gothelp = result.stdout.replace(extra, '')
507 self.assertEqual(len(gothelp), os.path.getsize(help_file))
508 self.assertEqual(0, len(result.stderr))
509 self.assertEqual(0, result.return_code)
511 def testFullHelpInternal(self):
512 """Test that the full help is displayed with -H"""
514 command.test_result = command.CommandResult()
515 result = self._DoBinman('-H')
516 help_file = os.path.join(self._binman_dir, 'README')
518 command.test_result = None
521 """Test that the basic help is displayed with -h"""
522 result = self._RunBinman('-h')
523 self.assertTrue(len(result.stdout) > 200)
524 self.assertEqual(0, len(result.stderr))
525 self.assertEqual(0, result.return_code)
528 """Test that we can run it with a specific board"""
529 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
530 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
531 result = self._DoBinman('build', '-b', 'sandbox')
532 self.assertEqual(0, result)
534 def testNeedBoard(self):
535 """Test that we get an error when no board ius supplied"""
536 with self.assertRaises(ValueError) as e:
537 result = self._DoBinman('build')
538 self.assertIn("Must provide a board to process (use -b <board>)",
541 def testMissingDt(self):
542 """Test that an invalid device-tree file generates an error"""
543 with self.assertRaises(Exception) as e:
544 self._RunBinman('build', '-d', 'missing_file')
545 # We get one error from libfdt, and a different one from fdtget.
546 self.AssertInList(["Couldn't open blob from 'missing_file'",
547 'No such file or directory'], str(e.exception))
549 def testBrokenDt(self):
550 """Test that an invalid device-tree source file generates an error
552 Since this is a source file it should be compiled and the error
553 will come from the device-tree compiler (dtc).
555 with self.assertRaises(Exception) as e:
556 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
557 self.assertIn("FATAL ERROR: Unable to parse input tree",
560 def testMissingNode(self):
561 """Test that a device tree without a 'binman' node generates an error"""
562 with self.assertRaises(Exception) as e:
563 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
564 self.assertIn("does not have a 'binman' node", str(e.exception))
567 """Test that an empty binman node works OK (i.e. does nothing)"""
568 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
569 self.assertEqual(0, len(result.stderr))
570 self.assertEqual(0, result.return_code)
572 def testInvalidEntry(self):
573 """Test that an invalid entry is flagged"""
574 with self.assertRaises(Exception) as e:
575 result = self._RunBinman('build', '-d',
576 self.TestFile('004_invalid_entry.dts'))
577 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
578 "'/binman/not-a-valid-type'", str(e.exception))
580 def testSimple(self):
581 """Test a simple binman with a single file"""
582 data = self._DoReadFile('005_simple.dts')
583 self.assertEqual(U_BOOT_DATA, data)
585 def testSimpleDebug(self):
586 """Test a simple binman run with debugging enabled"""
587 data = self._DoTestFile('005_simple.dts', debug=True)
590 """Test that we can handle creating two images
592 This also tests image padding.
594 retcode = self._DoTestFile('006_dual_image.dts')
595 self.assertEqual(0, retcode)
597 image = control.images['image1']
598 self.assertEqual(len(U_BOOT_DATA), image._size)
599 fname = tools.GetOutputFilename('image1.bin')
600 self.assertTrue(os.path.exists(fname))
601 with open(fname, 'rb') as fd:
603 self.assertEqual(U_BOOT_DATA, data)
605 image = control.images['image2']
606 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
607 fname = tools.GetOutputFilename('image2.bin')
608 self.assertTrue(os.path.exists(fname))
609 with open(fname, 'rb') as fd:
611 self.assertEqual(U_BOOT_DATA, data[3:7])
612 self.assertEqual(tools.GetBytes(0, 3), data[:3])
613 self.assertEqual(tools.GetBytes(0, 5), data[7:])
615 def testBadAlign(self):
616 """Test that an invalid alignment value is detected"""
617 with self.assertRaises(ValueError) as e:
618 self._DoTestFile('007_bad_align.dts')
619 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
620 "of two", str(e.exception))
622 def testPackSimple(self):
623 """Test that packing works as expected"""
624 retcode = self._DoTestFile('008_pack.dts')
625 self.assertEqual(0, retcode)
626 self.assertIn('image', control.images)
627 image = control.images['image']
628 entries = image.GetEntries()
629 self.assertEqual(5, len(entries))
632 self.assertIn('u-boot', entries)
633 entry = entries['u-boot']
634 self.assertEqual(0, entry.offset)
635 self.assertEqual(len(U_BOOT_DATA), entry.size)
637 # Second u-boot, aligned to 16-byte boundary
638 self.assertIn('u-boot-align', entries)
639 entry = entries['u-boot-align']
640 self.assertEqual(16, entry.offset)
641 self.assertEqual(len(U_BOOT_DATA), entry.size)
643 # Third u-boot, size 23 bytes
644 self.assertIn('u-boot-size', entries)
645 entry = entries['u-boot-size']
646 self.assertEqual(20, entry.offset)
647 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
648 self.assertEqual(23, entry.size)
650 # Fourth u-boot, placed immediate after the above
651 self.assertIn('u-boot-next', entries)
652 entry = entries['u-boot-next']
653 self.assertEqual(43, entry.offset)
654 self.assertEqual(len(U_BOOT_DATA), entry.size)
656 # Fifth u-boot, placed at a fixed offset
657 self.assertIn('u-boot-fixed', entries)
658 entry = entries['u-boot-fixed']
659 self.assertEqual(61, entry.offset)
660 self.assertEqual(len(U_BOOT_DATA), entry.size)
662 self.assertEqual(65, image._size)
664 def testPackExtra(self):
665 """Test that extra packing feature works as expected"""
666 retcode = self._DoTestFile('009_pack_extra.dts')
668 self.assertEqual(0, retcode)
669 self.assertIn('image', control.images)
670 image = control.images['image']
671 entries = image.GetEntries()
672 self.assertEqual(5, len(entries))
674 # First u-boot with padding before and after
675 self.assertIn('u-boot', entries)
676 entry = entries['u-boot']
677 self.assertEqual(0, entry.offset)
678 self.assertEqual(3, entry.pad_before)
679 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
681 # Second u-boot has an aligned size, but it has no effect
682 self.assertIn('u-boot-align-size-nop', entries)
683 entry = entries['u-boot-align-size-nop']
684 self.assertEqual(12, entry.offset)
685 self.assertEqual(4, entry.size)
687 # Third u-boot has an aligned size too
688 self.assertIn('u-boot-align-size', entries)
689 entry = entries['u-boot-align-size']
690 self.assertEqual(16, entry.offset)
691 self.assertEqual(32, entry.size)
693 # Fourth u-boot has an aligned end
694 self.assertIn('u-boot-align-end', entries)
695 entry = entries['u-boot-align-end']
696 self.assertEqual(48, entry.offset)
697 self.assertEqual(16, entry.size)
699 # Fifth u-boot immediately afterwards
700 self.assertIn('u-boot-align-both', entries)
701 entry = entries['u-boot-align-both']
702 self.assertEqual(64, entry.offset)
703 self.assertEqual(64, entry.size)
705 self.CheckNoGaps(entries)
706 self.assertEqual(128, image._size)
708 def testPackAlignPowerOf2(self):
709 """Test that invalid entry alignment is detected"""
710 with self.assertRaises(ValueError) as e:
711 self._DoTestFile('010_pack_align_power2.dts')
712 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
713 "of two", str(e.exception))
715 def testPackAlignSizePowerOf2(self):
716 """Test that invalid entry size alignment is detected"""
717 with self.assertRaises(ValueError) as e:
718 self._DoTestFile('011_pack_align_size_power2.dts')
719 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
720 "power of two", str(e.exception))
722 def testPackInvalidAlign(self):
723 """Test detection of an offset that does not match its alignment"""
724 with self.assertRaises(ValueError) as e:
725 self._DoTestFile('012_pack_inv_align.dts')
726 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
727 "align 0x4 (4)", str(e.exception))
729 def testPackInvalidSizeAlign(self):
730 """Test that invalid entry size alignment is detected"""
731 with self.assertRaises(ValueError) as e:
732 self._DoTestFile('013_pack_inv_size_align.dts')
733 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
734 "align-size 0x4 (4)", str(e.exception))
736 def testPackOverlap(self):
737 """Test that overlapping regions are detected"""
738 with self.assertRaises(ValueError) as e:
739 self._DoTestFile('014_pack_overlap.dts')
740 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
741 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
744 def testPackEntryOverflow(self):
745 """Test that entries that overflow their size are detected"""
746 with self.assertRaises(ValueError) as e:
747 self._DoTestFile('015_pack_overflow.dts')
748 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
749 "but entry size is 0x3 (3)", str(e.exception))
751 def testPackImageOverflow(self):
752 """Test that entries which overflow the image size are detected"""
753 with self.assertRaises(ValueError) as e:
754 self._DoTestFile('016_pack_image_overflow.dts')
755 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
756 "size 0x3 (3)", str(e.exception))
758 def testPackImageSize(self):
759 """Test that the image size can be set"""
760 retcode = self._DoTestFile('017_pack_image_size.dts')
761 self.assertEqual(0, retcode)
762 self.assertIn('image', control.images)
763 image = control.images['image']
764 self.assertEqual(7, image._size)
766 def testPackImageSizeAlign(self):
767 """Test that image size alignemnt works as expected"""
768 retcode = self._DoTestFile('018_pack_image_align.dts')
769 self.assertEqual(0, retcode)
770 self.assertIn('image', control.images)
771 image = control.images['image']
772 self.assertEqual(16, image._size)
774 def testPackInvalidImageAlign(self):
775 """Test that invalid image alignment is detected"""
776 with self.assertRaises(ValueError) as e:
777 self._DoTestFile('019_pack_inv_image_align.dts')
778 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
779 "align-size 0x8 (8)", str(e.exception))
781 def testPackAlignPowerOf2(self):
782 """Test that invalid image alignment is detected"""
783 with self.assertRaises(ValueError) as e:
784 self._DoTestFile('020_pack_inv_image_align_power2.dts')
785 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
786 "two", str(e.exception))
788 def testImagePadByte(self):
789 """Test that the image pad byte can be specified"""
791 data = self._DoReadFile('021_image_pad.dts')
792 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
795 def testImageName(self):
796 """Test that image files can be named"""
797 retcode = self._DoTestFile('022_image_name.dts')
798 self.assertEqual(0, retcode)
799 image = control.images['image1']
800 fname = tools.GetOutputFilename('test-name')
801 self.assertTrue(os.path.exists(fname))
803 image = control.images['image2']
804 fname = tools.GetOutputFilename('test-name.xx')
805 self.assertTrue(os.path.exists(fname))
807 def testBlobFilename(self):
808 """Test that generic blobs can be provided by filename"""
809 data = self._DoReadFile('023_blob.dts')
810 self.assertEqual(BLOB_DATA, data)
812 def testPackSorted(self):
813 """Test that entries can be sorted"""
815 data = self._DoReadFile('024_sorted.dts')
816 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
817 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
819 def testPackZeroOffset(self):
820 """Test that an entry at offset 0 is not given a new offset"""
821 with self.assertRaises(ValueError) as e:
822 self._DoTestFile('025_pack_zero_size.dts')
823 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
824 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
827 def testPackUbootDtb(self):
828 """Test that a device tree can be added to U-Boot"""
829 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
830 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
832 def testPackX86RomNoSize(self):
833 """Test that the end-at-4gb property requires a size property"""
834 with self.assertRaises(ValueError) as e:
835 self._DoTestFile('027_pack_4gb_no_size.dts')
836 self.assertIn("Section '/binman': Section size must be provided when "
837 "using end-at-4gb", str(e.exception))
839 def test4gbAndSkipAtStartTogether(self):
840 """Test that the end-at-4gb and skip-at-size property can't be used
842 with self.assertRaises(ValueError) as e:
843 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
844 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
845 "'skip-at-start'", str(e.exception))
847 def testPackX86RomOutside(self):
848 """Test that the end-at-4gb property checks for offset boundaries"""
849 with self.assertRaises(ValueError) as e:
850 self._DoTestFile('028_pack_4gb_outside.dts')
851 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
852 "the section starting at 0xffffffe0 (4294967264)",
855 def testPackX86Rom(self):
856 """Test that a basic x86 ROM can be created"""
858 data = self._DoReadFile('029_x86-rom.dts')
859 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
860 tools.GetBytes(0, 2), data)
862 def testPackX86RomMeNoDesc(self):
863 """Test that an invalid Intel descriptor entry is detected"""
864 TestFunctional._MakeInputFile('descriptor.bin', b'')
865 with self.assertRaises(ValueError) as e:
866 self._DoTestFile('031_x86-rom-me.dts')
867 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
870 def testPackX86RomBadDesc(self):
871 """Test that the Intel requires a descriptor entry"""
872 with self.assertRaises(ValueError) as e:
873 self._DoTestFile('030_x86-rom-me-no-desc.dts')
874 self.assertIn("Node '/binman/intel-me': No offset set with "
875 "offset-unset: should another entry provide this correct "
876 "offset?", str(e.exception))
878 def testPackX86RomMe(self):
879 """Test that an x86 ROM with an ME region can be created"""
880 data = self._DoReadFile('031_x86-rom-me.dts')
881 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
882 if data[:0x1000] != expected_desc:
883 self.fail('Expected descriptor binary at start of image')
884 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
886 def testPackVga(self):
887 """Test that an image with a VGA binary can be created"""
888 data = self._DoReadFile('032_intel-vga.dts')
889 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
891 def testPackStart16(self):
892 """Test that an image with an x86 start16 region can be created"""
893 data = self._DoReadFile('033_x86-start16.dts')
894 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
896 def testPackPowerpcMpc85xxBootpgResetvec(self):
897 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
899 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
900 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
902 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
903 """Handle running a test for insertion of microcode
906 dts_fname: Name of test .dts file
907 nodtb_data: Data that we expect in the first section
908 ucode_second: True if the microsecond entry is second instead of
913 Contents of first region (U-Boot or SPL)
914 Offset and size components of microcode pointer, as inserted
915 in the above (two 4-byte words)
917 data = self._DoReadFile(dts_fname, True)
919 # Now check the device tree has no microcode
921 ucode_content = data[len(nodtb_data):]
922 ucode_pos = len(nodtb_data)
923 dtb_with_ucode = ucode_content[16:]
924 fdt_len = self.GetFdtLen(dtb_with_ucode)
926 dtb_with_ucode = data[len(nodtb_data):]
927 fdt_len = self.GetFdtLen(dtb_with_ucode)
928 ucode_content = dtb_with_ucode[fdt_len:]
929 ucode_pos = len(nodtb_data) + fdt_len
930 fname = tools.GetOutputFilename('test.dtb')
931 with open(fname, 'wb') as fd:
932 fd.write(dtb_with_ucode)
933 dtb = fdt.FdtScan(fname)
934 ucode = dtb.GetNode('/microcode')
935 self.assertTrue(ucode)
936 for node in ucode.subnodes:
937 self.assertFalse(node.props.get('data'))
939 # Check that the microcode appears immediately after the Fdt
940 # This matches the concatenation of the data properties in
941 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
942 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
944 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
946 # Check that the microcode pointer was inserted. It should match the
947 # expected offset and size
948 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
950 u_boot = data[:len(nodtb_data)]
951 return u_boot, pos_and_size
953 def testPackUbootMicrocode(self):
954 """Test that x86 microcode can be handled correctly
956 We expect to see the following in the image, in order:
957 u-boot-nodtb.bin with a microcode pointer inserted at the correct
959 u-boot.dtb with the microcode removed
962 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
964 self.assertEqual(b'nodtb with microcode' + pos_and_size +
965 b' somewhere in here', first)
967 def _RunPackUbootSingleMicrocode(self):
968 """Test that x86 microcode can be handled correctly
970 We expect to see the following in the image, in order:
971 u-boot-nodtb.bin with a microcode pointer inserted at the correct
973 u-boot.dtb with the microcode
974 an empty microcode region
976 # We need the libfdt library to run this test since only that allows
977 # finding the offset of a property. This is required by
978 # Entry_u_boot_dtb_with_ucode.ObtainContents().
979 data = self._DoReadFile('035_x86_single_ucode.dts', True)
981 second = data[len(U_BOOT_NODTB_DATA):]
983 fdt_len = self.GetFdtLen(second)
984 third = second[fdt_len:]
985 second = second[:fdt_len]
987 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
988 self.assertIn(ucode_data, second)
989 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
991 # Check that the microcode pointer was inserted. It should match the
992 # expected offset and size
993 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
995 first = data[:len(U_BOOT_NODTB_DATA)]
996 self.assertEqual(b'nodtb with microcode' + pos_and_size +
997 b' somewhere in here', first)
999 def testPackUbootSingleMicrocode(self):
1000 """Test that x86 microcode can be handled correctly with fdt_normal.
1002 self._RunPackUbootSingleMicrocode()
1004 def testUBootImg(self):
1005 """Test that u-boot.img can be put in a file"""
1006 data = self._DoReadFile('036_u_boot_img.dts')
1007 self.assertEqual(U_BOOT_IMG_DATA, data)
1009 def testNoMicrocode(self):
1010 """Test that a missing microcode region is detected"""
1011 with self.assertRaises(ValueError) as e:
1012 self._DoReadFile('037_x86_no_ucode.dts', True)
1013 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1014 "node found in ", str(e.exception))
1016 def testMicrocodeWithoutNode(self):
1017 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1018 with self.assertRaises(ValueError) as e:
1019 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
1020 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1021 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1023 def testMicrocodeWithoutNode2(self):
1024 """Test that a missing u-boot-ucode node is detected"""
1025 with self.assertRaises(ValueError) as e:
1026 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
1027 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1028 "microcode region u-boot-ucode", str(e.exception))
1030 def testMicrocodeWithoutPtrInElf(self):
1031 """Test that a U-Boot binary without the microcode symbol is detected"""
1032 # ELF file without a '_dt_ucode_base_size' symbol
1034 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1035 TestFunctional._MakeInputFile('u-boot', fd.read())
1037 with self.assertRaises(ValueError) as e:
1038 self._RunPackUbootSingleMicrocode()
1039 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1040 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1043 # Put the original file back
1044 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1045 TestFunctional._MakeInputFile('u-boot', fd.read())
1047 def testMicrocodeNotInImage(self):
1048 """Test that microcode must be placed within the image"""
1049 with self.assertRaises(ValueError) as e:
1050 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
1051 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1052 "pointer _dt_ucode_base_size at fffffe14 is outside the "
1053 "section ranging from 00000000 to 0000002e", str(e.exception))
1055 def testWithoutMicrocode(self):
1056 """Test that we can cope with an image without microcode (e.g. qemu)"""
1057 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
1058 TestFunctional._MakeInputFile('u-boot', fd.read())
1059 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
1061 # Now check the device tree has no microcode
1062 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1063 second = data[len(U_BOOT_NODTB_DATA):]
1065 fdt_len = self.GetFdtLen(second)
1066 self.assertEqual(dtb, second[:fdt_len])
1068 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1069 third = data[used_len:]
1070 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
1072 def testUnknownPosSize(self):
1073 """Test that microcode must be placed within the image"""
1074 with self.assertRaises(ValueError) as e:
1075 self._DoReadFile('041_unknown_pos_size.dts', True)
1076 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
1077 "entry 'invalid-entry'", str(e.exception))
1079 def testPackFsp(self):
1080 """Test that an image with a FSP binary can be created"""
1081 data = self._DoReadFile('042_intel-fsp.dts')
1082 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1084 def testPackCmc(self):
1085 """Test that an image with a CMC binary can be created"""
1086 data = self._DoReadFile('043_intel-cmc.dts')
1087 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
1089 def testPackVbt(self):
1090 """Test that an image with a VBT binary can be created"""
1091 data = self._DoReadFile('046_intel-vbt.dts')
1092 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
1094 def testSplBssPad(self):
1095 """Test that we can pad SPL's BSS with zeros"""
1096 # ELF file with a '__bss_size' symbol
1098 data = self._DoReadFile('047_spl_bss_pad.dts')
1099 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1102 def testSplBssPadMissing(self):
1103 """Test that a missing symbol is detected"""
1104 self._SetupSplElf('u_boot_ucode_ptr')
1105 with self.assertRaises(ValueError) as e:
1106 self._DoReadFile('047_spl_bss_pad.dts')
1107 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1110 def testPackStart16Spl(self):
1111 """Test that an image with an x86 start16 SPL region can be created"""
1112 data = self._DoReadFile('048_x86-start16-spl.dts')
1113 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1115 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1116 """Helper function for microcode tests
1118 We expect to see the following in the image, in order:
1119 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1121 u-boot.dtb with the microcode removed
1125 dts: Device tree file to use for test
1126 ucode_second: True if the microsecond entry is second instead of
1129 self._SetupSplElf('u_boot_ucode_ptr')
1130 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1131 ucode_second=ucode_second)
1132 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1133 b'ter somewhere in here', first)
1135 def testPackUbootSplMicrocode(self):
1136 """Test that x86 microcode can be handled correctly in SPL"""
1137 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
1139 def testPackUbootSplMicrocodeReorder(self):
1140 """Test that order doesn't matter for microcode entries
1142 This is the same as testPackUbootSplMicrocode but when we process the
1143 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1144 entry, so we reply on binman to try later.
1146 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
1149 def testPackMrc(self):
1150 """Test that an image with an MRC binary can be created"""
1151 data = self._DoReadFile('050_intel_mrc.dts')
1152 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1154 def testSplDtb(self):
1155 """Test that an image with spl/u-boot-spl.dtb can be created"""
1156 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
1157 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1159 def testSplNoDtb(self):
1160 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1161 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
1162 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1164 def testSymbols(self):
1165 """Test binman can assign symbols embedded in U-Boot"""
1166 elf_fname = self.TestFile('u_boot_binman_syms')
1167 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1168 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
1169 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
1171 self._SetupSplElf('u_boot_binman_syms')
1172 data = self._DoReadFile('053_symbols.dts')
1173 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1174 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1175 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1176 U_BOOT_SPL_DATA[16:])
1177 self.assertEqual(expected, data)
1179 def testPackUnitAddress(self):
1180 """Test that we support multiple binaries with the same name"""
1181 data = self._DoReadFile('054_unit_address.dts')
1182 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1184 def testSections(self):
1185 """Basic test of sections"""
1186 data = self._DoReadFile('055_sections.dts')
1187 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1188 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1189 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
1190 self.assertEqual(expected, data)
1193 """Tests outputting a map of the images"""
1194 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
1195 self.assertEqual('''ImagePos Offset Size Name
1196 00000000 00000000 00000028 main-section
1197 00000000 00000000 00000010 section@0
1198 00000000 00000000 00000004 u-boot
1199 00000010 00000010 00000010 section@1
1200 00000010 00000000 00000004 u-boot
1201 00000020 00000020 00000004 section@2
1202 00000020 00000000 00000004 u-boot
1205 def testNamePrefix(self):
1206 """Tests that name prefixes are used"""
1207 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
1208 self.assertEqual('''ImagePos Offset Size Name
1209 00000000 00000000 00000028 main-section
1210 00000000 00000000 00000010 section@0
1211 00000000 00000000 00000004 ro-u-boot
1212 00000010 00000010 00000010 section@1
1213 00000010 00000000 00000004 rw-u-boot
1216 def testUnknownContents(self):
1217 """Test that obtaining the contents works as expected"""
1218 with self.assertRaises(ValueError) as e:
1219 self._DoReadFile('057_unknown_contents.dts', True)
1220 self.assertIn("Section '/binman': Internal error: Could not complete "
1221 "processing of contents: remaining [<_testing.Entry__testing ",
1224 def testBadChangeSize(self):
1225 """Test that trying to change the size of an entry fails"""
1227 state.SetAllowEntryExpansion(False)
1228 with self.assertRaises(ValueError) as e:
1229 self._DoReadFile('059_change_size.dts', True)
1230 self.assertIn("Node '/binman/_testing': Cannot update entry size from 1 to 2",
1233 state.SetAllowEntryExpansion(True)
1235 def testUpdateFdt(self):
1236 """Test that we can update the device tree with offset/size info"""
1237 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
1239 dtb = fdt.Fdt(out_dtb_fname)
1241 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
1245 '_testing:offset': 32,
1247 '_testing:image-pos': 32,
1248 'section@0/u-boot:offset': 0,
1249 'section@0/u-boot:size': len(U_BOOT_DATA),
1250 'section@0/u-boot:image-pos': 0,
1251 'section@0:offset': 0,
1252 'section@0:size': 16,
1253 'section@0:image-pos': 0,
1255 'section@1/u-boot:offset': 0,
1256 'section@1/u-boot:size': len(U_BOOT_DATA),
1257 'section@1/u-boot:image-pos': 16,
1258 'section@1:offset': 16,
1259 'section@1:size': 16,
1260 'section@1:image-pos': 16,
1264 def testUpdateFdtBad(self):
1265 """Test that we detect when ProcessFdt never completes"""
1266 with self.assertRaises(ValueError) as e:
1267 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
1268 self.assertIn('Could not complete processing of Fdt: remaining '
1269 '[<_testing.Entry__testing', str(e.exception))
1271 def testEntryArgs(self):
1272 """Test passing arguments to entries from the command line"""
1274 'test-str-arg': 'test1',
1275 'test-int-arg': '456',
1277 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1278 self.assertIn('image', control.images)
1279 entry = control.images['image'].GetEntries()['_testing']
1280 self.assertEqual('test0', entry.test_str_fdt)
1281 self.assertEqual('test1', entry.test_str_arg)
1282 self.assertEqual(123, entry.test_int_fdt)
1283 self.assertEqual(456, entry.test_int_arg)
1285 def testEntryArgsMissing(self):
1286 """Test missing arguments and properties"""
1288 'test-int-arg': '456',
1290 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
1291 entry = control.images['image'].GetEntries()['_testing']
1292 self.assertEqual('test0', entry.test_str_fdt)
1293 self.assertEqual(None, entry.test_str_arg)
1294 self.assertEqual(None, entry.test_int_fdt)
1295 self.assertEqual(456, entry.test_int_arg)
1297 def testEntryArgsRequired(self):
1298 """Test missing arguments and properties"""
1300 'test-int-arg': '456',
1302 with self.assertRaises(ValueError) as e:
1303 self._DoReadFileDtb('064_entry_args_required.dts')
1304 self.assertIn("Node '/binman/_testing': Missing required "
1305 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1308 def testEntryArgsInvalidFormat(self):
1309 """Test that an invalid entry-argument format is detected"""
1310 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1312 with self.assertRaises(ValueError) as e:
1313 self._DoBinman(*args)
1314 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1316 def testEntryArgsInvalidInteger(self):
1317 """Test that an invalid entry-argument integer is detected"""
1319 'test-int-arg': 'abc',
1321 with self.assertRaises(ValueError) as e:
1322 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
1323 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1324 "'test-int-arg' (value 'abc') to integer",
1327 def testEntryArgsInvalidDatatype(self):
1328 """Test that an invalid entry-argument datatype is detected
1330 This test could be written in entry_test.py except that it needs
1331 access to control.entry_args, which seems more than that module should
1335 'test-bad-datatype-arg': '12',
1337 with self.assertRaises(ValueError) as e:
1338 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
1339 entry_args=entry_args)
1340 self.assertIn('GetArg() internal error: Unknown data type ',
1344 """Test for a text entry type"""
1346 'test-id': TEXT_DATA,
1347 'test-id2': TEXT_DATA2,
1348 'test-id3': TEXT_DATA3,
1350 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
1351 entry_args=entry_args)
1352 expected = (tools.ToBytes(TEXT_DATA) +
1353 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1354 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1355 b'some text' + b'more text')
1356 self.assertEqual(expected, data)
1358 def testEntryDocs(self):
1359 """Test for creation of entry documentation"""
1360 with test_util.capture_sys_output() as (stdout, stderr):
1361 control.WriteEntryDocs(binman.GetEntryModules())
1362 self.assertTrue(len(stdout.getvalue()) > 0)
1364 def testEntryDocsMissing(self):
1365 """Test handling of missing entry documentation"""
1366 with self.assertRaises(ValueError) as e:
1367 with test_util.capture_sys_output() as (stdout, stderr):
1368 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1369 self.assertIn('Documentation is missing for modules: u_boot',
1373 """Basic test of generation of a flashrom fmap"""
1374 data = self._DoReadFile('067_fmap.dts')
1375 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1376 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1377 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
1378 self.assertEqual(expected, data[:32])
1379 self.assertEqual(b'__FMAP__', fhdr.signature)
1380 self.assertEqual(1, fhdr.ver_major)
1381 self.assertEqual(0, fhdr.ver_minor)
1382 self.assertEqual(0, fhdr.base)
1383 self.assertEqual(16 + 16 +
1384 fmap_util.FMAP_HEADER_LEN +
1385 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1386 self.assertEqual(b'FMAP', fhdr.name)
1387 self.assertEqual(3, fhdr.nareas)
1388 for fentry in fentries:
1389 self.assertEqual(0, fentry.flags)
1391 self.assertEqual(0, fentries[0].offset)
1392 self.assertEqual(4, fentries[0].size)
1393 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
1395 self.assertEqual(16, fentries[1].offset)
1396 self.assertEqual(4, fentries[1].size)
1397 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
1399 self.assertEqual(32, fentries[2].offset)
1400 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1401 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1402 self.assertEqual(b'FMAP', fentries[2].name)
1404 def testBlobNamedByArg(self):
1405 """Test we can add a blob with the filename coming from an entry arg"""
1407 'cros-ec-rw-path': 'ecrw.bin',
1409 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
1410 entry_args=entry_args)
1413 """Test for an fill entry type"""
1414 data = self._DoReadFile('069_fill.dts')
1415 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
1416 self.assertEqual(expected, data)
1418 def testFillNoSize(self):
1419 """Test for an fill entry type with no size"""
1420 with self.assertRaises(ValueError) as e:
1421 self._DoReadFile('070_fill_no_size.dts')
1422 self.assertIn("'fill' entry must have a size property",
1425 def _HandleGbbCommand(self, pipe_list):
1426 """Fake calls to the futility utility"""
1427 if pipe_list[0][0] == 'futility':
1428 fname = pipe_list[0][-1]
1429 # Append our GBB data to the file, which will happen every time the
1430 # futility command is called.
1431 with open(fname, 'ab') as fd:
1433 return command.CommandResult()
1436 """Test for the Chromium OS Google Binary Block"""
1437 command.test_result = self._HandleGbbCommand
1439 'keydir': 'devkeys',
1440 'bmpblk': 'bmpblk.bin',
1442 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
1445 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1446 tools.GetBytes(0, 0x2180 - 16))
1447 self.assertEqual(expected, data)
1449 def testGbbTooSmall(self):
1450 """Test for the Chromium OS Google Binary Block being large enough"""
1451 with self.assertRaises(ValueError) as e:
1452 self._DoReadFileDtb('072_gbb_too_small.dts')
1453 self.assertIn("Node '/binman/gbb': GBB is too small",
1456 def testGbbNoSize(self):
1457 """Test for the Chromium OS Google Binary Block having a size"""
1458 with self.assertRaises(ValueError) as e:
1459 self._DoReadFileDtb('073_gbb_no_size.dts')
1460 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1463 def _HandleVblockCommand(self, pipe_list):
1464 """Fake calls to the futility utility"""
1465 if pipe_list[0][0] == 'futility':
1466 fname = pipe_list[0][3]
1467 with open(fname, 'wb') as fd:
1468 fd.write(VBLOCK_DATA)
1469 return command.CommandResult()
1471 def testVblock(self):
1472 """Test for the Chromium OS Verified Boot Block"""
1473 command.test_result = self._HandleVblockCommand
1475 'keydir': 'devkeys',
1477 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
1478 entry_args=entry_args)
1479 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1480 self.assertEqual(expected, data)
1482 def testVblockNoContent(self):
1483 """Test we detect a vblock which has no content to sign"""
1484 with self.assertRaises(ValueError) as e:
1485 self._DoReadFile('075_vblock_no_content.dts')
1486 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1487 'property', str(e.exception))
1489 def testVblockBadPhandle(self):
1490 """Test that we detect a vblock with an invalid phandle in contents"""
1491 with self.assertRaises(ValueError) as e:
1492 self._DoReadFile('076_vblock_bad_phandle.dts')
1493 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1494 '1000', str(e.exception))
1496 def testVblockBadEntry(self):
1497 """Test that we detect an entry that points to a non-entry"""
1498 with self.assertRaises(ValueError) as e:
1499 self._DoReadFile('077_vblock_bad_entry.dts')
1500 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1501 "'other'", str(e.exception))
1504 """Test that an image with TPL and ots device tree can be created"""
1505 # ELF file with a '__bss_size' symbol
1506 with open(self.TestFile('bss_data'), 'rb') as fd:
1507 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1508 data = self._DoReadFile('078_u_boot_tpl.dts')
1509 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1511 def testUsesPos(self):
1512 """Test that the 'pos' property cannot be used anymore"""
1513 with self.assertRaises(ValueError) as e:
1514 data = self._DoReadFile('079_uses_pos.dts')
1515 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1516 "'pos'", str(e.exception))
1518 def testFillZero(self):
1519 """Test for an fill entry type with a size of 0"""
1520 data = self._DoReadFile('080_fill_empty.dts')
1521 self.assertEqual(tools.GetBytes(0, 16), data)
1523 def testTextMissing(self):
1524 """Test for a text entry type where there is no text"""
1525 with self.assertRaises(ValueError) as e:
1526 self._DoReadFileDtb('066_text.dts',)
1527 self.assertIn("Node '/binman/text': No value provided for text label "
1528 "'test-id'", str(e.exception))
1530 def testPackStart16Tpl(self):
1531 """Test that an image with an x86 start16 TPL region can be created"""
1532 data = self._DoReadFile('081_x86-start16-tpl.dts')
1533 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1535 def testSelectImage(self):
1536 """Test that we can select which images to build"""
1537 expected = 'Skipping images: image1'
1539 # We should only get the expected message in verbose mode
1540 for verbosity in (0, 2):
1541 with test_util.capture_sys_output() as (stdout, stderr):
1542 retcode = self._DoTestFile('006_dual_image.dts',
1543 verbosity=verbosity,
1545 self.assertEqual(0, retcode)
1547 self.assertIn(expected, stdout.getvalue())
1549 self.assertNotIn(expected, stdout.getvalue())
1551 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1552 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1554 def testUpdateFdtAll(self):
1555 """Test that all device trees are updated with offset/size info"""
1556 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
1559 'section:image-pos': 0,
1560 'u-boot-tpl-dtb:size': 513,
1561 'u-boot-spl-dtb:size': 513,
1562 'u-boot-spl-dtb:offset': 493,
1564 'section/u-boot-dtb:image-pos': 0,
1565 'u-boot-spl-dtb:image-pos': 493,
1566 'section/u-boot-dtb:size': 493,
1567 'u-boot-tpl-dtb:image-pos': 1006,
1568 'section/u-boot-dtb:offset': 0,
1569 'section:size': 493,
1571 'section:offset': 0,
1572 'u-boot-tpl-dtb:offset': 1006,
1576 # We expect three device-tree files in the output, one after the other.
1577 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1578 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1579 # main U-Boot tree. All three should have the same postions and offset.
1581 for item in ['', 'spl', 'tpl']:
1582 dtb = fdt.Fdt.FromData(data[start:])
1584 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1586 expected = dict(base_expected)
1589 self.assertEqual(expected, props)
1590 start += dtb._fdt_obj.totalsize()
1592 def testUpdateFdtOutput(self):
1593 """Test that output DTB files are updated"""
1595 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
1596 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1598 # Unfortunately, compiling a source file always results in a file
1599 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1600 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
1601 # binman as a file called u-boot.dtb. To fix this, copy the file
1602 # over to the expected place.
1603 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1604 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1606 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1607 'tpl/u-boot-tpl.dtb.out']:
1608 dtb = fdt.Fdt.FromData(data[start:])
1609 size = dtb._fdt_obj.totalsize()
1610 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1611 outdata = tools.ReadFile(pathname)
1612 name = os.path.split(fname)[0]
1615 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1617 orig_indata = dtb_data
1618 self.assertNotEqual(outdata, orig_indata,
1619 "Expected output file '%s' be updated" % pathname)
1620 self.assertEqual(outdata, data[start:start + size],
1621 "Expected output file '%s' to match output image" %
1627 def _decompress(self, data):
1628 return tools.Decompress(data, 'lz4')
1630 def testCompress(self):
1631 """Test compression of blobs"""
1633 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
1634 use_real_dtb=True, update_dtb=True)
1635 dtb = fdt.Fdt(out_dtb_fname)
1637 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1638 orig = self._decompress(data)
1639 self.assertEquals(COMPRESS_DATA, orig)
1641 'blob:uncomp-size': len(COMPRESS_DATA),
1642 'blob:size': len(data),
1645 self.assertEqual(expected, props)
1647 def testFiles(self):
1648 """Test bringing in multiple files"""
1649 data = self._DoReadFile('084_files.dts')
1650 self.assertEqual(FILES_DATA, data)
1652 def testFilesCompress(self):
1653 """Test bringing in multiple files and compressing them"""
1655 data = self._DoReadFile('085_files_compress.dts')
1657 image = control.images['image']
1658 entries = image.GetEntries()
1659 files = entries['files']
1660 entries = files._section._entries
1663 for i in range(1, 3):
1665 start = entries[key].image_pos
1666 len = entries[key].size
1667 chunk = data[start:start + len]
1668 orig += self._decompress(chunk)
1670 self.assertEqual(FILES_DATA, orig)
1672 def testFilesMissing(self):
1673 """Test missing files"""
1674 with self.assertRaises(ValueError) as e:
1675 data = self._DoReadFile('086_files_none.dts')
1676 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1677 'no files', str(e.exception))
1679 def testFilesNoPattern(self):
1680 """Test missing files"""
1681 with self.assertRaises(ValueError) as e:
1682 data = self._DoReadFile('087_files_no_pattern.dts')
1683 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1686 def testExpandSize(self):
1687 """Test an expanding entry"""
1688 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
1690 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1691 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1692 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1693 tools.GetBytes(ord('d'), 8))
1694 self.assertEqual(expect, data)
1695 self.assertEqual('''ImagePos Offset Size Name
1696 00000000 00000000 00000028 main-section
1697 00000000 00000000 00000008 fill
1698 00000008 00000008 00000004 u-boot
1699 0000000c 0000000c 00000004 section
1700 0000000c 00000000 00000003 intel-mrc
1701 00000010 00000010 00000004 u-boot2
1702 00000014 00000014 0000000c section2
1703 00000014 00000000 00000008 fill
1704 0000001c 00000008 00000004 u-boot
1705 00000020 00000020 00000008 fill2
1708 def testExpandSizeBad(self):
1709 """Test an expanding entry which fails to provide contents"""
1710 with test_util.capture_sys_output() as (stdout, stderr):
1711 with self.assertRaises(ValueError) as e:
1712 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
1713 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1714 'expanding entry', str(e.exception))
1717 """Test hashing of the contents of an entry"""
1718 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
1719 use_real_dtb=True, update_dtb=True)
1720 dtb = fdt.Fdt(out_dtb_fname)
1722 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1723 m = hashlib.sha256()
1724 m.update(U_BOOT_DATA)
1725 self.assertEqual(m.digest(), b''.join(hash_node.value))
1727 def testHashNoAlgo(self):
1728 with self.assertRaises(ValueError) as e:
1729 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
1730 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1731 'hash node', str(e.exception))
1733 def testHashBadAlgo(self):
1734 with self.assertRaises(ValueError) as e:
1735 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
1736 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1739 def testHashSection(self):
1740 """Test hashing of the contents of an entry"""
1741 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
1742 use_real_dtb=True, update_dtb=True)
1743 dtb = fdt.Fdt(out_dtb_fname)
1745 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1746 m = hashlib.sha256()
1747 m.update(U_BOOT_DATA)
1748 m.update(tools.GetBytes(ord('a'), 16))
1749 self.assertEqual(m.digest(), b''.join(hash_node.value))
1751 def testPackUBootTplMicrocode(self):
1752 """Test that x86 microcode can be handled correctly in TPL
1754 We expect to see the following in the image, in order:
1755 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1757 u-boot-tpl.dtb with the microcode removed
1760 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
1761 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1762 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
1763 U_BOOT_TPL_NODTB_DATA)
1764 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1765 b'ter somewhere in here', first)
1767 def testFmapX86(self):
1768 """Basic test of generation of a flashrom fmap"""
1769 data = self._DoReadFile('094_fmap_x86.dts')
1770 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1771 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
1772 self.assertEqual(expected, data[:32])
1773 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1775 self.assertEqual(0x100, fhdr.image_size)
1777 self.assertEqual(0, fentries[0].offset)
1778 self.assertEqual(4, fentries[0].size)
1779 self.assertEqual(b'U_BOOT', fentries[0].name)
1781 self.assertEqual(4, fentries[1].offset)
1782 self.assertEqual(3, fentries[1].size)
1783 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1785 self.assertEqual(32, fentries[2].offset)
1786 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1787 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1788 self.assertEqual(b'FMAP', fentries[2].name)
1790 def testFmapX86Section(self):
1791 """Basic test of generation of a flashrom fmap"""
1792 data = self._DoReadFile('095_fmap_x86_section.dts')
1793 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
1794 self.assertEqual(expected, data[:32])
1795 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1797 self.assertEqual(0x100, fhdr.image_size)
1799 self.assertEqual(0, fentries[0].offset)
1800 self.assertEqual(4, fentries[0].size)
1801 self.assertEqual(b'U_BOOT', fentries[0].name)
1803 self.assertEqual(4, fentries[1].offset)
1804 self.assertEqual(3, fentries[1].size)
1805 self.assertEqual(b'INTEL_MRC', fentries[1].name)
1807 self.assertEqual(36, fentries[2].offset)
1808 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1809 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1810 self.assertEqual(b'FMAP', fentries[2].name)
1813 """Basic test of ELF entries"""
1815 with open(self.TestFile('bss_data'), 'rb') as fd:
1816 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1817 with open(self.TestFile('bss_data'), 'rb') as fd:
1818 TestFunctional._MakeInputFile('-boot', fd.read())
1819 data = self._DoReadFile('096_elf.dts')
1821 def testElfStrip(self):
1822 """Basic test of ELF entries"""
1824 with open(self.TestFile('bss_data'), 'rb') as fd:
1825 TestFunctional._MakeInputFile('-boot', fd.read())
1826 data = self._DoReadFile('097_elf_strip.dts')
1828 def testPackOverlapMap(self):
1829 """Test that overlapping regions are detected"""
1830 with test_util.capture_sys_output() as (stdout, stderr):
1831 with self.assertRaises(ValueError) as e:
1832 self._DoTestFile('014_pack_overlap.dts', map=True)
1833 map_fname = tools.GetOutputFilename('image.map')
1834 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1837 # We should not get an inmage, but there should be a map file
1838 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1839 self.assertTrue(os.path.exists(map_fname))
1840 map_data = tools.ReadFile(map_fname, binary=False)
1841 self.assertEqual('''ImagePos Offset Size Name
1842 <none> 00000000 00000007 main-section
1843 <none> 00000000 00000004 u-boot
1844 <none> 00000003 00000004 u-boot-align
1847 def testPackRefCode(self):
1848 """Test that an image with an Intel Reference code binary works"""
1849 data = self._DoReadFile('100_intel_refcode.dts')
1850 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1852 def testSectionOffset(self):
1853 """Tests use of a section with an offset"""
1854 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1856 self.assertEqual('''ImagePos Offset Size Name
1857 00000000 00000000 00000038 main-section
1858 00000004 00000004 00000010 section@0
1859 00000004 00000000 00000004 u-boot
1860 00000018 00000018 00000010 section@1
1861 00000018 00000000 00000004 u-boot
1862 0000002c 0000002c 00000004 section@2
1863 0000002c 00000000 00000004 u-boot
1865 self.assertEqual(data,
1866 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1867 tools.GetBytes(0x21, 12) +
1868 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1869 tools.GetBytes(0x61, 12) +
1870 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1871 tools.GetBytes(0x26, 8))
1873 def testCbfsRaw(self):
1874 """Test base handling of a Coreboot Filesystem (CBFS)
1876 The exact contents of the CBFS is verified by similar tests in
1877 cbfs_util_test.py. The tests here merely check that the files added to
1878 the CBFS can be found in the final image.
1880 data = self._DoReadFile('102_cbfs_raw.dts')
1883 cbfs = cbfs_util.CbfsReader(data)
1884 self.assertEqual(size, cbfs.rom_size)
1886 self.assertIn('u-boot-dtb', cbfs.files)
1887 cfile = cbfs.files['u-boot-dtb']
1888 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1890 def testCbfsArch(self):
1891 """Test on non-x86 architecture"""
1892 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1895 cbfs = cbfs_util.CbfsReader(data)
1896 self.assertEqual(size, cbfs.rom_size)
1898 self.assertIn('u-boot-dtb', cbfs.files)
1899 cfile = cbfs.files['u-boot-dtb']
1900 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1902 def testCbfsStage(self):
1903 """Tests handling of a Coreboot Filesystem (CBFS)"""
1904 if not elf.ELF_TOOLS:
1905 self.skipTest('Python elftools not available')
1906 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1907 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1910 data = self._DoReadFile('104_cbfs_stage.dts')
1911 cbfs = cbfs_util.CbfsReader(data)
1912 self.assertEqual(size, cbfs.rom_size)
1914 self.assertIn('u-boot', cbfs.files)
1915 cfile = cbfs.files['u-boot']
1916 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1918 def testCbfsRawCompress(self):
1919 """Test handling of compressing raw files"""
1921 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1924 cbfs = cbfs_util.CbfsReader(data)
1925 self.assertIn('u-boot', cbfs.files)
1926 cfile = cbfs.files['u-boot']
1927 self.assertEqual(COMPRESS_DATA, cfile.data)
1929 def testCbfsBadArch(self):
1930 """Test handling of a bad architecture"""
1931 with self.assertRaises(ValueError) as e:
1932 self._DoReadFile('106_cbfs_bad_arch.dts')
1933 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1935 def testCbfsNoSize(self):
1936 """Test handling of a missing size property"""
1937 with self.assertRaises(ValueError) as e:
1938 self._DoReadFile('107_cbfs_no_size.dts')
1939 self.assertIn('entry must have a size property', str(e.exception))
1941 def testCbfsNoCOntents(self):
1942 """Test handling of a CBFS entry which does not provide contentsy"""
1943 with self.assertRaises(ValueError) as e:
1944 self._DoReadFile('108_cbfs_no_contents.dts')
1945 self.assertIn('Could not complete processing of contents',
1948 def testCbfsBadCompress(self):
1949 """Test handling of a bad architecture"""
1950 with self.assertRaises(ValueError) as e:
1951 self._DoReadFile('109_cbfs_bad_compress.dts')
1952 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1955 def testCbfsNamedEntries(self):
1956 """Test handling of named entries"""
1957 data = self._DoReadFile('110_cbfs_name.dts')
1959 cbfs = cbfs_util.CbfsReader(data)
1960 self.assertIn('FRED', cbfs.files)
1961 cfile1 = cbfs.files['FRED']
1962 self.assertEqual(U_BOOT_DATA, cfile1.data)
1964 self.assertIn('hello', cbfs.files)
1965 cfile2 = cbfs.files['hello']
1966 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1968 def _SetupIfwi(self, fname):
1969 """Set up to run an IFWI test
1972 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1976 # Intel Integrated Firmware Image (IFWI) file
1977 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1979 TestFunctional._MakeInputFile(fname,data)
1981 def _CheckIfwi(self, data):
1982 """Check that an image with an IFWI contains the correct output
1985 data: Conents of output file
1987 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1988 if data[:0x1000] != expected_desc:
1989 self.fail('Expected descriptor binary at start of image')
1991 # We expect to find the TPL wil in subpart IBBP entry IBBL
1992 image_fname = tools.GetOutputFilename('image.bin')
1993 tpl_fname = tools.GetOutputFilename('tpl.out')
1994 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
1995 subpart='IBBP', entry_name='IBBL')
1997 tpl_data = tools.ReadFile(tpl_fname)
1998 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2000 def testPackX86RomIfwi(self):
2001 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2002 self._SetupIfwi('fitimage.bin')
2003 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2004 self._CheckIfwi(data)
2006 def testPackX86RomIfwiNoDesc(self):
2007 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2008 self._SetupIfwi('ifwi.bin')
2009 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2010 self._CheckIfwi(data)
2012 def testPackX86RomIfwiNoData(self):
2013 """Test that an x86 ROM with IFWI handles missing data"""
2014 self._SetupIfwi('ifwi.bin')
2015 with self.assertRaises(ValueError) as e:
2016 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2017 self.assertIn('Could not complete processing of contents',
2020 def testCbfsOffset(self):
2021 """Test a CBFS with files at particular offsets
2023 Like all CFBS tests, this is just checking the logic that calls
2024 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2026 data = self._DoReadFile('114_cbfs_offset.dts')
2029 cbfs = cbfs_util.CbfsReader(data)
2030 self.assertEqual(size, cbfs.rom_size)
2032 self.assertIn('u-boot', cbfs.files)
2033 cfile = cbfs.files['u-boot']
2034 self.assertEqual(U_BOOT_DATA, cfile.data)
2035 self.assertEqual(0x40, cfile.cbfs_offset)
2037 self.assertIn('u-boot-dtb', cbfs.files)
2038 cfile2 = cbfs.files['u-boot-dtb']
2039 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2040 self.assertEqual(0x140, cfile2.cbfs_offset)
2042 def testFdtmap(self):
2043 """Test an FDT map can be inserted in the image"""
2044 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2045 fdtmap_data = data[len(U_BOOT_DATA):]
2046 magic = fdtmap_data[:8]
2047 self.assertEqual('_FDTMAP_', magic)
2048 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2050 fdt_data = fdtmap_data[16:]
2051 dtb = fdt.Fdt.FromData(fdt_data)
2053 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'],
2059 'u-boot:size': len(U_BOOT_DATA),
2060 'u-boot:image-pos': 0,
2061 'fdtmap:image-pos': 4,
2063 'fdtmap:size': len(fdtmap_data),
2067 def testFdtmapNoMatch(self):
2068 """Check handling of an FDT map when the section cannot be found"""
2069 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2071 # Mangle the section name, which should cause a mismatch between the
2072 # correct FDT path and the one expected by the section
2073 image = control.images['image']
2074 image._node.path += '-suffix'
2075 entries = image.GetEntries()
2076 fdtmap = entries['fdtmap']
2077 with self.assertRaises(ValueError) as e:
2079 self.assertIn("Cannot locate node for path '/binman-suffix'",
2082 def testFdtmapHeader(self):
2083 """Test an FDT map and image header can be inserted in the image"""
2084 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2085 fdtmap_pos = len(U_BOOT_DATA)
2086 fdtmap_data = data[fdtmap_pos:]
2087 fdt_data = fdtmap_data[16:]
2088 dtb = fdt.Fdt.FromData(fdt_data)
2089 fdt_size = dtb.GetFdtObj().totalsize()
2090 hdr_data = data[-8:]
2091 self.assertEqual('BinM', hdr_data[:4])
2092 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2093 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2095 def testFdtmapHeaderStart(self):
2096 """Test an image header can be inserted at the image start"""
2097 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2098 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2100 self.assertEqual('BinM', hdr_data[:4])
2101 offset = struct.unpack('<I', hdr_data[4:])[0]
2102 self.assertEqual(fdtmap_pos, offset)
2104 def testFdtmapHeaderPos(self):
2105 """Test an image header can be inserted at a chosen position"""
2106 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2107 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2108 hdr_data = data[0x80:0x88]
2109 self.assertEqual('BinM', hdr_data[:4])
2110 offset = struct.unpack('<I', hdr_data[4:])[0]
2111 self.assertEqual(fdtmap_pos, offset)
2113 def testHeaderMissingFdtmap(self):
2114 """Test an image header requires an fdtmap"""
2115 with self.assertRaises(ValueError) as e:
2116 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2117 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2120 def testHeaderNoLocation(self):
2121 """Test an image header with a no specified location is detected"""
2122 with self.assertRaises(ValueError) as e:
2123 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2124 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2127 def testEntryExpand(self):
2128 """Test expanding an entry after it is packed"""
2129 data = self._DoReadFile('121_entry_expand.dts')
2130 self.assertEqual(b'aa', data[:2])
2131 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2132 self.assertEqual(b'aa', data[-2:])
2134 def testEntryExpandBad(self):
2135 """Test expanding an entry after it is packed, twice"""
2136 with self.assertRaises(ValueError) as e:
2137 self._DoReadFile('122_entry_expand_twice.dts')
2138 self.assertIn("Image '/binman': Entries expanded after packing",
2141 def testEntryExpandSection(self):
2142 """Test expanding an entry within a section after it is packed"""
2143 data = self._DoReadFile('123_entry_expand_section.dts')
2144 self.assertEqual(b'aa', data[:2])
2145 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2146 self.assertEqual(b'aa', data[-2:])
2148 def testCompressDtb(self):
2149 """Test that compress of device-tree files is supported"""
2151 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2152 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2153 comp_data = data[len(U_BOOT_DATA):]
2154 orig = self._decompress(comp_data)
2155 dtb = fdt.Fdt.FromData(orig)
2157 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2159 'u-boot:size': len(U_BOOT_DATA),
2160 'u-boot-dtb:uncomp-size': len(orig),
2161 'u-boot-dtb:size': len(comp_data),
2164 self.assertEqual(expected, props)
2166 def testCbfsUpdateFdt(self):
2167 """Test that we can update the device tree with CBFS offset/size info"""
2169 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2171 dtb = fdt.Fdt(out_dtb_fname)
2173 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
2175 del props['cbfs/u-boot:size']
2181 'cbfs:size': len(data),
2182 'cbfs:image-pos': 0,
2183 'cbfs/u-boot:offset': 0x38,
2184 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2185 'cbfs/u-boot:image-pos': 0x38,
2186 'cbfs/u-boot-dtb:offset': 0xb8,
2187 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2188 'cbfs/u-boot-dtb:image-pos': 0xb8,
2191 def testCbfsBadType(self):
2192 """Test an image header with a no specified location is detected"""
2193 with self.assertRaises(ValueError) as e:
2194 self._DoReadFile('126_cbfs_bad_type.dts')
2195 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2198 """Test listing the files in an image"""
2200 data = self._DoReadFile('127_list.dts')
2201 image = control.images['image']
2202 entries = image.BuildEntryList()
2203 self.assertEqual(7, len(entries))
2206 self.assertEqual(0, ent.indent)
2207 self.assertEqual('main-section', ent.name)
2208 self.assertEqual('section', ent.etype)
2209 self.assertEqual(len(data), ent.size)
2210 self.assertEqual(0, ent.image_pos)
2211 self.assertEqual(None, ent.uncomp_size)
2212 self.assertEqual(None, ent.offset)
2215 self.assertEqual(1, ent.indent)
2216 self.assertEqual('u-boot', ent.name)
2217 self.assertEqual('u-boot', ent.etype)
2218 self.assertEqual(len(U_BOOT_DATA), ent.size)
2219 self.assertEqual(0, ent.image_pos)
2220 self.assertEqual(None, ent.uncomp_size)
2221 self.assertEqual(0, ent.offset)
2224 self.assertEqual(1, ent.indent)
2225 self.assertEqual('section', ent.name)
2226 self.assertEqual('section', ent.etype)
2227 section_size = ent.size
2228 self.assertEqual(0x100, ent.image_pos)
2229 self.assertEqual(None, ent.uncomp_size)
2230 self.assertEqual(len(U_BOOT_DATA), ent.offset)
2233 self.assertEqual(2, ent.indent)
2234 self.assertEqual('cbfs', ent.name)
2235 self.assertEqual('cbfs', ent.etype)
2236 self.assertEqual(0x400, ent.size)
2237 self.assertEqual(0x100, ent.image_pos)
2238 self.assertEqual(None, ent.uncomp_size)
2239 self.assertEqual(0, ent.offset)
2242 self.assertEqual(3, ent.indent)
2243 self.assertEqual('u-boot', ent.name)
2244 self.assertEqual('u-boot', ent.etype)
2245 self.assertEqual(len(U_BOOT_DATA), ent.size)
2246 self.assertEqual(0x138, ent.image_pos)
2247 self.assertEqual(None, ent.uncomp_size)
2248 self.assertEqual(0x38, ent.offset)
2251 self.assertEqual(3, ent.indent)
2252 self.assertEqual('u-boot-dtb', ent.name)
2253 self.assertEqual('text', ent.etype)
2254 self.assertGreater(len(COMPRESS_DATA), ent.size)
2255 self.assertEqual(0x178, ent.image_pos)
2256 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2257 self.assertEqual(0x78, ent.offset)
2260 self.assertEqual(2, ent.indent)
2261 self.assertEqual('u-boot-dtb', ent.name)
2262 self.assertEqual('u-boot-dtb', ent.etype)
2263 self.assertEqual(0x500, ent.image_pos)
2264 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2266 # Compressing this data expands it since headers are added
2267 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2268 self.assertEqual(0x400, ent.offset)
2270 self.assertEqual(len(data), 0x100 + section_size)
2271 self.assertEqual(section_size, 0x400 + dtb_size)
2273 def testFindFdtmap(self):
2274 """Test locating an FDT map in an image"""
2276 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2277 image = control.images['image']
2278 entries = image.GetEntries()
2279 entry = entries['fdtmap']
2280 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2282 def testFindFdtmapMissing(self):
2283 """Test failing to locate an FDP map"""
2284 data = self._DoReadFile('005_simple.dts')
2285 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2287 def testFindImageHeader(self):
2288 """Test locating a image header"""
2290 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2291 image = control.images['image']
2292 entries = image.GetEntries()
2293 entry = entries['fdtmap']
2294 # The header should point to the FDT map
2295 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2297 def testFindImageHeaderStart(self):
2298 """Test locating a image header located at the start of an image"""
2299 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2300 image = control.images['image']
2301 entries = image.GetEntries()
2302 entry = entries['fdtmap']
2303 # The header should point to the FDT map
2304 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2306 def testFindImageHeaderMissing(self):
2307 """Test failing to locate an image header"""
2308 data = self._DoReadFile('005_simple.dts')
2309 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2311 def testReadImage(self):
2312 """Test reading an image and accessing its FDT map"""
2314 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2315 image_fname = tools.GetOutputFilename('image.bin')
2316 orig_image = control.images['image']
2317 image = Image.FromFile(image_fname)
2318 self.assertEqual(orig_image.GetEntries().keys(),
2319 image.GetEntries().keys())
2321 orig_entry = orig_image.GetEntries()['fdtmap']
2322 entry = image.GetEntries()['fdtmap']
2323 self.assertEquals(orig_entry.offset, entry.offset)
2324 self.assertEquals(orig_entry.size, entry.size)
2325 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2327 def testReadImageNoHeader(self):
2328 """Test accessing an image's FDT map without an image header"""
2330 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2331 image_fname = tools.GetOutputFilename('image.bin')
2332 image = Image.FromFile(image_fname)
2333 self.assertTrue(isinstance(image, Image))
2334 self.assertEqual('image', image._name)
2336 def testReadImageFail(self):
2337 """Test failing to read an image image's FDT map"""
2338 self._DoReadFile('005_simple.dts')
2339 image_fname = tools.GetOutputFilename('image.bin')
2340 with self.assertRaises(ValueError) as e:
2341 image = Image.FromFile(image_fname)
2342 self.assertIn("Cannot find FDT map in image", str(e.exception))
2344 if __name__ == "__main__":