blob: daea1ea138229056629dd4b4b32d58892c846a4a [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glasse0e5df92018-09-14 04:57:31 -06009import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070010from optparse import OptionParser
11import os
12import shutil
13import struct
14import sys
15import tempfile
16import unittest
17
18import binman
19import cmdline
20import command
21import control
Simon Glass19790632017-11-13 18:55:01 -070022import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060023import fdt
Simon Glass4f443042016-11-25 20:15:52 -070024import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060025import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060026import test_util
Simon Glassc55a50f2018-09-14 04:57:19 -060027import state
Simon Glass4f443042016-11-25 20:15:52 -070028import tools
29import tout
30
31# Contents of test files, corresponding to different entry types
Simon Glass6b187df2017-11-12 21:52:27 -070032U_BOOT_DATA = '1234'
33U_BOOT_IMG_DATA = 'img'
Simon Glassf6898902017-11-13 18:54:59 -070034U_BOOT_SPL_DATA = '56780123456789abcde'
Simon Glassb8ef5b62018-07-17 13:25:48 -060035U_BOOT_TPL_DATA = 'tpl'
Simon Glass6b187df2017-11-12 21:52:27 -070036BLOB_DATA = '89'
37ME_DATA = '0abcd'
38VGA_DATA = 'vga'
39U_BOOT_DTB_DATA = 'udtb'
Simon Glass47419ea2017-11-13 18:54:55 -070040U_BOOT_SPL_DTB_DATA = 'spldtb'
Simon Glassb8ef5b62018-07-17 13:25:48 -060041U_BOOT_TPL_DTB_DATA = 'tpldtb'
Simon Glass6b187df2017-11-12 21:52:27 -070042X86_START16_DATA = 'start16'
43X86_START16_SPL_DATA = 'start16spl'
Simon Glass35b384c2018-09-14 04:57:10 -060044X86_START16_TPL_DATA = 'start16tpl'
Jagdish Gediya9d368f32018-09-03 21:35:08 +053045PPC_MPC85XX_BR_DATA = 'ppcmpc85xxbr'
Simon Glass6b187df2017-11-12 21:52:27 -070046U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
47U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
Simon Glassf0253632018-09-14 04:57:32 -060048U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here'
Simon Glass6b187df2017-11-12 21:52:27 -070049FSP_DATA = 'fsp'
50CMC_DATA = 'cmc'
51VBT_DATA = 'vbt'
Simon Glassca4f4ff2017-11-12 21:52:28 -070052MRC_DATA = 'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060053TEXT_DATA = 'text'
54TEXT_DATA2 = 'text2'
55TEXT_DATA3 = 'text3'
Simon Glassec127af2018-07-17 13:25:39 -060056CROS_EC_RW_DATA = 'ecrw'
Simon Glass0ef87aa2018-07-17 13:25:44 -060057GBB_DATA = 'gbbd'
58BMPBLK_DATA = 'bmp'
Simon Glass24d0d3c2018-07-17 13:25:47 -060059VBLOCK_DATA = 'vblk'
Simon Glass0a98b282018-09-14 04:57:28 -060060FILES_DATA = ("sorry I'm late\nOh, don't bother apologising, I'm " +
61 "sorry you're alive\n")
Simon Glass83d73c22018-09-14 04:57:26 -060062COMPRESS_DATA = 'data to compress'
Simon Glass3ae192c2018-10-01 12:22:31 -060063REFCODE_DATA = 'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060064
Simon Glass4f443042016-11-25 20:15:52 -070065
66class TestFunctional(unittest.TestCase):
67 """Functional tests for binman
68
69 Most of these use a sample .dts file to build an image and then check
70 that it looks correct. The sample files are in the test/ subdirectory
71 and are numbered.
72
73 For each entry type a very small test file is created using fixed
74 string contents. This makes it easy to test that things look right, and
75 debug problems.
76
77 In some cases a 'real' file must be used - these are also supplied in
78 the test/ diurectory.
79 """
80 @classmethod
81 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070082 global entry
83 import entry
84
Simon Glass4f443042016-11-25 20:15:52 -070085 # Handle the case where argv[0] is 'python'
86 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
87 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
88
89 # Create a temporary directory for input files
90 self._indir = tempfile.mkdtemp(prefix='binmant.')
91
92 # Create some test files
93 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
94 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
95 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060096 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070097 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -070098 TestFunctional._MakeInputFile('me.bin', ME_DATA)
99 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600100 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700101 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530102 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700103 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
104 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600105 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
106 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700107 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700108 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
109 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600110 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
111 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700112 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
113 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700114 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700115 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600116 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600117 TestFunctional._MakeInputDir('devkeys')
118 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600119 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700120
Simon Glasse0ff8552016-11-25 20:15:53 -0700121 # ELF file with a '_dt_ucode_base_size' symbol
122 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
123 TestFunctional._MakeInputFile('u-boot', fd.read())
124
125 # Intel flash descriptor file
126 with open(self.TestFile('descriptor.bin')) as fd:
127 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
128
Simon Glass0a98b282018-09-14 04:57:28 -0600129 shutil.copytree(self.TestFile('files'),
130 os.path.join(self._indir, 'files'))
131
Simon Glass83d73c22018-09-14 04:57:26 -0600132 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
133
Simon Glass4f443042016-11-25 20:15:52 -0700134 @classmethod
135 def tearDownClass(self):
136 """Remove the temporary input directory and its contents"""
137 if self._indir:
138 shutil.rmtree(self._indir)
139 self._indir = None
140
141 def setUp(self):
142 # Enable this to turn on debugging output
143 # tout.Init(tout.DEBUG)
144 command.test_result = None
145
146 def tearDown(self):
147 """Remove the temporary output directory"""
148 tools._FinaliseForTest()
149
Simon Glassb8ef5b62018-07-17 13:25:48 -0600150 @classmethod
151 def _ResetDtbs(self):
152 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
153 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
154 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
155
Simon Glass4f443042016-11-25 20:15:52 -0700156 def _RunBinman(self, *args, **kwargs):
157 """Run binman using the command line
158
159 Args:
160 Arguments to pass, as a list of strings
161 kwargs: Arguments to pass to Command.RunPipe()
162 """
163 result = command.RunPipe([[self._binman_pathname] + list(args)],
164 capture=True, capture_stderr=True, raise_on_error=False)
165 if result.return_code and kwargs.get('raise_on_error', True):
166 raise Exception("Error running '%s': %s" % (' '.join(args),
167 result.stdout + result.stderr))
168 return result
169
170 def _DoBinman(self, *args):
171 """Run binman using directly (in the same process)
172
173 Args:
174 Arguments to pass, as a list of strings
175 Returns:
176 Return value (0 for success)
177 """
Simon Glass7fe91732017-11-13 18:55:00 -0700178 args = list(args)
179 if '-D' in sys.argv:
180 args = args + ['-D']
181 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700182 options.pager = 'binman-invalid-pager'
183 options.build_dir = self._indir
184
185 # For testing, you can force an increase in verbosity here
186 # options.verbosity = tout.DEBUG
187 return control.Binman(options, args)
188
Simon Glass53af22a2018-07-17 13:25:32 -0600189 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600190 entry_args=None, images=None, use_real_dtb=False,
191 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700192 """Run binman with a given test file
193
194 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600195 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600196 debug: True to enable debugging output
Simon Glass3b0c38212018-06-01 09:38:20 -0600197 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600198 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600199 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600200 entry_args: Dict of entry args to supply to binman
201 key: arg name
202 value: value of that arg
203 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700204 """
Simon Glass7fe91732017-11-13 18:55:00 -0700205 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
206 if debug:
207 args.append('-D')
Simon Glass3b0c38212018-06-01 09:38:20 -0600208 if map:
209 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600210 if update_dtb:
211 args.append('-up')
Simon Glass93d17412018-09-14 04:57:23 -0600212 if not use_real_dtb:
213 args.append('--fake-dtb')
Simon Glasseb833d82019-04-25 21:58:34 -0600214 if verbosity is not None:
215 args.append('-v%d' % verbosity)
Simon Glass53af22a2018-07-17 13:25:32 -0600216 if entry_args:
217 for arg, value in entry_args.iteritems():
218 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600219 if images:
220 for image in images:
221 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700222 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700223
224 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700225 """Set up a new test device-tree file
226
227 The given file is compiled and set up as the device tree to be used
228 for ths test.
229
230 Args:
231 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600232 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700233
234 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600235 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700236 """
Simon Glasse0e62752018-10-01 21:12:41 -0600237 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700238 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
239 with open(dtb) as fd:
240 data = fd.read()
241 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600242 tools.FinaliseOutputDir()
243 return data
Simon Glass4f443042016-11-25 20:15:52 -0700244
Simon Glass6ed45ba2018-09-14 04:57:24 -0600245 def _GetDtbContentsForSplTpl(self, dtb_data, name):
246 """Create a version of the main DTB for SPL or SPL
247
248 For testing we don't actually have different versions of the DTB. With
249 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
250 we don't normally have any unwanted nodes.
251
252 We still want the DTBs for SPL and TPL to be different though, since
253 otherwise it is confusing to know which one we are looking at. So add
254 an 'spl' or 'tpl' property to the top-level node.
255 """
256 dtb = fdt.Fdt.FromData(dtb_data)
257 dtb.Scan()
258 dtb.GetNode('/binman').AddZeroProp(name)
259 dtb.Sync(auto_resize=True)
260 dtb.Pack()
261 return dtb.GetContents()
262
Simon Glass16b8d6b2018-07-06 10:27:42 -0600263 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600264 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700265 """Run binman and return the resulting image
266
267 This runs binman with a given test file and then reads the resulting
268 output file. It is a shortcut function since most tests need to do
269 these steps.
270
271 Raises an assertion failure if binman returns a non-zero exit code.
272
273 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600274 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700275 use_real_dtb: True to use the test file as the contents of
276 the u-boot-dtb entry. Normally this is not needed and the
277 test contents (the U_BOOT_DTB_DATA string) can be used.
278 But in some test we need the real contents.
Simon Glass3b0c38212018-06-01 09:38:20 -0600279 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600280 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600281 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700282
283 Returns:
284 Tuple:
285 Resulting image contents
286 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600287 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600288 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700289 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700290 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700291 # Use the compiled test file as the u-boot-dtb input
292 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700293 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600294 infile = os.path.join(self._indir, 'u-boot.dtb')
295
296 # For testing purposes, make a copy of the DT for SPL and TPL. Add
297 # a node indicating which it is, so aid verification.
298 for name in ['spl', 'tpl']:
299 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
300 outfile = os.path.join(self._indir, dtb_fname)
301 TestFunctional._MakeInputFile(dtb_fname,
302 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700303
304 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600305 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600306 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700307 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600308 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700309
310 # Find the (only) image, read it and return its contents
311 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600312 image_fname = tools.GetOutputFilename('image.bin')
313 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600314 if map:
315 map_fname = tools.GetOutputFilename('image.map')
316 with open(map_fname) as fd:
317 map_data = fd.read()
318 else:
319 map_data = None
Simon Glass16b8d6b2018-07-06 10:27:42 -0600320 with open(image_fname) as fd:
321 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700322 finally:
323 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600324 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600325 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700326
Simon Glasse0ff8552016-11-25 20:15:53 -0700327 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600328 """Helper function which discards the device-tree binary
329
330 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600331 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600332 use_real_dtb: True to use the test file as the contents of
333 the u-boot-dtb entry. Normally this is not needed and the
334 test contents (the U_BOOT_DTB_DATA string) can be used.
335 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600336
337 Returns:
338 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600339 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700340 return self._DoReadFileDtb(fname, use_real_dtb)[0]
341
Simon Glass4f443042016-11-25 20:15:52 -0700342 @classmethod
343 def _MakeInputFile(self, fname, contents):
344 """Create a new test input file, creating directories as needed
345
346 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600347 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700348 contents: File contents to write in to the file
349 Returns:
350 Full pathname of file created
351 """
352 pathname = os.path.join(self._indir, fname)
353 dirname = os.path.dirname(pathname)
354 if dirname and not os.path.exists(dirname):
355 os.makedirs(dirname)
356 with open(pathname, 'wb') as fd:
357 fd.write(contents)
358 return pathname
359
360 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600361 def _MakeInputDir(self, dirname):
362 """Create a new test input directory, creating directories as needed
363
364 Args:
365 dirname: Directory name to create
366
367 Returns:
368 Full pathname of directory created
369 """
370 pathname = os.path.join(self._indir, dirname)
371 if not os.path.exists(pathname):
372 os.makedirs(pathname)
373 return pathname
374
375 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600376 def _SetupSplElf(self, src_fname='bss_data'):
377 """Set up an ELF file with a '_dt_ucode_base_size' symbol
378
379 Args:
380 Filename of ELF file to use as SPL
381 """
382 with open(self.TestFile(src_fname)) as fd:
383 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
384
385 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700386 def TestFile(self, fname):
387 return os.path.join(self._binman_dir, 'test', fname)
388
389 def AssertInList(self, grep_list, target):
390 """Assert that at least one of a list of things is in a target
391
392 Args:
393 grep_list: List of strings to check
394 target: Target string
395 """
396 for grep in grep_list:
397 if grep in target:
398 return
399 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
400
401 def CheckNoGaps(self, entries):
402 """Check that all entries fit together without gaps
403
404 Args:
405 entries: List of entries to check
406 """
Simon Glass3ab95982018-08-01 15:22:37 -0600407 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700408 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600409 self.assertEqual(offset, entry.offset)
410 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700411
Simon Glasse0ff8552016-11-25 20:15:53 -0700412 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600413 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700414
415 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600416 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700417
418 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600419 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700420 """
421 return struct.unpack('>L', dtb[4:8])[0]
422
Simon Glasscee02e62018-07-17 13:25:52 -0600423 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600424 def AddNode(node, path):
425 if node.name != '/':
426 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600427 for subnode in node.subnodes:
428 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600429 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600430 prop_path = path + '/' + subnode.name + ':' + prop.name
431 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
432 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600433 AddNode(subnode, path)
434
435 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600436 AddNode(dtb.GetRoot(), '')
437 return tree
438
Simon Glass4f443042016-11-25 20:15:52 -0700439 def testRun(self):
440 """Test a basic run with valid args"""
441 result = self._RunBinman('-h')
442
443 def testFullHelp(self):
444 """Test that the full help is displayed with -H"""
445 result = self._RunBinman('-H')
446 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500447 # Remove possible extraneous strings
448 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
449 gothelp = result.stdout.replace(extra, '')
450 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700451 self.assertEqual(0, len(result.stderr))
452 self.assertEqual(0, result.return_code)
453
454 def testFullHelpInternal(self):
455 """Test that the full help is displayed with -H"""
456 try:
457 command.test_result = command.CommandResult()
458 result = self._DoBinman('-H')
459 help_file = os.path.join(self._binman_dir, 'README')
460 finally:
461 command.test_result = None
462
463 def testHelp(self):
464 """Test that the basic help is displayed with -h"""
465 result = self._RunBinman('-h')
466 self.assertTrue(len(result.stdout) > 200)
467 self.assertEqual(0, len(result.stderr))
468 self.assertEqual(0, result.return_code)
469
Simon Glass4f443042016-11-25 20:15:52 -0700470 def testBoard(self):
471 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600472 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700473 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
474 result = self._DoBinman('-b', 'sandbox')
475 self.assertEqual(0, result)
476
477 def testNeedBoard(self):
478 """Test that we get an error when no board ius supplied"""
479 with self.assertRaises(ValueError) as e:
480 result = self._DoBinman()
481 self.assertIn("Must provide a board to process (use -b <board>)",
482 str(e.exception))
483
484 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600485 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700486 with self.assertRaises(Exception) as e:
487 self._RunBinman('-d', 'missing_file')
488 # We get one error from libfdt, and a different one from fdtget.
489 self.AssertInList(["Couldn't open blob from 'missing_file'",
490 'No such file or directory'], str(e.exception))
491
492 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600493 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700494
495 Since this is a source file it should be compiled and the error
496 will come from the device-tree compiler (dtc).
497 """
498 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600499 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700500 self.assertIn("FATAL ERROR: Unable to parse input tree",
501 str(e.exception))
502
503 def testMissingNode(self):
504 """Test that a device tree without a 'binman' node generates an error"""
505 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600506 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700507 self.assertIn("does not have a 'binman' node", str(e.exception))
508
509 def testEmpty(self):
510 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass741f2d62018-10-01 12:22:30 -0600511 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700512 self.assertEqual(0, len(result.stderr))
513 self.assertEqual(0, result.return_code)
514
515 def testInvalidEntry(self):
516 """Test that an invalid entry is flagged"""
517 with self.assertRaises(Exception) as e:
518 result = self._RunBinman('-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600519 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700520 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
521 "'/binman/not-a-valid-type'", str(e.exception))
522
523 def testSimple(self):
524 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600525 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700526 self.assertEqual(U_BOOT_DATA, data)
527
Simon Glass7fe91732017-11-13 18:55:00 -0700528 def testSimpleDebug(self):
529 """Test a simple binman run with debugging enabled"""
Simon Glass741f2d62018-10-01 12:22:30 -0600530 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700531
Simon Glass4f443042016-11-25 20:15:52 -0700532 def testDual(self):
533 """Test that we can handle creating two images
534
535 This also tests image padding.
536 """
Simon Glass741f2d62018-10-01 12:22:30 -0600537 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700538 self.assertEqual(0, retcode)
539
540 image = control.images['image1']
541 self.assertEqual(len(U_BOOT_DATA), image._size)
542 fname = tools.GetOutputFilename('image1.bin')
543 self.assertTrue(os.path.exists(fname))
544 with open(fname) as fd:
545 data = fd.read()
546 self.assertEqual(U_BOOT_DATA, data)
547
548 image = control.images['image2']
549 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
550 fname = tools.GetOutputFilename('image2.bin')
551 self.assertTrue(os.path.exists(fname))
552 with open(fname) as fd:
553 data = fd.read()
554 self.assertEqual(U_BOOT_DATA, data[3:7])
555 self.assertEqual(chr(0) * 3, data[:3])
556 self.assertEqual(chr(0) * 5, data[7:])
557
558 def testBadAlign(self):
559 """Test that an invalid alignment value is detected"""
560 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600561 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700562 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
563 "of two", str(e.exception))
564
565 def testPackSimple(self):
566 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600567 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700568 self.assertEqual(0, retcode)
569 self.assertIn('image', control.images)
570 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600571 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700572 self.assertEqual(5, len(entries))
573
574 # First u-boot
575 self.assertIn('u-boot', entries)
576 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600577 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700578 self.assertEqual(len(U_BOOT_DATA), entry.size)
579
580 # Second u-boot, aligned to 16-byte boundary
581 self.assertIn('u-boot-align', entries)
582 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600583 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700584 self.assertEqual(len(U_BOOT_DATA), entry.size)
585
586 # Third u-boot, size 23 bytes
587 self.assertIn('u-boot-size', entries)
588 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600589 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700590 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
591 self.assertEqual(23, entry.size)
592
593 # Fourth u-boot, placed immediate after the above
594 self.assertIn('u-boot-next', entries)
595 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600596 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700597 self.assertEqual(len(U_BOOT_DATA), entry.size)
598
Simon Glass3ab95982018-08-01 15:22:37 -0600599 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700600 self.assertIn('u-boot-fixed', entries)
601 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600602 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700603 self.assertEqual(len(U_BOOT_DATA), entry.size)
604
605 self.assertEqual(65, image._size)
606
607 def testPackExtra(self):
608 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600609 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700610
611 self.assertEqual(0, retcode)
612 self.assertIn('image', control.images)
613 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600614 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700615 self.assertEqual(5, len(entries))
616
617 # First u-boot with padding before and after
618 self.assertIn('u-boot', entries)
619 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600620 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700621 self.assertEqual(3, entry.pad_before)
622 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
623
624 # Second u-boot has an aligned size, but it has no effect
625 self.assertIn('u-boot-align-size-nop', entries)
626 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600627 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700628 self.assertEqual(4, entry.size)
629
630 # Third u-boot has an aligned size too
631 self.assertIn('u-boot-align-size', entries)
632 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600633 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700634 self.assertEqual(32, entry.size)
635
636 # Fourth u-boot has an aligned end
637 self.assertIn('u-boot-align-end', entries)
638 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600639 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700640 self.assertEqual(16, entry.size)
641
642 # Fifth u-boot immediately afterwards
643 self.assertIn('u-boot-align-both', entries)
644 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600645 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700646 self.assertEqual(64, entry.size)
647
648 self.CheckNoGaps(entries)
649 self.assertEqual(128, image._size)
650
651 def testPackAlignPowerOf2(self):
652 """Test that invalid entry alignment is detected"""
653 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600654 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700655 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
656 "of two", str(e.exception))
657
658 def testPackAlignSizePowerOf2(self):
659 """Test that invalid entry size alignment is detected"""
660 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600661 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700662 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
663 "power of two", str(e.exception))
664
665 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600666 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700667 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600668 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600669 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700670 "align 0x4 (4)", str(e.exception))
671
672 def testPackInvalidSizeAlign(self):
673 """Test that invalid entry size alignment is detected"""
674 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600675 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700676 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
677 "align-size 0x4 (4)", str(e.exception))
678
679 def testPackOverlap(self):
680 """Test that overlapping regions are detected"""
681 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600682 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600683 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700684 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
685 str(e.exception))
686
687 def testPackEntryOverflow(self):
688 """Test that entries that overflow their size are detected"""
689 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600690 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700691 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
692 "but entry size is 0x3 (3)", str(e.exception))
693
694 def testPackImageOverflow(self):
695 """Test that entries which overflow the image size are detected"""
696 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600697 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600698 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700699 "size 0x3 (3)", str(e.exception))
700
701 def testPackImageSize(self):
702 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600703 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700704 self.assertEqual(0, retcode)
705 self.assertIn('image', control.images)
706 image = control.images['image']
707 self.assertEqual(7, image._size)
708
709 def testPackImageSizeAlign(self):
710 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600711 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700712 self.assertEqual(0, retcode)
713 self.assertIn('image', control.images)
714 image = control.images['image']
715 self.assertEqual(16, image._size)
716
717 def testPackInvalidImageAlign(self):
718 """Test that invalid image alignment is detected"""
719 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600720 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600721 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700722 "align-size 0x8 (8)", str(e.exception))
723
724 def testPackAlignPowerOf2(self):
725 """Test that invalid image alignment is detected"""
726 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600727 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600728 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700729 "two", str(e.exception))
730
731 def testImagePadByte(self):
732 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600733 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600734 data = self._DoReadFile('021_image_pad.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700735 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700736
737 def testImageName(self):
738 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600739 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700740 self.assertEqual(0, retcode)
741 image = control.images['image1']
742 fname = tools.GetOutputFilename('test-name')
743 self.assertTrue(os.path.exists(fname))
744
745 image = control.images['image2']
746 fname = tools.GetOutputFilename('test-name.xx')
747 self.assertTrue(os.path.exists(fname))
748
749 def testBlobFilename(self):
750 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600751 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertEqual(BLOB_DATA, data)
753
754 def testPackSorted(self):
755 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600756 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600757 data = self._DoReadFile('024_sorted.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700758 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
Simon Glass4f443042016-11-25 20:15:52 -0700759 U_BOOT_DATA, data)
760
Simon Glass3ab95982018-08-01 15:22:37 -0600761 def testPackZeroOffset(self):
762 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700763 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600764 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600765 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700766 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
767 str(e.exception))
768
769 def testPackUbootDtb(self):
770 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600771 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700772 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700773
774 def testPackX86RomNoSize(self):
775 """Test that the end-at-4gb property requires a size property"""
776 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600777 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600778 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700779 "using end-at-4gb", str(e.exception))
780
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530781 def test4gbAndSkipAtStartTogether(self):
782 """Test that the end-at-4gb and skip-at-size property can't be used
783 together"""
784 with self.assertRaises(ValueError) as e:
785 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
786 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
787 "'skip-at-start'", str(e.exception))
788
Simon Glasse0ff8552016-11-25 20:15:53 -0700789 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600790 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700791 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600792 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600793 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600794 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700795 str(e.exception))
796
797 def testPackX86Rom(self):
798 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600799 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600800 data = self._DoReadFile('029_x86-rom.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700801 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
802 chr(0) * 2, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700803
804 def testPackX86RomMeNoDesc(self):
805 """Test that an invalid Intel descriptor entry is detected"""
806 TestFunctional._MakeInputFile('descriptor.bin', '')
807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600808 self._DoTestFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700809 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
810 "signature", str(e.exception))
811
812 def testPackX86RomBadDesc(self):
813 """Test that the Intel requires a descriptor entry"""
814 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600815 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600816 self.assertIn("Node '/binman/intel-me': No offset set with "
817 "offset-unset: should another entry provide this correct "
818 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700819
820 def testPackX86RomMe(self):
821 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600822 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700823 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
824
825 def testPackVga(self):
826 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600827 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700828 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
829
830 def testPackStart16(self):
831 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600832 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700833 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
834
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530835 def testPackPowerpcMpc85xxBootpgResetvec(self):
836 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
837 created"""
838 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
839 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
840
Simon Glass736bb0a2018-07-06 10:27:17 -0600841 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600842 """Handle running a test for insertion of microcode
843
844 Args:
845 dts_fname: Name of test .dts file
846 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600847 ucode_second: True if the microsecond entry is second instead of
848 third
Simon Glassadc57012018-07-06 10:27:16 -0600849
850 Returns:
851 Tuple:
852 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600853 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600854 in the above (two 4-byte words)
855 """
Simon Glass6b187df2017-11-12 21:52:27 -0700856 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700857
858 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600859 if ucode_second:
860 ucode_content = data[len(nodtb_data):]
861 ucode_pos = len(nodtb_data)
862 dtb_with_ucode = ucode_content[16:]
863 fdt_len = self.GetFdtLen(dtb_with_ucode)
864 else:
865 dtb_with_ucode = data[len(nodtb_data):]
866 fdt_len = self.GetFdtLen(dtb_with_ucode)
867 ucode_content = dtb_with_ucode[fdt_len:]
868 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700869 fname = tools.GetOutputFilename('test.dtb')
870 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600871 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600872 dtb = fdt.FdtScan(fname)
873 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700874 self.assertTrue(ucode)
875 for node in ucode.subnodes:
876 self.assertFalse(node.props.get('data'))
877
Simon Glasse0ff8552016-11-25 20:15:53 -0700878 # Check that the microcode appears immediately after the Fdt
879 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700880 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700881 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
882 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600883 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700884
885 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600886 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700887 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
888 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600889 u_boot = data[:len(nodtb_data)]
890 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700891
892 def testPackUbootMicrocode(self):
893 """Test that x86 microcode can be handled correctly
894
895 We expect to see the following in the image, in order:
896 u-boot-nodtb.bin with a microcode pointer inserted at the correct
897 place
898 u-boot.dtb with the microcode removed
899 the microcode
900 """
Simon Glass741f2d62018-10-01 12:22:30 -0600901 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700902 U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700903 self.assertEqual('nodtb with microcode' + pos_and_size +
904 ' somewhere in here', first)
905
Simon Glass160a7662017-05-27 07:38:26 -0600906 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700907 """Test that x86 microcode can be handled correctly
908
909 We expect to see the following in the image, in order:
910 u-boot-nodtb.bin with a microcode pointer inserted at the correct
911 place
912 u-boot.dtb with the microcode
913 an empty microcode region
914 """
915 # We need the libfdt library to run this test since only that allows
916 # finding the offset of a property. This is required by
917 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600918 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700919
920 second = data[len(U_BOOT_NODTB_DATA):]
921
922 fdt_len = self.GetFdtLen(second)
923 third = second[fdt_len:]
924 second = second[:fdt_len]
925
Simon Glass160a7662017-05-27 07:38:26 -0600926 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
927 self.assertIn(ucode_data, second)
928 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700929
Simon Glass160a7662017-05-27 07:38:26 -0600930 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600931 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600932 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
933 len(ucode_data))
934 first = data[:len(U_BOOT_NODTB_DATA)]
935 self.assertEqual('nodtb with microcode' + pos_and_size +
936 ' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700937
Simon Glass75db0862016-11-25 20:15:55 -0700938 def testPackUbootSingleMicrocode(self):
939 """Test that x86 microcode can be handled correctly with fdt_normal.
940 """
Simon Glass160a7662017-05-27 07:38:26 -0600941 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700942
Simon Glassc49deb82016-11-25 20:15:54 -0700943 def testUBootImg(self):
944 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600945 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -0700946 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700947
948 def testNoMicrocode(self):
949 """Test that a missing microcode region is detected"""
950 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600951 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700952 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
953 "node found in ", str(e.exception))
954
955 def testMicrocodeWithoutNode(self):
956 """Test that a missing u-boot-dtb-with-ucode node is detected"""
957 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600958 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700959 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
960 "microcode region u-boot-dtb-with-ucode", str(e.exception))
961
962 def testMicrocodeWithoutNode2(self):
963 """Test that a missing u-boot-ucode node is detected"""
964 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600965 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700966 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
967 "microcode region u-boot-ucode", str(e.exception))
968
969 def testMicrocodeWithoutPtrInElf(self):
970 """Test that a U-Boot binary without the microcode symbol is detected"""
971 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700972 try:
973 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
974 TestFunctional._MakeInputFile('u-boot', fd.read())
975
976 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600977 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700978 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
979 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
980
981 finally:
982 # Put the original file back
983 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
984 TestFunctional._MakeInputFile('u-boot', fd.read())
985
986 def testMicrocodeNotInImage(self):
987 """Test that microcode must be placed within the image"""
988 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600989 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700990 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
991 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -0600992 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -0700993
994 def testWithoutMicrocode(self):
995 """Test that we can cope with an image without microcode (e.g. qemu)"""
996 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
997 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -0600998 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700999
1000 # Now check the device tree has no microcode
1001 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1002 second = data[len(U_BOOT_NODTB_DATA):]
1003
1004 fdt_len = self.GetFdtLen(second)
1005 self.assertEqual(dtb, second[:fdt_len])
1006
1007 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1008 third = data[used_len:]
1009 self.assertEqual(chr(0) * (0x200 - used_len), third)
1010
1011 def testUnknownPosSize(self):
1012 """Test that microcode must be placed within the image"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001014 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001015 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001016 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001017
1018 def testPackFsp(self):
1019 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001020 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001021 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1022
1023 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001024 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001025 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001026 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001027
1028 def testPackVbt(self):
1029 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001030 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001031 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001032
Simon Glass56509842017-11-12 21:52:25 -07001033 def testSplBssPad(self):
1034 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001035 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001036 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001037 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass56509842017-11-12 21:52:25 -07001038 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
1039
Simon Glass86af5112018-10-01 21:12:42 -06001040 def testSplBssPadMissing(self):
1041 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001042 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001043 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001044 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001045 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1046 str(e.exception))
1047
Simon Glass87722132017-11-12 21:52:26 -07001048 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001049 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001050 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001051 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1052
Simon Glass736bb0a2018-07-06 10:27:17 -06001053 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1054 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001055
1056 We expect to see the following in the image, in order:
1057 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1058 correct place
1059 u-boot.dtb with the microcode removed
1060 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001061
1062 Args:
1063 dts: Device tree file to use for test
1064 ucode_second: True if the microsecond entry is second instead of
1065 third
Simon Glass6b187df2017-11-12 21:52:27 -07001066 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001067 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001068 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1069 ucode_second=ucode_second)
Simon Glass6b187df2017-11-12 21:52:27 -07001070 self.assertEqual('splnodtb with microc' + pos_and_size +
1071 'ter somewhere in here', first)
1072
Simon Glass736bb0a2018-07-06 10:27:17 -06001073 def testPackUbootSplMicrocode(self):
1074 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001075 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001076
1077 def testPackUbootSplMicrocodeReorder(self):
1078 """Test that order doesn't matter for microcode entries
1079
1080 This is the same as testPackUbootSplMicrocode but when we process the
1081 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1082 entry, so we reply on binman to try later.
1083 """
Simon Glass741f2d62018-10-01 12:22:30 -06001084 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001085 ucode_second=True)
1086
Simon Glassca4f4ff2017-11-12 21:52:28 -07001087 def testPackMrc(self):
1088 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001089 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001090 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1091
Simon Glass47419ea2017-11-13 18:54:55 -07001092 def testSplDtb(self):
1093 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001094 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001095 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1096
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001097 def testSplNoDtb(self):
1098 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001099 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001100 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1101
Simon Glass19790632017-11-13 18:55:01 -07001102 def testSymbols(self):
1103 """Test binman can assign symbols embedded in U-Boot"""
1104 elf_fname = self.TestFile('u_boot_binman_syms')
1105 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1106 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001107 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001108
Simon Glass11ae93e2018-10-01 21:12:47 -06001109 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001110 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001111 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1112 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1113 U_BOOT_DATA +
1114 sym_values + U_BOOT_SPL_DATA[16:])
1115 self.assertEqual(expected, data)
1116
Simon Glassdd57c132018-06-01 09:38:11 -06001117 def testPackUnitAddress(self):
1118 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001119 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001120 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1121
Simon Glass18546952018-06-01 09:38:16 -06001122 def testSections(self):
1123 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001124 data = self._DoReadFile('055_sections.dts')
Simon Glass8122f392018-07-17 13:25:28 -06001125 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1126 U_BOOT_DATA + '&' * 4)
Simon Glass18546952018-06-01 09:38:16 -06001127 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001128
Simon Glass3b0c38212018-06-01 09:38:20 -06001129 def testMap(self):
1130 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001131 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001132 self.assertEqual('''ImagePos Offset Size Name
113300000000 00000000 00000028 main-section
113400000000 00000000 00000010 section@0
113500000000 00000000 00000004 u-boot
113600000010 00000010 00000010 section@1
113700000010 00000000 00000004 u-boot
113800000020 00000020 00000004 section@2
113900000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001140''', map_data)
1141
Simon Glassc8d48ef2018-06-01 09:38:21 -06001142 def testNamePrefix(self):
1143 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001144 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001145 self.assertEqual('''ImagePos Offset Size Name
114600000000 00000000 00000028 main-section
114700000000 00000000 00000010 section@0
114800000000 00000000 00000004 ro-u-boot
114900000010 00000010 00000010 section@1
115000000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001151''', map_data)
1152
Simon Glass736bb0a2018-07-06 10:27:17 -06001153 def testUnknownContents(self):
1154 """Test that obtaining the contents works as expected"""
1155 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001156 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-07-06 10:27:17 -06001157 self.assertIn("Section '/binman': Internal error: Could not complete "
1158 "processing of contents: remaining [<_testing.Entry__testing ",
1159 str(e.exception))
1160
Simon Glass5c890232018-07-06 10:27:19 -06001161 def testBadChangeSize(self):
1162 """Test that trying to change the size of an entry fails"""
1163 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001164 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-07-06 10:27:19 -06001165 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1166 '2 to 1', str(e.exception))
1167
Simon Glass16b8d6b2018-07-06 10:27:42 -06001168 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001169 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001170 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001171 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001172 dtb = fdt.Fdt(out_dtb_fname)
1173 dtb.Scan()
1174 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001175 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001176 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001177 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001178 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001179 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001180 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001181 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001182 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001183 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001184 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001185 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001186 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001187
Simon Glass3ab95982018-08-01 15:22:37 -06001188 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001189 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001190 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001191 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001192 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001193 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001194 'size': 40
1195 }, props)
1196
1197 def testUpdateFdtBad(self):
1198 """Test that we detect when ProcessFdt never completes"""
1199 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001200 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001201 self.assertIn('Could not complete processing of Fdt: remaining '
1202 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001203
Simon Glass53af22a2018-07-17 13:25:32 -06001204 def testEntryArgs(self):
1205 """Test passing arguments to entries from the command line"""
1206 entry_args = {
1207 'test-str-arg': 'test1',
1208 'test-int-arg': '456',
1209 }
Simon Glass741f2d62018-10-01 12:22:30 -06001210 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001211 self.assertIn('image', control.images)
1212 entry = control.images['image'].GetEntries()['_testing']
1213 self.assertEqual('test0', entry.test_str_fdt)
1214 self.assertEqual('test1', entry.test_str_arg)
1215 self.assertEqual(123, entry.test_int_fdt)
1216 self.assertEqual(456, entry.test_int_arg)
1217
1218 def testEntryArgsMissing(self):
1219 """Test missing arguments and properties"""
1220 entry_args = {
1221 'test-int-arg': '456',
1222 }
Simon Glass741f2d62018-10-01 12:22:30 -06001223 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001224 entry = control.images['image'].GetEntries()['_testing']
1225 self.assertEqual('test0', entry.test_str_fdt)
1226 self.assertEqual(None, entry.test_str_arg)
1227 self.assertEqual(None, entry.test_int_fdt)
1228 self.assertEqual(456, entry.test_int_arg)
1229
1230 def testEntryArgsRequired(self):
1231 """Test missing arguments and properties"""
1232 entry_args = {
1233 'test-int-arg': '456',
1234 }
1235 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001236 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001237 self.assertIn("Node '/binman/_testing': Missing required "
1238 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1239 str(e.exception))
1240
1241 def testEntryArgsInvalidFormat(self):
1242 """Test that an invalid entry-argument format is detected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001243 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001244 with self.assertRaises(ValueError) as e:
1245 self._DoBinman(*args)
1246 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1247
1248 def testEntryArgsInvalidInteger(self):
1249 """Test that an invalid entry-argument integer is detected"""
1250 entry_args = {
1251 'test-int-arg': 'abc',
1252 }
1253 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001254 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001255 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1256 "'test-int-arg' (value 'abc') to integer",
1257 str(e.exception))
1258
1259 def testEntryArgsInvalidDatatype(self):
1260 """Test that an invalid entry-argument datatype is detected
1261
1262 This test could be written in entry_test.py except that it needs
1263 access to control.entry_args, which seems more than that module should
1264 be able to see.
1265 """
1266 entry_args = {
1267 'test-bad-datatype-arg': '12',
1268 }
1269 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001270 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001271 entry_args=entry_args)
1272 self.assertIn('GetArg() internal error: Unknown data type ',
1273 str(e.exception))
1274
Simon Glassbb748372018-07-17 13:25:33 -06001275 def testText(self):
1276 """Test for a text entry type"""
1277 entry_args = {
1278 'test-id': TEXT_DATA,
1279 'test-id2': TEXT_DATA2,
1280 'test-id3': TEXT_DATA3,
1281 }
Simon Glass741f2d62018-10-01 12:22:30 -06001282 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001283 entry_args=entry_args)
1284 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1285 TEXT_DATA3 + 'some text')
1286 self.assertEqual(expected, data)
1287
Simon Glassfd8d1f72018-07-17 13:25:36 -06001288 def testEntryDocs(self):
1289 """Test for creation of entry documentation"""
1290 with test_util.capture_sys_output() as (stdout, stderr):
1291 control.WriteEntryDocs(binman.GetEntryModules())
1292 self.assertTrue(len(stdout.getvalue()) > 0)
1293
1294 def testEntryDocsMissing(self):
1295 """Test handling of missing entry documentation"""
1296 with self.assertRaises(ValueError) as e:
1297 with test_util.capture_sys_output() as (stdout, stderr):
1298 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1299 self.assertIn('Documentation is missing for modules: u_boot',
1300 str(e.exception))
1301
Simon Glass11e36cc2018-07-17 13:25:38 -06001302 def testFmap(self):
1303 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001304 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001305 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1306 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1307 self.assertEqual(expected, data[:32])
1308 self.assertEqual('__FMAP__', fhdr.signature)
1309 self.assertEqual(1, fhdr.ver_major)
1310 self.assertEqual(0, fhdr.ver_minor)
1311 self.assertEqual(0, fhdr.base)
1312 self.assertEqual(16 + 16 +
1313 fmap_util.FMAP_HEADER_LEN +
1314 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1315 self.assertEqual('FMAP', fhdr.name)
1316 self.assertEqual(3, fhdr.nareas)
1317 for fentry in fentries:
1318 self.assertEqual(0, fentry.flags)
1319
1320 self.assertEqual(0, fentries[0].offset)
1321 self.assertEqual(4, fentries[0].size)
1322 self.assertEqual('RO_U_BOOT', fentries[0].name)
1323
1324 self.assertEqual(16, fentries[1].offset)
1325 self.assertEqual(4, fentries[1].size)
1326 self.assertEqual('RW_U_BOOT', fentries[1].name)
1327
1328 self.assertEqual(32, fentries[2].offset)
1329 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1330 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1331 self.assertEqual('FMAP', fentries[2].name)
1332
Simon Glassec127af2018-07-17 13:25:39 -06001333 def testBlobNamedByArg(self):
1334 """Test we can add a blob with the filename coming from an entry arg"""
1335 entry_args = {
1336 'cros-ec-rw-path': 'ecrw.bin',
1337 }
Simon Glass741f2d62018-10-01 12:22:30 -06001338 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001339 entry_args=entry_args)
1340
Simon Glass3af8e492018-07-17 13:25:40 -06001341 def testFill(self):
1342 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001343 data = self._DoReadFile('069_fill.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001344 expected = 8 * chr(0xff) + 8 * chr(0)
1345 self.assertEqual(expected, data)
1346
1347 def testFillNoSize(self):
1348 """Test for an fill entry type with no size"""
1349 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001350 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001351 self.assertIn("'fill' entry must have a size property",
1352 str(e.exception))
1353
Simon Glass0ef87aa2018-07-17 13:25:44 -06001354 def _HandleGbbCommand(self, pipe_list):
1355 """Fake calls to the futility utility"""
1356 if pipe_list[0][0] == 'futility':
1357 fname = pipe_list[0][-1]
1358 # Append our GBB data to the file, which will happen every time the
1359 # futility command is called.
1360 with open(fname, 'a') as fd:
1361 fd.write(GBB_DATA)
1362 return command.CommandResult()
1363
1364 def testGbb(self):
1365 """Test for the Chromium OS Google Binary Block"""
1366 command.test_result = self._HandleGbbCommand
1367 entry_args = {
1368 'keydir': 'devkeys',
1369 'bmpblk': 'bmpblk.bin',
1370 }
Simon Glass741f2d62018-10-01 12:22:30 -06001371 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001372
1373 # Since futility
1374 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1375 self.assertEqual(expected, data)
1376
1377 def testGbbTooSmall(self):
1378 """Test for the Chromium OS Google Binary Block being large enough"""
1379 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001380 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001381 self.assertIn("Node '/binman/gbb': GBB is too small",
1382 str(e.exception))
1383
1384 def testGbbNoSize(self):
1385 """Test for the Chromium OS Google Binary Block having a size"""
1386 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001387 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001388 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1389 str(e.exception))
1390
Simon Glass24d0d3c2018-07-17 13:25:47 -06001391 def _HandleVblockCommand(self, pipe_list):
1392 """Fake calls to the futility utility"""
1393 if pipe_list[0][0] == 'futility':
1394 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001395 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001396 fd.write(VBLOCK_DATA)
1397 return command.CommandResult()
1398
1399 def testVblock(self):
1400 """Test for the Chromium OS Verified Boot Block"""
1401 command.test_result = self._HandleVblockCommand
1402 entry_args = {
1403 'keydir': 'devkeys',
1404 }
Simon Glass741f2d62018-10-01 12:22:30 -06001405 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001406 entry_args=entry_args)
1407 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1408 self.assertEqual(expected, data)
1409
1410 def testVblockNoContent(self):
1411 """Test we detect a vblock which has no content to sign"""
1412 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001413 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001414 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1415 'property', str(e.exception))
1416
1417 def testVblockBadPhandle(self):
1418 """Test that we detect a vblock with an invalid phandle in contents"""
1419 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001420 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001421 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1422 '1000', str(e.exception))
1423
1424 def testVblockBadEntry(self):
1425 """Test that we detect an entry that points to a non-entry"""
1426 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001427 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001428 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1429 "'other'", str(e.exception))
1430
Simon Glassb8ef5b62018-07-17 13:25:48 -06001431 def testTpl(self):
1432 """Test that an image with TPL and ots device tree can be created"""
1433 # ELF file with a '__bss_size' symbol
1434 with open(self.TestFile('bss_data')) as fd:
1435 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001436 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001437 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1438
Simon Glass15a587c2018-07-17 13:25:51 -06001439 def testUsesPos(self):
1440 """Test that the 'pos' property cannot be used anymore"""
1441 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001442 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001443 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1444 "'pos'", str(e.exception))
1445
Simon Glassd178eab2018-09-14 04:57:08 -06001446 def testFillZero(self):
1447 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001448 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassd178eab2018-09-14 04:57:08 -06001449 self.assertEqual(chr(0) * 16, data)
1450
Simon Glass0b489362018-09-14 04:57:09 -06001451 def testTextMissing(self):
1452 """Test for a text entry type where there is no text"""
1453 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001454 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001455 self.assertIn("Node '/binman/text': No value provided for text label "
1456 "'test-id'", str(e.exception))
1457
Simon Glass35b384c2018-09-14 04:57:10 -06001458 def testPackStart16Tpl(self):
1459 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001460 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001461 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1462
Simon Glass0bfa7b02018-09-14 04:57:12 -06001463 def testSelectImage(self):
1464 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001465 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001466
Simon Glasseb833d82019-04-25 21:58:34 -06001467 # We should only get the expected message in verbose mode
1468 for verbosity in (None, 2):
1469 with test_util.capture_sys_output() as (stdout, stderr):
1470 retcode = self._DoTestFile('006_dual_image.dts',
1471 verbosity=verbosity,
1472 images=['image2'])
1473 self.assertEqual(0, retcode)
1474 if verbosity:
1475 self.assertIn(expected, stdout.getvalue())
1476 else:
1477 self.assertNotIn(expected, stdout.getvalue())
1478
1479 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1480 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001481
Simon Glass6ed45ba2018-09-14 04:57:24 -06001482 def testUpdateFdtAll(self):
1483 """Test that all device trees are updated with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001484 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001485 use_real_dtb=True, update_dtb=True)
1486
1487 base_expected = {
1488 'section:image-pos': 0,
1489 'u-boot-tpl-dtb:size': 513,
1490 'u-boot-spl-dtb:size': 513,
1491 'u-boot-spl-dtb:offset': 493,
1492 'image-pos': 0,
1493 'section/u-boot-dtb:image-pos': 0,
1494 'u-boot-spl-dtb:image-pos': 493,
1495 'section/u-boot-dtb:size': 493,
1496 'u-boot-tpl-dtb:image-pos': 1006,
1497 'section/u-boot-dtb:offset': 0,
1498 'section:size': 493,
1499 'offset': 0,
1500 'section:offset': 0,
1501 'u-boot-tpl-dtb:offset': 1006,
1502 'size': 1519
1503 }
1504
1505 # We expect three device-tree files in the output, one after the other.
1506 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1507 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1508 # main U-Boot tree. All three should have the same postions and offset.
1509 start = 0
1510 for item in ['', 'spl', 'tpl']:
1511 dtb = fdt.Fdt.FromData(data[start:])
1512 dtb.Scan()
1513 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1514 'spl', 'tpl'])
1515 expected = dict(base_expected)
1516 if item:
1517 expected[item] = 0
1518 self.assertEqual(expected, props)
1519 start += dtb._fdt_obj.totalsize()
1520
1521 def testUpdateFdtOutput(self):
1522 """Test that output DTB files are updated"""
1523 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001524 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001525 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1526
1527 # Unfortunately, compiling a source file always results in a file
1528 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001529 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001530 # binman as a file called u-boot.dtb. To fix this, copy the file
1531 # over to the expected place.
1532 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1533 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1534 start = 0
1535 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1536 'tpl/u-boot-tpl.dtb.out']:
1537 dtb = fdt.Fdt.FromData(data[start:])
1538 size = dtb._fdt_obj.totalsize()
1539 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1540 outdata = tools.ReadFile(pathname)
1541 name = os.path.split(fname)[0]
1542
1543 if name:
1544 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1545 else:
1546 orig_indata = dtb_data
1547 self.assertNotEqual(outdata, orig_indata,
1548 "Expected output file '%s' be updated" % pathname)
1549 self.assertEqual(outdata, data[start:start + size],
1550 "Expected output file '%s' to match output image" %
1551 pathname)
1552 start += size
1553 finally:
1554 self._ResetDtbs()
1555
Simon Glass83d73c22018-09-14 04:57:26 -06001556 def _decompress(self, data):
1557 out = os.path.join(self._indir, 'lz4.tmp')
1558 with open(out, 'wb') as fd:
1559 fd.write(data)
1560 return tools.Run('lz4', '-dc', out)
1561 '''
1562 try:
1563 orig = lz4.frame.decompress(data)
1564 except AttributeError:
1565 orig = lz4.decompress(data)
1566 '''
1567
1568 def testCompress(self):
1569 """Test compression of blobs"""
Simon Glass741f2d62018-10-01 12:22:30 -06001570 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001571 use_real_dtb=True, update_dtb=True)
1572 dtb = fdt.Fdt(out_dtb_fname)
1573 dtb.Scan()
1574 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1575 orig = self._decompress(data)
1576 self.assertEquals(COMPRESS_DATA, orig)
1577 expected = {
1578 'blob:uncomp-size': len(COMPRESS_DATA),
1579 'blob:size': len(data),
1580 'size': len(data),
1581 }
1582 self.assertEqual(expected, props)
1583
Simon Glass0a98b282018-09-14 04:57:28 -06001584 def testFiles(self):
1585 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001586 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001587 self.assertEqual(FILES_DATA, data)
1588
1589 def testFilesCompress(self):
1590 """Test bringing in multiple files and compressing them"""
Simon Glass741f2d62018-10-01 12:22:30 -06001591 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001592
1593 image = control.images['image']
1594 entries = image.GetEntries()
1595 files = entries['files']
1596 entries = files._section._entries
1597
1598 orig = ''
1599 for i in range(1, 3):
1600 key = '%d.dat' % i
1601 start = entries[key].image_pos
1602 len = entries[key].size
1603 chunk = data[start:start + len]
1604 orig += self._decompress(chunk)
1605
1606 self.assertEqual(FILES_DATA, orig)
1607
1608 def testFilesMissing(self):
1609 """Test missing files"""
1610 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001611 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001612 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1613 'no files', str(e.exception))
1614
1615 def testFilesNoPattern(self):
1616 """Test missing files"""
1617 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001618 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001619 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1620 str(e.exception))
1621
Simon Glassba64a0b2018-09-14 04:57:29 -06001622 def testExpandSize(self):
1623 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001624 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001625 map=True)
1626 expect = ('a' * 8 + U_BOOT_DATA +
1627 MRC_DATA + 'b' * 1 + U_BOOT_DATA +
1628 'c' * 8 + U_BOOT_DATA +
1629 'd' * 8)
1630 self.assertEqual(expect, data)
1631 self.assertEqual('''ImagePos Offset Size Name
163200000000 00000000 00000028 main-section
163300000000 00000000 00000008 fill
163400000008 00000008 00000004 u-boot
16350000000c 0000000c 00000004 section
16360000000c 00000000 00000003 intel-mrc
163700000010 00000010 00000004 u-boot2
163800000014 00000014 0000000c section2
163900000014 00000000 00000008 fill
16400000001c 00000008 00000004 u-boot
164100000020 00000020 00000008 fill2
1642''', map_data)
1643
1644 def testExpandSizeBad(self):
1645 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001646 with test_util.capture_sys_output() as (stdout, stderr):
1647 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001648 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001649 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1650 'expanding entry', str(e.exception))
1651
Simon Glasse0e5df92018-09-14 04:57:31 -06001652 def testHash(self):
1653 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001654 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001655 use_real_dtb=True, update_dtb=True)
1656 dtb = fdt.Fdt(out_dtb_fname)
1657 dtb.Scan()
1658 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1659 m = hashlib.sha256()
1660 m.update(U_BOOT_DATA)
1661 self.assertEqual(m.digest(), ''.join(hash_node.value))
1662
1663 def testHashNoAlgo(self):
1664 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001665 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001666 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1667 'hash node', str(e.exception))
1668
1669 def testHashBadAlgo(self):
1670 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001671 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001672 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1673 str(e.exception))
1674
1675 def testHashSection(self):
1676 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001677 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001678 use_real_dtb=True, update_dtb=True)
1679 dtb = fdt.Fdt(out_dtb_fname)
1680 dtb.Scan()
1681 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1682 m = hashlib.sha256()
1683 m.update(U_BOOT_DATA)
1684 m.update(16 * 'a')
1685 self.assertEqual(m.digest(), ''.join(hash_node.value))
1686
Simon Glassf0253632018-09-14 04:57:32 -06001687 def testPackUBootTplMicrocode(self):
1688 """Test that x86 microcode can be handled correctly in TPL
1689
1690 We expect to see the following in the image, in order:
1691 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1692 place
1693 u-boot-tpl.dtb with the microcode removed
1694 the microcode
1695 """
1696 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1697 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001698 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001699 U_BOOT_TPL_NODTB_DATA)
1700 self.assertEqual('tplnodtb with microc' + pos_and_size +
1701 'ter somewhere in here', first)
1702
Simon Glassf8f8df62018-09-14 04:57:34 -06001703 def testFmapX86(self):
1704 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001705 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001706 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1707 expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7)
1708 self.assertEqual(expected, data[:32])
1709 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1710
1711 self.assertEqual(0x100, fhdr.image_size)
1712
1713 self.assertEqual(0, fentries[0].offset)
1714 self.assertEqual(4, fentries[0].size)
1715 self.assertEqual('U_BOOT', fentries[0].name)
1716
1717 self.assertEqual(4, fentries[1].offset)
1718 self.assertEqual(3, fentries[1].size)
1719 self.assertEqual('INTEL_MRC', fentries[1].name)
1720
1721 self.assertEqual(32, fentries[2].offset)
1722 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1723 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1724 self.assertEqual('FMAP', fentries[2].name)
1725
1726 def testFmapX86Section(self):
1727 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001728 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001729 expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7)
1730 self.assertEqual(expected, data[:32])
1731 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1732
1733 self.assertEqual(0x100, fhdr.image_size)
1734
1735 self.assertEqual(0, fentries[0].offset)
1736 self.assertEqual(4, fentries[0].size)
1737 self.assertEqual('U_BOOT', fentries[0].name)
1738
1739 self.assertEqual(4, fentries[1].offset)
1740 self.assertEqual(3, fentries[1].size)
1741 self.assertEqual('INTEL_MRC', fentries[1].name)
1742
1743 self.assertEqual(36, fentries[2].offset)
1744 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1745 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1746 self.assertEqual('FMAP', fentries[2].name)
1747
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001748 def testElf(self):
1749 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001750 self._SetupSplElf()
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001751 with open(self.TestFile('bss_data')) as fd:
1752 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001753 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001754
1755 def testElfStripg(self):
1756 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001757 self._SetupSplElf()
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001758 with open(self.TestFile('bss_data')) as fd:
1759 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001760 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001761
Simon Glass163ed6c2018-09-14 04:57:36 -06001762 def testPackOverlapMap(self):
1763 """Test that overlapping regions are detected"""
1764 with test_util.capture_sys_output() as (stdout, stderr):
1765 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001766 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001767 map_fname = tools.GetOutputFilename('image.map')
1768 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1769 stdout.getvalue())
1770
1771 # We should not get an inmage, but there should be a map file
1772 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1773 self.assertTrue(os.path.exists(map_fname))
1774 map_data = tools.ReadFile(map_fname)
1775 self.assertEqual('''ImagePos Offset Size Name
1776<none> 00000000 00000007 main-section
1777<none> 00000000 00000004 u-boot
1778<none> 00000003 00000004 u-boot-align
1779''', map_data)
1780
Simon Glass3ae192c2018-10-01 12:22:31 -06001781 def testPacRefCode(self):
1782 """Test that an image with an Intel Reference code binary works"""
1783 data = self._DoReadFile('100_intel_refcode.dts')
1784 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1785
Simon Glass9481c802019-04-25 21:58:39 -06001786 def testSectionOffset(self):
1787 """Tests use of a section with an offset"""
1788 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1789 map=True)
1790 self.assertEqual('''ImagePos Offset Size Name
179100000000 00000000 00000038 main-section
179200000004 00000004 00000010 section@0
179300000004 00000000 00000004 u-boot
179400000018 00000018 00000010 section@1
179500000018 00000000 00000004 u-boot
17960000002c 0000002c 00000004 section@2
17970000002c 00000000 00000004 u-boot
1798''', map_data)
1799 self.assertEqual(data,
1800 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x21) +
1801 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x61) +
1802 4 * chr(0x26) + U_BOOT_DATA + 8 * chr(0x26))
1803
Simon Glass53af22a2018-07-17 13:25:32 -06001804
Simon Glass9fc60b42017-11-12 21:52:22 -07001805if __name__ == "__main__":
1806 unittest.main()