blob: f5e0b9b97420a6094d2c3dd139cea6a1ea90dbdc [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 Glassc6c10e72019-05-17 22:00:46 -060032U_BOOT_DATA = b'1234'
33U_BOOT_IMG_DATA = b'img'
34U_BOOT_SPL_DATA = b'56780123456789abcde'
35U_BOOT_TPL_DATA = b'tpl'
36BLOB_DATA = b'89'
37ME_DATA = b'0abcd'
38VGA_DATA = b'vga'
39U_BOOT_DTB_DATA = b'udtb'
40U_BOOT_SPL_DTB_DATA = b'spldtb'
41U_BOOT_TPL_DTB_DATA = b'tpldtb'
42X86_START16_DATA = b'start16'
43X86_START16_SPL_DATA = b'start16spl'
44X86_START16_TPL_DATA = b'start16tpl'
45PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
46U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
47U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
48U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
49FSP_DATA = b'fsp'
50CMC_DATA = b'cmc'
51VBT_DATA = b'vbt'
52MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060053TEXT_DATA = 'text'
54TEXT_DATA2 = 'text2'
55TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060056CROS_EC_RW_DATA = b'ecrw'
57GBB_DATA = b'gbbd'
58BMPBLK_DATA = b'bmp'
59VBLOCK_DATA = b'vblk'
60FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
61 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060062COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060063REFCODE_DATA = b'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
Simon Glass1d0ebf72019-05-14 15:53:42 -0600122 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700123 TestFunctional._MakeInputFile('u-boot', fd.read())
124
125 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600126 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700127 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 Glassee0c9a72019-07-08 13:18:48 -0600156 def _GetVerbosity(self):
157 """Check if verbosity should be enabled
158
159 Returns:
160 list containing either:
161 - Verbosity flag (e.g. '-v2') if it is present on the cmd line
162 - nothing if the flag is not present
163 """
164 for arg in sys.argv[1:]:
165 if arg.startswith('-v'):
166 return [arg]
167 return []
168
Simon Glass4f443042016-11-25 20:15:52 -0700169 def _RunBinman(self, *args, **kwargs):
170 """Run binman using the command line
171
172 Args:
173 Arguments to pass, as a list of strings
174 kwargs: Arguments to pass to Command.RunPipe()
175 """
176 result = command.RunPipe([[self._binman_pathname] + list(args)],
177 capture=True, capture_stderr=True, raise_on_error=False)
178 if result.return_code and kwargs.get('raise_on_error', True):
179 raise Exception("Error running '%s': %s" % (' '.join(args),
180 result.stdout + result.stderr))
181 return result
182
183 def _DoBinman(self, *args):
184 """Run binman using directly (in the same process)
185
186 Args:
187 Arguments to pass, as a list of strings
188 Returns:
189 Return value (0 for success)
190 """
Simon Glass7fe91732017-11-13 18:55:00 -0700191 args = list(args)
192 if '-D' in sys.argv:
193 args = args + ['-D']
194 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700195 options.pager = 'binman-invalid-pager'
196 options.build_dir = self._indir
197
198 # For testing, you can force an increase in verbosity here
199 # options.verbosity = tout.DEBUG
200 return control.Binman(options, args)
201
Simon Glass53af22a2018-07-17 13:25:32 -0600202 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600203 entry_args=None, images=None, use_real_dtb=False,
204 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700205 """Run binman with a given test file
206
207 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600208 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600209 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600210 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600211 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600212 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600213 entry_args: Dict of entry args to supply to binman
214 key: arg name
215 value: value of that arg
216 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700217 """
Simon Glass7fe91732017-11-13 18:55:00 -0700218 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
219 if debug:
220 args.append('-D')
Simon Glass3b0c3822018-06-01 09:38:20 -0600221 if map:
222 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600223 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600224 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600225 if not use_real_dtb:
226 args.append('--fake-dtb')
Simon Glasseb833d82019-04-25 21:58:34 -0600227 if verbosity is not None:
228 args.append('-v%d' % verbosity)
Simon Glassee0c9a72019-07-08 13:18:48 -0600229 else:
230 args += self._GetVerbosity()
Simon Glass53af22a2018-07-17 13:25:32 -0600231 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600232 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600233 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600234 if images:
235 for image in images:
236 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700237 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700238
239 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700240 """Set up a new test device-tree file
241
242 The given file is compiled and set up as the device tree to be used
243 for ths test.
244
245 Args:
246 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600247 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700248
249 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600250 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700251 """
Simon Glasse0e62752018-10-01 21:12:41 -0600252 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700253 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600254 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700255 data = fd.read()
256 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600257 tools.FinaliseOutputDir()
258 return data
Simon Glass4f443042016-11-25 20:15:52 -0700259
Simon Glass6ed45ba2018-09-14 04:57:24 -0600260 def _GetDtbContentsForSplTpl(self, dtb_data, name):
261 """Create a version of the main DTB for SPL or SPL
262
263 For testing we don't actually have different versions of the DTB. With
264 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
265 we don't normally have any unwanted nodes.
266
267 We still want the DTBs for SPL and TPL to be different though, since
268 otherwise it is confusing to know which one we are looking at. So add
269 an 'spl' or 'tpl' property to the top-level node.
270 """
271 dtb = fdt.Fdt.FromData(dtb_data)
272 dtb.Scan()
273 dtb.GetNode('/binman').AddZeroProp(name)
274 dtb.Sync(auto_resize=True)
275 dtb.Pack()
276 return dtb.GetContents()
277
Simon Glass16b8d6b2018-07-06 10:27:42 -0600278 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600279 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700280 """Run binman and return the resulting image
281
282 This runs binman with a given test file and then reads the resulting
283 output file. It is a shortcut function since most tests need to do
284 these steps.
285
286 Raises an assertion failure if binman returns a non-zero exit code.
287
288 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600289 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700290 use_real_dtb: True to use the test file as the contents of
291 the u-boot-dtb entry. Normally this is not needed and the
292 test contents (the U_BOOT_DTB_DATA string) can be used.
293 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600294 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600295 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600296 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700297
298 Returns:
299 Tuple:
300 Resulting image contents
301 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600302 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600303 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700304 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700305 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700306 # Use the compiled test file as the u-boot-dtb input
307 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700308 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600309
310 # For testing purposes, make a copy of the DT for SPL and TPL. Add
311 # a node indicating which it is, so aid verification.
312 for name in ['spl', 'tpl']:
313 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
314 outfile = os.path.join(self._indir, dtb_fname)
315 TestFunctional._MakeInputFile(dtb_fname,
316 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700317
318 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600319 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600320 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700321 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600322 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700323
324 # Find the (only) image, read it and return its contents
325 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600326 image_fname = tools.GetOutputFilename('image.bin')
327 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600328 if map:
329 map_fname = tools.GetOutputFilename('image.map')
330 with open(map_fname) as fd:
331 map_data = fd.read()
332 else:
333 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600334 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600335 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700336 finally:
337 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600338 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600339 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700340
Simon Glasse0ff8552016-11-25 20:15:53 -0700341 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600342 """Helper function which discards the device-tree binary
343
344 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600345 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600346 use_real_dtb: True to use the test file as the contents of
347 the u-boot-dtb entry. Normally this is not needed and the
348 test contents (the U_BOOT_DTB_DATA string) can be used.
349 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600350
351 Returns:
352 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600353 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700354 return self._DoReadFileDtb(fname, use_real_dtb)[0]
355
Simon Glass4f443042016-11-25 20:15:52 -0700356 @classmethod
357 def _MakeInputFile(self, fname, contents):
358 """Create a new test input file, creating directories as needed
359
360 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600361 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700362 contents: File contents to write in to the file
363 Returns:
364 Full pathname of file created
365 """
366 pathname = os.path.join(self._indir, fname)
367 dirname = os.path.dirname(pathname)
368 if dirname and not os.path.exists(dirname):
369 os.makedirs(dirname)
370 with open(pathname, 'wb') as fd:
371 fd.write(contents)
372 return pathname
373
374 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600375 def _MakeInputDir(self, dirname):
376 """Create a new test input directory, creating directories as needed
377
378 Args:
379 dirname: Directory name to create
380
381 Returns:
382 Full pathname of directory created
383 """
384 pathname = os.path.join(self._indir, dirname)
385 if not os.path.exists(pathname):
386 os.makedirs(pathname)
387 return pathname
388
389 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600390 def _SetupSplElf(self, src_fname='bss_data'):
391 """Set up an ELF file with a '_dt_ucode_base_size' symbol
392
393 Args:
394 Filename of ELF file to use as SPL
395 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600396 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600397 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
398
399 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700400 def TestFile(self, fname):
401 return os.path.join(self._binman_dir, 'test', fname)
402
403 def AssertInList(self, grep_list, target):
404 """Assert that at least one of a list of things is in a target
405
406 Args:
407 grep_list: List of strings to check
408 target: Target string
409 """
410 for grep in grep_list:
411 if grep in target:
412 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600413 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700414
415 def CheckNoGaps(self, entries):
416 """Check that all entries fit together without gaps
417
418 Args:
419 entries: List of entries to check
420 """
Simon Glass3ab95982018-08-01 15:22:37 -0600421 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700422 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600423 self.assertEqual(offset, entry.offset)
424 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700425
Simon Glasse0ff8552016-11-25 20:15:53 -0700426 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600427 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700428
429 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600430 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700431
432 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600433 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700434 """
435 return struct.unpack('>L', dtb[4:8])[0]
436
Simon Glasscee02e62018-07-17 13:25:52 -0600437 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600438 def AddNode(node, path):
439 if node.name != '/':
440 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600441 for subnode in node.subnodes:
442 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600443 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600444 prop_path = path + '/' + subnode.name + ':' + prop.name
445 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
446 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600447 AddNode(subnode, path)
448
449 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600450 AddNode(dtb.GetRoot(), '')
451 return tree
452
Simon Glass4f443042016-11-25 20:15:52 -0700453 def testRun(self):
454 """Test a basic run with valid args"""
455 result = self._RunBinman('-h')
456
457 def testFullHelp(self):
458 """Test that the full help is displayed with -H"""
459 result = self._RunBinman('-H')
460 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500461 # Remove possible extraneous strings
462 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
463 gothelp = result.stdout.replace(extra, '')
464 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700465 self.assertEqual(0, len(result.stderr))
466 self.assertEqual(0, result.return_code)
467
468 def testFullHelpInternal(self):
469 """Test that the full help is displayed with -H"""
470 try:
471 command.test_result = command.CommandResult()
472 result = self._DoBinman('-H')
473 help_file = os.path.join(self._binman_dir, 'README')
474 finally:
475 command.test_result = None
476
477 def testHelp(self):
478 """Test that the basic help is displayed with -h"""
479 result = self._RunBinman('-h')
480 self.assertTrue(len(result.stdout) > 200)
481 self.assertEqual(0, len(result.stderr))
482 self.assertEqual(0, result.return_code)
483
Simon Glass4f443042016-11-25 20:15:52 -0700484 def testBoard(self):
485 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600486 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700487 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
488 result = self._DoBinman('-b', 'sandbox')
489 self.assertEqual(0, result)
490
491 def testNeedBoard(self):
492 """Test that we get an error when no board ius supplied"""
493 with self.assertRaises(ValueError) as e:
494 result = self._DoBinman()
495 self.assertIn("Must provide a board to process (use -b <board>)",
496 str(e.exception))
497
498 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600499 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700500 with self.assertRaises(Exception) as e:
501 self._RunBinman('-d', 'missing_file')
502 # We get one error from libfdt, and a different one from fdtget.
503 self.AssertInList(["Couldn't open blob from 'missing_file'",
504 'No such file or directory'], str(e.exception))
505
506 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600507 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700508
509 Since this is a source file it should be compiled and the error
510 will come from the device-tree compiler (dtc).
511 """
512 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600513 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700514 self.assertIn("FATAL ERROR: Unable to parse input tree",
515 str(e.exception))
516
517 def testMissingNode(self):
518 """Test that a device tree without a 'binman' node generates an error"""
519 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600520 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700521 self.assertIn("does not have a 'binman' node", str(e.exception))
522
523 def testEmpty(self):
524 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass741f2d62018-10-01 12:22:30 -0600525 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700526 self.assertEqual(0, len(result.stderr))
527 self.assertEqual(0, result.return_code)
528
529 def testInvalidEntry(self):
530 """Test that an invalid entry is flagged"""
531 with self.assertRaises(Exception) as e:
532 result = self._RunBinman('-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600533 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700534 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
535 "'/binman/not-a-valid-type'", str(e.exception))
536
537 def testSimple(self):
538 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600539 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700540 self.assertEqual(U_BOOT_DATA, data)
541
Simon Glass7fe91732017-11-13 18:55:00 -0700542 def testSimpleDebug(self):
543 """Test a simple binman run with debugging enabled"""
Simon Glass741f2d62018-10-01 12:22:30 -0600544 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700545
Simon Glass4f443042016-11-25 20:15:52 -0700546 def testDual(self):
547 """Test that we can handle creating two images
548
549 This also tests image padding.
550 """
Simon Glass741f2d62018-10-01 12:22:30 -0600551 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700552 self.assertEqual(0, retcode)
553
554 image = control.images['image1']
555 self.assertEqual(len(U_BOOT_DATA), image._size)
556 fname = tools.GetOutputFilename('image1.bin')
557 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600558 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700559 data = fd.read()
560 self.assertEqual(U_BOOT_DATA, data)
561
562 image = control.images['image2']
563 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
564 fname = tools.GetOutputFilename('image2.bin')
565 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600566 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700567 data = fd.read()
568 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600569 self.assertEqual(tools.GetBytes(0, 3), data[:3])
570 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700571
572 def testBadAlign(self):
573 """Test that an invalid alignment value is detected"""
574 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600575 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700576 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
577 "of two", str(e.exception))
578
579 def testPackSimple(self):
580 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600581 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700582 self.assertEqual(0, retcode)
583 self.assertIn('image', control.images)
584 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600585 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700586 self.assertEqual(5, len(entries))
587
588 # First u-boot
589 self.assertIn('u-boot', entries)
590 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600591 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700592 self.assertEqual(len(U_BOOT_DATA), entry.size)
593
594 # Second u-boot, aligned to 16-byte boundary
595 self.assertIn('u-boot-align', entries)
596 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600597 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700598 self.assertEqual(len(U_BOOT_DATA), entry.size)
599
600 # Third u-boot, size 23 bytes
601 self.assertIn('u-boot-size', entries)
602 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600603 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700604 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
605 self.assertEqual(23, entry.size)
606
607 # Fourth u-boot, placed immediate after the above
608 self.assertIn('u-boot-next', entries)
609 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600610 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700611 self.assertEqual(len(U_BOOT_DATA), entry.size)
612
Simon Glass3ab95982018-08-01 15:22:37 -0600613 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700614 self.assertIn('u-boot-fixed', entries)
615 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600616 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700617 self.assertEqual(len(U_BOOT_DATA), entry.size)
618
619 self.assertEqual(65, image._size)
620
621 def testPackExtra(self):
622 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600623 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700624
625 self.assertEqual(0, retcode)
626 self.assertIn('image', control.images)
627 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600628 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700629 self.assertEqual(5, len(entries))
630
631 # First u-boot with padding before and after
632 self.assertIn('u-boot', entries)
633 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600634 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700635 self.assertEqual(3, entry.pad_before)
636 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
637
638 # Second u-boot has an aligned size, but it has no effect
639 self.assertIn('u-boot-align-size-nop', entries)
640 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600641 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700642 self.assertEqual(4, entry.size)
643
644 # Third u-boot has an aligned size too
645 self.assertIn('u-boot-align-size', entries)
646 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600647 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700648 self.assertEqual(32, entry.size)
649
650 # Fourth u-boot has an aligned end
651 self.assertIn('u-boot-align-end', entries)
652 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600653 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertEqual(16, entry.size)
655
656 # Fifth u-boot immediately afterwards
657 self.assertIn('u-boot-align-both', entries)
658 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600659 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700660 self.assertEqual(64, entry.size)
661
662 self.CheckNoGaps(entries)
663 self.assertEqual(128, image._size)
664
665 def testPackAlignPowerOf2(self):
666 """Test that invalid entry alignment is detected"""
667 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600668 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700669 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
670 "of two", str(e.exception))
671
672 def testPackAlignSizePowerOf2(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('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700676 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
677 "power of two", str(e.exception))
678
679 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600680 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700681 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600682 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600683 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700684 "align 0x4 (4)", str(e.exception))
685
686 def testPackInvalidSizeAlign(self):
687 """Test that invalid entry size alignment is detected"""
688 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600689 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700690 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
691 "align-size 0x4 (4)", str(e.exception))
692
693 def testPackOverlap(self):
694 """Test that overlapping regions are detected"""
695 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600696 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600697 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700698 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
699 str(e.exception))
700
701 def testPackEntryOverflow(self):
702 """Test that entries that overflow their size are detected"""
703 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600704 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700705 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
706 "but entry size is 0x3 (3)", str(e.exception))
707
708 def testPackImageOverflow(self):
709 """Test that entries which overflow the image size are detected"""
710 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600711 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600712 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700713 "size 0x3 (3)", str(e.exception))
714
715 def testPackImageSize(self):
716 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600717 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700718 self.assertEqual(0, retcode)
719 self.assertIn('image', control.images)
720 image = control.images['image']
721 self.assertEqual(7, image._size)
722
723 def testPackImageSizeAlign(self):
724 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600725 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700726 self.assertEqual(0, retcode)
727 self.assertIn('image', control.images)
728 image = control.images['image']
729 self.assertEqual(16, image._size)
730
731 def testPackInvalidImageAlign(self):
732 """Test that invalid image alignment is detected"""
733 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600734 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600735 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700736 "align-size 0x8 (8)", str(e.exception))
737
738 def testPackAlignPowerOf2(self):
739 """Test that invalid image alignment is detected"""
740 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600741 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600742 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700743 "two", str(e.exception))
744
745 def testImagePadByte(self):
746 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600747 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600748 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600749 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
750 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700751
752 def testImageName(self):
753 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600754 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700755 self.assertEqual(0, retcode)
756 image = control.images['image1']
757 fname = tools.GetOutputFilename('test-name')
758 self.assertTrue(os.path.exists(fname))
759
760 image = control.images['image2']
761 fname = tools.GetOutputFilename('test-name.xx')
762 self.assertTrue(os.path.exists(fname))
763
764 def testBlobFilename(self):
765 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600766 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700767 self.assertEqual(BLOB_DATA, data)
768
769 def testPackSorted(self):
770 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600771 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600772 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600773 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
774 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700775
Simon Glass3ab95982018-08-01 15:22:37 -0600776 def testPackZeroOffset(self):
777 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700778 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600779 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600780 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700781 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
782 str(e.exception))
783
784 def testPackUbootDtb(self):
785 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600786 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700787 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700788
789 def testPackX86RomNoSize(self):
790 """Test that the end-at-4gb property requires a size property"""
791 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600792 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600793 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700794 "using end-at-4gb", str(e.exception))
795
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530796 def test4gbAndSkipAtStartTogether(self):
797 """Test that the end-at-4gb and skip-at-size property can't be used
798 together"""
799 with self.assertRaises(ValueError) as e:
800 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
801 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
802 "'skip-at-start'", str(e.exception))
803
Simon Glasse0ff8552016-11-25 20:15:53 -0700804 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600805 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700806 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600807 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600808 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600809 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700810 str(e.exception))
811
812 def testPackX86Rom(self):
813 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600814 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600815 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600816 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
817 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700818
819 def testPackX86RomMeNoDesc(self):
820 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600821 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700822 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600823 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600824 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
825 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700826
827 def testPackX86RomBadDesc(self):
828 """Test that the Intel requires a descriptor entry"""
829 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600830 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600831 self.assertIn("Node '/binman/intel-me': No offset set with "
832 "offset-unset: should another entry provide this correct "
833 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700834
835 def testPackX86RomMe(self):
836 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600837 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700838 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
839
840 def testPackVga(self):
841 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600842 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700843 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
844
845 def testPackStart16(self):
846 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600847 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700848 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
849
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530850 def testPackPowerpcMpc85xxBootpgResetvec(self):
851 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
852 created"""
853 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
854 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
855
Simon Glass736bb0a2018-07-06 10:27:17 -0600856 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600857 """Handle running a test for insertion of microcode
858
859 Args:
860 dts_fname: Name of test .dts file
861 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600862 ucode_second: True if the microsecond entry is second instead of
863 third
Simon Glassadc57012018-07-06 10:27:16 -0600864
865 Returns:
866 Tuple:
867 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600868 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600869 in the above (two 4-byte words)
870 """
Simon Glass6b187df2017-11-12 21:52:27 -0700871 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700872
873 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600874 if ucode_second:
875 ucode_content = data[len(nodtb_data):]
876 ucode_pos = len(nodtb_data)
877 dtb_with_ucode = ucode_content[16:]
878 fdt_len = self.GetFdtLen(dtb_with_ucode)
879 else:
880 dtb_with_ucode = data[len(nodtb_data):]
881 fdt_len = self.GetFdtLen(dtb_with_ucode)
882 ucode_content = dtb_with_ucode[fdt_len:]
883 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700884 fname = tools.GetOutputFilename('test.dtb')
885 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600886 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600887 dtb = fdt.FdtScan(fname)
888 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700889 self.assertTrue(ucode)
890 for node in ucode.subnodes:
891 self.assertFalse(node.props.get('data'))
892
Simon Glasse0ff8552016-11-25 20:15:53 -0700893 # Check that the microcode appears immediately after the Fdt
894 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700895 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700896 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
897 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600898 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700899
900 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600901 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700902 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
903 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600904 u_boot = data[:len(nodtb_data)]
905 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700906
907 def testPackUbootMicrocode(self):
908 """Test that x86 microcode can be handled correctly
909
910 We expect to see the following in the image, in order:
911 u-boot-nodtb.bin with a microcode pointer inserted at the correct
912 place
913 u-boot.dtb with the microcode removed
914 the microcode
915 """
Simon Glass741f2d62018-10-01 12:22:30 -0600916 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700917 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600918 self.assertEqual(b'nodtb with microcode' + pos_and_size +
919 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700920
Simon Glass160a7662017-05-27 07:38:26 -0600921 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700922 """Test that x86 microcode can be handled correctly
923
924 We expect to see the following in the image, in order:
925 u-boot-nodtb.bin with a microcode pointer inserted at the correct
926 place
927 u-boot.dtb with the microcode
928 an empty microcode region
929 """
930 # We need the libfdt library to run this test since only that allows
931 # finding the offset of a property. This is required by
932 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600933 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700934
935 second = data[len(U_BOOT_NODTB_DATA):]
936
937 fdt_len = self.GetFdtLen(second)
938 third = second[fdt_len:]
939 second = second[:fdt_len]
940
Simon Glass160a7662017-05-27 07:38:26 -0600941 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
942 self.assertIn(ucode_data, second)
943 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700944
Simon Glass160a7662017-05-27 07:38:26 -0600945 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600946 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600947 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
948 len(ucode_data))
949 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -0600950 self.assertEqual(b'nodtb with microcode' + pos_and_size +
951 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700952
Simon Glass75db0862016-11-25 20:15:55 -0700953 def testPackUbootSingleMicrocode(self):
954 """Test that x86 microcode can be handled correctly with fdt_normal.
955 """
Simon Glass160a7662017-05-27 07:38:26 -0600956 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700957
Simon Glassc49deb82016-11-25 20:15:54 -0700958 def testUBootImg(self):
959 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600960 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -0700961 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700962
963 def testNoMicrocode(self):
964 """Test that a missing microcode region is detected"""
965 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600966 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700967 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
968 "node found in ", str(e.exception))
969
970 def testMicrocodeWithoutNode(self):
971 """Test that a missing u-boot-dtb-with-ucode node is detected"""
972 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600973 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700974 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
975 "microcode region u-boot-dtb-with-ucode", str(e.exception))
976
977 def testMicrocodeWithoutNode2(self):
978 """Test that a missing u-boot-ucode node is detected"""
979 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600980 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700981 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
982 "microcode region u-boot-ucode", str(e.exception))
983
984 def testMicrocodeWithoutPtrInElf(self):
985 """Test that a U-Boot binary without the microcode symbol is detected"""
986 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700987 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -0600988 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700989 TestFunctional._MakeInputFile('u-boot', fd.read())
990
991 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600992 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700993 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
994 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
995
996 finally:
997 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -0600998 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700999 TestFunctional._MakeInputFile('u-boot', fd.read())
1000
1001 def testMicrocodeNotInImage(self):
1002 """Test that microcode must be placed within the image"""
1003 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001004 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001005 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1006 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001007 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001008
1009 def testWithoutMicrocode(self):
1010 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001011 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001012 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001013 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001014
1015 # Now check the device tree has no microcode
1016 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1017 second = data[len(U_BOOT_NODTB_DATA):]
1018
1019 fdt_len = self.GetFdtLen(second)
1020 self.assertEqual(dtb, second[:fdt_len])
1021
1022 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1023 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001024 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001025
1026 def testUnknownPosSize(self):
1027 """Test that microcode must be placed within the image"""
1028 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001029 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001030 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001031 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001032
1033 def testPackFsp(self):
1034 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001035 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001036 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1037
1038 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001039 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001040 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001041 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001042
1043 def testPackVbt(self):
1044 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001045 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001046 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001047
Simon Glass56509842017-11-12 21:52:25 -07001048 def testSplBssPad(self):
1049 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001050 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001051 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001052 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001053 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1054 data)
Simon Glass56509842017-11-12 21:52:25 -07001055
Simon Glass86af5112018-10-01 21:12:42 -06001056 def testSplBssPadMissing(self):
1057 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001058 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001059 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001060 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001061 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1062 str(e.exception))
1063
Simon Glass87722132017-11-12 21:52:26 -07001064 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001065 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001066 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001067 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1068
Simon Glass736bb0a2018-07-06 10:27:17 -06001069 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1070 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001071
1072 We expect to see the following in the image, in order:
1073 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1074 correct place
1075 u-boot.dtb with the microcode removed
1076 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001077
1078 Args:
1079 dts: Device tree file to use for test
1080 ucode_second: True if the microsecond entry is second instead of
1081 third
Simon Glass6b187df2017-11-12 21:52:27 -07001082 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001083 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001084 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1085 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001086 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1087 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001088
Simon Glass736bb0a2018-07-06 10:27:17 -06001089 def testPackUbootSplMicrocode(self):
1090 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001091 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001092
1093 def testPackUbootSplMicrocodeReorder(self):
1094 """Test that order doesn't matter for microcode entries
1095
1096 This is the same as testPackUbootSplMicrocode but when we process the
1097 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1098 entry, so we reply on binman to try later.
1099 """
Simon Glass741f2d62018-10-01 12:22:30 -06001100 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001101 ucode_second=True)
1102
Simon Glassca4f4ff2017-11-12 21:52:28 -07001103 def testPackMrc(self):
1104 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001105 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001106 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1107
Simon Glass47419ea2017-11-13 18:54:55 -07001108 def testSplDtb(self):
1109 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001110 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001111 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1112
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001113 def testSplNoDtb(self):
1114 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001115 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001116 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1117
Simon Glass19790632017-11-13 18:55:01 -07001118 def testSymbols(self):
1119 """Test binman can assign symbols embedded in U-Boot"""
1120 elf_fname = self.TestFile('u_boot_binman_syms')
1121 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1122 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001123 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001124
Simon Glass11ae93e2018-10-01 21:12:47 -06001125 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001126 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001127 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001128 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1129 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1130 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001131 self.assertEqual(expected, data)
1132
Simon Glassdd57c132018-06-01 09:38:11 -06001133 def testPackUnitAddress(self):
1134 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001135 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001136 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1137
Simon Glass18546952018-06-01 09:38:16 -06001138 def testSections(self):
1139 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001140 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001141 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1142 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1143 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001144 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001145
Simon Glass3b0c3822018-06-01 09:38:20 -06001146 def testMap(self):
1147 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001148 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001149 self.assertEqual('''ImagePos Offset Size Name
115000000000 00000000 00000028 main-section
115100000000 00000000 00000010 section@0
115200000000 00000000 00000004 u-boot
115300000010 00000010 00000010 section@1
115400000010 00000000 00000004 u-boot
115500000020 00000020 00000004 section@2
115600000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001157''', map_data)
1158
Simon Glassc8d48ef2018-06-01 09:38:21 -06001159 def testNamePrefix(self):
1160 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001161 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001162 self.assertEqual('''ImagePos Offset Size Name
116300000000 00000000 00000028 main-section
116400000000 00000000 00000010 section@0
116500000000 00000000 00000004 ro-u-boot
116600000010 00000010 00000010 section@1
116700000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001168''', map_data)
1169
Simon Glass736bb0a2018-07-06 10:27:17 -06001170 def testUnknownContents(self):
1171 """Test that obtaining the contents works as expected"""
1172 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001173 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-07-06 10:27:17 -06001174 self.assertIn("Section '/binman': Internal error: Could not complete "
1175 "processing of contents: remaining [<_testing.Entry__testing ",
1176 str(e.exception))
1177
Simon Glass5c890232018-07-06 10:27:19 -06001178 def testBadChangeSize(self):
1179 """Test that trying to change the size of an entry fails"""
1180 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001181 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-07-06 10:27:19 -06001182 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1183 '2 to 1', str(e.exception))
1184
Simon Glass16b8d6b2018-07-06 10:27:42 -06001185 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001186 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001187 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001188 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001189 dtb = fdt.Fdt(out_dtb_fname)
1190 dtb.Scan()
1191 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001192 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001193 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001194 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001195 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001196 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001197 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001198 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001199 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001200 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001201 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001202 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001203 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001204
Simon Glass3ab95982018-08-01 15:22:37 -06001205 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001206 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001207 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001208 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001209 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001210 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001211 'size': 40
1212 }, props)
1213
1214 def testUpdateFdtBad(self):
1215 """Test that we detect when ProcessFdt never completes"""
1216 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001217 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001218 self.assertIn('Could not complete processing of Fdt: remaining '
1219 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001220
Simon Glass53af22a2018-07-17 13:25:32 -06001221 def testEntryArgs(self):
1222 """Test passing arguments to entries from the command line"""
1223 entry_args = {
1224 'test-str-arg': 'test1',
1225 'test-int-arg': '456',
1226 }
Simon Glass741f2d62018-10-01 12:22:30 -06001227 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001228 self.assertIn('image', control.images)
1229 entry = control.images['image'].GetEntries()['_testing']
1230 self.assertEqual('test0', entry.test_str_fdt)
1231 self.assertEqual('test1', entry.test_str_arg)
1232 self.assertEqual(123, entry.test_int_fdt)
1233 self.assertEqual(456, entry.test_int_arg)
1234
1235 def testEntryArgsMissing(self):
1236 """Test missing arguments and properties"""
1237 entry_args = {
1238 'test-int-arg': '456',
1239 }
Simon Glass741f2d62018-10-01 12:22:30 -06001240 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001241 entry = control.images['image'].GetEntries()['_testing']
1242 self.assertEqual('test0', entry.test_str_fdt)
1243 self.assertEqual(None, entry.test_str_arg)
1244 self.assertEqual(None, entry.test_int_fdt)
1245 self.assertEqual(456, entry.test_int_arg)
1246
1247 def testEntryArgsRequired(self):
1248 """Test missing arguments and properties"""
1249 entry_args = {
1250 'test-int-arg': '456',
1251 }
1252 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001253 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001254 self.assertIn("Node '/binman/_testing': Missing required "
1255 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1256 str(e.exception))
1257
1258 def testEntryArgsInvalidFormat(self):
1259 """Test that an invalid entry-argument format is detected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001260 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001261 with self.assertRaises(ValueError) as e:
1262 self._DoBinman(*args)
1263 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1264
1265 def testEntryArgsInvalidInteger(self):
1266 """Test that an invalid entry-argument integer is detected"""
1267 entry_args = {
1268 'test-int-arg': 'abc',
1269 }
1270 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001271 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001272 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1273 "'test-int-arg' (value 'abc') to integer",
1274 str(e.exception))
1275
1276 def testEntryArgsInvalidDatatype(self):
1277 """Test that an invalid entry-argument datatype is detected
1278
1279 This test could be written in entry_test.py except that it needs
1280 access to control.entry_args, which seems more than that module should
1281 be able to see.
1282 """
1283 entry_args = {
1284 'test-bad-datatype-arg': '12',
1285 }
1286 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001287 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001288 entry_args=entry_args)
1289 self.assertIn('GetArg() internal error: Unknown data type ',
1290 str(e.exception))
1291
Simon Glassbb748372018-07-17 13:25:33 -06001292 def testText(self):
1293 """Test for a text entry type"""
1294 entry_args = {
1295 'test-id': TEXT_DATA,
1296 'test-id2': TEXT_DATA2,
1297 'test-id3': TEXT_DATA3,
1298 }
Simon Glass741f2d62018-10-01 12:22:30 -06001299 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001300 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001301 expected = (tools.ToBytes(TEXT_DATA) +
1302 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1303 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001304 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001305 self.assertEqual(expected, data)
1306
Simon Glassfd8d1f72018-07-17 13:25:36 -06001307 def testEntryDocs(self):
1308 """Test for creation of entry documentation"""
1309 with test_util.capture_sys_output() as (stdout, stderr):
1310 control.WriteEntryDocs(binman.GetEntryModules())
1311 self.assertTrue(len(stdout.getvalue()) > 0)
1312
1313 def testEntryDocsMissing(self):
1314 """Test handling of missing entry documentation"""
1315 with self.assertRaises(ValueError) as e:
1316 with test_util.capture_sys_output() as (stdout, stderr):
1317 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1318 self.assertIn('Documentation is missing for modules: u_boot',
1319 str(e.exception))
1320
Simon Glass11e36cc2018-07-17 13:25:38 -06001321 def testFmap(self):
1322 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001323 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001324 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001325 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1326 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001327 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001328 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001329 self.assertEqual(1, fhdr.ver_major)
1330 self.assertEqual(0, fhdr.ver_minor)
1331 self.assertEqual(0, fhdr.base)
1332 self.assertEqual(16 + 16 +
1333 fmap_util.FMAP_HEADER_LEN +
1334 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001335 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001336 self.assertEqual(3, fhdr.nareas)
1337 for fentry in fentries:
1338 self.assertEqual(0, fentry.flags)
1339
1340 self.assertEqual(0, fentries[0].offset)
1341 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001342 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001343
1344 self.assertEqual(16, fentries[1].offset)
1345 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001346 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001347
1348 self.assertEqual(32, fentries[2].offset)
1349 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1350 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001351 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001352
Simon Glassec127af2018-07-17 13:25:39 -06001353 def testBlobNamedByArg(self):
1354 """Test we can add a blob with the filename coming from an entry arg"""
1355 entry_args = {
1356 'cros-ec-rw-path': 'ecrw.bin',
1357 }
Simon Glass741f2d62018-10-01 12:22:30 -06001358 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001359 entry_args=entry_args)
1360
Simon Glass3af8e492018-07-17 13:25:40 -06001361 def testFill(self):
1362 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001363 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001364 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001365 self.assertEqual(expected, data)
1366
1367 def testFillNoSize(self):
1368 """Test for an fill entry type with no size"""
1369 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001370 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001371 self.assertIn("'fill' entry must have a size property",
1372 str(e.exception))
1373
Simon Glass0ef87aa2018-07-17 13:25:44 -06001374 def _HandleGbbCommand(self, pipe_list):
1375 """Fake calls to the futility utility"""
1376 if pipe_list[0][0] == 'futility':
1377 fname = pipe_list[0][-1]
1378 # Append our GBB data to the file, which will happen every time the
1379 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001380 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001381 fd.write(GBB_DATA)
1382 return command.CommandResult()
1383
1384 def testGbb(self):
1385 """Test for the Chromium OS Google Binary Block"""
1386 command.test_result = self._HandleGbbCommand
1387 entry_args = {
1388 'keydir': 'devkeys',
1389 'bmpblk': 'bmpblk.bin',
1390 }
Simon Glass741f2d62018-10-01 12:22:30 -06001391 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001392
1393 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001394 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1395 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001396 self.assertEqual(expected, data)
1397
1398 def testGbbTooSmall(self):
1399 """Test for the Chromium OS Google Binary Block being large enough"""
1400 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001401 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001402 self.assertIn("Node '/binman/gbb': GBB is too small",
1403 str(e.exception))
1404
1405 def testGbbNoSize(self):
1406 """Test for the Chromium OS Google Binary Block having a size"""
1407 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001408 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001409 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1410 str(e.exception))
1411
Simon Glass24d0d3c2018-07-17 13:25:47 -06001412 def _HandleVblockCommand(self, pipe_list):
1413 """Fake calls to the futility utility"""
1414 if pipe_list[0][0] == 'futility':
1415 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001416 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001417 fd.write(VBLOCK_DATA)
1418 return command.CommandResult()
1419
1420 def testVblock(self):
1421 """Test for the Chromium OS Verified Boot Block"""
1422 command.test_result = self._HandleVblockCommand
1423 entry_args = {
1424 'keydir': 'devkeys',
1425 }
Simon Glass741f2d62018-10-01 12:22:30 -06001426 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001427 entry_args=entry_args)
1428 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1429 self.assertEqual(expected, data)
1430
1431 def testVblockNoContent(self):
1432 """Test we detect a vblock which has no content to sign"""
1433 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001434 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001435 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1436 'property', str(e.exception))
1437
1438 def testVblockBadPhandle(self):
1439 """Test that we detect a vblock with an invalid phandle in contents"""
1440 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001441 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001442 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1443 '1000', str(e.exception))
1444
1445 def testVblockBadEntry(self):
1446 """Test that we detect an entry that points to a non-entry"""
1447 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001448 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001449 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1450 "'other'", str(e.exception))
1451
Simon Glassb8ef5b62018-07-17 13:25:48 -06001452 def testTpl(self):
1453 """Test that an image with TPL and ots device tree can be created"""
1454 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001455 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001456 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001457 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001458 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1459
Simon Glass15a587c2018-07-17 13:25:51 -06001460 def testUsesPos(self):
1461 """Test that the 'pos' property cannot be used anymore"""
1462 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001463 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001464 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1465 "'pos'", str(e.exception))
1466
Simon Glassd178eab2018-09-14 04:57:08 -06001467 def testFillZero(self):
1468 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001469 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001470 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001471
Simon Glass0b489362018-09-14 04:57:09 -06001472 def testTextMissing(self):
1473 """Test for a text entry type where there is no text"""
1474 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001475 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001476 self.assertIn("Node '/binman/text': No value provided for text label "
1477 "'test-id'", str(e.exception))
1478
Simon Glass35b384c2018-09-14 04:57:10 -06001479 def testPackStart16Tpl(self):
1480 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001481 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001482 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1483
Simon Glass0bfa7b02018-09-14 04:57:12 -06001484 def testSelectImage(self):
1485 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001486 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001487
Simon Glasseb833d82019-04-25 21:58:34 -06001488 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001489 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001490 with test_util.capture_sys_output() as (stdout, stderr):
1491 retcode = self._DoTestFile('006_dual_image.dts',
1492 verbosity=verbosity,
1493 images=['image2'])
1494 self.assertEqual(0, retcode)
1495 if verbosity:
1496 self.assertIn(expected, stdout.getvalue())
1497 else:
1498 self.assertNotIn(expected, stdout.getvalue())
1499
1500 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1501 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001502
Simon Glass6ed45ba2018-09-14 04:57:24 -06001503 def testUpdateFdtAll(self):
1504 """Test that all device trees are updated with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001505 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001506 use_real_dtb=True, update_dtb=True)
1507
1508 base_expected = {
1509 'section:image-pos': 0,
1510 'u-boot-tpl-dtb:size': 513,
1511 'u-boot-spl-dtb:size': 513,
1512 'u-boot-spl-dtb:offset': 493,
1513 'image-pos': 0,
1514 'section/u-boot-dtb:image-pos': 0,
1515 'u-boot-spl-dtb:image-pos': 493,
1516 'section/u-boot-dtb:size': 493,
1517 'u-boot-tpl-dtb:image-pos': 1006,
1518 'section/u-boot-dtb:offset': 0,
1519 'section:size': 493,
1520 'offset': 0,
1521 'section:offset': 0,
1522 'u-boot-tpl-dtb:offset': 1006,
1523 'size': 1519
1524 }
1525
1526 # We expect three device-tree files in the output, one after the other.
1527 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1528 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1529 # main U-Boot tree. All three should have the same postions and offset.
1530 start = 0
1531 for item in ['', 'spl', 'tpl']:
1532 dtb = fdt.Fdt.FromData(data[start:])
1533 dtb.Scan()
1534 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1535 'spl', 'tpl'])
1536 expected = dict(base_expected)
1537 if item:
1538 expected[item] = 0
1539 self.assertEqual(expected, props)
1540 start += dtb._fdt_obj.totalsize()
1541
1542 def testUpdateFdtOutput(self):
1543 """Test that output DTB files are updated"""
1544 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001545 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001546 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1547
1548 # Unfortunately, compiling a source file always results in a file
1549 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001550 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001551 # binman as a file called u-boot.dtb. To fix this, copy the file
1552 # over to the expected place.
1553 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1554 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1555 start = 0
1556 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1557 'tpl/u-boot-tpl.dtb.out']:
1558 dtb = fdt.Fdt.FromData(data[start:])
1559 size = dtb._fdt_obj.totalsize()
1560 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1561 outdata = tools.ReadFile(pathname)
1562 name = os.path.split(fname)[0]
1563
1564 if name:
1565 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1566 else:
1567 orig_indata = dtb_data
1568 self.assertNotEqual(outdata, orig_indata,
1569 "Expected output file '%s' be updated" % pathname)
1570 self.assertEqual(outdata, data[start:start + size],
1571 "Expected output file '%s' to match output image" %
1572 pathname)
1573 start += size
1574 finally:
1575 self._ResetDtbs()
1576
Simon Glass83d73c22018-09-14 04:57:26 -06001577 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001578 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001579
1580 def testCompress(self):
1581 """Test compression of blobs"""
Simon Glass741f2d62018-10-01 12:22:30 -06001582 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001583 use_real_dtb=True, update_dtb=True)
1584 dtb = fdt.Fdt(out_dtb_fname)
1585 dtb.Scan()
1586 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1587 orig = self._decompress(data)
1588 self.assertEquals(COMPRESS_DATA, orig)
1589 expected = {
1590 'blob:uncomp-size': len(COMPRESS_DATA),
1591 'blob:size': len(data),
1592 'size': len(data),
1593 }
1594 self.assertEqual(expected, props)
1595
Simon Glass0a98b282018-09-14 04:57:28 -06001596 def testFiles(self):
1597 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001598 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001599 self.assertEqual(FILES_DATA, data)
1600
1601 def testFilesCompress(self):
1602 """Test bringing in multiple files and compressing them"""
Simon Glass741f2d62018-10-01 12:22:30 -06001603 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001604
1605 image = control.images['image']
1606 entries = image.GetEntries()
1607 files = entries['files']
1608 entries = files._section._entries
1609
Simon Glassc6c10e72019-05-17 22:00:46 -06001610 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001611 for i in range(1, 3):
1612 key = '%d.dat' % i
1613 start = entries[key].image_pos
1614 len = entries[key].size
1615 chunk = data[start:start + len]
1616 orig += self._decompress(chunk)
1617
1618 self.assertEqual(FILES_DATA, orig)
1619
1620 def testFilesMissing(self):
1621 """Test missing files"""
1622 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001623 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001624 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1625 'no files', str(e.exception))
1626
1627 def testFilesNoPattern(self):
1628 """Test missing files"""
1629 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001630 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001631 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1632 str(e.exception))
1633
Simon Glassba64a0b2018-09-14 04:57:29 -06001634 def testExpandSize(self):
1635 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001636 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001637 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001638 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1639 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1640 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1641 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001642 self.assertEqual(expect, data)
1643 self.assertEqual('''ImagePos Offset Size Name
164400000000 00000000 00000028 main-section
164500000000 00000000 00000008 fill
164600000008 00000008 00000004 u-boot
16470000000c 0000000c 00000004 section
16480000000c 00000000 00000003 intel-mrc
164900000010 00000010 00000004 u-boot2
165000000014 00000014 0000000c section2
165100000014 00000000 00000008 fill
16520000001c 00000008 00000004 u-boot
165300000020 00000020 00000008 fill2
1654''', map_data)
1655
1656 def testExpandSizeBad(self):
1657 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001658 with test_util.capture_sys_output() as (stdout, stderr):
1659 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001660 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001661 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1662 'expanding entry', str(e.exception))
1663
Simon Glasse0e5df92018-09-14 04:57:31 -06001664 def testHash(self):
1665 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001666 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001667 use_real_dtb=True, update_dtb=True)
1668 dtb = fdt.Fdt(out_dtb_fname)
1669 dtb.Scan()
1670 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1671 m = hashlib.sha256()
1672 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001673 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001674
1675 def testHashNoAlgo(self):
1676 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001677 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001678 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1679 'hash node', str(e.exception))
1680
1681 def testHashBadAlgo(self):
1682 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001683 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001684 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1685 str(e.exception))
1686
1687 def testHashSection(self):
1688 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001689 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001690 use_real_dtb=True, update_dtb=True)
1691 dtb = fdt.Fdt(out_dtb_fname)
1692 dtb.Scan()
1693 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1694 m = hashlib.sha256()
1695 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001696 m.update(tools.GetBytes(ord('a'), 16))
1697 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001698
Simon Glassf0253632018-09-14 04:57:32 -06001699 def testPackUBootTplMicrocode(self):
1700 """Test that x86 microcode can be handled correctly in TPL
1701
1702 We expect to see the following in the image, in order:
1703 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1704 place
1705 u-boot-tpl.dtb with the microcode removed
1706 the microcode
1707 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001708 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001709 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001710 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001711 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001712 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1713 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001714
Simon Glassf8f8df62018-09-14 04:57:34 -06001715 def testFmapX86(self):
1716 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001717 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001718 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001719 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001720 self.assertEqual(expected, data[:32])
1721 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1722
1723 self.assertEqual(0x100, fhdr.image_size)
1724
1725 self.assertEqual(0, fentries[0].offset)
1726 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001727 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001728
1729 self.assertEqual(4, fentries[1].offset)
1730 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001731 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001732
1733 self.assertEqual(32, fentries[2].offset)
1734 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1735 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001736 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001737
1738 def testFmapX86Section(self):
1739 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001740 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001741 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001742 self.assertEqual(expected, data[:32])
1743 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1744
1745 self.assertEqual(0x100, fhdr.image_size)
1746
1747 self.assertEqual(0, fentries[0].offset)
1748 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001749 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001750
1751 self.assertEqual(4, fentries[1].offset)
1752 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001753 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001754
1755 self.assertEqual(36, fentries[2].offset)
1756 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1757 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001758 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001759
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001760 def testElf(self):
1761 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001762 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001763 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001764 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1765 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001766 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001767 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001768
Simon Glass093d1682019-07-08 13:18:25 -06001769 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001770 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001771 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001772 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001773 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001774 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001775
Simon Glass163ed6c2018-09-14 04:57:36 -06001776 def testPackOverlapMap(self):
1777 """Test that overlapping regions are detected"""
1778 with test_util.capture_sys_output() as (stdout, stderr):
1779 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001780 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001781 map_fname = tools.GetOutputFilename('image.map')
1782 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1783 stdout.getvalue())
1784
1785 # We should not get an inmage, but there should be a map file
1786 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1787 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001788 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001789 self.assertEqual('''ImagePos Offset Size Name
1790<none> 00000000 00000007 main-section
1791<none> 00000000 00000004 u-boot
1792<none> 00000003 00000004 u-boot-align
1793''', map_data)
1794
Simon Glass093d1682019-07-08 13:18:25 -06001795 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001796 """Test that an image with an Intel Reference code binary works"""
1797 data = self._DoReadFile('100_intel_refcode.dts')
1798 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1799
Simon Glass9481c802019-04-25 21:58:39 -06001800 def testSectionOffset(self):
1801 """Tests use of a section with an offset"""
1802 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1803 map=True)
1804 self.assertEqual('''ImagePos Offset Size Name
180500000000 00000000 00000038 main-section
180600000004 00000004 00000010 section@0
180700000004 00000000 00000004 u-boot
180800000018 00000018 00000010 section@1
180900000018 00000000 00000004 u-boot
18100000002c 0000002c 00000004 section@2
18110000002c 00000000 00000004 u-boot
1812''', map_data)
1813 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001814 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1815 tools.GetBytes(0x21, 12) +
1816 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1817 tools.GetBytes(0x61, 12) +
1818 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1819 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001820
Simon Glass53af22a2018-07-17 13:25:32 -06001821
Simon Glass9fc60b42017-11-12 21:52:22 -07001822if __name__ == "__main__":
1823 unittest.main()