blob: 256d4a1c5d8c1e062bad1d452ec6a8aa9f90fe80 [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 Glassd5164a72019-07-08 13:18:49 -06009from __future__ import print_function
10
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
14import shutil
15import struct
16import sys
17import tempfile
18import unittest
19
20import binman
21import cmdline
22import command
23import control
Simon Glass19790632017-11-13 18:55:01 -070024import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060025import fdt
Simon Glass4f443042016-11-25 20:15:52 -070026import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060027import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060028import test_util
Simon Glassc55a50f2018-09-14 04:57:19 -060029import state
Simon Glass4f443042016-11-25 20:15:52 -070030import tools
31import tout
32
33# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060034U_BOOT_DATA = b'1234'
35U_BOOT_IMG_DATA = b'img'
36U_BOOT_SPL_DATA = b'56780123456789abcde'
37U_BOOT_TPL_DATA = b'tpl'
38BLOB_DATA = b'89'
39ME_DATA = b'0abcd'
40VGA_DATA = b'vga'
41U_BOOT_DTB_DATA = b'udtb'
42U_BOOT_SPL_DTB_DATA = b'spldtb'
43U_BOOT_TPL_DTB_DATA = b'tpldtb'
44X86_START16_DATA = b'start16'
45X86_START16_SPL_DATA = b'start16spl'
46X86_START16_TPL_DATA = b'start16tpl'
47PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
48U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
49U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
50U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
51FSP_DATA = b'fsp'
52CMC_DATA = b'cmc'
53VBT_DATA = b'vbt'
54MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060055TEXT_DATA = 'text'
56TEXT_DATA2 = 'text2'
57TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060058CROS_EC_RW_DATA = b'ecrw'
59GBB_DATA = b'gbbd'
60BMPBLK_DATA = b'bmp'
61VBLOCK_DATA = b'vblk'
62FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
63 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060064COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060065REFCODE_DATA = b'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060066
Simon Glass4f443042016-11-25 20:15:52 -070067
68class TestFunctional(unittest.TestCase):
69 """Functional tests for binman
70
71 Most of these use a sample .dts file to build an image and then check
72 that it looks correct. The sample files are in the test/ subdirectory
73 and are numbered.
74
75 For each entry type a very small test file is created using fixed
76 string contents. This makes it easy to test that things look right, and
77 debug problems.
78
79 In some cases a 'real' file must be used - these are also supplied in
80 the test/ diurectory.
81 """
82 @classmethod
83 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070084 global entry
85 import entry
86
Simon Glass4f443042016-11-25 20:15:52 -070087 # Handle the case where argv[0] is 'python'
88 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
89 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
90
91 # Create a temporary directory for input files
92 self._indir = tempfile.mkdtemp(prefix='binmant.')
93
94 # Create some test files
95 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
96 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
97 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060098 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070099 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700100 TestFunctional._MakeInputFile('me.bin', ME_DATA)
101 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600102 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700103 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530104 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700105 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
106 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600107 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
108 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700109 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700110 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
111 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600112 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
113 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700114 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
115 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700116 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700117 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600118 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600119 TestFunctional._MakeInputDir('devkeys')
120 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600121 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700122
Simon Glasse0ff8552016-11-25 20:15:53 -0700123 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600124 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700125 TestFunctional._MakeInputFile('u-boot', fd.read())
126
127 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600128 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700129 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
130
Simon Glass0a98b282018-09-14 04:57:28 -0600131 shutil.copytree(self.TestFile('files'),
132 os.path.join(self._indir, 'files'))
133
Simon Glass83d73c22018-09-14 04:57:26 -0600134 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
135
Simon Glass4f443042016-11-25 20:15:52 -0700136 @classmethod
137 def tearDownClass(self):
138 """Remove the temporary input directory and its contents"""
Simon Glassd5164a72019-07-08 13:18:49 -0600139 if self.preserve_indir:
140 print('Preserving input dir: %s' % self._indir)
141 else:
142 if self._indir:
143 shutil.rmtree(self._indir)
Simon Glass4f443042016-11-25 20:15:52 -0700144 self._indir = None
145
Simon Glassd5164a72019-07-08 13:18:49 -0600146 @classmethod
147 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False):
148 """Accept arguments controlling test execution
149
150 Args:
151 preserve_indir: Preserve the shared input directory used by all
152 tests in this class.
153 preserve_outdir: Preserve the output directories used by tests. Each
154 test has its own, so this is normally only useful when running a
155 single test.
156 """
157 cls.preserve_indir = preserve_indir
158 cls.preserve_outdirs = preserve_outdirs
159
Simon Glass4f443042016-11-25 20:15:52 -0700160 def setUp(self):
161 # Enable this to turn on debugging output
162 # tout.Init(tout.DEBUG)
163 command.test_result = None
164
165 def tearDown(self):
166 """Remove the temporary output directory"""
Simon Glassd5164a72019-07-08 13:18:49 -0600167 if self.preserve_outdirs:
168 print('Preserving output dir: %s' % tools.outdir)
169 else:
170 tools._FinaliseForTest()
Simon Glass4f443042016-11-25 20:15:52 -0700171
Simon Glassb8ef5b62018-07-17 13:25:48 -0600172 @classmethod
173 def _ResetDtbs(self):
174 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
176 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
177
Simon Glassee0c9a72019-07-08 13:18:48 -0600178 def _GetVerbosity(self):
179 """Check if verbosity should be enabled
180
181 Returns:
182 list containing either:
183 - Verbosity flag (e.g. '-v2') if it is present on the cmd line
184 - nothing if the flag is not present
185 """
186 for arg in sys.argv[1:]:
187 if arg.startswith('-v'):
188 return [arg]
189 return []
190
Simon Glass4f443042016-11-25 20:15:52 -0700191 def _RunBinman(self, *args, **kwargs):
192 """Run binman using the command line
193
194 Args:
195 Arguments to pass, as a list of strings
196 kwargs: Arguments to pass to Command.RunPipe()
197 """
198 result = command.RunPipe([[self._binman_pathname] + list(args)],
199 capture=True, capture_stderr=True, raise_on_error=False)
200 if result.return_code and kwargs.get('raise_on_error', True):
201 raise Exception("Error running '%s': %s" % (' '.join(args),
202 result.stdout + result.stderr))
203 return result
204
205 def _DoBinman(self, *args):
206 """Run binman using directly (in the same process)
207
208 Args:
209 Arguments to pass, as a list of strings
210 Returns:
211 Return value (0 for success)
212 """
Simon Glass7fe91732017-11-13 18:55:00 -0700213 args = list(args)
214 if '-D' in sys.argv:
215 args = args + ['-D']
216 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700217 options.pager = 'binman-invalid-pager'
218 options.build_dir = self._indir
219
220 # For testing, you can force an increase in verbosity here
221 # options.verbosity = tout.DEBUG
222 return control.Binman(options, args)
223
Simon Glass53af22a2018-07-17 13:25:32 -0600224 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600225 entry_args=None, images=None, use_real_dtb=False,
226 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700227 """Run binman with a given test file
228
229 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600230 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600231 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600232 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600233 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600234 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600235 entry_args: Dict of entry args to supply to binman
236 key: arg name
237 value: value of that arg
238 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700239 """
Simon Glass7fe91732017-11-13 18:55:00 -0700240 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
241 if debug:
242 args.append('-D')
Simon Glass3b0c3822018-06-01 09:38:20 -0600243 if map:
244 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600245 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600246 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600247 if not use_real_dtb:
248 args.append('--fake-dtb')
Simon Glasseb833d82019-04-25 21:58:34 -0600249 if verbosity is not None:
250 args.append('-v%d' % verbosity)
Simon Glassee0c9a72019-07-08 13:18:48 -0600251 else:
252 args += self._GetVerbosity()
Simon Glass53af22a2018-07-17 13:25:32 -0600253 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600254 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600255 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600256 if images:
257 for image in images:
258 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700259 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700260
261 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700262 """Set up a new test device-tree file
263
264 The given file is compiled and set up as the device tree to be used
265 for ths test.
266
267 Args:
268 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600269 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700270
271 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600272 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700273 """
Simon Glasse0e62752018-10-01 21:12:41 -0600274 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700275 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600276 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700277 data = fd.read()
278 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600279 tools.FinaliseOutputDir()
280 return data
Simon Glass4f443042016-11-25 20:15:52 -0700281
Simon Glass6ed45ba2018-09-14 04:57:24 -0600282 def _GetDtbContentsForSplTpl(self, dtb_data, name):
283 """Create a version of the main DTB for SPL or SPL
284
285 For testing we don't actually have different versions of the DTB. With
286 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
287 we don't normally have any unwanted nodes.
288
289 We still want the DTBs for SPL and TPL to be different though, since
290 otherwise it is confusing to know which one we are looking at. So add
291 an 'spl' or 'tpl' property to the top-level node.
292 """
293 dtb = fdt.Fdt.FromData(dtb_data)
294 dtb.Scan()
295 dtb.GetNode('/binman').AddZeroProp(name)
296 dtb.Sync(auto_resize=True)
297 dtb.Pack()
298 return dtb.GetContents()
299
Simon Glass16b8d6b2018-07-06 10:27:42 -0600300 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600301 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700302 """Run binman and return the resulting image
303
304 This runs binman with a given test file and then reads the resulting
305 output file. It is a shortcut function since most tests need to do
306 these steps.
307
308 Raises an assertion failure if binman returns a non-zero exit code.
309
310 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600311 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700312 use_real_dtb: True to use the test file as the contents of
313 the u-boot-dtb entry. Normally this is not needed and the
314 test contents (the U_BOOT_DTB_DATA string) can be used.
315 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600316 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600317 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600318 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700319
320 Returns:
321 Tuple:
322 Resulting image contents
323 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600324 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600325 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700326 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700327 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700328 # Use the compiled test file as the u-boot-dtb input
329 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700330 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600331
332 # For testing purposes, make a copy of the DT for SPL and TPL. Add
333 # a node indicating which it is, so aid verification.
334 for name in ['spl', 'tpl']:
335 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
336 outfile = os.path.join(self._indir, dtb_fname)
337 TestFunctional._MakeInputFile(dtb_fname,
338 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700339
340 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600341 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600342 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700343 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600344 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700345
346 # Find the (only) image, read it and return its contents
347 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600348 image_fname = tools.GetOutputFilename('image.bin')
349 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600350 if map:
351 map_fname = tools.GetOutputFilename('image.map')
352 with open(map_fname) as fd:
353 map_data = fd.read()
354 else:
355 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600356 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600357 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700358 finally:
359 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600360 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600361 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700362
Simon Glasse0ff8552016-11-25 20:15:53 -0700363 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600364 """Helper function which discards the device-tree binary
365
366 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600367 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600368 use_real_dtb: True to use the test file as the contents of
369 the u-boot-dtb entry. Normally this is not needed and the
370 test contents (the U_BOOT_DTB_DATA string) can be used.
371 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600372
373 Returns:
374 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600375 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700376 return self._DoReadFileDtb(fname, use_real_dtb)[0]
377
Simon Glass4f443042016-11-25 20:15:52 -0700378 @classmethod
379 def _MakeInputFile(self, fname, contents):
380 """Create a new test input file, creating directories as needed
381
382 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600383 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700384 contents: File contents to write in to the file
385 Returns:
386 Full pathname of file created
387 """
388 pathname = os.path.join(self._indir, fname)
389 dirname = os.path.dirname(pathname)
390 if dirname and not os.path.exists(dirname):
391 os.makedirs(dirname)
392 with open(pathname, 'wb') as fd:
393 fd.write(contents)
394 return pathname
395
396 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600397 def _MakeInputDir(self, dirname):
398 """Create a new test input directory, creating directories as needed
399
400 Args:
401 dirname: Directory name to create
402
403 Returns:
404 Full pathname of directory created
405 """
406 pathname = os.path.join(self._indir, dirname)
407 if not os.path.exists(pathname):
408 os.makedirs(pathname)
409 return pathname
410
411 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600412 def _SetupSplElf(self, src_fname='bss_data'):
413 """Set up an ELF file with a '_dt_ucode_base_size' symbol
414
415 Args:
416 Filename of ELF file to use as SPL
417 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600418 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600419 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
420
421 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700422 def TestFile(self, fname):
423 return os.path.join(self._binman_dir, 'test', fname)
424
425 def AssertInList(self, grep_list, target):
426 """Assert that at least one of a list of things is in a target
427
428 Args:
429 grep_list: List of strings to check
430 target: Target string
431 """
432 for grep in grep_list:
433 if grep in target:
434 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600435 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700436
437 def CheckNoGaps(self, entries):
438 """Check that all entries fit together without gaps
439
440 Args:
441 entries: List of entries to check
442 """
Simon Glass3ab95982018-08-01 15:22:37 -0600443 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700444 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600445 self.assertEqual(offset, entry.offset)
446 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700447
Simon Glasse0ff8552016-11-25 20:15:53 -0700448 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600449 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700450
451 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600452 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700453
454 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600455 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700456 """
457 return struct.unpack('>L', dtb[4:8])[0]
458
Simon Glasscee02e62018-07-17 13:25:52 -0600459 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600460 def AddNode(node, path):
461 if node.name != '/':
462 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600463 for subnode in node.subnodes:
464 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600465 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600466 prop_path = path + '/' + subnode.name + ':' + prop.name
467 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
468 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600469 AddNode(subnode, path)
470
471 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600472 AddNode(dtb.GetRoot(), '')
473 return tree
474
Simon Glass4f443042016-11-25 20:15:52 -0700475 def testRun(self):
476 """Test a basic run with valid args"""
477 result = self._RunBinman('-h')
478
479 def testFullHelp(self):
480 """Test that the full help is displayed with -H"""
481 result = self._RunBinman('-H')
482 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500483 # Remove possible extraneous strings
484 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
485 gothelp = result.stdout.replace(extra, '')
486 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700487 self.assertEqual(0, len(result.stderr))
488 self.assertEqual(0, result.return_code)
489
490 def testFullHelpInternal(self):
491 """Test that the full help is displayed with -H"""
492 try:
493 command.test_result = command.CommandResult()
494 result = self._DoBinman('-H')
495 help_file = os.path.join(self._binman_dir, 'README')
496 finally:
497 command.test_result = None
498
499 def testHelp(self):
500 """Test that the basic help is displayed with -h"""
501 result = self._RunBinman('-h')
502 self.assertTrue(len(result.stdout) > 200)
503 self.assertEqual(0, len(result.stderr))
504 self.assertEqual(0, result.return_code)
505
Simon Glass4f443042016-11-25 20:15:52 -0700506 def testBoard(self):
507 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600508 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700509 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
510 result = self._DoBinman('-b', 'sandbox')
511 self.assertEqual(0, result)
512
513 def testNeedBoard(self):
514 """Test that we get an error when no board ius supplied"""
515 with self.assertRaises(ValueError) as e:
516 result = self._DoBinman()
517 self.assertIn("Must provide a board to process (use -b <board>)",
518 str(e.exception))
519
520 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600521 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700522 with self.assertRaises(Exception) as e:
523 self._RunBinman('-d', 'missing_file')
524 # We get one error from libfdt, and a different one from fdtget.
525 self.AssertInList(["Couldn't open blob from 'missing_file'",
526 'No such file or directory'], str(e.exception))
527
528 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600529 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700530
531 Since this is a source file it should be compiled and the error
532 will come from the device-tree compiler (dtc).
533 """
534 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600535 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700536 self.assertIn("FATAL ERROR: Unable to parse input tree",
537 str(e.exception))
538
539 def testMissingNode(self):
540 """Test that a device tree without a 'binman' node generates an error"""
541 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600542 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700543 self.assertIn("does not have a 'binman' node", str(e.exception))
544
545 def testEmpty(self):
546 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass741f2d62018-10-01 12:22:30 -0600547 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700548 self.assertEqual(0, len(result.stderr))
549 self.assertEqual(0, result.return_code)
550
551 def testInvalidEntry(self):
552 """Test that an invalid entry is flagged"""
553 with self.assertRaises(Exception) as e:
554 result = self._RunBinman('-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600555 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700556 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
557 "'/binman/not-a-valid-type'", str(e.exception))
558
559 def testSimple(self):
560 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600561 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700562 self.assertEqual(U_BOOT_DATA, data)
563
Simon Glass7fe91732017-11-13 18:55:00 -0700564 def testSimpleDebug(self):
565 """Test a simple binman run with debugging enabled"""
Simon Glass741f2d62018-10-01 12:22:30 -0600566 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700567
Simon Glass4f443042016-11-25 20:15:52 -0700568 def testDual(self):
569 """Test that we can handle creating two images
570
571 This also tests image padding.
572 """
Simon Glass741f2d62018-10-01 12:22:30 -0600573 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700574 self.assertEqual(0, retcode)
575
576 image = control.images['image1']
577 self.assertEqual(len(U_BOOT_DATA), image._size)
578 fname = tools.GetOutputFilename('image1.bin')
579 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600580 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700581 data = fd.read()
582 self.assertEqual(U_BOOT_DATA, data)
583
584 image = control.images['image2']
585 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
586 fname = tools.GetOutputFilename('image2.bin')
587 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600588 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700589 data = fd.read()
590 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600591 self.assertEqual(tools.GetBytes(0, 3), data[:3])
592 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700593
594 def testBadAlign(self):
595 """Test that an invalid alignment value is detected"""
596 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600597 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700598 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
599 "of two", str(e.exception))
600
601 def testPackSimple(self):
602 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600603 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700604 self.assertEqual(0, retcode)
605 self.assertIn('image', control.images)
606 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600607 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700608 self.assertEqual(5, len(entries))
609
610 # First u-boot
611 self.assertIn('u-boot', entries)
612 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600613 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700614 self.assertEqual(len(U_BOOT_DATA), entry.size)
615
616 # Second u-boot, aligned to 16-byte boundary
617 self.assertIn('u-boot-align', entries)
618 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600619 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700620 self.assertEqual(len(U_BOOT_DATA), entry.size)
621
622 # Third u-boot, size 23 bytes
623 self.assertIn('u-boot-size', entries)
624 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600625 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700626 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
627 self.assertEqual(23, entry.size)
628
629 # Fourth u-boot, placed immediate after the above
630 self.assertIn('u-boot-next', entries)
631 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600632 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700633 self.assertEqual(len(U_BOOT_DATA), entry.size)
634
Simon Glass3ab95982018-08-01 15:22:37 -0600635 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700636 self.assertIn('u-boot-fixed', entries)
637 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600638 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700639 self.assertEqual(len(U_BOOT_DATA), entry.size)
640
641 self.assertEqual(65, image._size)
642
643 def testPackExtra(self):
644 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600645 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700646
647 self.assertEqual(0, retcode)
648 self.assertIn('image', control.images)
649 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600650 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700651 self.assertEqual(5, len(entries))
652
653 # First u-boot with padding before and after
654 self.assertIn('u-boot', entries)
655 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600656 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700657 self.assertEqual(3, entry.pad_before)
658 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
659
660 # Second u-boot has an aligned size, but it has no effect
661 self.assertIn('u-boot-align-size-nop', entries)
662 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600663 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700664 self.assertEqual(4, entry.size)
665
666 # Third u-boot has an aligned size too
667 self.assertIn('u-boot-align-size', entries)
668 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600669 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700670 self.assertEqual(32, entry.size)
671
672 # Fourth u-boot has an aligned end
673 self.assertIn('u-boot-align-end', entries)
674 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600675 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700676 self.assertEqual(16, entry.size)
677
678 # Fifth u-boot immediately afterwards
679 self.assertIn('u-boot-align-both', entries)
680 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600681 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700682 self.assertEqual(64, entry.size)
683
684 self.CheckNoGaps(entries)
685 self.assertEqual(128, image._size)
686
687 def testPackAlignPowerOf2(self):
688 """Test that invalid entry alignment is detected"""
689 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600690 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700691 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
692 "of two", str(e.exception))
693
694 def testPackAlignSizePowerOf2(self):
695 """Test that invalid entry size alignment is detected"""
696 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600697 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700698 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
699 "power of two", str(e.exception))
700
701 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600702 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700703 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600704 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600705 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700706 "align 0x4 (4)", str(e.exception))
707
708 def testPackInvalidSizeAlign(self):
709 """Test that invalid entry size alignment is detected"""
710 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600711 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700712 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
713 "align-size 0x4 (4)", str(e.exception))
714
715 def testPackOverlap(self):
716 """Test that overlapping regions are detected"""
717 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600718 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600719 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700720 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
721 str(e.exception))
722
723 def testPackEntryOverflow(self):
724 """Test that entries that overflow their size are detected"""
725 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600726 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700727 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
728 "but entry size is 0x3 (3)", str(e.exception))
729
730 def testPackImageOverflow(self):
731 """Test that entries which overflow the image size are detected"""
732 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600733 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600734 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700735 "size 0x3 (3)", str(e.exception))
736
737 def testPackImageSize(self):
738 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600739 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700740 self.assertEqual(0, retcode)
741 self.assertIn('image', control.images)
742 image = control.images['image']
743 self.assertEqual(7, image._size)
744
745 def testPackImageSizeAlign(self):
746 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600747 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700748 self.assertEqual(0, retcode)
749 self.assertIn('image', control.images)
750 image = control.images['image']
751 self.assertEqual(16, image._size)
752
753 def testPackInvalidImageAlign(self):
754 """Test that invalid image alignment is detected"""
755 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600756 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600757 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700758 "align-size 0x8 (8)", str(e.exception))
759
760 def testPackAlignPowerOf2(self):
761 """Test that invalid image alignment is detected"""
762 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600763 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600764 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700765 "two", str(e.exception))
766
767 def testImagePadByte(self):
768 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600769 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600770 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600771 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
772 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700773
774 def testImageName(self):
775 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600776 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700777 self.assertEqual(0, retcode)
778 image = control.images['image1']
779 fname = tools.GetOutputFilename('test-name')
780 self.assertTrue(os.path.exists(fname))
781
782 image = control.images['image2']
783 fname = tools.GetOutputFilename('test-name.xx')
784 self.assertTrue(os.path.exists(fname))
785
786 def testBlobFilename(self):
787 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600788 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700789 self.assertEqual(BLOB_DATA, data)
790
791 def testPackSorted(self):
792 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600793 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600794 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600795 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
796 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700797
Simon Glass3ab95982018-08-01 15:22:37 -0600798 def testPackZeroOffset(self):
799 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700800 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600801 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600802 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700803 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
804 str(e.exception))
805
806 def testPackUbootDtb(self):
807 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600808 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700809 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700810
811 def testPackX86RomNoSize(self):
812 """Test that the end-at-4gb property requires a size property"""
813 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600814 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600815 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700816 "using end-at-4gb", str(e.exception))
817
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530818 def test4gbAndSkipAtStartTogether(self):
819 """Test that the end-at-4gb and skip-at-size property can't be used
820 together"""
821 with self.assertRaises(ValueError) as e:
822 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
823 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
824 "'skip-at-start'", str(e.exception))
825
Simon Glasse0ff8552016-11-25 20:15:53 -0700826 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600827 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700828 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600829 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600830 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600831 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700832 str(e.exception))
833
834 def testPackX86Rom(self):
835 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600836 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600837 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600838 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
839 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700840
841 def testPackX86RomMeNoDesc(self):
842 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600843 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700844 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600845 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600846 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
847 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700848
849 def testPackX86RomBadDesc(self):
850 """Test that the Intel requires a descriptor entry"""
851 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600852 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600853 self.assertIn("Node '/binman/intel-me': No offset set with "
854 "offset-unset: should another entry provide this correct "
855 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700856
857 def testPackX86RomMe(self):
858 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600859 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700860 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
861
862 def testPackVga(self):
863 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600864 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700865 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
866
867 def testPackStart16(self):
868 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600869 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700870 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
871
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530872 def testPackPowerpcMpc85xxBootpgResetvec(self):
873 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
874 created"""
875 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
876 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
877
Simon Glass736bb0a2018-07-06 10:27:17 -0600878 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600879 """Handle running a test for insertion of microcode
880
881 Args:
882 dts_fname: Name of test .dts file
883 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600884 ucode_second: True if the microsecond entry is second instead of
885 third
Simon Glassadc57012018-07-06 10:27:16 -0600886
887 Returns:
888 Tuple:
889 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600890 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600891 in the above (two 4-byte words)
892 """
Simon Glass6b187df2017-11-12 21:52:27 -0700893 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700894
895 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600896 if ucode_second:
897 ucode_content = data[len(nodtb_data):]
898 ucode_pos = len(nodtb_data)
899 dtb_with_ucode = ucode_content[16:]
900 fdt_len = self.GetFdtLen(dtb_with_ucode)
901 else:
902 dtb_with_ucode = data[len(nodtb_data):]
903 fdt_len = self.GetFdtLen(dtb_with_ucode)
904 ucode_content = dtb_with_ucode[fdt_len:]
905 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700906 fname = tools.GetOutputFilename('test.dtb')
907 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600908 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600909 dtb = fdt.FdtScan(fname)
910 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700911 self.assertTrue(ucode)
912 for node in ucode.subnodes:
913 self.assertFalse(node.props.get('data'))
914
Simon Glasse0ff8552016-11-25 20:15:53 -0700915 # Check that the microcode appears immediately after the Fdt
916 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700917 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700918 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
919 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600920 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700921
922 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600923 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700924 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
925 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600926 u_boot = data[:len(nodtb_data)]
927 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700928
929 def testPackUbootMicrocode(self):
930 """Test that x86 microcode can be handled correctly
931
932 We expect to see the following in the image, in order:
933 u-boot-nodtb.bin with a microcode pointer inserted at the correct
934 place
935 u-boot.dtb with the microcode removed
936 the microcode
937 """
Simon Glass741f2d62018-10-01 12:22:30 -0600938 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700939 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600940 self.assertEqual(b'nodtb with microcode' + pos_and_size +
941 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700942
Simon Glass160a7662017-05-27 07:38:26 -0600943 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700944 """Test that x86 microcode can be handled correctly
945
946 We expect to see the following in the image, in order:
947 u-boot-nodtb.bin with a microcode pointer inserted at the correct
948 place
949 u-boot.dtb with the microcode
950 an empty microcode region
951 """
952 # We need the libfdt library to run this test since only that allows
953 # finding the offset of a property. This is required by
954 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600955 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700956
957 second = data[len(U_BOOT_NODTB_DATA):]
958
959 fdt_len = self.GetFdtLen(second)
960 third = second[fdt_len:]
961 second = second[:fdt_len]
962
Simon Glass160a7662017-05-27 07:38:26 -0600963 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
964 self.assertIn(ucode_data, second)
965 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700966
Simon Glass160a7662017-05-27 07:38:26 -0600967 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600968 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600969 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
970 len(ucode_data))
971 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -0600972 self.assertEqual(b'nodtb with microcode' + pos_and_size +
973 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700974
Simon Glass75db0862016-11-25 20:15:55 -0700975 def testPackUbootSingleMicrocode(self):
976 """Test that x86 microcode can be handled correctly with fdt_normal.
977 """
Simon Glass160a7662017-05-27 07:38:26 -0600978 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700979
Simon Glassc49deb82016-11-25 20:15:54 -0700980 def testUBootImg(self):
981 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600982 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -0700983 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700984
985 def testNoMicrocode(self):
986 """Test that a missing microcode region is detected"""
987 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600988 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700989 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
990 "node found in ", str(e.exception))
991
992 def testMicrocodeWithoutNode(self):
993 """Test that a missing u-boot-dtb-with-ucode node is detected"""
994 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600995 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700996 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
997 "microcode region u-boot-dtb-with-ucode", str(e.exception))
998
999 def testMicrocodeWithoutNode2(self):
1000 """Test that a missing u-boot-ucode node is detected"""
1001 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001002 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001003 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1004 "microcode region u-boot-ucode", str(e.exception))
1005
1006 def testMicrocodeWithoutPtrInElf(self):
1007 """Test that a U-Boot binary without the microcode symbol is detected"""
1008 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001009 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001010 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001011 TestFunctional._MakeInputFile('u-boot', fd.read())
1012
1013 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001014 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001015 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1016 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1017
1018 finally:
1019 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -06001020 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001021 TestFunctional._MakeInputFile('u-boot', fd.read())
1022
1023 def testMicrocodeNotInImage(self):
1024 """Test that microcode must be placed within the image"""
1025 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001026 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001027 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1028 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001029 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001030
1031 def testWithoutMicrocode(self):
1032 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001033 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001034 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001035 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001036
1037 # Now check the device tree has no microcode
1038 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1039 second = data[len(U_BOOT_NODTB_DATA):]
1040
1041 fdt_len = self.GetFdtLen(second)
1042 self.assertEqual(dtb, second[:fdt_len])
1043
1044 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1045 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001046 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001047
1048 def testUnknownPosSize(self):
1049 """Test that microcode must be placed within the image"""
1050 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001051 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001052 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001053 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001054
1055 def testPackFsp(self):
1056 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001057 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001058 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1059
1060 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001061 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001062 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001063 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001064
1065 def testPackVbt(self):
1066 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001067 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001068 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001069
Simon Glass56509842017-11-12 21:52:25 -07001070 def testSplBssPad(self):
1071 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001072 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001073 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001074 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001075 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1076 data)
Simon Glass56509842017-11-12 21:52:25 -07001077
Simon Glass86af5112018-10-01 21:12:42 -06001078 def testSplBssPadMissing(self):
1079 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001080 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001081 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001082 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001083 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1084 str(e.exception))
1085
Simon Glass87722132017-11-12 21:52:26 -07001086 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001087 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001088 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001089 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1090
Simon Glass736bb0a2018-07-06 10:27:17 -06001091 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1092 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001093
1094 We expect to see the following in the image, in order:
1095 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1096 correct place
1097 u-boot.dtb with the microcode removed
1098 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001099
1100 Args:
1101 dts: Device tree file to use for test
1102 ucode_second: True if the microsecond entry is second instead of
1103 third
Simon Glass6b187df2017-11-12 21:52:27 -07001104 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001105 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001106 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1107 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001108 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1109 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001110
Simon Glass736bb0a2018-07-06 10:27:17 -06001111 def testPackUbootSplMicrocode(self):
1112 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001113 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001114
1115 def testPackUbootSplMicrocodeReorder(self):
1116 """Test that order doesn't matter for microcode entries
1117
1118 This is the same as testPackUbootSplMicrocode but when we process the
1119 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1120 entry, so we reply on binman to try later.
1121 """
Simon Glass741f2d62018-10-01 12:22:30 -06001122 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001123 ucode_second=True)
1124
Simon Glassca4f4ff2017-11-12 21:52:28 -07001125 def testPackMrc(self):
1126 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001127 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001128 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1129
Simon Glass47419ea2017-11-13 18:54:55 -07001130 def testSplDtb(self):
1131 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001132 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001133 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1134
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001135 def testSplNoDtb(self):
1136 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001137 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001138 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1139
Simon Glass19790632017-11-13 18:55:01 -07001140 def testSymbols(self):
1141 """Test binman can assign symbols embedded in U-Boot"""
1142 elf_fname = self.TestFile('u_boot_binman_syms')
1143 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1144 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001145 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001146
Simon Glass11ae93e2018-10-01 21:12:47 -06001147 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001148 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001149 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001150 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1151 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1152 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001153 self.assertEqual(expected, data)
1154
Simon Glassdd57c132018-06-01 09:38:11 -06001155 def testPackUnitAddress(self):
1156 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001157 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001158 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1159
Simon Glass18546952018-06-01 09:38:16 -06001160 def testSections(self):
1161 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001162 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001163 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1164 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1165 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001166 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001167
Simon Glass3b0c3822018-06-01 09:38:20 -06001168 def testMap(self):
1169 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001170 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001171 self.assertEqual('''ImagePos Offset Size Name
117200000000 00000000 00000028 main-section
117300000000 00000000 00000010 section@0
117400000000 00000000 00000004 u-boot
117500000010 00000010 00000010 section@1
117600000010 00000000 00000004 u-boot
117700000020 00000020 00000004 section@2
117800000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001179''', map_data)
1180
Simon Glassc8d48ef2018-06-01 09:38:21 -06001181 def testNamePrefix(self):
1182 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001183 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001184 self.assertEqual('''ImagePos Offset Size Name
118500000000 00000000 00000028 main-section
118600000000 00000000 00000010 section@0
118700000000 00000000 00000004 ro-u-boot
118800000010 00000010 00000010 section@1
118900000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001190''', map_data)
1191
Simon Glass736bb0a2018-07-06 10:27:17 -06001192 def testUnknownContents(self):
1193 """Test that obtaining the contents works as expected"""
1194 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001195 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-07-06 10:27:17 -06001196 self.assertIn("Section '/binman': Internal error: Could not complete "
1197 "processing of contents: remaining [<_testing.Entry__testing ",
1198 str(e.exception))
1199
Simon Glass5c890232018-07-06 10:27:19 -06001200 def testBadChangeSize(self):
1201 """Test that trying to change the size of an entry fails"""
1202 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001203 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-07-06 10:27:19 -06001204 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1205 '2 to 1', str(e.exception))
1206
Simon Glass16b8d6b2018-07-06 10:27:42 -06001207 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001208 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001209 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001210 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001211 dtb = fdt.Fdt(out_dtb_fname)
1212 dtb.Scan()
1213 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001214 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001215 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001216 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001217 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001218 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001219 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001220 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001221 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001222 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001223 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001224 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001225 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001226
Simon Glass3ab95982018-08-01 15:22:37 -06001227 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001228 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001229 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001230 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001231 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001232 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001233 'size': 40
1234 }, props)
1235
1236 def testUpdateFdtBad(self):
1237 """Test that we detect when ProcessFdt never completes"""
1238 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001239 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001240 self.assertIn('Could not complete processing of Fdt: remaining '
1241 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001242
Simon Glass53af22a2018-07-17 13:25:32 -06001243 def testEntryArgs(self):
1244 """Test passing arguments to entries from the command line"""
1245 entry_args = {
1246 'test-str-arg': 'test1',
1247 'test-int-arg': '456',
1248 }
Simon Glass741f2d62018-10-01 12:22:30 -06001249 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001250 self.assertIn('image', control.images)
1251 entry = control.images['image'].GetEntries()['_testing']
1252 self.assertEqual('test0', entry.test_str_fdt)
1253 self.assertEqual('test1', entry.test_str_arg)
1254 self.assertEqual(123, entry.test_int_fdt)
1255 self.assertEqual(456, entry.test_int_arg)
1256
1257 def testEntryArgsMissing(self):
1258 """Test missing arguments and properties"""
1259 entry_args = {
1260 'test-int-arg': '456',
1261 }
Simon Glass741f2d62018-10-01 12:22:30 -06001262 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001263 entry = control.images['image'].GetEntries()['_testing']
1264 self.assertEqual('test0', entry.test_str_fdt)
1265 self.assertEqual(None, entry.test_str_arg)
1266 self.assertEqual(None, entry.test_int_fdt)
1267 self.assertEqual(456, entry.test_int_arg)
1268
1269 def testEntryArgsRequired(self):
1270 """Test missing arguments and properties"""
1271 entry_args = {
1272 'test-int-arg': '456',
1273 }
1274 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001275 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001276 self.assertIn("Node '/binman/_testing': Missing required "
1277 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1278 str(e.exception))
1279
1280 def testEntryArgsInvalidFormat(self):
1281 """Test that an invalid entry-argument format is detected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001282 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001283 with self.assertRaises(ValueError) as e:
1284 self._DoBinman(*args)
1285 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1286
1287 def testEntryArgsInvalidInteger(self):
1288 """Test that an invalid entry-argument integer is detected"""
1289 entry_args = {
1290 'test-int-arg': 'abc',
1291 }
1292 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001293 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001294 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1295 "'test-int-arg' (value 'abc') to integer",
1296 str(e.exception))
1297
1298 def testEntryArgsInvalidDatatype(self):
1299 """Test that an invalid entry-argument datatype is detected
1300
1301 This test could be written in entry_test.py except that it needs
1302 access to control.entry_args, which seems more than that module should
1303 be able to see.
1304 """
1305 entry_args = {
1306 'test-bad-datatype-arg': '12',
1307 }
1308 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001309 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001310 entry_args=entry_args)
1311 self.assertIn('GetArg() internal error: Unknown data type ',
1312 str(e.exception))
1313
Simon Glassbb748372018-07-17 13:25:33 -06001314 def testText(self):
1315 """Test for a text entry type"""
1316 entry_args = {
1317 'test-id': TEXT_DATA,
1318 'test-id2': TEXT_DATA2,
1319 'test-id3': TEXT_DATA3,
1320 }
Simon Glass741f2d62018-10-01 12:22:30 -06001321 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001322 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001323 expected = (tools.ToBytes(TEXT_DATA) +
1324 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1325 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001326 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001327 self.assertEqual(expected, data)
1328
Simon Glassfd8d1f72018-07-17 13:25:36 -06001329 def testEntryDocs(self):
1330 """Test for creation of entry documentation"""
1331 with test_util.capture_sys_output() as (stdout, stderr):
1332 control.WriteEntryDocs(binman.GetEntryModules())
1333 self.assertTrue(len(stdout.getvalue()) > 0)
1334
1335 def testEntryDocsMissing(self):
1336 """Test handling of missing entry documentation"""
1337 with self.assertRaises(ValueError) as e:
1338 with test_util.capture_sys_output() as (stdout, stderr):
1339 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1340 self.assertIn('Documentation is missing for modules: u_boot',
1341 str(e.exception))
1342
Simon Glass11e36cc2018-07-17 13:25:38 -06001343 def testFmap(self):
1344 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001345 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001346 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001347 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1348 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001349 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001350 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001351 self.assertEqual(1, fhdr.ver_major)
1352 self.assertEqual(0, fhdr.ver_minor)
1353 self.assertEqual(0, fhdr.base)
1354 self.assertEqual(16 + 16 +
1355 fmap_util.FMAP_HEADER_LEN +
1356 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001357 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001358 self.assertEqual(3, fhdr.nareas)
1359 for fentry in fentries:
1360 self.assertEqual(0, fentry.flags)
1361
1362 self.assertEqual(0, fentries[0].offset)
1363 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001364 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001365
1366 self.assertEqual(16, fentries[1].offset)
1367 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001368 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001369
1370 self.assertEqual(32, fentries[2].offset)
1371 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1372 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001373 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001374
Simon Glassec127af2018-07-17 13:25:39 -06001375 def testBlobNamedByArg(self):
1376 """Test we can add a blob with the filename coming from an entry arg"""
1377 entry_args = {
1378 'cros-ec-rw-path': 'ecrw.bin',
1379 }
Simon Glass741f2d62018-10-01 12:22:30 -06001380 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001381 entry_args=entry_args)
1382
Simon Glass3af8e492018-07-17 13:25:40 -06001383 def testFill(self):
1384 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001385 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001386 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001387 self.assertEqual(expected, data)
1388
1389 def testFillNoSize(self):
1390 """Test for an fill entry type with no size"""
1391 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001392 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001393 self.assertIn("'fill' entry must have a size property",
1394 str(e.exception))
1395
Simon Glass0ef87aa2018-07-17 13:25:44 -06001396 def _HandleGbbCommand(self, pipe_list):
1397 """Fake calls to the futility utility"""
1398 if pipe_list[0][0] == 'futility':
1399 fname = pipe_list[0][-1]
1400 # Append our GBB data to the file, which will happen every time the
1401 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001402 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001403 fd.write(GBB_DATA)
1404 return command.CommandResult()
1405
1406 def testGbb(self):
1407 """Test for the Chromium OS Google Binary Block"""
1408 command.test_result = self._HandleGbbCommand
1409 entry_args = {
1410 'keydir': 'devkeys',
1411 'bmpblk': 'bmpblk.bin',
1412 }
Simon Glass741f2d62018-10-01 12:22:30 -06001413 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001414
1415 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001416 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1417 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001418 self.assertEqual(expected, data)
1419
1420 def testGbbTooSmall(self):
1421 """Test for the Chromium OS Google Binary Block being large enough"""
1422 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001423 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001424 self.assertIn("Node '/binman/gbb': GBB is too small",
1425 str(e.exception))
1426
1427 def testGbbNoSize(self):
1428 """Test for the Chromium OS Google Binary Block having a size"""
1429 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001430 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001431 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1432 str(e.exception))
1433
Simon Glass24d0d3c2018-07-17 13:25:47 -06001434 def _HandleVblockCommand(self, pipe_list):
1435 """Fake calls to the futility utility"""
1436 if pipe_list[0][0] == 'futility':
1437 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001438 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001439 fd.write(VBLOCK_DATA)
1440 return command.CommandResult()
1441
1442 def testVblock(self):
1443 """Test for the Chromium OS Verified Boot Block"""
1444 command.test_result = self._HandleVblockCommand
1445 entry_args = {
1446 'keydir': 'devkeys',
1447 }
Simon Glass741f2d62018-10-01 12:22:30 -06001448 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001449 entry_args=entry_args)
1450 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1451 self.assertEqual(expected, data)
1452
1453 def testVblockNoContent(self):
1454 """Test we detect a vblock which has no content to sign"""
1455 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001456 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001457 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1458 'property', str(e.exception))
1459
1460 def testVblockBadPhandle(self):
1461 """Test that we detect a vblock with an invalid phandle in contents"""
1462 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001463 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001464 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1465 '1000', str(e.exception))
1466
1467 def testVblockBadEntry(self):
1468 """Test that we detect an entry that points to a non-entry"""
1469 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001470 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001471 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1472 "'other'", str(e.exception))
1473
Simon Glassb8ef5b62018-07-17 13:25:48 -06001474 def testTpl(self):
1475 """Test that an image with TPL and ots device tree can be created"""
1476 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001477 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001478 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001479 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001480 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1481
Simon Glass15a587c2018-07-17 13:25:51 -06001482 def testUsesPos(self):
1483 """Test that the 'pos' property cannot be used anymore"""
1484 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001485 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001486 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1487 "'pos'", str(e.exception))
1488
Simon Glassd178eab2018-09-14 04:57:08 -06001489 def testFillZero(self):
1490 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001491 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001492 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001493
Simon Glass0b489362018-09-14 04:57:09 -06001494 def testTextMissing(self):
1495 """Test for a text entry type where there is no text"""
1496 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001497 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001498 self.assertIn("Node '/binman/text': No value provided for text label "
1499 "'test-id'", str(e.exception))
1500
Simon Glass35b384c2018-09-14 04:57:10 -06001501 def testPackStart16Tpl(self):
1502 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001503 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001504 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1505
Simon Glass0bfa7b02018-09-14 04:57:12 -06001506 def testSelectImage(self):
1507 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001508 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001509
Simon Glasseb833d82019-04-25 21:58:34 -06001510 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001511 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001512 with test_util.capture_sys_output() as (stdout, stderr):
1513 retcode = self._DoTestFile('006_dual_image.dts',
1514 verbosity=verbosity,
1515 images=['image2'])
1516 self.assertEqual(0, retcode)
1517 if verbosity:
1518 self.assertIn(expected, stdout.getvalue())
1519 else:
1520 self.assertNotIn(expected, stdout.getvalue())
1521
1522 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1523 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001524
Simon Glass6ed45ba2018-09-14 04:57:24 -06001525 def testUpdateFdtAll(self):
1526 """Test that all device trees are updated with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001527 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001528 use_real_dtb=True, update_dtb=True)
1529
1530 base_expected = {
1531 'section:image-pos': 0,
1532 'u-boot-tpl-dtb:size': 513,
1533 'u-boot-spl-dtb:size': 513,
1534 'u-boot-spl-dtb:offset': 493,
1535 'image-pos': 0,
1536 'section/u-boot-dtb:image-pos': 0,
1537 'u-boot-spl-dtb:image-pos': 493,
1538 'section/u-boot-dtb:size': 493,
1539 'u-boot-tpl-dtb:image-pos': 1006,
1540 'section/u-boot-dtb:offset': 0,
1541 'section:size': 493,
1542 'offset': 0,
1543 'section:offset': 0,
1544 'u-boot-tpl-dtb:offset': 1006,
1545 'size': 1519
1546 }
1547
1548 # We expect three device-tree files in the output, one after the other.
1549 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1550 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1551 # main U-Boot tree. All three should have the same postions and offset.
1552 start = 0
1553 for item in ['', 'spl', 'tpl']:
1554 dtb = fdt.Fdt.FromData(data[start:])
1555 dtb.Scan()
1556 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1557 'spl', 'tpl'])
1558 expected = dict(base_expected)
1559 if item:
1560 expected[item] = 0
1561 self.assertEqual(expected, props)
1562 start += dtb._fdt_obj.totalsize()
1563
1564 def testUpdateFdtOutput(self):
1565 """Test that output DTB files are updated"""
1566 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001567 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001568 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1569
1570 # Unfortunately, compiling a source file always results in a file
1571 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001572 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001573 # binman as a file called u-boot.dtb. To fix this, copy the file
1574 # over to the expected place.
1575 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1576 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1577 start = 0
1578 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1579 'tpl/u-boot-tpl.dtb.out']:
1580 dtb = fdt.Fdt.FromData(data[start:])
1581 size = dtb._fdt_obj.totalsize()
1582 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1583 outdata = tools.ReadFile(pathname)
1584 name = os.path.split(fname)[0]
1585
1586 if name:
1587 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1588 else:
1589 orig_indata = dtb_data
1590 self.assertNotEqual(outdata, orig_indata,
1591 "Expected output file '%s' be updated" % pathname)
1592 self.assertEqual(outdata, data[start:start + size],
1593 "Expected output file '%s' to match output image" %
1594 pathname)
1595 start += size
1596 finally:
1597 self._ResetDtbs()
1598
Simon Glass83d73c22018-09-14 04:57:26 -06001599 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001600 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001601
1602 def testCompress(self):
1603 """Test compression of blobs"""
Simon Glass741f2d62018-10-01 12:22:30 -06001604 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001605 use_real_dtb=True, update_dtb=True)
1606 dtb = fdt.Fdt(out_dtb_fname)
1607 dtb.Scan()
1608 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1609 orig = self._decompress(data)
1610 self.assertEquals(COMPRESS_DATA, orig)
1611 expected = {
1612 'blob:uncomp-size': len(COMPRESS_DATA),
1613 'blob:size': len(data),
1614 'size': len(data),
1615 }
1616 self.assertEqual(expected, props)
1617
Simon Glass0a98b282018-09-14 04:57:28 -06001618 def testFiles(self):
1619 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001620 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001621 self.assertEqual(FILES_DATA, data)
1622
1623 def testFilesCompress(self):
1624 """Test bringing in multiple files and compressing them"""
Simon Glass741f2d62018-10-01 12:22:30 -06001625 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001626
1627 image = control.images['image']
1628 entries = image.GetEntries()
1629 files = entries['files']
1630 entries = files._section._entries
1631
Simon Glassc6c10e72019-05-17 22:00:46 -06001632 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001633 for i in range(1, 3):
1634 key = '%d.dat' % i
1635 start = entries[key].image_pos
1636 len = entries[key].size
1637 chunk = data[start:start + len]
1638 orig += self._decompress(chunk)
1639
1640 self.assertEqual(FILES_DATA, orig)
1641
1642 def testFilesMissing(self):
1643 """Test missing files"""
1644 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001645 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001646 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1647 'no files', str(e.exception))
1648
1649 def testFilesNoPattern(self):
1650 """Test missing files"""
1651 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001652 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001653 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1654 str(e.exception))
1655
Simon Glassba64a0b2018-09-14 04:57:29 -06001656 def testExpandSize(self):
1657 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001658 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001659 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001660 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1661 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1662 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1663 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001664 self.assertEqual(expect, data)
1665 self.assertEqual('''ImagePos Offset Size Name
166600000000 00000000 00000028 main-section
166700000000 00000000 00000008 fill
166800000008 00000008 00000004 u-boot
16690000000c 0000000c 00000004 section
16700000000c 00000000 00000003 intel-mrc
167100000010 00000010 00000004 u-boot2
167200000014 00000014 0000000c section2
167300000014 00000000 00000008 fill
16740000001c 00000008 00000004 u-boot
167500000020 00000020 00000008 fill2
1676''', map_data)
1677
1678 def testExpandSizeBad(self):
1679 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001680 with test_util.capture_sys_output() as (stdout, stderr):
1681 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001682 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001683 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1684 'expanding entry', str(e.exception))
1685
Simon Glasse0e5df92018-09-14 04:57:31 -06001686 def testHash(self):
1687 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001688 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001689 use_real_dtb=True, update_dtb=True)
1690 dtb = fdt.Fdt(out_dtb_fname)
1691 dtb.Scan()
1692 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1693 m = hashlib.sha256()
1694 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001695 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001696
1697 def testHashNoAlgo(self):
1698 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001699 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001700 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1701 'hash node', str(e.exception))
1702
1703 def testHashBadAlgo(self):
1704 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001705 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001706 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1707 str(e.exception))
1708
1709 def testHashSection(self):
1710 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001711 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001712 use_real_dtb=True, update_dtb=True)
1713 dtb = fdt.Fdt(out_dtb_fname)
1714 dtb.Scan()
1715 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1716 m = hashlib.sha256()
1717 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001718 m.update(tools.GetBytes(ord('a'), 16))
1719 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001720
Simon Glassf0253632018-09-14 04:57:32 -06001721 def testPackUBootTplMicrocode(self):
1722 """Test that x86 microcode can be handled correctly in TPL
1723
1724 We expect to see the following in the image, in order:
1725 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1726 place
1727 u-boot-tpl.dtb with the microcode removed
1728 the microcode
1729 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001730 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001731 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001732 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001733 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001734 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1735 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001736
Simon Glassf8f8df62018-09-14 04:57:34 -06001737 def testFmapX86(self):
1738 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001739 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001740 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001741 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001742 self.assertEqual(expected, data[:32])
1743 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
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(32, 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
1760 def testFmapX86Section(self):
1761 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001762 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001763 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001764 self.assertEqual(expected, data[:32])
1765 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1766
1767 self.assertEqual(0x100, fhdr.image_size)
1768
1769 self.assertEqual(0, fentries[0].offset)
1770 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001771 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001772
1773 self.assertEqual(4, fentries[1].offset)
1774 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001775 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001776
1777 self.assertEqual(36, fentries[2].offset)
1778 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1779 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001780 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001781
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001782 def testElf(self):
1783 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001784 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001785 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001786 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1787 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001788 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001789 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001790
Simon Glass093d1682019-07-08 13:18:25 -06001791 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001792 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001793 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001794 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001795 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001796 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001797
Simon Glass163ed6c2018-09-14 04:57:36 -06001798 def testPackOverlapMap(self):
1799 """Test that overlapping regions are detected"""
1800 with test_util.capture_sys_output() as (stdout, stderr):
1801 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001802 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001803 map_fname = tools.GetOutputFilename('image.map')
1804 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1805 stdout.getvalue())
1806
1807 # We should not get an inmage, but there should be a map file
1808 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1809 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001810 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001811 self.assertEqual('''ImagePos Offset Size Name
1812<none> 00000000 00000007 main-section
1813<none> 00000000 00000004 u-boot
1814<none> 00000003 00000004 u-boot-align
1815''', map_data)
1816
Simon Glass093d1682019-07-08 13:18:25 -06001817 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001818 """Test that an image with an Intel Reference code binary works"""
1819 data = self._DoReadFile('100_intel_refcode.dts')
1820 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1821
Simon Glass9481c802019-04-25 21:58:39 -06001822 def testSectionOffset(self):
1823 """Tests use of a section with an offset"""
1824 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1825 map=True)
1826 self.assertEqual('''ImagePos Offset Size Name
182700000000 00000000 00000038 main-section
182800000004 00000004 00000010 section@0
182900000004 00000000 00000004 u-boot
183000000018 00000018 00000010 section@1
183100000018 00000000 00000004 u-boot
18320000002c 0000002c 00000004 section@2
18330000002c 00000000 00000004 u-boot
1834''', map_data)
1835 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001836 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1837 tools.GetBytes(0x21, 12) +
1838 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1839 tools.GetBytes(0x61, 12) +
1840 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1841 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001842
Simon Glass53af22a2018-07-17 13:25:32 -06001843
Simon Glass9fc60b42017-11-12 21:52:22 -07001844if __name__ == "__main__":
1845 unittest.main()