blob: 3455b8ccebd47ce896c3ede502a8e83359a57545 [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
Simon Glass8acce602019-07-08 13:18:50 -0600147 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
148 toolpath=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600149 """Accept arguments controlling test execution
150
151 Args:
152 preserve_indir: Preserve the shared input directory used by all
153 tests in this class.
154 preserve_outdir: Preserve the output directories used by tests. Each
155 test has its own, so this is normally only useful when running a
156 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600157 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600158 """
159 cls.preserve_indir = preserve_indir
160 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600161 cls.toolpath = toolpath
Simon Glassd5164a72019-07-08 13:18:49 -0600162
Simon Glass4f443042016-11-25 20:15:52 -0700163 def setUp(self):
164 # Enable this to turn on debugging output
165 # tout.Init(tout.DEBUG)
166 command.test_result = None
167
168 def tearDown(self):
169 """Remove the temporary output directory"""
Simon Glassd5164a72019-07-08 13:18:49 -0600170 if self.preserve_outdirs:
171 print('Preserving output dir: %s' % tools.outdir)
172 else:
173 tools._FinaliseForTest()
Simon Glass4f443042016-11-25 20:15:52 -0700174
Simon Glassb8ef5b62018-07-17 13:25:48 -0600175 @classmethod
176 def _ResetDtbs(self):
177 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
178 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
179 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
180
Simon Glassee0c9a72019-07-08 13:18:48 -0600181 def _GetVerbosity(self):
182 """Check if verbosity should be enabled
183
184 Returns:
185 list containing either:
186 - Verbosity flag (e.g. '-v2') if it is present on the cmd line
187 - nothing if the flag is not present
188 """
189 for arg in sys.argv[1:]:
190 if arg.startswith('-v'):
191 return [arg]
192 return []
193
Simon Glass4f443042016-11-25 20:15:52 -0700194 def _RunBinman(self, *args, **kwargs):
195 """Run binman using the command line
196
197 Args:
198 Arguments to pass, as a list of strings
199 kwargs: Arguments to pass to Command.RunPipe()
200 """
201 result = command.RunPipe([[self._binman_pathname] + list(args)],
202 capture=True, capture_stderr=True, raise_on_error=False)
203 if result.return_code and kwargs.get('raise_on_error', True):
204 raise Exception("Error running '%s': %s" % (' '.join(args),
205 result.stdout + result.stderr))
206 return result
207
208 def _DoBinman(self, *args):
209 """Run binman using directly (in the same process)
210
211 Args:
212 Arguments to pass, as a list of strings
213 Returns:
214 Return value (0 for success)
215 """
Simon Glass7fe91732017-11-13 18:55:00 -0700216 args = list(args)
217 if '-D' in sys.argv:
218 args = args + ['-D']
219 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700220 options.pager = 'binman-invalid-pager'
221 options.build_dir = self._indir
222
223 # For testing, you can force an increase in verbosity here
224 # options.verbosity = tout.DEBUG
225 return control.Binman(options, args)
226
Simon Glass53af22a2018-07-17 13:25:32 -0600227 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600228 entry_args=None, images=None, use_real_dtb=False,
229 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700230 """Run binman with a given test file
231
232 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600233 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600234 debug: True to enable debugging output
Simon Glass3b0c38212018-06-01 09:38:20 -0600235 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600236 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600237 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600238 entry_args: Dict of entry args to supply to binman
239 key: arg name
240 value: value of that arg
241 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700242 """
Simon Glass7fe91732017-11-13 18:55:00 -0700243 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
244 if debug:
245 args.append('-D')
Simon Glass3b0c38212018-06-01 09:38:20 -0600246 if map:
247 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600248 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600249 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600250 if not use_real_dtb:
251 args.append('--fake-dtb')
Simon Glasseb833d82019-04-25 21:58:34 -0600252 if verbosity is not None:
253 args.append('-v%d' % verbosity)
Simon Glassee0c9a72019-07-08 13:18:48 -0600254 else:
255 args += self._GetVerbosity()
Simon Glass53af22a2018-07-17 13:25:32 -0600256 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600257 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600258 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600259 if images:
260 for image in images:
261 args += ['-i', image]
Simon Glass8acce602019-07-08 13:18:50 -0600262 if self.toolpath:
263 for path in self.toolpath:
264 args += ['--toolpath', path]
Simon Glass7fe91732017-11-13 18:55:00 -0700265 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700266
267 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700268 """Set up a new test device-tree file
269
270 The given file is compiled and set up as the device tree to be used
271 for ths test.
272
273 Args:
274 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600275 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700276
277 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600278 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700279 """
Simon Glasse0e62752018-10-01 21:12:41 -0600280 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700281 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600282 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700283 data = fd.read()
284 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600285 tools.FinaliseOutputDir()
286 return data
Simon Glass4f443042016-11-25 20:15:52 -0700287
Simon Glass6ed45ba2018-09-14 04:57:24 -0600288 def _GetDtbContentsForSplTpl(self, dtb_data, name):
289 """Create a version of the main DTB for SPL or SPL
290
291 For testing we don't actually have different versions of the DTB. With
292 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
293 we don't normally have any unwanted nodes.
294
295 We still want the DTBs for SPL and TPL to be different though, since
296 otherwise it is confusing to know which one we are looking at. So add
297 an 'spl' or 'tpl' property to the top-level node.
298 """
299 dtb = fdt.Fdt.FromData(dtb_data)
300 dtb.Scan()
301 dtb.GetNode('/binman').AddZeroProp(name)
302 dtb.Sync(auto_resize=True)
303 dtb.Pack()
304 return dtb.GetContents()
305
Simon Glass16b8d6b2018-07-06 10:27:42 -0600306 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600307 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700308 """Run binman and return the resulting image
309
310 This runs binman with a given test file and then reads the resulting
311 output file. It is a shortcut function since most tests need to do
312 these steps.
313
314 Raises an assertion failure if binman returns a non-zero exit code.
315
316 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600317 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700318 use_real_dtb: True to use the test file as the contents of
319 the u-boot-dtb entry. Normally this is not needed and the
320 test contents (the U_BOOT_DTB_DATA string) can be used.
321 But in some test we need the real contents.
Simon Glass3b0c38212018-06-01 09:38:20 -0600322 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600323 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600324 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700325
326 Returns:
327 Tuple:
328 Resulting image contents
329 Device tree contents
Simon Glass3b0c38212018-06-01 09:38:20 -0600330 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600331 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700332 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700333 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700334 # Use the compiled test file as the u-boot-dtb input
335 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700336 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600337
338 # For testing purposes, make a copy of the DT for SPL and TPL. Add
339 # a node indicating which it is, so aid verification.
340 for name in ['spl', 'tpl']:
341 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
342 outfile = os.path.join(self._indir, dtb_fname)
343 TestFunctional._MakeInputFile(dtb_fname,
344 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700345
346 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600347 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600348 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700349 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600350 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700351
352 # Find the (only) image, read it and return its contents
353 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600354 image_fname = tools.GetOutputFilename('image.bin')
355 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c38212018-06-01 09:38:20 -0600356 if map:
357 map_fname = tools.GetOutputFilename('image.map')
358 with open(map_fname) as fd:
359 map_data = fd.read()
360 else:
361 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600362 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600363 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700364 finally:
365 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600366 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600367 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700368
Simon Glasse0ff8552016-11-25 20:15:53 -0700369 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600370 """Helper function which discards the device-tree binary
371
372 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600373 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600374 use_real_dtb: True to use the test file as the contents of
375 the u-boot-dtb entry. Normally this is not needed and the
376 test contents (the U_BOOT_DTB_DATA string) can be used.
377 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600378
379 Returns:
380 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600381 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700382 return self._DoReadFileDtb(fname, use_real_dtb)[0]
383
Simon Glass4f443042016-11-25 20:15:52 -0700384 @classmethod
385 def _MakeInputFile(self, fname, contents):
386 """Create a new test input file, creating directories as needed
387
388 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600389 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700390 contents: File contents to write in to the file
391 Returns:
392 Full pathname of file created
393 """
394 pathname = os.path.join(self._indir, fname)
395 dirname = os.path.dirname(pathname)
396 if dirname and not os.path.exists(dirname):
397 os.makedirs(dirname)
398 with open(pathname, 'wb') as fd:
399 fd.write(contents)
400 return pathname
401
402 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600403 def _MakeInputDir(self, dirname):
404 """Create a new test input directory, creating directories as needed
405
406 Args:
407 dirname: Directory name to create
408
409 Returns:
410 Full pathname of directory created
411 """
412 pathname = os.path.join(self._indir, dirname)
413 if not os.path.exists(pathname):
414 os.makedirs(pathname)
415 return pathname
416
417 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600418 def _SetupSplElf(self, src_fname='bss_data'):
419 """Set up an ELF file with a '_dt_ucode_base_size' symbol
420
421 Args:
422 Filename of ELF file to use as SPL
423 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600424 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600425 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
426
427 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700428 def TestFile(self, fname):
429 return os.path.join(self._binman_dir, 'test', fname)
430
431 def AssertInList(self, grep_list, target):
432 """Assert that at least one of a list of things is in a target
433
434 Args:
435 grep_list: List of strings to check
436 target: Target string
437 """
438 for grep in grep_list:
439 if grep in target:
440 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600441 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700442
443 def CheckNoGaps(self, entries):
444 """Check that all entries fit together without gaps
445
446 Args:
447 entries: List of entries to check
448 """
Simon Glass3ab95982018-08-01 15:22:37 -0600449 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700450 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600451 self.assertEqual(offset, entry.offset)
452 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700453
Simon Glasse0ff8552016-11-25 20:15:53 -0700454 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600455 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700456
457 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600458 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700459
460 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600461 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700462 """
463 return struct.unpack('>L', dtb[4:8])[0]
464
Simon Glasscee02e62018-07-17 13:25:52 -0600465 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600466 def AddNode(node, path):
467 if node.name != '/':
468 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600469 for subnode in node.subnodes:
470 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600471 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600472 prop_path = path + '/' + subnode.name + ':' + prop.name
473 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
474 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600475 AddNode(subnode, path)
476
477 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600478 AddNode(dtb.GetRoot(), '')
479 return tree
480
Simon Glass4f443042016-11-25 20:15:52 -0700481 def testRun(self):
482 """Test a basic run with valid args"""
483 result = self._RunBinman('-h')
484
485 def testFullHelp(self):
486 """Test that the full help is displayed with -H"""
487 result = self._RunBinman('-H')
488 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500489 # Remove possible extraneous strings
490 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
491 gothelp = result.stdout.replace(extra, '')
492 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700493 self.assertEqual(0, len(result.stderr))
494 self.assertEqual(0, result.return_code)
495
496 def testFullHelpInternal(self):
497 """Test that the full help is displayed with -H"""
498 try:
499 command.test_result = command.CommandResult()
500 result = self._DoBinman('-H')
501 help_file = os.path.join(self._binman_dir, 'README')
502 finally:
503 command.test_result = None
504
505 def testHelp(self):
506 """Test that the basic help is displayed with -h"""
507 result = self._RunBinman('-h')
508 self.assertTrue(len(result.stdout) > 200)
509 self.assertEqual(0, len(result.stderr))
510 self.assertEqual(0, result.return_code)
511
Simon Glass4f443042016-11-25 20:15:52 -0700512 def testBoard(self):
513 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600514 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700515 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
516 result = self._DoBinman('-b', 'sandbox')
517 self.assertEqual(0, result)
518
519 def testNeedBoard(self):
520 """Test that we get an error when no board ius supplied"""
521 with self.assertRaises(ValueError) as e:
522 result = self._DoBinman()
523 self.assertIn("Must provide a board to process (use -b <board>)",
524 str(e.exception))
525
526 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600527 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700528 with self.assertRaises(Exception) as e:
529 self._RunBinman('-d', 'missing_file')
530 # We get one error from libfdt, and a different one from fdtget.
531 self.AssertInList(["Couldn't open blob from 'missing_file'",
532 'No such file or directory'], str(e.exception))
533
534 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600535 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700536
537 Since this is a source file it should be compiled and the error
538 will come from the device-tree compiler (dtc).
539 """
540 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600541 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700542 self.assertIn("FATAL ERROR: Unable to parse input tree",
543 str(e.exception))
544
545 def testMissingNode(self):
546 """Test that a device tree without a 'binman' node generates an error"""
547 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600548 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700549 self.assertIn("does not have a 'binman' node", str(e.exception))
550
551 def testEmpty(self):
552 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass741f2d62018-10-01 12:22:30 -0600553 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700554 self.assertEqual(0, len(result.stderr))
555 self.assertEqual(0, result.return_code)
556
557 def testInvalidEntry(self):
558 """Test that an invalid entry is flagged"""
559 with self.assertRaises(Exception) as e:
560 result = self._RunBinman('-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600561 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700562 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
563 "'/binman/not-a-valid-type'", str(e.exception))
564
565 def testSimple(self):
566 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600567 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700568 self.assertEqual(U_BOOT_DATA, data)
569
Simon Glass7fe91732017-11-13 18:55:00 -0700570 def testSimpleDebug(self):
571 """Test a simple binman run with debugging enabled"""
Simon Glass741f2d62018-10-01 12:22:30 -0600572 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700573
Simon Glass4f443042016-11-25 20:15:52 -0700574 def testDual(self):
575 """Test that we can handle creating two images
576
577 This also tests image padding.
578 """
Simon Glass741f2d62018-10-01 12:22:30 -0600579 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700580 self.assertEqual(0, retcode)
581
582 image = control.images['image1']
583 self.assertEqual(len(U_BOOT_DATA), image._size)
584 fname = tools.GetOutputFilename('image1.bin')
585 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600586 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700587 data = fd.read()
588 self.assertEqual(U_BOOT_DATA, data)
589
590 image = control.images['image2']
591 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
592 fname = tools.GetOutputFilename('image2.bin')
593 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600594 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700595 data = fd.read()
596 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600597 self.assertEqual(tools.GetBytes(0, 3), data[:3])
598 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700599
600 def testBadAlign(self):
601 """Test that an invalid alignment value is detected"""
602 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600603 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700604 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
605 "of two", str(e.exception))
606
607 def testPackSimple(self):
608 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600609 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700610 self.assertEqual(0, retcode)
611 self.assertIn('image', control.images)
612 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600613 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700614 self.assertEqual(5, len(entries))
615
616 # First u-boot
617 self.assertIn('u-boot', entries)
618 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600619 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700620 self.assertEqual(len(U_BOOT_DATA), entry.size)
621
622 # Second u-boot, aligned to 16-byte boundary
623 self.assertIn('u-boot-align', entries)
624 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600625 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700626 self.assertEqual(len(U_BOOT_DATA), entry.size)
627
628 # Third u-boot, size 23 bytes
629 self.assertIn('u-boot-size', entries)
630 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600631 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700632 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
633 self.assertEqual(23, entry.size)
634
635 # Fourth u-boot, placed immediate after the above
636 self.assertIn('u-boot-next', entries)
637 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600638 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700639 self.assertEqual(len(U_BOOT_DATA), entry.size)
640
Simon Glass3ab95982018-08-01 15:22:37 -0600641 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700642 self.assertIn('u-boot-fixed', entries)
643 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600644 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700645 self.assertEqual(len(U_BOOT_DATA), entry.size)
646
647 self.assertEqual(65, image._size)
648
649 def testPackExtra(self):
650 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600651 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700652
653 self.assertEqual(0, retcode)
654 self.assertIn('image', control.images)
655 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600656 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700657 self.assertEqual(5, len(entries))
658
659 # First u-boot with padding before and after
660 self.assertIn('u-boot', entries)
661 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600662 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700663 self.assertEqual(3, entry.pad_before)
664 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
665
666 # Second u-boot has an aligned size, but it has no effect
667 self.assertIn('u-boot-align-size-nop', entries)
668 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600669 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700670 self.assertEqual(4, entry.size)
671
672 # Third u-boot has an aligned size too
673 self.assertIn('u-boot-align-size', entries)
674 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600675 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700676 self.assertEqual(32, entry.size)
677
678 # Fourth u-boot has an aligned end
679 self.assertIn('u-boot-align-end', entries)
680 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600681 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700682 self.assertEqual(16, entry.size)
683
684 # Fifth u-boot immediately afterwards
685 self.assertIn('u-boot-align-both', entries)
686 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600687 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700688 self.assertEqual(64, entry.size)
689
690 self.CheckNoGaps(entries)
691 self.assertEqual(128, image._size)
692
693 def testPackAlignPowerOf2(self):
694 """Test that invalid entry alignment is detected"""
695 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600696 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700697 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
698 "of two", str(e.exception))
699
700 def testPackAlignSizePowerOf2(self):
701 """Test that invalid entry size alignment is detected"""
702 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600703 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700704 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
705 "power of two", str(e.exception))
706
707 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600708 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700709 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600710 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600711 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700712 "align 0x4 (4)", str(e.exception))
713
714 def testPackInvalidSizeAlign(self):
715 """Test that invalid entry size alignment is detected"""
716 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600717 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700718 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
719 "align-size 0x4 (4)", str(e.exception))
720
721 def testPackOverlap(self):
722 """Test that overlapping regions are detected"""
723 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600724 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600725 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700726 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
727 str(e.exception))
728
729 def testPackEntryOverflow(self):
730 """Test that entries that overflow their size are detected"""
731 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600732 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700733 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
734 "but entry size is 0x3 (3)", str(e.exception))
735
736 def testPackImageOverflow(self):
737 """Test that entries which overflow the image size are detected"""
738 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600739 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600740 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700741 "size 0x3 (3)", str(e.exception))
742
743 def testPackImageSize(self):
744 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600745 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700746 self.assertEqual(0, retcode)
747 self.assertIn('image', control.images)
748 image = control.images['image']
749 self.assertEqual(7, image._size)
750
751 def testPackImageSizeAlign(self):
752 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600753 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700754 self.assertEqual(0, retcode)
755 self.assertIn('image', control.images)
756 image = control.images['image']
757 self.assertEqual(16, image._size)
758
759 def testPackInvalidImageAlign(self):
760 """Test that invalid image alignment is detected"""
761 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600762 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600763 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700764 "align-size 0x8 (8)", str(e.exception))
765
766 def testPackAlignPowerOf2(self):
767 """Test that invalid image alignment is detected"""
768 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600769 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600770 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700771 "two", str(e.exception))
772
773 def testImagePadByte(self):
774 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600775 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600776 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600777 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
778 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700779
780 def testImageName(self):
781 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600782 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700783 self.assertEqual(0, retcode)
784 image = control.images['image1']
785 fname = tools.GetOutputFilename('test-name')
786 self.assertTrue(os.path.exists(fname))
787
788 image = control.images['image2']
789 fname = tools.GetOutputFilename('test-name.xx')
790 self.assertTrue(os.path.exists(fname))
791
792 def testBlobFilename(self):
793 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600794 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700795 self.assertEqual(BLOB_DATA, data)
796
797 def testPackSorted(self):
798 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600799 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600800 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600801 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
802 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700803
Simon Glass3ab95982018-08-01 15:22:37 -0600804 def testPackZeroOffset(self):
805 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700806 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600807 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600808 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700809 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
810 str(e.exception))
811
812 def testPackUbootDtb(self):
813 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600814 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700815 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700816
817 def testPackX86RomNoSize(self):
818 """Test that the end-at-4gb property requires a size property"""
819 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600820 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600821 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700822 "using end-at-4gb", str(e.exception))
823
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530824 def test4gbAndSkipAtStartTogether(self):
825 """Test that the end-at-4gb and skip-at-size property can't be used
826 together"""
827 with self.assertRaises(ValueError) as e:
828 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
829 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
830 "'skip-at-start'", str(e.exception))
831
Simon Glasse0ff8552016-11-25 20:15:53 -0700832 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600833 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700834 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600835 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600836 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600837 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700838 str(e.exception))
839
840 def testPackX86Rom(self):
841 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600842 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600843 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600844 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
845 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700846
847 def testPackX86RomMeNoDesc(self):
848 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600849 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700850 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600851 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600852 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
853 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700854
855 def testPackX86RomBadDesc(self):
856 """Test that the Intel requires a descriptor entry"""
857 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600858 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600859 self.assertIn("Node '/binman/intel-me': No offset set with "
860 "offset-unset: should another entry provide this correct "
861 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700862
863 def testPackX86RomMe(self):
864 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600865 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700866 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
867
868 def testPackVga(self):
869 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600870 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700871 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
872
873 def testPackStart16(self):
874 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600875 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700876 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
877
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530878 def testPackPowerpcMpc85xxBootpgResetvec(self):
879 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
880 created"""
881 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
882 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
883
Simon Glass736bb0a2018-07-06 10:27:17 -0600884 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600885 """Handle running a test for insertion of microcode
886
887 Args:
888 dts_fname: Name of test .dts file
889 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600890 ucode_second: True if the microsecond entry is second instead of
891 third
Simon Glassadc57012018-07-06 10:27:16 -0600892
893 Returns:
894 Tuple:
895 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600896 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600897 in the above (two 4-byte words)
898 """
Simon Glass6b187df2017-11-12 21:52:27 -0700899 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700900
901 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600902 if ucode_second:
903 ucode_content = data[len(nodtb_data):]
904 ucode_pos = len(nodtb_data)
905 dtb_with_ucode = ucode_content[16:]
906 fdt_len = self.GetFdtLen(dtb_with_ucode)
907 else:
908 dtb_with_ucode = data[len(nodtb_data):]
909 fdt_len = self.GetFdtLen(dtb_with_ucode)
910 ucode_content = dtb_with_ucode[fdt_len:]
911 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700912 fname = tools.GetOutputFilename('test.dtb')
913 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600914 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600915 dtb = fdt.FdtScan(fname)
916 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700917 self.assertTrue(ucode)
918 for node in ucode.subnodes:
919 self.assertFalse(node.props.get('data'))
920
Simon Glasse0ff8552016-11-25 20:15:53 -0700921 # Check that the microcode appears immediately after the Fdt
922 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700923 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700924 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
925 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600926 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700927
928 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600929 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700930 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
931 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600932 u_boot = data[:len(nodtb_data)]
933 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700934
935 def testPackUbootMicrocode(self):
936 """Test that x86 microcode can be handled correctly
937
938 We expect to see the following in the image, in order:
939 u-boot-nodtb.bin with a microcode pointer inserted at the correct
940 place
941 u-boot.dtb with the microcode removed
942 the microcode
943 """
Simon Glass741f2d62018-10-01 12:22:30 -0600944 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700945 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600946 self.assertEqual(b'nodtb with microcode' + pos_and_size +
947 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700948
Simon Glass160a7662017-05-27 07:38:26 -0600949 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700950 """Test that x86 microcode can be handled correctly
951
952 We expect to see the following in the image, in order:
953 u-boot-nodtb.bin with a microcode pointer inserted at the correct
954 place
955 u-boot.dtb with the microcode
956 an empty microcode region
957 """
958 # We need the libfdt library to run this test since only that allows
959 # finding the offset of a property. This is required by
960 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600961 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700962
963 second = data[len(U_BOOT_NODTB_DATA):]
964
965 fdt_len = self.GetFdtLen(second)
966 third = second[fdt_len:]
967 second = second[:fdt_len]
968
Simon Glass160a7662017-05-27 07:38:26 -0600969 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
970 self.assertIn(ucode_data, second)
971 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700972
Simon Glass160a7662017-05-27 07:38:26 -0600973 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600974 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600975 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
976 len(ucode_data))
977 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -0600978 self.assertEqual(b'nodtb with microcode' + pos_and_size +
979 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700980
Simon Glass75db0862016-11-25 20:15:55 -0700981 def testPackUbootSingleMicrocode(self):
982 """Test that x86 microcode can be handled correctly with fdt_normal.
983 """
Simon Glass160a7662017-05-27 07:38:26 -0600984 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700985
Simon Glassc49deb82016-11-25 20:15:54 -0700986 def testUBootImg(self):
987 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600988 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -0700989 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700990
991 def testNoMicrocode(self):
992 """Test that a missing microcode region is detected"""
993 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600994 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700995 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
996 "node found in ", str(e.exception))
997
998 def testMicrocodeWithoutNode(self):
999 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1000 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001001 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001002 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1003 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1004
1005 def testMicrocodeWithoutNode2(self):
1006 """Test that a missing u-boot-ucode node is detected"""
1007 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001008 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001009 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1010 "microcode region u-boot-ucode", str(e.exception))
1011
1012 def testMicrocodeWithoutPtrInElf(self):
1013 """Test that a U-Boot binary without the microcode symbol is detected"""
1014 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001015 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001016 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001017 TestFunctional._MakeInputFile('u-boot', fd.read())
1018
1019 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001020 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001021 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1022 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1023
1024 finally:
1025 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -06001026 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001027 TestFunctional._MakeInputFile('u-boot', fd.read())
1028
1029 def testMicrocodeNotInImage(self):
1030 """Test that microcode must be placed within the image"""
1031 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001032 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001033 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1034 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001035 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001036
1037 def testWithoutMicrocode(self):
1038 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001039 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001040 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001041 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001042
1043 # Now check the device tree has no microcode
1044 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1045 second = data[len(U_BOOT_NODTB_DATA):]
1046
1047 fdt_len = self.GetFdtLen(second)
1048 self.assertEqual(dtb, second[:fdt_len])
1049
1050 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1051 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001052 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001053
1054 def testUnknownPosSize(self):
1055 """Test that microcode must be placed within the image"""
1056 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001057 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001058 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001059 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001060
1061 def testPackFsp(self):
1062 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001063 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001064 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1065
1066 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001067 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001068 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001069 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001070
1071 def testPackVbt(self):
1072 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001073 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001074 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001075
Simon Glass56509842017-11-12 21:52:25 -07001076 def testSplBssPad(self):
1077 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001078 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001079 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001080 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001081 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1082 data)
Simon Glass56509842017-11-12 21:52:25 -07001083
Simon Glass86af5112018-10-01 21:12:42 -06001084 def testSplBssPadMissing(self):
1085 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001086 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001087 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001088 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001089 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1090 str(e.exception))
1091
Simon Glass87722132017-11-12 21:52:26 -07001092 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001093 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001094 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001095 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1096
Simon Glass736bb0a2018-07-06 10:27:17 -06001097 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1098 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001099
1100 We expect to see the following in the image, in order:
1101 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1102 correct place
1103 u-boot.dtb with the microcode removed
1104 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001105
1106 Args:
1107 dts: Device tree file to use for test
1108 ucode_second: True if the microsecond entry is second instead of
1109 third
Simon Glass6b187df2017-11-12 21:52:27 -07001110 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001111 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001112 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1113 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001114 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1115 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001116
Simon Glass736bb0a2018-07-06 10:27:17 -06001117 def testPackUbootSplMicrocode(self):
1118 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001119 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001120
1121 def testPackUbootSplMicrocodeReorder(self):
1122 """Test that order doesn't matter for microcode entries
1123
1124 This is the same as testPackUbootSplMicrocode but when we process the
1125 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1126 entry, so we reply on binman to try later.
1127 """
Simon Glass741f2d62018-10-01 12:22:30 -06001128 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001129 ucode_second=True)
1130
Simon Glassca4f4ff2017-11-12 21:52:28 -07001131 def testPackMrc(self):
1132 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001133 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001134 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1135
Simon Glass47419ea2017-11-13 18:54:55 -07001136 def testSplDtb(self):
1137 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001138 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001139 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1140
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001141 def testSplNoDtb(self):
1142 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001143 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001144 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1145
Simon Glass19790632017-11-13 18:55:01 -07001146 def testSymbols(self):
1147 """Test binman can assign symbols embedded in U-Boot"""
1148 elf_fname = self.TestFile('u_boot_binman_syms')
1149 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1150 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001151 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001152
Simon Glass11ae93e2018-10-01 21:12:47 -06001153 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001154 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001155 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001156 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1157 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1158 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001159 self.assertEqual(expected, data)
1160
Simon Glassdd57c132018-06-01 09:38:11 -06001161 def testPackUnitAddress(self):
1162 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001163 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001164 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1165
Simon Glass18546952018-06-01 09:38:16 -06001166 def testSections(self):
1167 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001168 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001169 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1170 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1171 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001172 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001173
Simon Glass3b0c38212018-06-01 09:38:20 -06001174 def testMap(self):
1175 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001176 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001177 self.assertEqual('''ImagePos Offset Size Name
117800000000 00000000 00000028 main-section
117900000000 00000000 00000010 section@0
118000000000 00000000 00000004 u-boot
118100000010 00000010 00000010 section@1
118200000010 00000000 00000004 u-boot
118300000020 00000020 00000004 section@2
118400000020 00000000 00000004 u-boot
Simon Glass3b0c38212018-06-01 09:38:20 -06001185''', map_data)
1186
Simon Glassc8d48ef2018-06-01 09:38:21 -06001187 def testNamePrefix(self):
1188 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001189 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001190 self.assertEqual('''ImagePos Offset Size Name
119100000000 00000000 00000028 main-section
119200000000 00000000 00000010 section@0
119300000000 00000000 00000004 ro-u-boot
119400000010 00000010 00000010 section@1
119500000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001196''', map_data)
1197
Simon Glass736bb0a2018-07-06 10:27:17 -06001198 def testUnknownContents(self):
1199 """Test that obtaining the contents works as expected"""
1200 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001201 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-07-06 10:27:17 -06001202 self.assertIn("Section '/binman': Internal error: Could not complete "
1203 "processing of contents: remaining [<_testing.Entry__testing ",
1204 str(e.exception))
1205
Simon Glass5c890232018-07-06 10:27:19 -06001206 def testBadChangeSize(self):
1207 """Test that trying to change the size of an entry fails"""
1208 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001209 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-07-06 10:27:19 -06001210 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1211 '2 to 1', str(e.exception))
1212
Simon Glass16b8d6b2018-07-06 10:27:42 -06001213 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001214 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001215 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001216 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001217 dtb = fdt.Fdt(out_dtb_fname)
1218 dtb.Scan()
1219 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001220 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001221 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001222 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001223 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001224 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001225 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001226 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001227 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001228 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001229 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001230 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001231 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001232
Simon Glass3ab95982018-08-01 15:22:37 -06001233 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001234 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001235 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001236 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001237 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001238 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001239 'size': 40
1240 }, props)
1241
1242 def testUpdateFdtBad(self):
1243 """Test that we detect when ProcessFdt never completes"""
1244 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001245 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001246 self.assertIn('Could not complete processing of Fdt: remaining '
1247 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001248
Simon Glass53af22a2018-07-17 13:25:32 -06001249 def testEntryArgs(self):
1250 """Test passing arguments to entries from the command line"""
1251 entry_args = {
1252 'test-str-arg': 'test1',
1253 'test-int-arg': '456',
1254 }
Simon Glass741f2d62018-10-01 12:22:30 -06001255 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001256 self.assertIn('image', control.images)
1257 entry = control.images['image'].GetEntries()['_testing']
1258 self.assertEqual('test0', entry.test_str_fdt)
1259 self.assertEqual('test1', entry.test_str_arg)
1260 self.assertEqual(123, entry.test_int_fdt)
1261 self.assertEqual(456, entry.test_int_arg)
1262
1263 def testEntryArgsMissing(self):
1264 """Test missing arguments and properties"""
1265 entry_args = {
1266 'test-int-arg': '456',
1267 }
Simon Glass741f2d62018-10-01 12:22:30 -06001268 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001269 entry = control.images['image'].GetEntries()['_testing']
1270 self.assertEqual('test0', entry.test_str_fdt)
1271 self.assertEqual(None, entry.test_str_arg)
1272 self.assertEqual(None, entry.test_int_fdt)
1273 self.assertEqual(456, entry.test_int_arg)
1274
1275 def testEntryArgsRequired(self):
1276 """Test missing arguments and properties"""
1277 entry_args = {
1278 'test-int-arg': '456',
1279 }
1280 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001281 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001282 self.assertIn("Node '/binman/_testing': Missing required "
1283 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1284 str(e.exception))
1285
1286 def testEntryArgsInvalidFormat(self):
1287 """Test that an invalid entry-argument format is detected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001288 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001289 with self.assertRaises(ValueError) as e:
1290 self._DoBinman(*args)
1291 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1292
1293 def testEntryArgsInvalidInteger(self):
1294 """Test that an invalid entry-argument integer is detected"""
1295 entry_args = {
1296 'test-int-arg': 'abc',
1297 }
1298 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001299 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001300 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1301 "'test-int-arg' (value 'abc') to integer",
1302 str(e.exception))
1303
1304 def testEntryArgsInvalidDatatype(self):
1305 """Test that an invalid entry-argument datatype is detected
1306
1307 This test could be written in entry_test.py except that it needs
1308 access to control.entry_args, which seems more than that module should
1309 be able to see.
1310 """
1311 entry_args = {
1312 'test-bad-datatype-arg': '12',
1313 }
1314 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001315 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001316 entry_args=entry_args)
1317 self.assertIn('GetArg() internal error: Unknown data type ',
1318 str(e.exception))
1319
Simon Glassbb748372018-07-17 13:25:33 -06001320 def testText(self):
1321 """Test for a text entry type"""
1322 entry_args = {
1323 'test-id': TEXT_DATA,
1324 'test-id2': TEXT_DATA2,
1325 'test-id3': TEXT_DATA3,
1326 }
Simon Glass741f2d62018-10-01 12:22:30 -06001327 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001328 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001329 expected = (tools.ToBytes(TEXT_DATA) +
1330 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1331 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001332 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001333 self.assertEqual(expected, data)
1334
Simon Glassfd8d1f72018-07-17 13:25:36 -06001335 def testEntryDocs(self):
1336 """Test for creation of entry documentation"""
1337 with test_util.capture_sys_output() as (stdout, stderr):
1338 control.WriteEntryDocs(binman.GetEntryModules())
1339 self.assertTrue(len(stdout.getvalue()) > 0)
1340
1341 def testEntryDocsMissing(self):
1342 """Test handling of missing entry documentation"""
1343 with self.assertRaises(ValueError) as e:
1344 with test_util.capture_sys_output() as (stdout, stderr):
1345 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1346 self.assertIn('Documentation is missing for modules: u_boot',
1347 str(e.exception))
1348
Simon Glass11e36cc2018-07-17 13:25:38 -06001349 def testFmap(self):
1350 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001351 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001352 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001353 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1354 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001355 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001356 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001357 self.assertEqual(1, fhdr.ver_major)
1358 self.assertEqual(0, fhdr.ver_minor)
1359 self.assertEqual(0, fhdr.base)
1360 self.assertEqual(16 + 16 +
1361 fmap_util.FMAP_HEADER_LEN +
1362 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001363 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001364 self.assertEqual(3, fhdr.nareas)
1365 for fentry in fentries:
1366 self.assertEqual(0, fentry.flags)
1367
1368 self.assertEqual(0, fentries[0].offset)
1369 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001370 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001371
1372 self.assertEqual(16, fentries[1].offset)
1373 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001374 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001375
1376 self.assertEqual(32, fentries[2].offset)
1377 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1378 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001379 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001380
Simon Glassec127af2018-07-17 13:25:39 -06001381 def testBlobNamedByArg(self):
1382 """Test we can add a blob with the filename coming from an entry arg"""
1383 entry_args = {
1384 'cros-ec-rw-path': 'ecrw.bin',
1385 }
Simon Glass741f2d62018-10-01 12:22:30 -06001386 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001387 entry_args=entry_args)
1388
Simon Glass3af8e492018-07-17 13:25:40 -06001389 def testFill(self):
1390 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001391 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001392 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001393 self.assertEqual(expected, data)
1394
1395 def testFillNoSize(self):
1396 """Test for an fill entry type with no size"""
1397 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001398 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001399 self.assertIn("'fill' entry must have a size property",
1400 str(e.exception))
1401
Simon Glass0ef87aa2018-07-17 13:25:44 -06001402 def _HandleGbbCommand(self, pipe_list):
1403 """Fake calls to the futility utility"""
1404 if pipe_list[0][0] == 'futility':
1405 fname = pipe_list[0][-1]
1406 # Append our GBB data to the file, which will happen every time the
1407 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001408 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001409 fd.write(GBB_DATA)
1410 return command.CommandResult()
1411
1412 def testGbb(self):
1413 """Test for the Chromium OS Google Binary Block"""
1414 command.test_result = self._HandleGbbCommand
1415 entry_args = {
1416 'keydir': 'devkeys',
1417 'bmpblk': 'bmpblk.bin',
1418 }
Simon Glass741f2d62018-10-01 12:22:30 -06001419 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001420
1421 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001422 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1423 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001424 self.assertEqual(expected, data)
1425
1426 def testGbbTooSmall(self):
1427 """Test for the Chromium OS Google Binary Block being large enough"""
1428 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001429 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001430 self.assertIn("Node '/binman/gbb': GBB is too small",
1431 str(e.exception))
1432
1433 def testGbbNoSize(self):
1434 """Test for the Chromium OS Google Binary Block having a size"""
1435 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001436 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001437 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1438 str(e.exception))
1439
Simon Glass24d0d3c2018-07-17 13:25:47 -06001440 def _HandleVblockCommand(self, pipe_list):
1441 """Fake calls to the futility utility"""
1442 if pipe_list[0][0] == 'futility':
1443 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001444 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001445 fd.write(VBLOCK_DATA)
1446 return command.CommandResult()
1447
1448 def testVblock(self):
1449 """Test for the Chromium OS Verified Boot Block"""
1450 command.test_result = self._HandleVblockCommand
1451 entry_args = {
1452 'keydir': 'devkeys',
1453 }
Simon Glass741f2d62018-10-01 12:22:30 -06001454 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001455 entry_args=entry_args)
1456 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1457 self.assertEqual(expected, data)
1458
1459 def testVblockNoContent(self):
1460 """Test we detect a vblock which has no content to sign"""
1461 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001462 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001463 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1464 'property', str(e.exception))
1465
1466 def testVblockBadPhandle(self):
1467 """Test that we detect a vblock with an invalid phandle in contents"""
1468 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001469 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001470 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1471 '1000', str(e.exception))
1472
1473 def testVblockBadEntry(self):
1474 """Test that we detect an entry that points to a non-entry"""
1475 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001476 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001477 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1478 "'other'", str(e.exception))
1479
Simon Glassb8ef5b62018-07-17 13:25:48 -06001480 def testTpl(self):
1481 """Test that an image with TPL and ots device tree can be created"""
1482 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001483 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001484 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001485 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001486 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1487
Simon Glass15a587c2018-07-17 13:25:51 -06001488 def testUsesPos(self):
1489 """Test that the 'pos' property cannot be used anymore"""
1490 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001491 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001492 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1493 "'pos'", str(e.exception))
1494
Simon Glassd178eab2018-09-14 04:57:08 -06001495 def testFillZero(self):
1496 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001497 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001498 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001499
Simon Glass0b489362018-09-14 04:57:09 -06001500 def testTextMissing(self):
1501 """Test for a text entry type where there is no text"""
1502 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001503 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001504 self.assertIn("Node '/binman/text': No value provided for text label "
1505 "'test-id'", str(e.exception))
1506
Simon Glass35b384c2018-09-14 04:57:10 -06001507 def testPackStart16Tpl(self):
1508 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001509 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001510 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1511
Simon Glass0bfa7b02018-09-14 04:57:12 -06001512 def testSelectImage(self):
1513 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001514 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001515
Simon Glasseb833d82019-04-25 21:58:34 -06001516 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001517 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001518 with test_util.capture_sys_output() as (stdout, stderr):
1519 retcode = self._DoTestFile('006_dual_image.dts',
1520 verbosity=verbosity,
1521 images=['image2'])
1522 self.assertEqual(0, retcode)
1523 if verbosity:
1524 self.assertIn(expected, stdout.getvalue())
1525 else:
1526 self.assertNotIn(expected, stdout.getvalue())
1527
1528 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1529 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001530
Simon Glass6ed45ba2018-09-14 04:57:24 -06001531 def testUpdateFdtAll(self):
1532 """Test that all device trees are updated with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001533 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001534 use_real_dtb=True, update_dtb=True)
1535
1536 base_expected = {
1537 'section:image-pos': 0,
1538 'u-boot-tpl-dtb:size': 513,
1539 'u-boot-spl-dtb:size': 513,
1540 'u-boot-spl-dtb:offset': 493,
1541 'image-pos': 0,
1542 'section/u-boot-dtb:image-pos': 0,
1543 'u-boot-spl-dtb:image-pos': 493,
1544 'section/u-boot-dtb:size': 493,
1545 'u-boot-tpl-dtb:image-pos': 1006,
1546 'section/u-boot-dtb:offset': 0,
1547 'section:size': 493,
1548 'offset': 0,
1549 'section:offset': 0,
1550 'u-boot-tpl-dtb:offset': 1006,
1551 'size': 1519
1552 }
1553
1554 # We expect three device-tree files in the output, one after the other.
1555 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1556 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1557 # main U-Boot tree. All three should have the same postions and offset.
1558 start = 0
1559 for item in ['', 'spl', 'tpl']:
1560 dtb = fdt.Fdt.FromData(data[start:])
1561 dtb.Scan()
1562 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1563 'spl', 'tpl'])
1564 expected = dict(base_expected)
1565 if item:
1566 expected[item] = 0
1567 self.assertEqual(expected, props)
1568 start += dtb._fdt_obj.totalsize()
1569
1570 def testUpdateFdtOutput(self):
1571 """Test that output DTB files are updated"""
1572 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001573 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001574 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1575
1576 # Unfortunately, compiling a source file always results in a file
1577 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001578 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001579 # binman as a file called u-boot.dtb. To fix this, copy the file
1580 # over to the expected place.
1581 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1582 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1583 start = 0
1584 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1585 'tpl/u-boot-tpl.dtb.out']:
1586 dtb = fdt.Fdt.FromData(data[start:])
1587 size = dtb._fdt_obj.totalsize()
1588 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1589 outdata = tools.ReadFile(pathname)
1590 name = os.path.split(fname)[0]
1591
1592 if name:
1593 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1594 else:
1595 orig_indata = dtb_data
1596 self.assertNotEqual(outdata, orig_indata,
1597 "Expected output file '%s' be updated" % pathname)
1598 self.assertEqual(outdata, data[start:start + size],
1599 "Expected output file '%s' to match output image" %
1600 pathname)
1601 start += size
1602 finally:
1603 self._ResetDtbs()
1604
Simon Glass83d73c22018-09-14 04:57:26 -06001605 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001606 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001607
1608 def testCompress(self):
1609 """Test compression of blobs"""
Simon Glass741f2d62018-10-01 12:22:30 -06001610 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001611 use_real_dtb=True, update_dtb=True)
1612 dtb = fdt.Fdt(out_dtb_fname)
1613 dtb.Scan()
1614 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1615 orig = self._decompress(data)
1616 self.assertEquals(COMPRESS_DATA, orig)
1617 expected = {
1618 'blob:uncomp-size': len(COMPRESS_DATA),
1619 'blob:size': len(data),
1620 'size': len(data),
1621 }
1622 self.assertEqual(expected, props)
1623
Simon Glass0a98b282018-09-14 04:57:28 -06001624 def testFiles(self):
1625 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001626 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001627 self.assertEqual(FILES_DATA, data)
1628
1629 def testFilesCompress(self):
1630 """Test bringing in multiple files and compressing them"""
Simon Glass741f2d62018-10-01 12:22:30 -06001631 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001632
1633 image = control.images['image']
1634 entries = image.GetEntries()
1635 files = entries['files']
1636 entries = files._section._entries
1637
Simon Glassc6c10e72019-05-17 22:00:46 -06001638 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001639 for i in range(1, 3):
1640 key = '%d.dat' % i
1641 start = entries[key].image_pos
1642 len = entries[key].size
1643 chunk = data[start:start + len]
1644 orig += self._decompress(chunk)
1645
1646 self.assertEqual(FILES_DATA, orig)
1647
1648 def testFilesMissing(self):
1649 """Test missing files"""
1650 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001651 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001652 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1653 'no files', str(e.exception))
1654
1655 def testFilesNoPattern(self):
1656 """Test missing files"""
1657 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001658 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001659 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1660 str(e.exception))
1661
Simon Glassba64a0b2018-09-14 04:57:29 -06001662 def testExpandSize(self):
1663 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001664 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001665 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001666 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1667 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1668 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1669 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001670 self.assertEqual(expect, data)
1671 self.assertEqual('''ImagePos Offset Size Name
167200000000 00000000 00000028 main-section
167300000000 00000000 00000008 fill
167400000008 00000008 00000004 u-boot
16750000000c 0000000c 00000004 section
16760000000c 00000000 00000003 intel-mrc
167700000010 00000010 00000004 u-boot2
167800000014 00000014 0000000c section2
167900000014 00000000 00000008 fill
16800000001c 00000008 00000004 u-boot
168100000020 00000020 00000008 fill2
1682''', map_data)
1683
1684 def testExpandSizeBad(self):
1685 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001686 with test_util.capture_sys_output() as (stdout, stderr):
1687 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001688 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001689 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1690 'expanding entry', str(e.exception))
1691
Simon Glasse0e5df92018-09-14 04:57:31 -06001692 def testHash(self):
1693 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001694 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001695 use_real_dtb=True, update_dtb=True)
1696 dtb = fdt.Fdt(out_dtb_fname)
1697 dtb.Scan()
1698 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1699 m = hashlib.sha256()
1700 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001701 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001702
1703 def testHashNoAlgo(self):
1704 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001705 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001706 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1707 'hash node', str(e.exception))
1708
1709 def testHashBadAlgo(self):
1710 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001711 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001712 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1713 str(e.exception))
1714
1715 def testHashSection(self):
1716 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001717 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001718 use_real_dtb=True, update_dtb=True)
1719 dtb = fdt.Fdt(out_dtb_fname)
1720 dtb.Scan()
1721 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1722 m = hashlib.sha256()
1723 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001724 m.update(tools.GetBytes(ord('a'), 16))
1725 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001726
Simon Glassf0253632018-09-14 04:57:32 -06001727 def testPackUBootTplMicrocode(self):
1728 """Test that x86 microcode can be handled correctly in TPL
1729
1730 We expect to see the following in the image, in order:
1731 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1732 place
1733 u-boot-tpl.dtb with the microcode removed
1734 the microcode
1735 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001736 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001737 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001738 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001739 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001740 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1741 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001742
Simon Glassf8f8df62018-09-14 04:57:34 -06001743 def testFmapX86(self):
1744 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001745 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001746 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001747 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001748 self.assertEqual(expected, data[:32])
1749 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1750
1751 self.assertEqual(0x100, fhdr.image_size)
1752
1753 self.assertEqual(0, fentries[0].offset)
1754 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001755 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001756
1757 self.assertEqual(4, fentries[1].offset)
1758 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001759 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001760
1761 self.assertEqual(32, fentries[2].offset)
1762 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1763 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001764 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001765
1766 def testFmapX86Section(self):
1767 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001768 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001769 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001770 self.assertEqual(expected, data[:32])
1771 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1772
1773 self.assertEqual(0x100, fhdr.image_size)
1774
1775 self.assertEqual(0, fentries[0].offset)
1776 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001777 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001778
1779 self.assertEqual(4, fentries[1].offset)
1780 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001781 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001782
1783 self.assertEqual(36, fentries[2].offset)
1784 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1785 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001786 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001787
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001788 def testElf(self):
1789 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001790 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001791 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001792 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1793 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001794 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001795 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001796
Simon Glass093d1682019-07-08 13:18:25 -06001797 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001798 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001799 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001800 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001801 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001802 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001803
Simon Glass163ed6c2018-09-14 04:57:36 -06001804 def testPackOverlapMap(self):
1805 """Test that overlapping regions are detected"""
1806 with test_util.capture_sys_output() as (stdout, stderr):
1807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001808 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001809 map_fname = tools.GetOutputFilename('image.map')
1810 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1811 stdout.getvalue())
1812
1813 # We should not get an inmage, but there should be a map file
1814 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1815 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001816 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001817 self.assertEqual('''ImagePos Offset Size Name
1818<none> 00000000 00000007 main-section
1819<none> 00000000 00000004 u-boot
1820<none> 00000003 00000004 u-boot-align
1821''', map_data)
1822
Simon Glass093d1682019-07-08 13:18:25 -06001823 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001824 """Test that an image with an Intel Reference code binary works"""
1825 data = self._DoReadFile('100_intel_refcode.dts')
1826 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1827
Simon Glass9481c802019-04-25 21:58:39 -06001828 def testSectionOffset(self):
1829 """Tests use of a section with an offset"""
1830 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1831 map=True)
1832 self.assertEqual('''ImagePos Offset Size Name
183300000000 00000000 00000038 main-section
183400000004 00000004 00000010 section@0
183500000004 00000000 00000004 u-boot
183600000018 00000018 00000010 section@1
183700000018 00000000 00000004 u-boot
18380000002c 0000002c 00000004 section@2
18390000002c 00000000 00000004 u-boot
1840''', map_data)
1841 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001842 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1843 tools.GetBytes(0x21, 12) +
1844 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1845 tools.GetBytes(0x61, 12) +
1846 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1847 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001848
Simon Glass53af22a2018-07-17 13:25:32 -06001849
Simon Glass9fc60b42017-11-12 21:52:22 -07001850if __name__ == "__main__":
1851 unittest.main()