blob: 6fdecb2f3bff810416419e4a53c35f338c9e2348 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-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 Glass1c420c92019-07-08 13:18:49 -06009from __future__ import print_function
10
Simon Glassae7cf032018-09-14 04:57:31 -060011import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
14import shutil
15import struct
16import sys
17import tempfile
18import unittest
19
20import binman
Simon Glass1de34482019-07-08 13:18:53 -060021import cbfs_util
Simon Glass57454f42016-11-25 20:15:52 -070022import cmdline
23import command
24import control
Simon Glass4ca8e042017-11-13 18:55:01 -070025import elf
Simon Glassa9440932017-05-27 07:38:30 -060026import fdt
Simon Glass57454f42016-11-25 20:15:52 -070027import fdt_util
Simon Glass704784b2018-07-17 13:25:38 -060028import fmap_util
Simon Glass969616c2018-07-17 13:25:36 -060029import test_util
Simon Glass759af872019-07-08 13:18:54 -060030import gzip
Simon Glass29aa7362018-09-14 04:57:19 -060031import state
Simon Glass57454f42016-11-25 20:15:52 -070032import tools
33import tout
34
35# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060036U_BOOT_DATA = b'1234'
37U_BOOT_IMG_DATA = b'img'
38U_BOOT_SPL_DATA = b'56780123456789abcde'
39U_BOOT_TPL_DATA = b'tpl'
40BLOB_DATA = b'89'
41ME_DATA = b'0abcd'
42VGA_DATA = b'vga'
43U_BOOT_DTB_DATA = b'udtb'
44U_BOOT_SPL_DTB_DATA = b'spldtb'
45U_BOOT_TPL_DTB_DATA = b'tpldtb'
46X86_START16_DATA = b'start16'
47X86_START16_SPL_DATA = b'start16spl'
48X86_START16_TPL_DATA = b'start16tpl'
49PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
50U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
51U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
52U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
53FSP_DATA = b'fsp'
54CMC_DATA = b'cmc'
55VBT_DATA = b'vbt'
56MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060057TEXT_DATA = 'text'
58TEXT_DATA2 = 'text2'
59TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060060CROS_EC_RW_DATA = b'ecrw'
61GBB_DATA = b'gbbd'
62BMPBLK_DATA = b'bmp'
63VBLOCK_DATA = b'vblk'
64FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
65 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060066COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass303f62f2019-05-17 22:00:46 -060067REFCODE_DATA = b'refcode'
Simon Glassdb168d42018-07-17 13:25:39 -060068
Simon Glass57454f42016-11-25 20:15:52 -070069
70class TestFunctional(unittest.TestCase):
71 """Functional tests for binman
72
73 Most of these use a sample .dts file to build an image and then check
74 that it looks correct. The sample files are in the test/ subdirectory
75 and are numbered.
76
77 For each entry type a very small test file is created using fixed
78 string contents. This makes it easy to test that things look right, and
79 debug problems.
80
81 In some cases a 'real' file must be used - these are also supplied in
82 the test/ diurectory.
83 """
84 @classmethod
85 def setUpClass(self):
Simon Glassb3393262017-11-12 21:52:20 -070086 global entry
87 import entry
88
Simon Glass57454f42016-11-25 20:15:52 -070089 # Handle the case where argv[0] is 'python'
90 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
91 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
92
93 # Create a temporary directory for input files
94 self._indir = tempfile.mkdtemp(prefix='binmant.')
95
96 # Create some test files
97 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
98 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
99 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600100 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700101 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700102 TestFunctional._MakeInputFile('me.bin', ME_DATA)
103 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600104 self._ResetDtbs()
Simon Glass72232452016-11-25 20:15:53 -0700105 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya311d4842018-09-03 21:35:08 +0530106 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glasse83679d2017-11-12 21:52:26 -0700107 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
108 X86_START16_SPL_DATA)
Simon Glassed40e962018-09-14 04:57:10 -0600109 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
110 X86_START16_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700111 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700112 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
113 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600114 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
115 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700116 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
117 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700118 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700119 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600120 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600121 TestFunctional._MakeInputDir('devkeys')
122 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600123 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700124
Simon Glass72232452016-11-25 20:15:53 -0700125 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass33486662019-05-14 15:53:42 -0600126 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass72232452016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('u-boot', fd.read())
128
129 # Intel flash descriptor file
Simon Glass33486662019-05-14 15:53:42 -0600130 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glass72232452016-11-25 20:15:53 -0700131 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
132
Simon Glassac6328c2018-09-14 04:57:28 -0600133 shutil.copytree(self.TestFile('files'),
134 os.path.join(self._indir, 'files'))
135
Simon Glass7ba33592018-09-14 04:57:26 -0600136 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
137
Simon Glass1de34482019-07-08 13:18:53 -0600138 # Travis-CI may have an old lz4
139 self.have_lz4 = True
140 try:
141 tools.Run('lz4', '--no-frame-crc', '-c',
142 os.path.join(self._indir, 'u-boot.bin'))
143 except:
144 self.have_lz4 = False
145
Simon Glass57454f42016-11-25 20:15:52 -0700146 @classmethod
147 def tearDownClass(self):
148 """Remove the temporary input directory and its contents"""
Simon Glass1c420c92019-07-08 13:18:49 -0600149 if self.preserve_indir:
150 print('Preserving input dir: %s' % self._indir)
151 else:
152 if self._indir:
153 shutil.rmtree(self._indir)
Simon Glass57454f42016-11-25 20:15:52 -0700154 self._indir = None
155
Simon Glass1c420c92019-07-08 13:18:49 -0600156 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600157 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
158 toolpath=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600159 """Accept arguments controlling test execution
160
161 Args:
162 preserve_indir: Preserve the shared input directory used by all
163 tests in this class.
164 preserve_outdir: Preserve the output directories used by tests. Each
165 test has its own, so this is normally only useful when running a
166 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600167 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600168 """
169 cls.preserve_indir = preserve_indir
170 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600171 cls.toolpath = toolpath
Simon Glass1c420c92019-07-08 13:18:49 -0600172
Simon Glass1de34482019-07-08 13:18:53 -0600173 def _CheckLz4(self):
174 if not self.have_lz4:
175 self.skipTest('lz4 --no-frame-crc not available')
176
Simon Glass57454f42016-11-25 20:15:52 -0700177 def setUp(self):
178 # Enable this to turn on debugging output
179 # tout.Init(tout.DEBUG)
180 command.test_result = None
181
182 def tearDown(self):
183 """Remove the temporary output directory"""
Simon Glass1c420c92019-07-08 13:18:49 -0600184 if self.preserve_outdirs:
185 print('Preserving output dir: %s' % tools.outdir)
186 else:
187 tools._FinaliseForTest()
Simon Glass57454f42016-11-25 20:15:52 -0700188
Simon Glass8425a1f2018-07-17 13:25:48 -0600189 @classmethod
190 def _ResetDtbs(self):
191 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
192 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
193 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
194
Simon Glass8a50b4a2019-07-08 13:18:48 -0600195 def _GetVerbosity(self):
196 """Check if verbosity should be enabled
197
198 Returns:
199 list containing either:
200 - Verbosity flag (e.g. '-v2') if it is present on the cmd line
201 - nothing if the flag is not present
202 """
203 for arg in sys.argv[1:]:
204 if arg.startswith('-v'):
205 return [arg]
206 return []
207
Simon Glass57454f42016-11-25 20:15:52 -0700208 def _RunBinman(self, *args, **kwargs):
209 """Run binman using the command line
210
211 Args:
212 Arguments to pass, as a list of strings
213 kwargs: Arguments to pass to Command.RunPipe()
214 """
215 result = command.RunPipe([[self._binman_pathname] + list(args)],
216 capture=True, capture_stderr=True, raise_on_error=False)
217 if result.return_code and kwargs.get('raise_on_error', True):
218 raise Exception("Error running '%s': %s" % (' '.join(args),
219 result.stdout + result.stderr))
220 return result
221
222 def _DoBinman(self, *args):
223 """Run binman using directly (in the same process)
224
225 Args:
226 Arguments to pass, as a list of strings
227 Returns:
228 Return value (0 for success)
229 """
Simon Glass075a45c2017-11-13 18:55:00 -0700230 args = list(args)
231 if '-D' in sys.argv:
232 args = args + ['-D']
233 (options, args) = cmdline.ParseArgs(args)
Simon Glass57454f42016-11-25 20:15:52 -0700234 options.pager = 'binman-invalid-pager'
235 options.build_dir = self._indir
236
237 # For testing, you can force an increase in verbosity here
238 # options.verbosity = tout.DEBUG
239 return control.Binman(options, args)
240
Simon Glass91710b32018-07-17 13:25:32 -0600241 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600242 entry_args=None, images=None, use_real_dtb=False,
243 verbosity=None):
Simon Glass57454f42016-11-25 20:15:52 -0700244 """Run binman with a given test file
245
246 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600247 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600248 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600249 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600250 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600251 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600252 entry_args: Dict of entry args to supply to binman
253 key: arg name
254 value: value of that arg
255 images: List of image names to build
Simon Glass57454f42016-11-25 20:15:52 -0700256 """
Simon Glass075a45c2017-11-13 18:55:00 -0700257 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
258 if debug:
259 args.append('-D')
Simon Glass30732662018-06-01 09:38:20 -0600260 if map:
261 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600262 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600263 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600264 if not use_real_dtb:
265 args.append('--fake-dtb')
Simon Glassb4595d82019-04-25 21:58:34 -0600266 if verbosity is not None:
267 args.append('-v%d' % verbosity)
Simon Glass8a50b4a2019-07-08 13:18:48 -0600268 else:
269 args += self._GetVerbosity()
Simon Glass91710b32018-07-17 13:25:32 -0600270 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600271 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600272 args.append('-a%s=%s' % (arg, value))
Simon Glass3b376c32018-09-14 04:57:12 -0600273 if images:
274 for image in images:
275 args += ['-i', image]
Simon Glasscebfab22019-07-08 13:18:50 -0600276 if self.toolpath:
277 for path in self.toolpath:
278 args += ['--toolpath', path]
Simon Glass075a45c2017-11-13 18:55:00 -0700279 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700280
281 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700282 """Set up a new test device-tree file
283
284 The given file is compiled and set up as the device tree to be used
285 for ths test.
286
287 Args:
288 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600289 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700290
291 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600292 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700293 """
Simon Glass752e7552018-10-01 21:12:41 -0600294 tools.PrepareOutputDir(None)
Simon Glass57454f42016-11-25 20:15:52 -0700295 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass33486662019-05-14 15:53:42 -0600296 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700297 data = fd.read()
298 TestFunctional._MakeInputFile(outfile, data)
Simon Glass752e7552018-10-01 21:12:41 -0600299 tools.FinaliseOutputDir()
300 return data
Simon Glass57454f42016-11-25 20:15:52 -0700301
Simon Glasse219aa42018-09-14 04:57:24 -0600302 def _GetDtbContentsForSplTpl(self, dtb_data, name):
303 """Create a version of the main DTB for SPL or SPL
304
305 For testing we don't actually have different versions of the DTB. With
306 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
307 we don't normally have any unwanted nodes.
308
309 We still want the DTBs for SPL and TPL to be different though, since
310 otherwise it is confusing to know which one we are looking at. So add
311 an 'spl' or 'tpl' property to the top-level node.
312 """
313 dtb = fdt.Fdt.FromData(dtb_data)
314 dtb.Scan()
315 dtb.GetNode('/binman').AddZeroProp(name)
316 dtb.Sync(auto_resize=True)
317 dtb.Pack()
318 return dtb.GetContents()
319
Simon Glassa87014e2018-07-06 10:27:42 -0600320 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glasse219aa42018-09-14 04:57:24 -0600321 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass57454f42016-11-25 20:15:52 -0700322 """Run binman and return the resulting image
323
324 This runs binman with a given test file and then reads the resulting
325 output file. It is a shortcut function since most tests need to do
326 these steps.
327
328 Raises an assertion failure if binman returns a non-zero exit code.
329
330 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600331 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700332 use_real_dtb: True to use the test file as the contents of
333 the u-boot-dtb entry. Normally this is not needed and the
334 test contents (the U_BOOT_DTB_DATA string) can be used.
335 But in some test we need the real contents.
Simon Glass30732662018-06-01 09:38:20 -0600336 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600337 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600338 tree before packing it into the image
Simon Glass72232452016-11-25 20:15:53 -0700339
340 Returns:
341 Tuple:
342 Resulting image contents
343 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600344 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600345 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700346 """
Simon Glass72232452016-11-25 20:15:53 -0700347 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700348 # Use the compiled test file as the u-boot-dtb input
349 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700350 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600351
352 # For testing purposes, make a copy of the DT for SPL and TPL. Add
353 # a node indicating which it is, so aid verification.
354 for name in ['spl', 'tpl']:
355 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
356 outfile = os.path.join(self._indir, dtb_fname)
357 TestFunctional._MakeInputFile(dtb_fname,
358 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700359
360 try:
Simon Glass91710b32018-07-17 13:25:32 -0600361 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glasse219aa42018-09-14 04:57:24 -0600362 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass57454f42016-11-25 20:15:52 -0700363 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600364 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700365
366 # Find the (only) image, read it and return its contents
367 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600368 image_fname = tools.GetOutputFilename('image.bin')
369 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600370 if map:
371 map_fname = tools.GetOutputFilename('image.map')
372 with open(map_fname) as fd:
373 map_data = fd.read()
374 else:
375 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600376 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600377 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700378 finally:
379 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600380 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600381 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700382
Simon Glass5b4bce32019-07-08 14:25:26 -0600383 def _DoReadFileRealDtb(self, fname):
384 """Run binman with a real .dtb file and return the resulting data
385
386 Args:
387 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
388
389 Returns:
390 Resulting image contents
391 """
392 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
393
Simon Glass72232452016-11-25 20:15:53 -0700394 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600395 """Helper function which discards the device-tree binary
396
397 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600398 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600399 use_real_dtb: True to use the test file as the contents of
400 the u-boot-dtb entry. Normally this is not needed and the
401 test contents (the U_BOOT_DTB_DATA string) can be used.
402 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600403
404 Returns:
405 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600406 """
Simon Glass72232452016-11-25 20:15:53 -0700407 return self._DoReadFileDtb(fname, use_real_dtb)[0]
408
Simon Glass57454f42016-11-25 20:15:52 -0700409 @classmethod
410 def _MakeInputFile(self, fname, contents):
411 """Create a new test input file, creating directories as needed
412
413 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600414 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700415 contents: File contents to write in to the file
416 Returns:
417 Full pathname of file created
418 """
419 pathname = os.path.join(self._indir, fname)
420 dirname = os.path.dirname(pathname)
421 if dirname and not os.path.exists(dirname):
422 os.makedirs(dirname)
423 with open(pathname, 'wb') as fd:
424 fd.write(contents)
425 return pathname
426
427 @classmethod
Simon Glassc1ae83c2018-07-17 13:25:44 -0600428 def _MakeInputDir(self, dirname):
429 """Create a new test input directory, creating directories as needed
430
431 Args:
432 dirname: Directory name to create
433
434 Returns:
435 Full pathname of directory created
436 """
437 pathname = os.path.join(self._indir, dirname)
438 if not os.path.exists(pathname):
439 os.makedirs(pathname)
440 return pathname
441
442 @classmethod
Simon Glass7057d022018-10-01 21:12:47 -0600443 def _SetupSplElf(self, src_fname='bss_data'):
444 """Set up an ELF file with a '_dt_ucode_base_size' symbol
445
446 Args:
447 Filename of ELF file to use as SPL
448 """
Simon Glass33486662019-05-14 15:53:42 -0600449 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass7057d022018-10-01 21:12:47 -0600450 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
451
452 @classmethod
Simon Glass57454f42016-11-25 20:15:52 -0700453 def TestFile(self, fname):
454 return os.path.join(self._binman_dir, 'test', fname)
455
456 def AssertInList(self, grep_list, target):
457 """Assert that at least one of a list of things is in a target
458
459 Args:
460 grep_list: List of strings to check
461 target: Target string
462 """
463 for grep in grep_list:
464 if grep in target:
465 return
Simon Glass848cdb52019-05-17 22:00:50 -0600466 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700467
468 def CheckNoGaps(self, entries):
469 """Check that all entries fit together without gaps
470
471 Args:
472 entries: List of entries to check
473 """
Simon Glasse8561af2018-08-01 15:22:37 -0600474 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700475 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600476 self.assertEqual(offset, entry.offset)
477 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700478
Simon Glass72232452016-11-25 20:15:53 -0700479 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600480 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700481
482 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600483 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700484
485 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600486 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700487 """
488 return struct.unpack('>L', dtb[4:8])[0]
489
Simon Glass0f621332019-07-08 14:25:27 -0600490 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600491 def AddNode(node, path):
492 if node.name != '/':
493 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600494 for prop in node.props.values():
495 if prop.name in prop_names:
496 prop_path = path + ':' + prop.name
497 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
498 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600499 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600500 AddNode(subnode, path)
501
502 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600503 AddNode(dtb.GetRoot(), '')
504 return tree
505
Simon Glass57454f42016-11-25 20:15:52 -0700506 def testRun(self):
507 """Test a basic run with valid args"""
508 result = self._RunBinman('-h')
509
510 def testFullHelp(self):
511 """Test that the full help is displayed with -H"""
512 result = self._RunBinman('-H')
513 help_file = os.path.join(self._binman_dir, 'README')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500514 # Remove possible extraneous strings
515 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
516 gothelp = result.stdout.replace(extra, '')
517 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700518 self.assertEqual(0, len(result.stderr))
519 self.assertEqual(0, result.return_code)
520
521 def testFullHelpInternal(self):
522 """Test that the full help is displayed with -H"""
523 try:
524 command.test_result = command.CommandResult()
525 result = self._DoBinman('-H')
526 help_file = os.path.join(self._binman_dir, 'README')
527 finally:
528 command.test_result = None
529
530 def testHelp(self):
531 """Test that the basic help is displayed with -h"""
532 result = self._RunBinman('-h')
533 self.assertTrue(len(result.stdout) > 200)
534 self.assertEqual(0, len(result.stderr))
535 self.assertEqual(0, result.return_code)
536
Simon Glass57454f42016-11-25 20:15:52 -0700537 def testBoard(self):
538 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600539 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700540 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
541 result = self._DoBinman('-b', 'sandbox')
542 self.assertEqual(0, result)
543
544 def testNeedBoard(self):
545 """Test that we get an error when no board ius supplied"""
546 with self.assertRaises(ValueError) as e:
547 result = self._DoBinman()
548 self.assertIn("Must provide a board to process (use -b <board>)",
549 str(e.exception))
550
551 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600552 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700553 with self.assertRaises(Exception) as e:
554 self._RunBinman('-d', 'missing_file')
555 # We get one error from libfdt, and a different one from fdtget.
556 self.AssertInList(["Couldn't open blob from 'missing_file'",
557 'No such file or directory'], str(e.exception))
558
559 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600560 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700561
562 Since this is a source file it should be compiled and the error
563 will come from the device-tree compiler (dtc).
564 """
565 with self.assertRaises(Exception) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600566 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700567 self.assertIn("FATAL ERROR: Unable to parse input tree",
568 str(e.exception))
569
570 def testMissingNode(self):
571 """Test that a device tree without a 'binman' node generates an error"""
572 with self.assertRaises(Exception) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600573 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700574 self.assertIn("does not have a 'binman' node", str(e.exception))
575
576 def testEmpty(self):
577 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass511f6582018-10-01 12:22:30 -0600578 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700579 self.assertEqual(0, len(result.stderr))
580 self.assertEqual(0, result.return_code)
581
582 def testInvalidEntry(self):
583 """Test that an invalid entry is flagged"""
584 with self.assertRaises(Exception) as e:
585 result = self._RunBinman('-d',
Simon Glass511f6582018-10-01 12:22:30 -0600586 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700587 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
588 "'/binman/not-a-valid-type'", str(e.exception))
589
590 def testSimple(self):
591 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600592 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700593 self.assertEqual(U_BOOT_DATA, data)
594
Simon Glass075a45c2017-11-13 18:55:00 -0700595 def testSimpleDebug(self):
596 """Test a simple binman run with debugging enabled"""
Simon Glass511f6582018-10-01 12:22:30 -0600597 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700598
Simon Glass57454f42016-11-25 20:15:52 -0700599 def testDual(self):
600 """Test that we can handle creating two images
601
602 This also tests image padding.
603 """
Simon Glass511f6582018-10-01 12:22:30 -0600604 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700605 self.assertEqual(0, retcode)
606
607 image = control.images['image1']
608 self.assertEqual(len(U_BOOT_DATA), image._size)
609 fname = tools.GetOutputFilename('image1.bin')
610 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600611 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700612 data = fd.read()
613 self.assertEqual(U_BOOT_DATA, data)
614
615 image = control.images['image2']
616 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
617 fname = tools.GetOutputFilename('image2.bin')
618 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600619 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700620 data = fd.read()
621 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600622 self.assertEqual(tools.GetBytes(0, 3), data[:3])
623 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700624
625 def testBadAlign(self):
626 """Test that an invalid alignment value is detected"""
627 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600628 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700629 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
630 "of two", str(e.exception))
631
632 def testPackSimple(self):
633 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600634 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700635 self.assertEqual(0, retcode)
636 self.assertIn('image', control.images)
637 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600638 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700639 self.assertEqual(5, len(entries))
640
641 # First u-boot
642 self.assertIn('u-boot', entries)
643 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600644 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700645 self.assertEqual(len(U_BOOT_DATA), entry.size)
646
647 # Second u-boot, aligned to 16-byte boundary
648 self.assertIn('u-boot-align', entries)
649 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600650 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700651 self.assertEqual(len(U_BOOT_DATA), entry.size)
652
653 # Third u-boot, size 23 bytes
654 self.assertIn('u-boot-size', entries)
655 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600656 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700657 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
658 self.assertEqual(23, entry.size)
659
660 # Fourth u-boot, placed immediate after the above
661 self.assertIn('u-boot-next', entries)
662 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600663 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700664 self.assertEqual(len(U_BOOT_DATA), entry.size)
665
Simon Glasse8561af2018-08-01 15:22:37 -0600666 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700667 self.assertIn('u-boot-fixed', entries)
668 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600669 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700670 self.assertEqual(len(U_BOOT_DATA), entry.size)
671
672 self.assertEqual(65, image._size)
673
674 def testPackExtra(self):
675 """Test that extra packing feature works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600676 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700677
678 self.assertEqual(0, retcode)
679 self.assertIn('image', control.images)
680 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600681 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700682 self.assertEqual(5, len(entries))
683
684 # First u-boot with padding before and after
685 self.assertIn('u-boot', entries)
686 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600687 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700688 self.assertEqual(3, entry.pad_before)
689 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
690
691 # Second u-boot has an aligned size, but it has no effect
692 self.assertIn('u-boot-align-size-nop', entries)
693 entry = entries['u-boot-align-size-nop']
Simon Glasse8561af2018-08-01 15:22:37 -0600694 self.assertEqual(12, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700695 self.assertEqual(4, entry.size)
696
697 # Third u-boot has an aligned size too
698 self.assertIn('u-boot-align-size', entries)
699 entry = entries['u-boot-align-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600700 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700701 self.assertEqual(32, entry.size)
702
703 # Fourth u-boot has an aligned end
704 self.assertIn('u-boot-align-end', entries)
705 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600706 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700707 self.assertEqual(16, entry.size)
708
709 # Fifth u-boot immediately afterwards
710 self.assertIn('u-boot-align-both', entries)
711 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600712 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700713 self.assertEqual(64, entry.size)
714
715 self.CheckNoGaps(entries)
716 self.assertEqual(128, image._size)
717
718 def testPackAlignPowerOf2(self):
719 """Test that invalid entry alignment is detected"""
720 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600721 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700722 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
723 "of two", str(e.exception))
724
725 def testPackAlignSizePowerOf2(self):
726 """Test that invalid entry size alignment is detected"""
727 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600728 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700729 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
730 "power of two", str(e.exception))
731
732 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600733 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700734 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600735 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600736 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700737 "align 0x4 (4)", str(e.exception))
738
739 def testPackInvalidSizeAlign(self):
740 """Test that invalid entry size alignment is detected"""
741 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600742 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700743 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
744 "align-size 0x4 (4)", str(e.exception))
745
746 def testPackOverlap(self):
747 """Test that overlapping regions are detected"""
748 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600749 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600750 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700751 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
752 str(e.exception))
753
754 def testPackEntryOverflow(self):
755 """Test that entries that overflow their size are detected"""
756 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600757 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700758 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
759 "but entry size is 0x3 (3)", str(e.exception))
760
761 def testPackImageOverflow(self):
762 """Test that entries which overflow the image size are detected"""
763 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600764 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600765 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700766 "size 0x3 (3)", str(e.exception))
767
768 def testPackImageSize(self):
769 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600770 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700771 self.assertEqual(0, retcode)
772 self.assertIn('image', control.images)
773 image = control.images['image']
774 self.assertEqual(7, image._size)
775
776 def testPackImageSizeAlign(self):
777 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600778 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700779 self.assertEqual(0, retcode)
780 self.assertIn('image', control.images)
781 image = control.images['image']
782 self.assertEqual(16, image._size)
783
784 def testPackInvalidImageAlign(self):
785 """Test that invalid image alignment is detected"""
786 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600787 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600788 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700789 "align-size 0x8 (8)", str(e.exception))
790
791 def testPackAlignPowerOf2(self):
792 """Test that invalid image alignment is detected"""
793 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600794 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600795 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700796 "two", str(e.exception))
797
798 def testImagePadByte(self):
799 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600800 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600801 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600802 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
803 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700804
805 def testImageName(self):
806 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600807 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700808 self.assertEqual(0, retcode)
809 image = control.images['image1']
810 fname = tools.GetOutputFilename('test-name')
811 self.assertTrue(os.path.exists(fname))
812
813 image = control.images['image2']
814 fname = tools.GetOutputFilename('test-name.xx')
815 self.assertTrue(os.path.exists(fname))
816
817 def testBlobFilename(self):
818 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600819 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700820 self.assertEqual(BLOB_DATA, data)
821
822 def testPackSorted(self):
823 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600824 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600825 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600826 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
827 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700828
Simon Glasse8561af2018-08-01 15:22:37 -0600829 def testPackZeroOffset(self):
830 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -0700831 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600832 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600833 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700834 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
835 str(e.exception))
836
837 def testPackUbootDtb(self):
838 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -0600839 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700840 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -0700841
842 def testPackX86RomNoSize(self):
843 """Test that the end-at-4gb property requires a size property"""
844 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600845 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600846 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -0700847 "using end-at-4gb", str(e.exception))
848
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530849 def test4gbAndSkipAtStartTogether(self):
850 """Test that the end-at-4gb and skip-at-size property can't be used
851 together"""
852 with self.assertRaises(ValueError) as e:
853 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
854 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
855 "'skip-at-start'", str(e.exception))
856
Simon Glass72232452016-11-25 20:15:53 -0700857 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600858 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -0700859 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600860 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600861 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glasseca32212018-06-01 09:38:12 -0600862 "the section starting at 0xffffffe0 (4294967264)",
Simon Glass72232452016-11-25 20:15:53 -0700863 str(e.exception))
864
865 def testPackX86Rom(self):
866 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -0600867 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600868 data = self._DoReadFile('029_x86-rom.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600869 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
870 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -0700871
872 def testPackX86RomMeNoDesc(self):
873 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass303f62f2019-05-17 22:00:46 -0600874 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glass72232452016-11-25 20:15:53 -0700875 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600876 self._DoTestFile('031_x86-rom-me.dts')
Simon Glassac4738b2019-07-08 13:18:32 -0600877 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
878 str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700879
880 def testPackX86RomBadDesc(self):
881 """Test that the Intel requires a descriptor entry"""
882 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600883 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600884 self.assertIn("Node '/binman/intel-me': No offset set with "
885 "offset-unset: should another entry provide this correct "
886 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700887
888 def testPackX86RomMe(self):
889 """Test that an x86 ROM with an ME region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600890 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glass759af872019-07-08 13:18:54 -0600891 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
892 if data[:0x1000] != expected_desc:
893 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -0700894 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
895
896 def testPackVga(self):
897 """Test that an image with a VGA binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600898 data = self._DoReadFile('032_intel-vga.dts')
Simon Glass72232452016-11-25 20:15:53 -0700899 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
900
901 def testPackStart16(self):
902 """Test that an image with an x86 start16 region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600903 data = self._DoReadFile('033_x86-start16.dts')
Simon Glass72232452016-11-25 20:15:53 -0700904 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
905
Jagdish Gediya311d4842018-09-03 21:35:08 +0530906 def testPackPowerpcMpc85xxBootpgResetvec(self):
907 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
908 created"""
909 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
910 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
911
Simon Glass6ba679c2018-07-06 10:27:17 -0600912 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -0600913 """Handle running a test for insertion of microcode
914
915 Args:
916 dts_fname: Name of test .dts file
917 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -0600918 ucode_second: True if the microsecond entry is second instead of
919 third
Simon Glass820af1d2018-07-06 10:27:16 -0600920
921 Returns:
922 Tuple:
923 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -0600924 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -0600925 in the above (two 4-byte words)
926 """
Simon Glass3d274232017-11-12 21:52:27 -0700927 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -0700928
929 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -0600930 if ucode_second:
931 ucode_content = data[len(nodtb_data):]
932 ucode_pos = len(nodtb_data)
933 dtb_with_ucode = ucode_content[16:]
934 fdt_len = self.GetFdtLen(dtb_with_ucode)
935 else:
936 dtb_with_ucode = data[len(nodtb_data):]
937 fdt_len = self.GetFdtLen(dtb_with_ucode)
938 ucode_content = dtb_with_ucode[fdt_len:]
939 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -0700940 fname = tools.GetOutputFilename('test.dtb')
941 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -0600942 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -0600943 dtb = fdt.FdtScan(fname)
944 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -0700945 self.assertTrue(ucode)
946 for node in ucode.subnodes:
947 self.assertFalse(node.props.get('data'))
948
Simon Glass72232452016-11-25 20:15:53 -0700949 # Check that the microcode appears immediately after the Fdt
950 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -0700951 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -0700952 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
953 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -0600954 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -0700955
956 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -0600957 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -0700958 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
959 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -0600960 u_boot = data[:len(nodtb_data)]
961 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -0700962
963 def testPackUbootMicrocode(self):
964 """Test that x86 microcode can be handled correctly
965
966 We expect to see the following in the image, in order:
967 u-boot-nodtb.bin with a microcode pointer inserted at the correct
968 place
969 u-boot.dtb with the microcode removed
970 the microcode
971 """
Simon Glass511f6582018-10-01 12:22:30 -0600972 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -0700973 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -0600974 self.assertEqual(b'nodtb with microcode' + pos_and_size +
975 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -0700976
Simon Glassbac25c82017-05-27 07:38:26 -0600977 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -0700978 """Test that x86 microcode can be handled correctly
979
980 We expect to see the following in the image, in order:
981 u-boot-nodtb.bin with a microcode pointer inserted at the correct
982 place
983 u-boot.dtb with the microcode
984 an empty microcode region
985 """
986 # We need the libfdt library to run this test since only that allows
987 # finding the offset of a property. This is required by
988 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -0600989 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -0700990
991 second = data[len(U_BOOT_NODTB_DATA):]
992
993 fdt_len = self.GetFdtLen(second)
994 third = second[fdt_len:]
995 second = second[:fdt_len]
996
Simon Glassbac25c82017-05-27 07:38:26 -0600997 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
998 self.assertIn(ucode_data, second)
999 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001000
Simon Glassbac25c82017-05-27 07:38:26 -06001001 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001002 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001003 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1004 len(ucode_data))
1005 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001006 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1007 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001008
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001009 def testPackUbootSingleMicrocode(self):
1010 """Test that x86 microcode can be handled correctly with fdt_normal.
1011 """
Simon Glassbac25c82017-05-27 07:38:26 -06001012 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001013
Simon Glass996021e2016-11-25 20:15:54 -07001014 def testUBootImg(self):
1015 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001016 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001017 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001018
1019 def testNoMicrocode(self):
1020 """Test that a missing microcode region is detected"""
1021 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001022 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001023 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1024 "node found in ", str(e.exception))
1025
1026 def testMicrocodeWithoutNode(self):
1027 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1028 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001029 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001030 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1031 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1032
1033 def testMicrocodeWithoutNode2(self):
1034 """Test that a missing u-boot-ucode node is detected"""
1035 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001036 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001037 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1038 "microcode region u-boot-ucode", str(e.exception))
1039
1040 def testMicrocodeWithoutPtrInElf(self):
1041 """Test that a U-Boot binary without the microcode symbol is detected"""
1042 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001043 try:
Simon Glass33486662019-05-14 15:53:42 -06001044 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001045 TestFunctional._MakeInputFile('u-boot', fd.read())
1046
1047 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001048 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001049 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1050 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1051
1052 finally:
1053 # Put the original file back
Simon Glass33486662019-05-14 15:53:42 -06001054 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001055 TestFunctional._MakeInputFile('u-boot', fd.read())
1056
1057 def testMicrocodeNotInImage(self):
1058 """Test that microcode must be placed within the image"""
1059 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001060 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001061 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1062 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001063 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001064
1065 def testWithoutMicrocode(self):
1066 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass33486662019-05-14 15:53:42 -06001067 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001068 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001069 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001070
1071 # Now check the device tree has no microcode
1072 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1073 second = data[len(U_BOOT_NODTB_DATA):]
1074
1075 fdt_len = self.GetFdtLen(second)
1076 self.assertEqual(dtb, second[:fdt_len])
1077
1078 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1079 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001080 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001081
1082 def testUnknownPosSize(self):
1083 """Test that microcode must be placed within the image"""
1084 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001085 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001086 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001087 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001088
1089 def testPackFsp(self):
1090 """Test that an image with a FSP binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001091 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001092 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1093
1094 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001095 """Test that an image with a CMC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001096 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001097 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001098
1099 def testPackVbt(self):
1100 """Test that an image with a VBT binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001101 data = self._DoReadFile('046_intel-vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001102 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001103
Simon Glass7f94e832017-11-12 21:52:25 -07001104 def testSplBssPad(self):
1105 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001106 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001107 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001108 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001109 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1110 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001111
Simon Glass04cda032018-10-01 21:12:42 -06001112 def testSplBssPadMissing(self):
1113 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001114 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001115 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001116 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001117 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1118 str(e.exception))
1119
Simon Glasse83679d2017-11-12 21:52:26 -07001120 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001121 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001122 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001123 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1124
Simon Glass6ba679c2018-07-06 10:27:17 -06001125 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1126 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001127
1128 We expect to see the following in the image, in order:
1129 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1130 correct place
1131 u-boot.dtb with the microcode removed
1132 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001133
1134 Args:
1135 dts: Device tree file to use for test
1136 ucode_second: True if the microsecond entry is second instead of
1137 third
Simon Glass3d274232017-11-12 21:52:27 -07001138 """
Simon Glass7057d022018-10-01 21:12:47 -06001139 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001140 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1141 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001142 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1143 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001144
Simon Glass6ba679c2018-07-06 10:27:17 -06001145 def testPackUbootSplMicrocode(self):
1146 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001147 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001148
1149 def testPackUbootSplMicrocodeReorder(self):
1150 """Test that order doesn't matter for microcode entries
1151
1152 This is the same as testPackUbootSplMicrocode but when we process the
1153 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1154 entry, so we reply on binman to try later.
1155 """
Simon Glass511f6582018-10-01 12:22:30 -06001156 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001157 ucode_second=True)
1158
Simon Glassa409c932017-11-12 21:52:28 -07001159 def testPackMrc(self):
1160 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001161 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001162 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1163
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001164 def testSplDtb(self):
1165 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001166 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001167 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1168
Simon Glass0a6da312017-11-13 18:54:56 -07001169 def testSplNoDtb(self):
1170 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001171 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001172 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1173
Simon Glass4ca8e042017-11-13 18:55:01 -07001174 def testSymbols(self):
1175 """Test binman can assign symbols embedded in U-Boot"""
1176 elf_fname = self.TestFile('u_boot_binman_syms')
1177 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1178 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glasse8561af2018-08-01 15:22:37 -06001179 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001180
Simon Glass7057d022018-10-01 21:12:47 -06001181 self._SetupSplElf('u_boot_binman_syms')
Simon Glass511f6582018-10-01 12:22:30 -06001182 data = self._DoReadFile('053_symbols.dts')
Simon Glass4ca8e042017-11-13 18:55:01 -07001183 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glassac0d4952019-05-14 15:53:47 -06001184 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1185 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1186 U_BOOT_SPL_DATA[16:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001187 self.assertEqual(expected, data)
1188
Simon Glasse76a3e62018-06-01 09:38:11 -06001189 def testPackUnitAddress(self):
1190 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001191 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001192 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1193
Simon Glassa91e1152018-06-01 09:38:16 -06001194 def testSections(self):
1195 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001196 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001197 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1198 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1199 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001200 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001201
Simon Glass30732662018-06-01 09:38:20 -06001202 def testMap(self):
1203 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001204 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001205 self.assertEqual('''ImagePos Offset Size Name
120600000000 00000000 00000028 main-section
120700000000 00000000 00000010 section@0
120800000000 00000000 00000004 u-boot
120900000010 00000010 00000010 section@1
121000000010 00000000 00000004 u-boot
121100000020 00000020 00000004 section@2
121200000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001213''', map_data)
1214
Simon Glass3b78d532018-06-01 09:38:21 -06001215 def testNamePrefix(self):
1216 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001217 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001218 self.assertEqual('''ImagePos Offset Size Name
121900000000 00000000 00000028 main-section
122000000000 00000000 00000010 section@0
122100000000 00000000 00000004 ro-u-boot
122200000010 00000010 00000010 section@1
122300000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001224''', map_data)
1225
Simon Glass6ba679c2018-07-06 10:27:17 -06001226 def testUnknownContents(self):
1227 """Test that obtaining the contents works as expected"""
1228 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001229 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass6ba679c2018-07-06 10:27:17 -06001230 self.assertIn("Section '/binman': Internal error: Could not complete "
1231 "processing of contents: remaining [<_testing.Entry__testing ",
1232 str(e.exception))
1233
Simon Glass2e1169f2018-07-06 10:27:19 -06001234 def testBadChangeSize(self):
1235 """Test that trying to change the size of an entry fails"""
1236 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001237 self._DoReadFile('059_change_size.dts', True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001238 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1239 '2 to 1', str(e.exception))
1240
Simon Glassa87014e2018-07-06 10:27:42 -06001241 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001242 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001243 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001244 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001245 dtb = fdt.Fdt(out_dtb_fname)
1246 dtb.Scan()
1247 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glassa87014e2018-07-06 10:27:42 -06001248 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001249 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001250 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001251 '_testing:offset': 32,
Simon Glassa87014e2018-07-06 10:27:42 -06001252 '_testing:size': 1,
Simon Glass9dcc8612018-08-01 15:22:42 -06001253 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001254 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001255 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001256 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001257 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001258 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001259 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001260
Simon Glasse8561af2018-08-01 15:22:37 -06001261 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001262 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001263 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001264 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001265 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001266 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001267 'size': 40
1268 }, props)
1269
1270 def testUpdateFdtBad(self):
1271 """Test that we detect when ProcessFdt never completes"""
1272 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001273 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001274 self.assertIn('Could not complete processing of Fdt: remaining '
1275 '[<_testing.Entry__testing', str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001276
Simon Glass91710b32018-07-17 13:25:32 -06001277 def testEntryArgs(self):
1278 """Test passing arguments to entries from the command line"""
1279 entry_args = {
1280 'test-str-arg': 'test1',
1281 'test-int-arg': '456',
1282 }
Simon Glass511f6582018-10-01 12:22:30 -06001283 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001284 self.assertIn('image', control.images)
1285 entry = control.images['image'].GetEntries()['_testing']
1286 self.assertEqual('test0', entry.test_str_fdt)
1287 self.assertEqual('test1', entry.test_str_arg)
1288 self.assertEqual(123, entry.test_int_fdt)
1289 self.assertEqual(456, entry.test_int_arg)
1290
1291 def testEntryArgsMissing(self):
1292 """Test missing arguments and properties"""
1293 entry_args = {
1294 'test-int-arg': '456',
1295 }
Simon Glass511f6582018-10-01 12:22:30 -06001296 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001297 entry = control.images['image'].GetEntries()['_testing']
1298 self.assertEqual('test0', entry.test_str_fdt)
1299 self.assertEqual(None, entry.test_str_arg)
1300 self.assertEqual(None, entry.test_int_fdt)
1301 self.assertEqual(456, entry.test_int_arg)
1302
1303 def testEntryArgsRequired(self):
1304 """Test missing arguments and properties"""
1305 entry_args = {
1306 'test-int-arg': '456',
1307 }
1308 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001309 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass91710b32018-07-17 13:25:32 -06001310 self.assertIn("Node '/binman/_testing': Missing required "
1311 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1312 str(e.exception))
1313
1314 def testEntryArgsInvalidFormat(self):
1315 """Test that an invalid entry-argument format is detected"""
Simon Glass511f6582018-10-01 12:22:30 -06001316 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001317 with self.assertRaises(ValueError) as e:
1318 self._DoBinman(*args)
1319 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1320
1321 def testEntryArgsInvalidInteger(self):
1322 """Test that an invalid entry-argument integer is detected"""
1323 entry_args = {
1324 'test-int-arg': 'abc',
1325 }
1326 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001327 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001328 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1329 "'test-int-arg' (value 'abc') to integer",
1330 str(e.exception))
1331
1332 def testEntryArgsInvalidDatatype(self):
1333 """Test that an invalid entry-argument datatype is detected
1334
1335 This test could be written in entry_test.py except that it needs
1336 access to control.entry_args, which seems more than that module should
1337 be able to see.
1338 """
1339 entry_args = {
1340 'test-bad-datatype-arg': '12',
1341 }
1342 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001343 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001344 entry_args=entry_args)
1345 self.assertIn('GetArg() internal error: Unknown data type ',
1346 str(e.exception))
1347
Simon Glass2ca52032018-07-17 13:25:33 -06001348 def testText(self):
1349 """Test for a text entry type"""
1350 entry_args = {
1351 'test-id': TEXT_DATA,
1352 'test-id2': TEXT_DATA2,
1353 'test-id3': TEXT_DATA3,
1354 }
Simon Glass511f6582018-10-01 12:22:30 -06001355 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001356 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001357 expected = (tools.ToBytes(TEXT_DATA) +
1358 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1359 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001360 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001361 self.assertEqual(expected, data)
1362
Simon Glass969616c2018-07-17 13:25:36 -06001363 def testEntryDocs(self):
1364 """Test for creation of entry documentation"""
1365 with test_util.capture_sys_output() as (stdout, stderr):
1366 control.WriteEntryDocs(binman.GetEntryModules())
1367 self.assertTrue(len(stdout.getvalue()) > 0)
1368
1369 def testEntryDocsMissing(self):
1370 """Test handling of missing entry documentation"""
1371 with self.assertRaises(ValueError) as e:
1372 with test_util.capture_sys_output() as (stdout, stderr):
1373 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1374 self.assertIn('Documentation is missing for modules: u_boot',
1375 str(e.exception))
1376
Simon Glass704784b2018-07-17 13:25:38 -06001377 def testFmap(self):
1378 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001379 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001380 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001381 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1382 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001383 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001384 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001385 self.assertEqual(1, fhdr.ver_major)
1386 self.assertEqual(0, fhdr.ver_minor)
1387 self.assertEqual(0, fhdr.base)
1388 self.assertEqual(16 + 16 +
1389 fmap_util.FMAP_HEADER_LEN +
1390 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001391 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass704784b2018-07-17 13:25:38 -06001392 self.assertEqual(3, fhdr.nareas)
1393 for fentry in fentries:
1394 self.assertEqual(0, fentry.flags)
1395
1396 self.assertEqual(0, fentries[0].offset)
1397 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001398 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass704784b2018-07-17 13:25:38 -06001399
1400 self.assertEqual(16, fentries[1].offset)
1401 self.assertEqual(4, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001402 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass704784b2018-07-17 13:25:38 -06001403
1404 self.assertEqual(32, fentries[2].offset)
1405 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1406 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001407 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass704784b2018-07-17 13:25:38 -06001408
Simon Glassdb168d42018-07-17 13:25:39 -06001409 def testBlobNamedByArg(self):
1410 """Test we can add a blob with the filename coming from an entry arg"""
1411 entry_args = {
1412 'cros-ec-rw-path': 'ecrw.bin',
1413 }
Simon Glass511f6582018-10-01 12:22:30 -06001414 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassdb168d42018-07-17 13:25:39 -06001415 entry_args=entry_args)
1416
Simon Glass53f53992018-07-17 13:25:40 -06001417 def testFill(self):
1418 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001419 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001420 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001421 self.assertEqual(expected, data)
1422
1423 def testFillNoSize(self):
1424 """Test for an fill entry type with no size"""
1425 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001426 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001427 self.assertIn("'fill' entry must have a size property",
1428 str(e.exception))
1429
Simon Glassc1ae83c2018-07-17 13:25:44 -06001430 def _HandleGbbCommand(self, pipe_list):
1431 """Fake calls to the futility utility"""
1432 if pipe_list[0][0] == 'futility':
1433 fname = pipe_list[0][-1]
1434 # Append our GBB data to the file, which will happen every time the
1435 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001436 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001437 fd.write(GBB_DATA)
1438 return command.CommandResult()
1439
1440 def testGbb(self):
1441 """Test for the Chromium OS Google Binary Block"""
1442 command.test_result = self._HandleGbbCommand
1443 entry_args = {
1444 'keydir': 'devkeys',
1445 'bmpblk': 'bmpblk.bin',
1446 }
Simon Glass511f6582018-10-01 12:22:30 -06001447 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001448
1449 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001450 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1451 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001452 self.assertEqual(expected, data)
1453
1454 def testGbbTooSmall(self):
1455 """Test for the Chromium OS Google Binary Block being large enough"""
1456 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001457 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001458 self.assertIn("Node '/binman/gbb': GBB is too small",
1459 str(e.exception))
1460
1461 def testGbbNoSize(self):
1462 """Test for the Chromium OS Google Binary Block having a size"""
1463 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001464 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001465 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1466 str(e.exception))
1467
Simon Glass5c350162018-07-17 13:25:47 -06001468 def _HandleVblockCommand(self, pipe_list):
1469 """Fake calls to the futility utility"""
1470 if pipe_list[0][0] == 'futility':
1471 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001472 with open(fname, 'wb') as fd:
Simon Glass5c350162018-07-17 13:25:47 -06001473 fd.write(VBLOCK_DATA)
1474 return command.CommandResult()
1475
1476 def testVblock(self):
1477 """Test for the Chromium OS Verified Boot Block"""
1478 command.test_result = self._HandleVblockCommand
1479 entry_args = {
1480 'keydir': 'devkeys',
1481 }
Simon Glass511f6582018-10-01 12:22:30 -06001482 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001483 entry_args=entry_args)
1484 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1485 self.assertEqual(expected, data)
1486
1487 def testVblockNoContent(self):
1488 """Test we detect a vblock which has no content to sign"""
1489 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001490 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001491 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1492 'property', str(e.exception))
1493
1494 def testVblockBadPhandle(self):
1495 """Test that we detect a vblock with an invalid phandle in contents"""
1496 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001497 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001498 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1499 '1000', str(e.exception))
1500
1501 def testVblockBadEntry(self):
1502 """Test that we detect an entry that points to a non-entry"""
1503 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001504 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001505 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1506 "'other'", str(e.exception))
1507
Simon Glass8425a1f2018-07-17 13:25:48 -06001508 def testTpl(self):
1509 """Test that an image with TPL and ots device tree can be created"""
1510 # ELF file with a '__bss_size' symbol
Simon Glass33486662019-05-14 15:53:42 -06001511 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass8425a1f2018-07-17 13:25:48 -06001512 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001513 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001514 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1515
Simon Glass24b97442018-07-17 13:25:51 -06001516 def testUsesPos(self):
1517 """Test that the 'pos' property cannot be used anymore"""
1518 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001519 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001520 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1521 "'pos'", str(e.exception))
1522
Simon Glass274bf092018-09-14 04:57:08 -06001523 def testFillZero(self):
1524 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001525 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001526 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001527
Simon Glass267de432018-09-14 04:57:09 -06001528 def testTextMissing(self):
1529 """Test for a text entry type where there is no text"""
1530 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001531 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001532 self.assertIn("Node '/binman/text': No value provided for text label "
1533 "'test-id'", str(e.exception))
1534
Simon Glassed40e962018-09-14 04:57:10 -06001535 def testPackStart16Tpl(self):
1536 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001537 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001538 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1539
Simon Glass3b376c32018-09-14 04:57:12 -06001540 def testSelectImage(self):
1541 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001542 expected = 'Skipping images: image1'
1543
1544 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001545 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001546 with test_util.capture_sys_output() as (stdout, stderr):
1547 retcode = self._DoTestFile('006_dual_image.dts',
1548 verbosity=verbosity,
1549 images=['image2'])
1550 self.assertEqual(0, retcode)
1551 if verbosity:
1552 self.assertIn(expected, stdout.getvalue())
1553 else:
1554 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001555
Simon Glassb4595d82019-04-25 21:58:34 -06001556 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1557 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass3b376c32018-09-14 04:57:12 -06001558
Simon Glasse219aa42018-09-14 04:57:24 -06001559 def testUpdateFdtAll(self):
1560 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001561 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001562
1563 base_expected = {
1564 'section:image-pos': 0,
1565 'u-boot-tpl-dtb:size': 513,
1566 'u-boot-spl-dtb:size': 513,
1567 'u-boot-spl-dtb:offset': 493,
1568 'image-pos': 0,
1569 'section/u-boot-dtb:image-pos': 0,
1570 'u-boot-spl-dtb:image-pos': 493,
1571 'section/u-boot-dtb:size': 493,
1572 'u-boot-tpl-dtb:image-pos': 1006,
1573 'section/u-boot-dtb:offset': 0,
1574 'section:size': 493,
1575 'offset': 0,
1576 'section:offset': 0,
1577 'u-boot-tpl-dtb:offset': 1006,
1578 'size': 1519
1579 }
1580
1581 # We expect three device-tree files in the output, one after the other.
1582 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1583 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1584 # main U-Boot tree. All three should have the same postions and offset.
1585 start = 0
1586 for item in ['', 'spl', 'tpl']:
1587 dtb = fdt.Fdt.FromData(data[start:])
1588 dtb.Scan()
1589 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1590 'spl', 'tpl'])
1591 expected = dict(base_expected)
1592 if item:
1593 expected[item] = 0
1594 self.assertEqual(expected, props)
1595 start += dtb._fdt_obj.totalsize()
1596
1597 def testUpdateFdtOutput(self):
1598 """Test that output DTB files are updated"""
1599 try:
Simon Glass511f6582018-10-01 12:22:30 -06001600 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001601 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1602
1603 # Unfortunately, compiling a source file always results in a file
1604 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001605 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001606 # binman as a file called u-boot.dtb. To fix this, copy the file
1607 # over to the expected place.
1608 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1609 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1610 start = 0
1611 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1612 'tpl/u-boot-tpl.dtb.out']:
1613 dtb = fdt.Fdt.FromData(data[start:])
1614 size = dtb._fdt_obj.totalsize()
1615 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1616 outdata = tools.ReadFile(pathname)
1617 name = os.path.split(fname)[0]
1618
1619 if name:
1620 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1621 else:
1622 orig_indata = dtb_data
1623 self.assertNotEqual(outdata, orig_indata,
1624 "Expected output file '%s' be updated" % pathname)
1625 self.assertEqual(outdata, data[start:start + size],
1626 "Expected output file '%s' to match output image" %
1627 pathname)
1628 start += size
1629 finally:
1630 self._ResetDtbs()
1631
Simon Glass7ba33592018-09-14 04:57:26 -06001632 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001633 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001634
1635 def testCompress(self):
1636 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001637 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001638 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001639 use_real_dtb=True, update_dtb=True)
1640 dtb = fdt.Fdt(out_dtb_fname)
1641 dtb.Scan()
1642 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1643 orig = self._decompress(data)
1644 self.assertEquals(COMPRESS_DATA, orig)
1645 expected = {
1646 'blob:uncomp-size': len(COMPRESS_DATA),
1647 'blob:size': len(data),
1648 'size': len(data),
1649 }
1650 self.assertEqual(expected, props)
1651
Simon Glassac6328c2018-09-14 04:57:28 -06001652 def testFiles(self):
1653 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001654 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001655 self.assertEqual(FILES_DATA, data)
1656
1657 def testFilesCompress(self):
1658 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001659 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001660 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001661
1662 image = control.images['image']
1663 entries = image.GetEntries()
1664 files = entries['files']
1665 entries = files._section._entries
1666
Simon Glass303f62f2019-05-17 22:00:46 -06001667 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001668 for i in range(1, 3):
1669 key = '%d.dat' % i
1670 start = entries[key].image_pos
1671 len = entries[key].size
1672 chunk = data[start:start + len]
1673 orig += self._decompress(chunk)
1674
1675 self.assertEqual(FILES_DATA, orig)
1676
1677 def testFilesMissing(self):
1678 """Test missing files"""
1679 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001680 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001681 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1682 'no files', str(e.exception))
1683
1684 def testFilesNoPattern(self):
1685 """Test missing files"""
1686 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001687 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001688 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1689 str(e.exception))
1690
Simon Glassfa79a812018-09-14 04:57:29 -06001691 def testExpandSize(self):
1692 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001693 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001694 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001695 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1696 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1697 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1698 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001699 self.assertEqual(expect, data)
1700 self.assertEqual('''ImagePos Offset Size Name
170100000000 00000000 00000028 main-section
170200000000 00000000 00000008 fill
170300000008 00000008 00000004 u-boot
17040000000c 0000000c 00000004 section
17050000000c 00000000 00000003 intel-mrc
170600000010 00000010 00000004 u-boot2
170700000014 00000014 0000000c section2
170800000014 00000000 00000008 fill
17090000001c 00000008 00000004 u-boot
171000000020 00000020 00000008 fill2
1711''', map_data)
1712
1713 def testExpandSizeBad(self):
1714 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001715 with test_util.capture_sys_output() as (stdout, stderr):
1716 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001717 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001718 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1719 'expanding entry', str(e.exception))
1720
Simon Glassae7cf032018-09-14 04:57:31 -06001721 def testHash(self):
1722 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001723 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001724 use_real_dtb=True, update_dtb=True)
1725 dtb = fdt.Fdt(out_dtb_fname)
1726 dtb.Scan()
1727 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1728 m = hashlib.sha256()
1729 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001730 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001731
1732 def testHashNoAlgo(self):
1733 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001734 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001735 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1736 'hash node', str(e.exception))
1737
1738 def testHashBadAlgo(self):
1739 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001740 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001741 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1742 str(e.exception))
1743
1744 def testHashSection(self):
1745 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001746 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001747 use_real_dtb=True, update_dtb=True)
1748 dtb = fdt.Fdt(out_dtb_fname)
1749 dtb.Scan()
1750 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1751 m = hashlib.sha256()
1752 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001753 m.update(tools.GetBytes(ord('a'), 16))
1754 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001755
Simon Glass3fb4f422018-09-14 04:57:32 -06001756 def testPackUBootTplMicrocode(self):
1757 """Test that x86 microcode can be handled correctly in TPL
1758
1759 We expect to see the following in the image, in order:
1760 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1761 place
1762 u-boot-tpl.dtb with the microcode removed
1763 the microcode
1764 """
Simon Glass33486662019-05-14 15:53:42 -06001765 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass3fb4f422018-09-14 04:57:32 -06001766 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001767 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06001768 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001769 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1770 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06001771
Simon Glassc64aea52018-09-14 04:57:34 -06001772 def testFmapX86(self):
1773 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001774 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001775 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001776 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001777 self.assertEqual(expected, data[:32])
1778 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1779
1780 self.assertEqual(0x100, fhdr.image_size)
1781
1782 self.assertEqual(0, fentries[0].offset)
1783 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001784 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001785
1786 self.assertEqual(4, fentries[1].offset)
1787 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001788 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001789
1790 self.assertEqual(32, fentries[2].offset)
1791 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1792 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001793 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001794
1795 def testFmapX86Section(self):
1796 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001797 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001798 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001799 self.assertEqual(expected, data[:32])
1800 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1801
1802 self.assertEqual(0x100, fhdr.image_size)
1803
1804 self.assertEqual(0, fentries[0].offset)
1805 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001806 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001807
1808 self.assertEqual(4, fentries[1].offset)
1809 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001810 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001811
1812 self.assertEqual(36, fentries[2].offset)
1813 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1814 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001815 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001816
Simon Glassb1714232018-09-14 04:57:35 -06001817 def testElf(self):
1818 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001819 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001820 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassa899f712019-07-08 13:18:46 -06001821 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1822 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001823 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001824 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001825
Simon Glass0d673792019-07-08 13:18:25 -06001826 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06001827 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001828 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001829 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001830 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001831 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001832
Simon Glasscd817d52018-09-14 04:57:36 -06001833 def testPackOverlapMap(self):
1834 """Test that overlapping regions are detected"""
1835 with test_util.capture_sys_output() as (stdout, stderr):
1836 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001837 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06001838 map_fname = tools.GetOutputFilename('image.map')
1839 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1840 stdout.getvalue())
1841
1842 # We should not get an inmage, but there should be a map file
1843 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1844 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06001845 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06001846 self.assertEqual('''ImagePos Offset Size Name
1847<none> 00000000 00000007 main-section
1848<none> 00000000 00000004 u-boot
1849<none> 00000003 00000004 u-boot-align
1850''', map_data)
1851
Simon Glass0d673792019-07-08 13:18:25 -06001852 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06001853 """Test that an image with an Intel Reference code binary works"""
1854 data = self._DoReadFile('100_intel_refcode.dts')
1855 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1856
Simon Glasseb023b32019-04-25 21:58:39 -06001857 def testSectionOffset(self):
1858 """Tests use of a section with an offset"""
1859 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1860 map=True)
1861 self.assertEqual('''ImagePos Offset Size Name
186200000000 00000000 00000038 main-section
186300000004 00000004 00000010 section@0
186400000004 00000000 00000004 u-boot
186500000018 00000018 00000010 section@1
186600000018 00000000 00000004 u-boot
18670000002c 0000002c 00000004 section@2
18680000002c 00000000 00000004 u-boot
1869''', map_data)
1870 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06001871 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1872 tools.GetBytes(0x21, 12) +
1873 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1874 tools.GetBytes(0x61, 12) +
1875 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1876 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06001877
Simon Glass1de34482019-07-08 13:18:53 -06001878 def testCbfsRaw(self):
1879 """Test base handling of a Coreboot Filesystem (CBFS)
1880
1881 The exact contents of the CBFS is verified by similar tests in
1882 cbfs_util_test.py. The tests here merely check that the files added to
1883 the CBFS can be found in the final image.
1884 """
1885 data = self._DoReadFile('102_cbfs_raw.dts')
1886 size = 0xb0
1887
1888 cbfs = cbfs_util.CbfsReader(data)
1889 self.assertEqual(size, cbfs.rom_size)
1890
1891 self.assertIn('u-boot-dtb', cbfs.files)
1892 cfile = cbfs.files['u-boot-dtb']
1893 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1894
1895 def testCbfsArch(self):
1896 """Test on non-x86 architecture"""
1897 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1898 size = 0x100
1899
1900 cbfs = cbfs_util.CbfsReader(data)
1901 self.assertEqual(size, cbfs.rom_size)
1902
1903 self.assertIn('u-boot-dtb', cbfs.files)
1904 cfile = cbfs.files['u-boot-dtb']
1905 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1906
1907 def testCbfsStage(self):
1908 """Tests handling of a Coreboot Filesystem (CBFS)"""
1909 if not elf.ELF_TOOLS:
1910 self.skipTest('Python elftools not available')
1911 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1912 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1913 size = 0xb0
1914
1915 data = self._DoReadFile('104_cbfs_stage.dts')
1916 cbfs = cbfs_util.CbfsReader(data)
1917 self.assertEqual(size, cbfs.rom_size)
1918
1919 self.assertIn('u-boot', cbfs.files)
1920 cfile = cbfs.files['u-boot']
1921 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1922
1923 def testCbfsRawCompress(self):
1924 """Test handling of compressing raw files"""
1925 self._CheckLz4()
1926 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1927 size = 0x140
1928
1929 cbfs = cbfs_util.CbfsReader(data)
1930 self.assertIn('u-boot', cbfs.files)
1931 cfile = cbfs.files['u-boot']
1932 self.assertEqual(COMPRESS_DATA, cfile.data)
1933
1934 def testCbfsBadArch(self):
1935 """Test handling of a bad architecture"""
1936 with self.assertRaises(ValueError) as e:
1937 self._DoReadFile('106_cbfs_bad_arch.dts')
1938 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1939
1940 def testCbfsNoSize(self):
1941 """Test handling of a missing size property"""
1942 with self.assertRaises(ValueError) as e:
1943 self._DoReadFile('107_cbfs_no_size.dts')
1944 self.assertIn('entry must have a size property', str(e.exception))
1945
1946 def testCbfsNoCOntents(self):
1947 """Test handling of a CBFS entry which does not provide contentsy"""
1948 with self.assertRaises(ValueError) as e:
1949 self._DoReadFile('108_cbfs_no_contents.dts')
1950 self.assertIn('Could not complete processing of contents',
1951 str(e.exception))
1952
1953 def testCbfsBadCompress(self):
1954 """Test handling of a bad architecture"""
1955 with self.assertRaises(ValueError) as e:
1956 self._DoReadFile('109_cbfs_bad_compress.dts')
1957 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1958 str(e.exception))
1959
1960 def testCbfsNamedEntries(self):
1961 """Test handling of named entries"""
1962 data = self._DoReadFile('110_cbfs_name.dts')
1963
1964 cbfs = cbfs_util.CbfsReader(data)
1965 self.assertIn('FRED', cbfs.files)
1966 cfile1 = cbfs.files['FRED']
1967 self.assertEqual(U_BOOT_DATA, cfile1.data)
1968
1969 self.assertIn('hello', cbfs.files)
1970 cfile2 = cbfs.files['hello']
1971 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1972
Simon Glass759af872019-07-08 13:18:54 -06001973 def _SetupIfwi(self, fname):
1974 """Set up to run an IFWI test
1975
1976 Args:
1977 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1978 """
1979 self._SetupSplElf()
1980
1981 # Intel Integrated Firmware Image (IFWI) file
1982 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1983 data = fd.read()
1984 TestFunctional._MakeInputFile(fname,data)
1985
1986 def _CheckIfwi(self, data):
1987 """Check that an image with an IFWI contains the correct output
1988
1989 Args:
1990 data: Conents of output file
1991 """
1992 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1993 if data[:0x1000] != expected_desc:
1994 self.fail('Expected descriptor binary at start of image')
1995
1996 # We expect to find the TPL wil in subpart IBBP entry IBBL
1997 image_fname = tools.GetOutputFilename('image.bin')
1998 tpl_fname = tools.GetOutputFilename('tpl.out')
1999 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2000 subpart='IBBP', entry_name='IBBL')
2001
2002 tpl_data = tools.ReadFile(tpl_fname)
2003 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2004
2005 def testPackX86RomIfwi(self):
2006 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2007 self._SetupIfwi('fitimage.bin')
2008 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2009 self._CheckIfwi(data)
2010
2011 def testPackX86RomIfwiNoDesc(self):
2012 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2013 self._SetupIfwi('ifwi.bin')
2014 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2015 self._CheckIfwi(data)
2016
2017 def testPackX86RomIfwiNoData(self):
2018 """Test that an x86 ROM with IFWI handles missing data"""
2019 self._SetupIfwi('ifwi.bin')
2020 with self.assertRaises(ValueError) as e:
2021 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2022 self.assertIn('Could not complete processing of contents',
2023 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002024
Simon Glassc2f1aed2019-07-08 13:18:56 -06002025 def testCbfsOffset(self):
2026 """Test a CBFS with files at particular offsets
2027
2028 Like all CFBS tests, this is just checking the logic that calls
2029 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2030 """
2031 data = self._DoReadFile('114_cbfs_offset.dts')
2032 size = 0x200
2033
2034 cbfs = cbfs_util.CbfsReader(data)
2035 self.assertEqual(size, cbfs.rom_size)
2036
2037 self.assertIn('u-boot', cbfs.files)
2038 cfile = cbfs.files['u-boot']
2039 self.assertEqual(U_BOOT_DATA, cfile.data)
2040 self.assertEqual(0x40, cfile.cbfs_offset)
2041
2042 self.assertIn('u-boot-dtb', cbfs.files)
2043 cfile2 = cbfs.files['u-boot-dtb']
2044 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2045 self.assertEqual(0x140, cfile2.cbfs_offset)
2046
Simon Glass0f621332019-07-08 14:25:27 -06002047 def testFdtmap(self):
2048 """Test an FDT map can be inserted in the image"""
2049 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2050 fdtmap_data = data[len(U_BOOT_DATA):]
2051 magic = fdtmap_data[:8]
2052 self.assertEqual('_FDTMAP_', magic)
2053 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2054
2055 fdt_data = fdtmap_data[16:]
2056 dtb = fdt.Fdt.FromData(fdt_data)
2057 dtb.Scan()
2058 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'],
2059 prefix='/')
2060 self.assertEqual({
2061 'image-pos': 0,
2062 'offset': 0,
2063 'u-boot:offset': 0,
2064 'u-boot:size': len(U_BOOT_DATA),
2065 'u-boot:image-pos': 0,
2066 'fdtmap:image-pos': 4,
2067 'fdtmap:offset': 4,
2068 'fdtmap:size': len(fdtmap_data),
2069 'size': len(data),
2070 }, props)
2071
2072 def testFdtmapNoMatch(self):
2073 """Check handling of an FDT map when the section cannot be found"""
2074 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2075
2076 # Mangle the section name, which should cause a mismatch between the
2077 # correct FDT path and the one expected by the section
2078 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002079 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002080 entries = image.GetEntries()
2081 fdtmap = entries['fdtmap']
2082 with self.assertRaises(ValueError) as e:
2083 fdtmap._GetFdtmap()
2084 self.assertIn("Cannot locate node for path '/binman-suffix'",
2085 str(e.exception))
2086
Simon Glasscec34ba2019-07-08 14:25:28 -06002087 def testFdtmapHeader(self):
2088 """Test an FDT map and image header can be inserted in the image"""
2089 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2090 fdtmap_pos = len(U_BOOT_DATA)
2091 fdtmap_data = data[fdtmap_pos:]
2092 fdt_data = fdtmap_data[16:]
2093 dtb = fdt.Fdt.FromData(fdt_data)
2094 fdt_size = dtb.GetFdtObj().totalsize()
2095 hdr_data = data[-8:]
2096 self.assertEqual('BinM', hdr_data[:4])
2097 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2098 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2099
2100 def testFdtmapHeaderStart(self):
2101 """Test an image header can be inserted at the image start"""
2102 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2103 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2104 hdr_data = data[:8]
2105 self.assertEqual('BinM', hdr_data[:4])
2106 offset = struct.unpack('<I', hdr_data[4:])[0]
2107 self.assertEqual(fdtmap_pos, offset)
2108
2109 def testFdtmapHeaderPos(self):
2110 """Test an image header can be inserted at a chosen position"""
2111 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2112 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2113 hdr_data = data[0x80:0x88]
2114 self.assertEqual('BinM', hdr_data[:4])
2115 offset = struct.unpack('<I', hdr_data[4:])[0]
2116 self.assertEqual(fdtmap_pos, offset)
2117
2118 def testHeaderMissingFdtmap(self):
2119 """Test an image header requires an fdtmap"""
2120 with self.assertRaises(ValueError) as e:
2121 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2122 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2123 str(e.exception))
2124
2125 def testHeaderNoLocation(self):
2126 """Test an image header with a no specified location is detected"""
2127 with self.assertRaises(ValueError) as e:
2128 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2129 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2130 str(e.exception))
2131
Simon Glassc2f1aed2019-07-08 13:18:56 -06002132
Simon Glassac599912017-11-12 21:52:22 -07002133if __name__ == "__main__":
2134 unittest.main()