blob: 999d8884acacc3ecdafe4a161c61815f46009c6e [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,
Simon Glassf46732a2019-07-08 14:25:29 -0600158 toolpath=None, verbosity=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 Glassf46732a2019-07-08 14:25:29 -0600172 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600173
Simon Glass1de34482019-07-08 13:18:53 -0600174 def _CheckLz4(self):
175 if not self.have_lz4:
176 self.skipTest('lz4 --no-frame-crc not available')
177
Simon Glass57454f42016-11-25 20:15:52 -0700178 def setUp(self):
179 # Enable this to turn on debugging output
180 # tout.Init(tout.DEBUG)
181 command.test_result = None
182
183 def tearDown(self):
184 """Remove the temporary output directory"""
Simon Glass1c420c92019-07-08 13:18:49 -0600185 if self.preserve_outdirs:
186 print('Preserving output dir: %s' % tools.outdir)
187 else:
188 tools._FinaliseForTest()
Simon Glass57454f42016-11-25 20:15:52 -0700189
Simon Glass8425a1f2018-07-17 13:25:48 -0600190 @classmethod
191 def _ResetDtbs(self):
192 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
193 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
194 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
195
Simon Glass57454f42016-11-25 20:15:52 -0700196 def _RunBinman(self, *args, **kwargs):
197 """Run binman using the command line
198
199 Args:
200 Arguments to pass, as a list of strings
201 kwargs: Arguments to pass to Command.RunPipe()
202 """
203 result = command.RunPipe([[self._binman_pathname] + list(args)],
204 capture=True, capture_stderr=True, raise_on_error=False)
205 if result.return_code and kwargs.get('raise_on_error', True):
206 raise Exception("Error running '%s': %s" % (' '.join(args),
207 result.stdout + result.stderr))
208 return result
209
Simon Glassf46732a2019-07-08 14:25:29 -0600210 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700211 """Run binman using directly (in the same process)
212
213 Args:
214 Arguments to pass, as a list of strings
215 Returns:
216 Return value (0 for success)
217 """
Simon Glassf46732a2019-07-08 14:25:29 -0600218 argv = list(argv)
219 args = cmdline.ParseArgs(argv)
220 args.pager = 'binman-invalid-pager'
221 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700222
223 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600224 # args.verbosity = tout.DEBUG
225 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700226
Simon Glass91710b32018-07-17 13:25:32 -0600227 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600228 entry_args=None, images=None, use_real_dtb=False,
229 verbosity=None):
Simon Glass57454f42016-11-25 20:15:52 -0700230 """Run binman with a given test file
231
232 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600233 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600234 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600235 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600236 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600237 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600238 entry_args: Dict of entry args to supply to binman
239 key: arg name
240 value: value of that arg
241 images: List of image names to build
Simon Glass57454f42016-11-25 20:15:52 -0700242 """
Simon Glassf46732a2019-07-08 14:25:29 -0600243 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700244 if debug:
245 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600246 if verbosity is not None:
247 args.append('-v%d' % verbosity)
248 elif self.verbosity:
249 args.append('-v%d' % self.verbosity)
250 if self.toolpath:
251 for path in self.toolpath:
252 args += ['--toolpath', path]
253 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600254 if map:
255 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600256 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600257 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600258 if not use_real_dtb:
259 args.append('--fake-dtb')
Simon Glass91710b32018-07-17 13:25:32 -0600260 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600261 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600262 args.append('-a%s=%s' % (arg, value))
Simon Glass3b376c32018-09-14 04:57:12 -0600263 if images:
264 for image in images:
265 args += ['-i', image]
Simon Glass075a45c2017-11-13 18:55:00 -0700266 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700267
268 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700269 """Set up a new test device-tree file
270
271 The given file is compiled and set up as the device tree to be used
272 for ths test.
273
274 Args:
275 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600276 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700277
278 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600279 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700280 """
Simon Glass752e7552018-10-01 21:12:41 -0600281 tools.PrepareOutputDir(None)
Simon Glass57454f42016-11-25 20:15:52 -0700282 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass33486662019-05-14 15:53:42 -0600283 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700284 data = fd.read()
285 TestFunctional._MakeInputFile(outfile, data)
Simon Glass752e7552018-10-01 21:12:41 -0600286 tools.FinaliseOutputDir()
287 return data
Simon Glass57454f42016-11-25 20:15:52 -0700288
Simon Glasse219aa42018-09-14 04:57:24 -0600289 def _GetDtbContentsForSplTpl(self, dtb_data, name):
290 """Create a version of the main DTB for SPL or SPL
291
292 For testing we don't actually have different versions of the DTB. With
293 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
294 we don't normally have any unwanted nodes.
295
296 We still want the DTBs for SPL and TPL to be different though, since
297 otherwise it is confusing to know which one we are looking at. So add
298 an 'spl' or 'tpl' property to the top-level node.
299 """
300 dtb = fdt.Fdt.FromData(dtb_data)
301 dtb.Scan()
302 dtb.GetNode('/binman').AddZeroProp(name)
303 dtb.Sync(auto_resize=True)
304 dtb.Pack()
305 return dtb.GetContents()
306
Simon Glassa87014e2018-07-06 10:27:42 -0600307 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glasse219aa42018-09-14 04:57:24 -0600308 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass57454f42016-11-25 20:15:52 -0700309 """Run binman and return the resulting image
310
311 This runs binman with a given test file and then reads the resulting
312 output file. It is a shortcut function since most tests need to do
313 these steps.
314
315 Raises an assertion failure if binman returns a non-zero exit code.
316
317 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600318 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700319 use_real_dtb: True to use the test file as the contents of
320 the u-boot-dtb entry. Normally this is not needed and the
321 test contents (the U_BOOT_DTB_DATA string) can be used.
322 But in some test we need the real contents.
Simon Glass30732662018-06-01 09:38:20 -0600323 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600324 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600325 tree before packing it into the image
Simon Glass72232452016-11-25 20:15:53 -0700326
327 Returns:
328 Tuple:
329 Resulting image contents
330 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600331 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600332 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700333 """
Simon Glass72232452016-11-25 20:15:53 -0700334 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700335 # Use the compiled test file as the u-boot-dtb input
336 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700337 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600338
339 # For testing purposes, make a copy of the DT for SPL and TPL. Add
340 # a node indicating which it is, so aid verification.
341 for name in ['spl', 'tpl']:
342 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
343 outfile = os.path.join(self._indir, dtb_fname)
344 TestFunctional._MakeInputFile(dtb_fname,
345 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700346
347 try:
Simon Glass91710b32018-07-17 13:25:32 -0600348 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glasse219aa42018-09-14 04:57:24 -0600349 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass57454f42016-11-25 20:15:52 -0700350 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600351 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700352
353 # Find the (only) image, read it and return its contents
354 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600355 image_fname = tools.GetOutputFilename('image.bin')
356 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600357 if map:
358 map_fname = tools.GetOutputFilename('image.map')
359 with open(map_fname) as fd:
360 map_data = fd.read()
361 else:
362 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600363 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600364 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700365 finally:
366 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600367 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600368 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700369
Simon Glass5b4bce32019-07-08 14:25:26 -0600370 def _DoReadFileRealDtb(self, fname):
371 """Run binman with a real .dtb file and return the resulting data
372
373 Args:
374 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
375
376 Returns:
377 Resulting image contents
378 """
379 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
380
Simon Glass72232452016-11-25 20:15:53 -0700381 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600382 """Helper function which discards the device-tree binary
383
384 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600385 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600386 use_real_dtb: True to use the test file as the contents of
387 the u-boot-dtb entry. Normally this is not needed and the
388 test contents (the U_BOOT_DTB_DATA string) can be used.
389 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600390
391 Returns:
392 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600393 """
Simon Glass72232452016-11-25 20:15:53 -0700394 return self._DoReadFileDtb(fname, use_real_dtb)[0]
395
Simon Glass57454f42016-11-25 20:15:52 -0700396 @classmethod
397 def _MakeInputFile(self, fname, contents):
398 """Create a new test input file, creating directories as needed
399
400 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600401 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700402 contents: File contents to write in to the file
403 Returns:
404 Full pathname of file created
405 """
406 pathname = os.path.join(self._indir, fname)
407 dirname = os.path.dirname(pathname)
408 if dirname and not os.path.exists(dirname):
409 os.makedirs(dirname)
410 with open(pathname, 'wb') as fd:
411 fd.write(contents)
412 return pathname
413
414 @classmethod
Simon Glassc1ae83c2018-07-17 13:25:44 -0600415 def _MakeInputDir(self, dirname):
416 """Create a new test input directory, creating directories as needed
417
418 Args:
419 dirname: Directory name to create
420
421 Returns:
422 Full pathname of directory created
423 """
424 pathname = os.path.join(self._indir, dirname)
425 if not os.path.exists(pathname):
426 os.makedirs(pathname)
427 return pathname
428
429 @classmethod
Simon Glass7057d022018-10-01 21:12:47 -0600430 def _SetupSplElf(self, src_fname='bss_data'):
431 """Set up an ELF file with a '_dt_ucode_base_size' symbol
432
433 Args:
434 Filename of ELF file to use as SPL
435 """
Simon Glass33486662019-05-14 15:53:42 -0600436 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass7057d022018-10-01 21:12:47 -0600437 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
438
439 @classmethod
Simon Glass57454f42016-11-25 20:15:52 -0700440 def TestFile(self, fname):
441 return os.path.join(self._binman_dir, 'test', fname)
442
443 def AssertInList(self, grep_list, target):
444 """Assert that at least one of a list of things is in a target
445
446 Args:
447 grep_list: List of strings to check
448 target: Target string
449 """
450 for grep in grep_list:
451 if grep in target:
452 return
Simon Glass848cdb52019-05-17 22:00:50 -0600453 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700454
455 def CheckNoGaps(self, entries):
456 """Check that all entries fit together without gaps
457
458 Args:
459 entries: List of entries to check
460 """
Simon Glasse8561af2018-08-01 15:22:37 -0600461 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700462 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600463 self.assertEqual(offset, entry.offset)
464 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700465
Simon Glass72232452016-11-25 20:15:53 -0700466 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600467 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700468
469 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600470 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700471
472 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600473 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700474 """
475 return struct.unpack('>L', dtb[4:8])[0]
476
Simon Glass0f621332019-07-08 14:25:27 -0600477 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600478 def AddNode(node, path):
479 if node.name != '/':
480 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600481 for prop in node.props.values():
482 if prop.name in prop_names:
483 prop_path = path + ':' + prop.name
484 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
485 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600486 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600487 AddNode(subnode, path)
488
489 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600490 AddNode(dtb.GetRoot(), '')
491 return tree
492
Simon Glass57454f42016-11-25 20:15:52 -0700493 def testRun(self):
494 """Test a basic run with valid args"""
495 result = self._RunBinman('-h')
496
497 def testFullHelp(self):
498 """Test that the full help is displayed with -H"""
499 result = self._RunBinman('-H')
500 help_file = os.path.join(self._binman_dir, 'README')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500501 # Remove possible extraneous strings
502 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
503 gothelp = result.stdout.replace(extra, '')
504 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700505 self.assertEqual(0, len(result.stderr))
506 self.assertEqual(0, result.return_code)
507
508 def testFullHelpInternal(self):
509 """Test that the full help is displayed with -H"""
510 try:
511 command.test_result = command.CommandResult()
512 result = self._DoBinman('-H')
513 help_file = os.path.join(self._binman_dir, 'README')
514 finally:
515 command.test_result = None
516
517 def testHelp(self):
518 """Test that the basic help is displayed with -h"""
519 result = self._RunBinman('-h')
520 self.assertTrue(len(result.stdout) > 200)
521 self.assertEqual(0, len(result.stderr))
522 self.assertEqual(0, result.return_code)
523
Simon Glass57454f42016-11-25 20:15:52 -0700524 def testBoard(self):
525 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600526 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700527 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassf46732a2019-07-08 14:25:29 -0600528 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700529 self.assertEqual(0, result)
530
531 def testNeedBoard(self):
532 """Test that we get an error when no board ius supplied"""
533 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600534 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700535 self.assertIn("Must provide a board to process (use -b <board>)",
536 str(e.exception))
537
538 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600539 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700540 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600541 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700542 # We get one error from libfdt, and a different one from fdtget.
543 self.AssertInList(["Couldn't open blob from 'missing_file'",
544 'No such file or directory'], str(e.exception))
545
546 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600547 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700548
549 Since this is a source file it should be compiled and the error
550 will come from the device-tree compiler (dtc).
551 """
552 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600553 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700554 self.assertIn("FATAL ERROR: Unable to parse input tree",
555 str(e.exception))
556
557 def testMissingNode(self):
558 """Test that a device tree without a 'binman' node generates an error"""
559 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600560 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700561 self.assertIn("does not have a 'binman' node", str(e.exception))
562
563 def testEmpty(self):
564 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600565 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700566 self.assertEqual(0, len(result.stderr))
567 self.assertEqual(0, result.return_code)
568
569 def testInvalidEntry(self):
570 """Test that an invalid entry is flagged"""
571 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600572 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600573 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700574 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
575 "'/binman/not-a-valid-type'", str(e.exception))
576
577 def testSimple(self):
578 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600579 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700580 self.assertEqual(U_BOOT_DATA, data)
581
Simon Glass075a45c2017-11-13 18:55:00 -0700582 def testSimpleDebug(self):
583 """Test a simple binman run with debugging enabled"""
Simon Glass511f6582018-10-01 12:22:30 -0600584 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700585
Simon Glass57454f42016-11-25 20:15:52 -0700586 def testDual(self):
587 """Test that we can handle creating two images
588
589 This also tests image padding.
590 """
Simon Glass511f6582018-10-01 12:22:30 -0600591 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700592 self.assertEqual(0, retcode)
593
594 image = control.images['image1']
595 self.assertEqual(len(U_BOOT_DATA), image._size)
596 fname = tools.GetOutputFilename('image1.bin')
597 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600598 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700599 data = fd.read()
600 self.assertEqual(U_BOOT_DATA, data)
601
602 image = control.images['image2']
603 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
604 fname = tools.GetOutputFilename('image2.bin')
605 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600606 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700607 data = fd.read()
608 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600609 self.assertEqual(tools.GetBytes(0, 3), data[:3])
610 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700611
612 def testBadAlign(self):
613 """Test that an invalid alignment value is detected"""
614 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600615 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700616 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
617 "of two", str(e.exception))
618
619 def testPackSimple(self):
620 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600621 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700622 self.assertEqual(0, retcode)
623 self.assertIn('image', control.images)
624 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600625 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700626 self.assertEqual(5, len(entries))
627
628 # First u-boot
629 self.assertIn('u-boot', entries)
630 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600631 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700632 self.assertEqual(len(U_BOOT_DATA), entry.size)
633
634 # Second u-boot, aligned to 16-byte boundary
635 self.assertIn('u-boot-align', entries)
636 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600637 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700638 self.assertEqual(len(U_BOOT_DATA), entry.size)
639
640 # Third u-boot, size 23 bytes
641 self.assertIn('u-boot-size', entries)
642 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600643 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700644 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
645 self.assertEqual(23, entry.size)
646
647 # Fourth u-boot, placed immediate after the above
648 self.assertIn('u-boot-next', entries)
649 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600650 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700651 self.assertEqual(len(U_BOOT_DATA), entry.size)
652
Simon Glasse8561af2018-08-01 15:22:37 -0600653 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700654 self.assertIn('u-boot-fixed', entries)
655 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600656 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700657 self.assertEqual(len(U_BOOT_DATA), entry.size)
658
659 self.assertEqual(65, image._size)
660
661 def testPackExtra(self):
662 """Test that extra packing feature works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600663 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700664
665 self.assertEqual(0, retcode)
666 self.assertIn('image', control.images)
667 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600668 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700669 self.assertEqual(5, len(entries))
670
671 # First u-boot with padding before and after
672 self.assertIn('u-boot', entries)
673 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600674 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700675 self.assertEqual(3, entry.pad_before)
676 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
677
678 # Second u-boot has an aligned size, but it has no effect
679 self.assertIn('u-boot-align-size-nop', entries)
680 entry = entries['u-boot-align-size-nop']
Simon Glasse8561af2018-08-01 15:22:37 -0600681 self.assertEqual(12, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700682 self.assertEqual(4, entry.size)
683
684 # Third u-boot has an aligned size too
685 self.assertIn('u-boot-align-size', entries)
686 entry = entries['u-boot-align-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600687 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700688 self.assertEqual(32, entry.size)
689
690 # Fourth u-boot has an aligned end
691 self.assertIn('u-boot-align-end', entries)
692 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600693 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700694 self.assertEqual(16, entry.size)
695
696 # Fifth u-boot immediately afterwards
697 self.assertIn('u-boot-align-both', entries)
698 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600699 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700700 self.assertEqual(64, entry.size)
701
702 self.CheckNoGaps(entries)
703 self.assertEqual(128, image._size)
704
705 def testPackAlignPowerOf2(self):
706 """Test that invalid entry alignment is detected"""
707 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600708 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700709 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
710 "of two", str(e.exception))
711
712 def testPackAlignSizePowerOf2(self):
713 """Test that invalid entry size alignment is detected"""
714 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600715 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700716 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
717 "power of two", str(e.exception))
718
719 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600720 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700721 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600722 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600723 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700724 "align 0x4 (4)", str(e.exception))
725
726 def testPackInvalidSizeAlign(self):
727 """Test that invalid entry size alignment is detected"""
728 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600729 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700730 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
731 "align-size 0x4 (4)", str(e.exception))
732
733 def testPackOverlap(self):
734 """Test that overlapping regions are detected"""
735 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600736 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600737 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700738 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
739 str(e.exception))
740
741 def testPackEntryOverflow(self):
742 """Test that entries that overflow their size are detected"""
743 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600744 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700745 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
746 "but entry size is 0x3 (3)", str(e.exception))
747
748 def testPackImageOverflow(self):
749 """Test that entries which overflow the image size are detected"""
750 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600751 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600752 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700753 "size 0x3 (3)", str(e.exception))
754
755 def testPackImageSize(self):
756 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600757 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700758 self.assertEqual(0, retcode)
759 self.assertIn('image', control.images)
760 image = control.images['image']
761 self.assertEqual(7, image._size)
762
763 def testPackImageSizeAlign(self):
764 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600765 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700766 self.assertEqual(0, retcode)
767 self.assertIn('image', control.images)
768 image = control.images['image']
769 self.assertEqual(16, image._size)
770
771 def testPackInvalidImageAlign(self):
772 """Test that invalid image alignment is detected"""
773 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600774 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600775 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700776 "align-size 0x8 (8)", str(e.exception))
777
778 def testPackAlignPowerOf2(self):
779 """Test that invalid image alignment is detected"""
780 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600781 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600782 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700783 "two", str(e.exception))
784
785 def testImagePadByte(self):
786 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600787 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600788 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600789 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
790 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700791
792 def testImageName(self):
793 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600794 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700795 self.assertEqual(0, retcode)
796 image = control.images['image1']
797 fname = tools.GetOutputFilename('test-name')
798 self.assertTrue(os.path.exists(fname))
799
800 image = control.images['image2']
801 fname = tools.GetOutputFilename('test-name.xx')
802 self.assertTrue(os.path.exists(fname))
803
804 def testBlobFilename(self):
805 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600806 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertEqual(BLOB_DATA, data)
808
809 def testPackSorted(self):
810 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600811 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600812 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600813 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
814 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700815
Simon Glasse8561af2018-08-01 15:22:37 -0600816 def testPackZeroOffset(self):
817 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -0700818 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600819 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600820 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700821 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
822 str(e.exception))
823
824 def testPackUbootDtb(self):
825 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -0600826 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700827 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -0700828
829 def testPackX86RomNoSize(self):
830 """Test that the end-at-4gb property requires a size property"""
831 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600832 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600833 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -0700834 "using end-at-4gb", str(e.exception))
835
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530836 def test4gbAndSkipAtStartTogether(self):
837 """Test that the end-at-4gb and skip-at-size property can't be used
838 together"""
839 with self.assertRaises(ValueError) as e:
840 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
841 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
842 "'skip-at-start'", str(e.exception))
843
Simon Glass72232452016-11-25 20:15:53 -0700844 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600845 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -0700846 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600847 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600848 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glasseca32212018-06-01 09:38:12 -0600849 "the section starting at 0xffffffe0 (4294967264)",
Simon Glass72232452016-11-25 20:15:53 -0700850 str(e.exception))
851
852 def testPackX86Rom(self):
853 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -0600854 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600855 data = self._DoReadFile('029_x86-rom.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600856 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
857 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -0700858
859 def testPackX86RomMeNoDesc(self):
860 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass303f62f2019-05-17 22:00:46 -0600861 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glass72232452016-11-25 20:15:53 -0700862 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600863 self._DoTestFile('031_x86-rom-me.dts')
Simon Glassac4738b2019-07-08 13:18:32 -0600864 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
865 str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700866
867 def testPackX86RomBadDesc(self):
868 """Test that the Intel requires a descriptor entry"""
869 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600870 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600871 self.assertIn("Node '/binman/intel-me': No offset set with "
872 "offset-unset: should another entry provide this correct "
873 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700874
875 def testPackX86RomMe(self):
876 """Test that an x86 ROM with an ME region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600877 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glass759af872019-07-08 13:18:54 -0600878 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
879 if data[:0x1000] != expected_desc:
880 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -0700881 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
882
883 def testPackVga(self):
884 """Test that an image with a VGA binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600885 data = self._DoReadFile('032_intel-vga.dts')
Simon Glass72232452016-11-25 20:15:53 -0700886 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
887
888 def testPackStart16(self):
889 """Test that an image with an x86 start16 region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600890 data = self._DoReadFile('033_x86-start16.dts')
Simon Glass72232452016-11-25 20:15:53 -0700891 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
892
Jagdish Gediya311d4842018-09-03 21:35:08 +0530893 def testPackPowerpcMpc85xxBootpgResetvec(self):
894 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
895 created"""
896 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
897 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
898
Simon Glass6ba679c2018-07-06 10:27:17 -0600899 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -0600900 """Handle running a test for insertion of microcode
901
902 Args:
903 dts_fname: Name of test .dts file
904 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -0600905 ucode_second: True if the microsecond entry is second instead of
906 third
Simon Glass820af1d2018-07-06 10:27:16 -0600907
908 Returns:
909 Tuple:
910 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -0600911 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -0600912 in the above (two 4-byte words)
913 """
Simon Glass3d274232017-11-12 21:52:27 -0700914 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -0700915
916 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -0600917 if ucode_second:
918 ucode_content = data[len(nodtb_data):]
919 ucode_pos = len(nodtb_data)
920 dtb_with_ucode = ucode_content[16:]
921 fdt_len = self.GetFdtLen(dtb_with_ucode)
922 else:
923 dtb_with_ucode = data[len(nodtb_data):]
924 fdt_len = self.GetFdtLen(dtb_with_ucode)
925 ucode_content = dtb_with_ucode[fdt_len:]
926 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -0700927 fname = tools.GetOutputFilename('test.dtb')
928 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -0600929 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -0600930 dtb = fdt.FdtScan(fname)
931 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -0700932 self.assertTrue(ucode)
933 for node in ucode.subnodes:
934 self.assertFalse(node.props.get('data'))
935
Simon Glass72232452016-11-25 20:15:53 -0700936 # Check that the microcode appears immediately after the Fdt
937 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -0700938 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -0700939 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
940 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -0600941 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -0700942
943 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -0600944 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -0700945 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
946 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -0600947 u_boot = data[:len(nodtb_data)]
948 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -0700949
950 def testPackUbootMicrocode(self):
951 """Test that x86 microcode can be handled correctly
952
953 We expect to see the following in the image, in order:
954 u-boot-nodtb.bin with a microcode pointer inserted at the correct
955 place
956 u-boot.dtb with the microcode removed
957 the microcode
958 """
Simon Glass511f6582018-10-01 12:22:30 -0600959 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -0700960 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -0600961 self.assertEqual(b'nodtb with microcode' + pos_and_size +
962 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -0700963
Simon Glassbac25c82017-05-27 07:38:26 -0600964 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -0700965 """Test that x86 microcode can be handled correctly
966
967 We expect to see the following in the image, in order:
968 u-boot-nodtb.bin with a microcode pointer inserted at the correct
969 place
970 u-boot.dtb with the microcode
971 an empty microcode region
972 """
973 # We need the libfdt library to run this test since only that allows
974 # finding the offset of a property. This is required by
975 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -0600976 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -0700977
978 second = data[len(U_BOOT_NODTB_DATA):]
979
980 fdt_len = self.GetFdtLen(second)
981 third = second[fdt_len:]
982 second = second[:fdt_len]
983
Simon Glassbac25c82017-05-27 07:38:26 -0600984 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
985 self.assertIn(ucode_data, second)
986 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700987
Simon Glassbac25c82017-05-27 07:38:26 -0600988 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -0600989 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -0600990 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
991 len(ucode_data))
992 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -0600993 self.assertEqual(b'nodtb with microcode' + pos_and_size +
994 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -0700995
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700996 def testPackUbootSingleMicrocode(self):
997 """Test that x86 microcode can be handled correctly with fdt_normal.
998 """
Simon Glassbac25c82017-05-27 07:38:26 -0600999 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001000
Simon Glass996021e2016-11-25 20:15:54 -07001001 def testUBootImg(self):
1002 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001003 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001004 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001005
1006 def testNoMicrocode(self):
1007 """Test that a missing microcode region is detected"""
1008 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001009 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001010 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1011 "node found in ", str(e.exception))
1012
1013 def testMicrocodeWithoutNode(self):
1014 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1015 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001016 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001017 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1018 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1019
1020 def testMicrocodeWithoutNode2(self):
1021 """Test that a missing u-boot-ucode node is detected"""
1022 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001023 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001024 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1025 "microcode region u-boot-ucode", str(e.exception))
1026
1027 def testMicrocodeWithoutPtrInElf(self):
1028 """Test that a U-Boot binary without the microcode symbol is detected"""
1029 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001030 try:
Simon Glass33486662019-05-14 15:53:42 -06001031 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001032 TestFunctional._MakeInputFile('u-boot', fd.read())
1033
1034 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001035 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001036 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1037 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1038
1039 finally:
1040 # Put the original file back
Simon Glass33486662019-05-14 15:53:42 -06001041 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001042 TestFunctional._MakeInputFile('u-boot', fd.read())
1043
1044 def testMicrocodeNotInImage(self):
1045 """Test that microcode must be placed within the image"""
1046 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001047 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001048 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1049 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001050 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001051
1052 def testWithoutMicrocode(self):
1053 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass33486662019-05-14 15:53:42 -06001054 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001055 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001056 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001057
1058 # Now check the device tree has no microcode
1059 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1060 second = data[len(U_BOOT_NODTB_DATA):]
1061
1062 fdt_len = self.GetFdtLen(second)
1063 self.assertEqual(dtb, second[:fdt_len])
1064
1065 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1066 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001067 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001068
1069 def testUnknownPosSize(self):
1070 """Test that microcode must be placed within the image"""
1071 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001072 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001073 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001074 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001075
1076 def testPackFsp(self):
1077 """Test that an image with a FSP binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001078 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001079 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1080
1081 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001082 """Test that an image with a CMC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001083 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001084 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001085
1086 def testPackVbt(self):
1087 """Test that an image with a VBT binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001088 data = self._DoReadFile('046_intel-vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001089 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001090
Simon Glass7f94e832017-11-12 21:52:25 -07001091 def testSplBssPad(self):
1092 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001093 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001094 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001095 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001096 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1097 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001098
Simon Glass04cda032018-10-01 21:12:42 -06001099 def testSplBssPadMissing(self):
1100 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001101 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001102 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001103 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001104 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1105 str(e.exception))
1106
Simon Glasse83679d2017-11-12 21:52:26 -07001107 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001108 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001109 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001110 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1111
Simon Glass6ba679c2018-07-06 10:27:17 -06001112 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1113 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001114
1115 We expect to see the following in the image, in order:
1116 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1117 correct place
1118 u-boot.dtb with the microcode removed
1119 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001120
1121 Args:
1122 dts: Device tree file to use for test
1123 ucode_second: True if the microsecond entry is second instead of
1124 third
Simon Glass3d274232017-11-12 21:52:27 -07001125 """
Simon Glass7057d022018-10-01 21:12:47 -06001126 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001127 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1128 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001129 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1130 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001131
Simon Glass6ba679c2018-07-06 10:27:17 -06001132 def testPackUbootSplMicrocode(self):
1133 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001134 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001135
1136 def testPackUbootSplMicrocodeReorder(self):
1137 """Test that order doesn't matter for microcode entries
1138
1139 This is the same as testPackUbootSplMicrocode but when we process the
1140 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1141 entry, so we reply on binman to try later.
1142 """
Simon Glass511f6582018-10-01 12:22:30 -06001143 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001144 ucode_second=True)
1145
Simon Glassa409c932017-11-12 21:52:28 -07001146 def testPackMrc(self):
1147 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001148 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001149 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1150
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001151 def testSplDtb(self):
1152 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001153 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001154 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1155
Simon Glass0a6da312017-11-13 18:54:56 -07001156 def testSplNoDtb(self):
1157 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001158 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001159 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1160
Simon Glass4ca8e042017-11-13 18:55:01 -07001161 def testSymbols(self):
1162 """Test binman can assign symbols embedded in U-Boot"""
1163 elf_fname = self.TestFile('u_boot_binman_syms')
1164 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1165 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glasse8561af2018-08-01 15:22:37 -06001166 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001167
Simon Glass7057d022018-10-01 21:12:47 -06001168 self._SetupSplElf('u_boot_binman_syms')
Simon Glass511f6582018-10-01 12:22:30 -06001169 data = self._DoReadFile('053_symbols.dts')
Simon Glass4ca8e042017-11-13 18:55:01 -07001170 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glassac0d4952019-05-14 15:53:47 -06001171 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1172 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1173 U_BOOT_SPL_DATA[16:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001174 self.assertEqual(expected, data)
1175
Simon Glasse76a3e62018-06-01 09:38:11 -06001176 def testPackUnitAddress(self):
1177 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001178 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001179 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1180
Simon Glassa91e1152018-06-01 09:38:16 -06001181 def testSections(self):
1182 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001183 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001184 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1185 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1186 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001187 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001188
Simon Glass30732662018-06-01 09:38:20 -06001189 def testMap(self):
1190 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001191 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001192 self.assertEqual('''ImagePos Offset Size Name
119300000000 00000000 00000028 main-section
119400000000 00000000 00000010 section@0
119500000000 00000000 00000004 u-boot
119600000010 00000010 00000010 section@1
119700000010 00000000 00000004 u-boot
119800000020 00000020 00000004 section@2
119900000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001200''', map_data)
1201
Simon Glass3b78d532018-06-01 09:38:21 -06001202 def testNamePrefix(self):
1203 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001204 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.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 ro-u-boot
120900000010 00000010 00000010 section@1
121000000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001211''', map_data)
1212
Simon Glass6ba679c2018-07-06 10:27:17 -06001213 def testUnknownContents(self):
1214 """Test that obtaining the contents works as expected"""
1215 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001216 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass6ba679c2018-07-06 10:27:17 -06001217 self.assertIn("Section '/binman': Internal error: Could not complete "
1218 "processing of contents: remaining [<_testing.Entry__testing ",
1219 str(e.exception))
1220
Simon Glass2e1169f2018-07-06 10:27:19 -06001221 def testBadChangeSize(self):
1222 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001223 try:
1224 state.SetAllowEntryExpansion(False)
1225 with self.assertRaises(ValueError) as e:
1226 self._DoReadFile('059_change_size.dts', True)
1227 self.assertIn("Node '/binman/_testing': Cannot update entry size from 1 to 2",
1228 str(e.exception))
1229 finally:
1230 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001231
Simon Glassa87014e2018-07-06 10:27:42 -06001232 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001233 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001234 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001235 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001236 dtb = fdt.Fdt(out_dtb_fname)
1237 dtb.Scan()
1238 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glassa87014e2018-07-06 10:27:42 -06001239 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001240 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001241 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001242 '_testing:offset': 32,
Simon Glassa87014e2018-07-06 10:27:42 -06001243 '_testing:size': 1,
Simon Glass9dcc8612018-08-01 15:22:42 -06001244 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001245 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001246 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001247 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001248 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001249 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001250 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001251
Simon Glasse8561af2018-08-01 15:22:37 -06001252 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001253 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001254 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001255 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001256 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001257 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001258 'size': 40
1259 }, props)
1260
1261 def testUpdateFdtBad(self):
1262 """Test that we detect when ProcessFdt never completes"""
1263 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001264 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001265 self.assertIn('Could not complete processing of Fdt: remaining '
1266 '[<_testing.Entry__testing', str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001267
Simon Glass91710b32018-07-17 13:25:32 -06001268 def testEntryArgs(self):
1269 """Test passing arguments to entries from the command line"""
1270 entry_args = {
1271 'test-str-arg': 'test1',
1272 'test-int-arg': '456',
1273 }
Simon Glass511f6582018-10-01 12:22:30 -06001274 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001275 self.assertIn('image', control.images)
1276 entry = control.images['image'].GetEntries()['_testing']
1277 self.assertEqual('test0', entry.test_str_fdt)
1278 self.assertEqual('test1', entry.test_str_arg)
1279 self.assertEqual(123, entry.test_int_fdt)
1280 self.assertEqual(456, entry.test_int_arg)
1281
1282 def testEntryArgsMissing(self):
1283 """Test missing arguments and properties"""
1284 entry_args = {
1285 'test-int-arg': '456',
1286 }
Simon Glass511f6582018-10-01 12:22:30 -06001287 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001288 entry = control.images['image'].GetEntries()['_testing']
1289 self.assertEqual('test0', entry.test_str_fdt)
1290 self.assertEqual(None, entry.test_str_arg)
1291 self.assertEqual(None, entry.test_int_fdt)
1292 self.assertEqual(456, entry.test_int_arg)
1293
1294 def testEntryArgsRequired(self):
1295 """Test missing arguments and properties"""
1296 entry_args = {
1297 'test-int-arg': '456',
1298 }
1299 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001300 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass91710b32018-07-17 13:25:32 -06001301 self.assertIn("Node '/binman/_testing': Missing required "
1302 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1303 str(e.exception))
1304
1305 def testEntryArgsInvalidFormat(self):
1306 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001307 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1308 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001309 with self.assertRaises(ValueError) as e:
1310 self._DoBinman(*args)
1311 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1312
1313 def testEntryArgsInvalidInteger(self):
1314 """Test that an invalid entry-argument integer is detected"""
1315 entry_args = {
1316 'test-int-arg': 'abc',
1317 }
1318 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001319 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001320 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1321 "'test-int-arg' (value 'abc') to integer",
1322 str(e.exception))
1323
1324 def testEntryArgsInvalidDatatype(self):
1325 """Test that an invalid entry-argument datatype is detected
1326
1327 This test could be written in entry_test.py except that it needs
1328 access to control.entry_args, which seems more than that module should
1329 be able to see.
1330 """
1331 entry_args = {
1332 'test-bad-datatype-arg': '12',
1333 }
1334 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001335 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001336 entry_args=entry_args)
1337 self.assertIn('GetArg() internal error: Unknown data type ',
1338 str(e.exception))
1339
Simon Glass2ca52032018-07-17 13:25:33 -06001340 def testText(self):
1341 """Test for a text entry type"""
1342 entry_args = {
1343 'test-id': TEXT_DATA,
1344 'test-id2': TEXT_DATA2,
1345 'test-id3': TEXT_DATA3,
1346 }
Simon Glass511f6582018-10-01 12:22:30 -06001347 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001348 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001349 expected = (tools.ToBytes(TEXT_DATA) +
1350 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1351 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001352 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001353 self.assertEqual(expected, data)
1354
Simon Glass969616c2018-07-17 13:25:36 -06001355 def testEntryDocs(self):
1356 """Test for creation of entry documentation"""
1357 with test_util.capture_sys_output() as (stdout, stderr):
1358 control.WriteEntryDocs(binman.GetEntryModules())
1359 self.assertTrue(len(stdout.getvalue()) > 0)
1360
1361 def testEntryDocsMissing(self):
1362 """Test handling of missing entry documentation"""
1363 with self.assertRaises(ValueError) as e:
1364 with test_util.capture_sys_output() as (stdout, stderr):
1365 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1366 self.assertIn('Documentation is missing for modules: u_boot',
1367 str(e.exception))
1368
Simon Glass704784b2018-07-17 13:25:38 -06001369 def testFmap(self):
1370 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001371 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001372 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001373 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1374 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001375 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001376 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001377 self.assertEqual(1, fhdr.ver_major)
1378 self.assertEqual(0, fhdr.ver_minor)
1379 self.assertEqual(0, fhdr.base)
1380 self.assertEqual(16 + 16 +
1381 fmap_util.FMAP_HEADER_LEN +
1382 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001383 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass704784b2018-07-17 13:25:38 -06001384 self.assertEqual(3, fhdr.nareas)
1385 for fentry in fentries:
1386 self.assertEqual(0, fentry.flags)
1387
1388 self.assertEqual(0, fentries[0].offset)
1389 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001390 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass704784b2018-07-17 13:25:38 -06001391
1392 self.assertEqual(16, fentries[1].offset)
1393 self.assertEqual(4, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001394 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass704784b2018-07-17 13:25:38 -06001395
1396 self.assertEqual(32, fentries[2].offset)
1397 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1398 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001399 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass704784b2018-07-17 13:25:38 -06001400
Simon Glassdb168d42018-07-17 13:25:39 -06001401 def testBlobNamedByArg(self):
1402 """Test we can add a blob with the filename coming from an entry arg"""
1403 entry_args = {
1404 'cros-ec-rw-path': 'ecrw.bin',
1405 }
Simon Glass511f6582018-10-01 12:22:30 -06001406 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassdb168d42018-07-17 13:25:39 -06001407 entry_args=entry_args)
1408
Simon Glass53f53992018-07-17 13:25:40 -06001409 def testFill(self):
1410 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001411 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001412 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001413 self.assertEqual(expected, data)
1414
1415 def testFillNoSize(self):
1416 """Test for an fill entry type with no size"""
1417 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001418 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001419 self.assertIn("'fill' entry must have a size property",
1420 str(e.exception))
1421
Simon Glassc1ae83c2018-07-17 13:25:44 -06001422 def _HandleGbbCommand(self, pipe_list):
1423 """Fake calls to the futility utility"""
1424 if pipe_list[0][0] == 'futility':
1425 fname = pipe_list[0][-1]
1426 # Append our GBB data to the file, which will happen every time the
1427 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001428 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001429 fd.write(GBB_DATA)
1430 return command.CommandResult()
1431
1432 def testGbb(self):
1433 """Test for the Chromium OS Google Binary Block"""
1434 command.test_result = self._HandleGbbCommand
1435 entry_args = {
1436 'keydir': 'devkeys',
1437 'bmpblk': 'bmpblk.bin',
1438 }
Simon Glass511f6582018-10-01 12:22:30 -06001439 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001440
1441 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001442 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1443 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001444 self.assertEqual(expected, data)
1445
1446 def testGbbTooSmall(self):
1447 """Test for the Chromium OS Google Binary Block being large enough"""
1448 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001449 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001450 self.assertIn("Node '/binman/gbb': GBB is too small",
1451 str(e.exception))
1452
1453 def testGbbNoSize(self):
1454 """Test for the Chromium OS Google Binary Block having a size"""
1455 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001456 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001457 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1458 str(e.exception))
1459
Simon Glass5c350162018-07-17 13:25:47 -06001460 def _HandleVblockCommand(self, pipe_list):
1461 """Fake calls to the futility utility"""
1462 if pipe_list[0][0] == 'futility':
1463 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001464 with open(fname, 'wb') as fd:
Simon Glass5c350162018-07-17 13:25:47 -06001465 fd.write(VBLOCK_DATA)
1466 return command.CommandResult()
1467
1468 def testVblock(self):
1469 """Test for the Chromium OS Verified Boot Block"""
1470 command.test_result = self._HandleVblockCommand
1471 entry_args = {
1472 'keydir': 'devkeys',
1473 }
Simon Glass511f6582018-10-01 12:22:30 -06001474 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001475 entry_args=entry_args)
1476 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1477 self.assertEqual(expected, data)
1478
1479 def testVblockNoContent(self):
1480 """Test we detect a vblock which has no content to sign"""
1481 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001482 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001483 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1484 'property', str(e.exception))
1485
1486 def testVblockBadPhandle(self):
1487 """Test that we detect a vblock with an invalid phandle in contents"""
1488 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001489 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001490 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1491 '1000', str(e.exception))
1492
1493 def testVblockBadEntry(self):
1494 """Test that we detect an entry that points to a non-entry"""
1495 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001496 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001497 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1498 "'other'", str(e.exception))
1499
Simon Glass8425a1f2018-07-17 13:25:48 -06001500 def testTpl(self):
1501 """Test that an image with TPL and ots device tree can be created"""
1502 # ELF file with a '__bss_size' symbol
Simon Glass33486662019-05-14 15:53:42 -06001503 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass8425a1f2018-07-17 13:25:48 -06001504 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001505 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001506 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1507
Simon Glass24b97442018-07-17 13:25:51 -06001508 def testUsesPos(self):
1509 """Test that the 'pos' property cannot be used anymore"""
1510 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001511 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001512 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1513 "'pos'", str(e.exception))
1514
Simon Glass274bf092018-09-14 04:57:08 -06001515 def testFillZero(self):
1516 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001517 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001518 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001519
Simon Glass267de432018-09-14 04:57:09 -06001520 def testTextMissing(self):
1521 """Test for a text entry type where there is no text"""
1522 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001523 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001524 self.assertIn("Node '/binman/text': No value provided for text label "
1525 "'test-id'", str(e.exception))
1526
Simon Glassed40e962018-09-14 04:57:10 -06001527 def testPackStart16Tpl(self):
1528 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001529 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001530 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1531
Simon Glass3b376c32018-09-14 04:57:12 -06001532 def testSelectImage(self):
1533 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001534 expected = 'Skipping images: image1'
1535
1536 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001537 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001538 with test_util.capture_sys_output() as (stdout, stderr):
1539 retcode = self._DoTestFile('006_dual_image.dts',
1540 verbosity=verbosity,
1541 images=['image2'])
1542 self.assertEqual(0, retcode)
1543 if verbosity:
1544 self.assertIn(expected, stdout.getvalue())
1545 else:
1546 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001547
Simon Glassb4595d82019-04-25 21:58:34 -06001548 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1549 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass3b376c32018-09-14 04:57:12 -06001550
Simon Glasse219aa42018-09-14 04:57:24 -06001551 def testUpdateFdtAll(self):
1552 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001553 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001554
1555 base_expected = {
1556 'section:image-pos': 0,
1557 'u-boot-tpl-dtb:size': 513,
1558 'u-boot-spl-dtb:size': 513,
1559 'u-boot-spl-dtb:offset': 493,
1560 'image-pos': 0,
1561 'section/u-boot-dtb:image-pos': 0,
1562 'u-boot-spl-dtb:image-pos': 493,
1563 'section/u-boot-dtb:size': 493,
1564 'u-boot-tpl-dtb:image-pos': 1006,
1565 'section/u-boot-dtb:offset': 0,
1566 'section:size': 493,
1567 'offset': 0,
1568 'section:offset': 0,
1569 'u-boot-tpl-dtb:offset': 1006,
1570 'size': 1519
1571 }
1572
1573 # We expect three device-tree files in the output, one after the other.
1574 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1575 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1576 # main U-Boot tree. All three should have the same postions and offset.
1577 start = 0
1578 for item in ['', 'spl', 'tpl']:
1579 dtb = fdt.Fdt.FromData(data[start:])
1580 dtb.Scan()
1581 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1582 'spl', 'tpl'])
1583 expected = dict(base_expected)
1584 if item:
1585 expected[item] = 0
1586 self.assertEqual(expected, props)
1587 start += dtb._fdt_obj.totalsize()
1588
1589 def testUpdateFdtOutput(self):
1590 """Test that output DTB files are updated"""
1591 try:
Simon Glass511f6582018-10-01 12:22:30 -06001592 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001593 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1594
1595 # Unfortunately, compiling a source file always results in a file
1596 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001597 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001598 # binman as a file called u-boot.dtb. To fix this, copy the file
1599 # over to the expected place.
1600 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1601 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1602 start = 0
1603 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1604 'tpl/u-boot-tpl.dtb.out']:
1605 dtb = fdt.Fdt.FromData(data[start:])
1606 size = dtb._fdt_obj.totalsize()
1607 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1608 outdata = tools.ReadFile(pathname)
1609 name = os.path.split(fname)[0]
1610
1611 if name:
1612 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1613 else:
1614 orig_indata = dtb_data
1615 self.assertNotEqual(outdata, orig_indata,
1616 "Expected output file '%s' be updated" % pathname)
1617 self.assertEqual(outdata, data[start:start + size],
1618 "Expected output file '%s' to match output image" %
1619 pathname)
1620 start += size
1621 finally:
1622 self._ResetDtbs()
1623
Simon Glass7ba33592018-09-14 04:57:26 -06001624 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001625 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001626
1627 def testCompress(self):
1628 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001629 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001630 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001631 use_real_dtb=True, update_dtb=True)
1632 dtb = fdt.Fdt(out_dtb_fname)
1633 dtb.Scan()
1634 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1635 orig = self._decompress(data)
1636 self.assertEquals(COMPRESS_DATA, orig)
1637 expected = {
1638 'blob:uncomp-size': len(COMPRESS_DATA),
1639 'blob:size': len(data),
1640 'size': len(data),
1641 }
1642 self.assertEqual(expected, props)
1643
Simon Glassac6328c2018-09-14 04:57:28 -06001644 def testFiles(self):
1645 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001646 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001647 self.assertEqual(FILES_DATA, data)
1648
1649 def testFilesCompress(self):
1650 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001651 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001652 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001653
1654 image = control.images['image']
1655 entries = image.GetEntries()
1656 files = entries['files']
1657 entries = files._section._entries
1658
Simon Glass303f62f2019-05-17 22:00:46 -06001659 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001660 for i in range(1, 3):
1661 key = '%d.dat' % i
1662 start = entries[key].image_pos
1663 len = entries[key].size
1664 chunk = data[start:start + len]
1665 orig += self._decompress(chunk)
1666
1667 self.assertEqual(FILES_DATA, orig)
1668
1669 def testFilesMissing(self):
1670 """Test missing files"""
1671 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001672 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001673 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1674 'no files', str(e.exception))
1675
1676 def testFilesNoPattern(self):
1677 """Test missing files"""
1678 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001679 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001680 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1681 str(e.exception))
1682
Simon Glassfa79a812018-09-14 04:57:29 -06001683 def testExpandSize(self):
1684 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001685 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001686 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001687 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1688 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1689 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1690 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001691 self.assertEqual(expect, data)
1692 self.assertEqual('''ImagePos Offset Size Name
169300000000 00000000 00000028 main-section
169400000000 00000000 00000008 fill
169500000008 00000008 00000004 u-boot
16960000000c 0000000c 00000004 section
16970000000c 00000000 00000003 intel-mrc
169800000010 00000010 00000004 u-boot2
169900000014 00000014 0000000c section2
170000000014 00000000 00000008 fill
17010000001c 00000008 00000004 u-boot
170200000020 00000020 00000008 fill2
1703''', map_data)
1704
1705 def testExpandSizeBad(self):
1706 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001707 with test_util.capture_sys_output() as (stdout, stderr):
1708 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001709 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001710 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1711 'expanding entry', str(e.exception))
1712
Simon Glassae7cf032018-09-14 04:57:31 -06001713 def testHash(self):
1714 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001715 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001716 use_real_dtb=True, update_dtb=True)
1717 dtb = fdt.Fdt(out_dtb_fname)
1718 dtb.Scan()
1719 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1720 m = hashlib.sha256()
1721 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001722 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001723
1724 def testHashNoAlgo(self):
1725 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001726 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001727 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1728 'hash node', str(e.exception))
1729
1730 def testHashBadAlgo(self):
1731 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001732 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001733 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1734 str(e.exception))
1735
1736 def testHashSection(self):
1737 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001738 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001739 use_real_dtb=True, update_dtb=True)
1740 dtb = fdt.Fdt(out_dtb_fname)
1741 dtb.Scan()
1742 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1743 m = hashlib.sha256()
1744 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001745 m.update(tools.GetBytes(ord('a'), 16))
1746 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001747
Simon Glass3fb4f422018-09-14 04:57:32 -06001748 def testPackUBootTplMicrocode(self):
1749 """Test that x86 microcode can be handled correctly in TPL
1750
1751 We expect to see the following in the image, in order:
1752 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1753 place
1754 u-boot-tpl.dtb with the microcode removed
1755 the microcode
1756 """
Simon Glass33486662019-05-14 15:53:42 -06001757 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass3fb4f422018-09-14 04:57:32 -06001758 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001759 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06001760 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001761 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1762 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06001763
Simon Glassc64aea52018-09-14 04:57:34 -06001764 def testFmapX86(self):
1765 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001766 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001767 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001768 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001769 self.assertEqual(expected, data[:32])
1770 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1771
1772 self.assertEqual(0x100, fhdr.image_size)
1773
1774 self.assertEqual(0, fentries[0].offset)
1775 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001776 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001777
1778 self.assertEqual(4, fentries[1].offset)
1779 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001780 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001781
1782 self.assertEqual(32, fentries[2].offset)
1783 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1784 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001785 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001786
1787 def testFmapX86Section(self):
1788 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001789 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001790 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001791 self.assertEqual(expected, data[:32])
1792 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1793
1794 self.assertEqual(0x100, fhdr.image_size)
1795
1796 self.assertEqual(0, fentries[0].offset)
1797 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001798 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001799
1800 self.assertEqual(4, fentries[1].offset)
1801 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001802 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001803
1804 self.assertEqual(36, fentries[2].offset)
1805 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1806 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001807 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001808
Simon Glassb1714232018-09-14 04:57:35 -06001809 def testElf(self):
1810 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001811 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001812 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassa899f712019-07-08 13:18:46 -06001813 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1814 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001815 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001816 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001817
Simon Glass0d673792019-07-08 13:18:25 -06001818 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06001819 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001820 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001821 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001822 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001823 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001824
Simon Glasscd817d52018-09-14 04:57:36 -06001825 def testPackOverlapMap(self):
1826 """Test that overlapping regions are detected"""
1827 with test_util.capture_sys_output() as (stdout, stderr):
1828 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001829 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06001830 map_fname = tools.GetOutputFilename('image.map')
1831 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1832 stdout.getvalue())
1833
1834 # We should not get an inmage, but there should be a map file
1835 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1836 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06001837 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06001838 self.assertEqual('''ImagePos Offset Size Name
1839<none> 00000000 00000007 main-section
1840<none> 00000000 00000004 u-boot
1841<none> 00000003 00000004 u-boot-align
1842''', map_data)
1843
Simon Glass0d673792019-07-08 13:18:25 -06001844 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06001845 """Test that an image with an Intel Reference code binary works"""
1846 data = self._DoReadFile('100_intel_refcode.dts')
1847 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1848
Simon Glasseb023b32019-04-25 21:58:39 -06001849 def testSectionOffset(self):
1850 """Tests use of a section with an offset"""
1851 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1852 map=True)
1853 self.assertEqual('''ImagePos Offset Size Name
185400000000 00000000 00000038 main-section
185500000004 00000004 00000010 section@0
185600000004 00000000 00000004 u-boot
185700000018 00000018 00000010 section@1
185800000018 00000000 00000004 u-boot
18590000002c 0000002c 00000004 section@2
18600000002c 00000000 00000004 u-boot
1861''', map_data)
1862 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06001863 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1864 tools.GetBytes(0x21, 12) +
1865 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1866 tools.GetBytes(0x61, 12) +
1867 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1868 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06001869
Simon Glass1de34482019-07-08 13:18:53 -06001870 def testCbfsRaw(self):
1871 """Test base handling of a Coreboot Filesystem (CBFS)
1872
1873 The exact contents of the CBFS is verified by similar tests in
1874 cbfs_util_test.py. The tests here merely check that the files added to
1875 the CBFS can be found in the final image.
1876 """
1877 data = self._DoReadFile('102_cbfs_raw.dts')
1878 size = 0xb0
1879
1880 cbfs = cbfs_util.CbfsReader(data)
1881 self.assertEqual(size, cbfs.rom_size)
1882
1883 self.assertIn('u-boot-dtb', cbfs.files)
1884 cfile = cbfs.files['u-boot-dtb']
1885 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1886
1887 def testCbfsArch(self):
1888 """Test on non-x86 architecture"""
1889 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1890 size = 0x100
1891
1892 cbfs = cbfs_util.CbfsReader(data)
1893 self.assertEqual(size, cbfs.rom_size)
1894
1895 self.assertIn('u-boot-dtb', cbfs.files)
1896 cfile = cbfs.files['u-boot-dtb']
1897 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1898
1899 def testCbfsStage(self):
1900 """Tests handling of a Coreboot Filesystem (CBFS)"""
1901 if not elf.ELF_TOOLS:
1902 self.skipTest('Python elftools not available')
1903 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1904 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1905 size = 0xb0
1906
1907 data = self._DoReadFile('104_cbfs_stage.dts')
1908 cbfs = cbfs_util.CbfsReader(data)
1909 self.assertEqual(size, cbfs.rom_size)
1910
1911 self.assertIn('u-boot', cbfs.files)
1912 cfile = cbfs.files['u-boot']
1913 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1914
1915 def testCbfsRawCompress(self):
1916 """Test handling of compressing raw files"""
1917 self._CheckLz4()
1918 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1919 size = 0x140
1920
1921 cbfs = cbfs_util.CbfsReader(data)
1922 self.assertIn('u-boot', cbfs.files)
1923 cfile = cbfs.files['u-boot']
1924 self.assertEqual(COMPRESS_DATA, cfile.data)
1925
1926 def testCbfsBadArch(self):
1927 """Test handling of a bad architecture"""
1928 with self.assertRaises(ValueError) as e:
1929 self._DoReadFile('106_cbfs_bad_arch.dts')
1930 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1931
1932 def testCbfsNoSize(self):
1933 """Test handling of a missing size property"""
1934 with self.assertRaises(ValueError) as e:
1935 self._DoReadFile('107_cbfs_no_size.dts')
1936 self.assertIn('entry must have a size property', str(e.exception))
1937
1938 def testCbfsNoCOntents(self):
1939 """Test handling of a CBFS entry which does not provide contentsy"""
1940 with self.assertRaises(ValueError) as e:
1941 self._DoReadFile('108_cbfs_no_contents.dts')
1942 self.assertIn('Could not complete processing of contents',
1943 str(e.exception))
1944
1945 def testCbfsBadCompress(self):
1946 """Test handling of a bad architecture"""
1947 with self.assertRaises(ValueError) as e:
1948 self._DoReadFile('109_cbfs_bad_compress.dts')
1949 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1950 str(e.exception))
1951
1952 def testCbfsNamedEntries(self):
1953 """Test handling of named entries"""
1954 data = self._DoReadFile('110_cbfs_name.dts')
1955
1956 cbfs = cbfs_util.CbfsReader(data)
1957 self.assertIn('FRED', cbfs.files)
1958 cfile1 = cbfs.files['FRED']
1959 self.assertEqual(U_BOOT_DATA, cfile1.data)
1960
1961 self.assertIn('hello', cbfs.files)
1962 cfile2 = cbfs.files['hello']
1963 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1964
Simon Glass759af872019-07-08 13:18:54 -06001965 def _SetupIfwi(self, fname):
1966 """Set up to run an IFWI test
1967
1968 Args:
1969 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1970 """
1971 self._SetupSplElf()
1972
1973 # Intel Integrated Firmware Image (IFWI) file
1974 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1975 data = fd.read()
1976 TestFunctional._MakeInputFile(fname,data)
1977
1978 def _CheckIfwi(self, data):
1979 """Check that an image with an IFWI contains the correct output
1980
1981 Args:
1982 data: Conents of output file
1983 """
1984 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1985 if data[:0x1000] != expected_desc:
1986 self.fail('Expected descriptor binary at start of image')
1987
1988 # We expect to find the TPL wil in subpart IBBP entry IBBL
1989 image_fname = tools.GetOutputFilename('image.bin')
1990 tpl_fname = tools.GetOutputFilename('tpl.out')
1991 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
1992 subpart='IBBP', entry_name='IBBL')
1993
1994 tpl_data = tools.ReadFile(tpl_fname)
1995 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
1996
1997 def testPackX86RomIfwi(self):
1998 """Test that an x86 ROM with Integrated Firmware Image can be created"""
1999 self._SetupIfwi('fitimage.bin')
2000 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2001 self._CheckIfwi(data)
2002
2003 def testPackX86RomIfwiNoDesc(self):
2004 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2005 self._SetupIfwi('ifwi.bin')
2006 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2007 self._CheckIfwi(data)
2008
2009 def testPackX86RomIfwiNoData(self):
2010 """Test that an x86 ROM with IFWI handles missing data"""
2011 self._SetupIfwi('ifwi.bin')
2012 with self.assertRaises(ValueError) as e:
2013 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2014 self.assertIn('Could not complete processing of contents',
2015 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002016
Simon Glassc2f1aed2019-07-08 13:18:56 -06002017 def testCbfsOffset(self):
2018 """Test a CBFS with files at particular offsets
2019
2020 Like all CFBS tests, this is just checking the logic that calls
2021 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2022 """
2023 data = self._DoReadFile('114_cbfs_offset.dts')
2024 size = 0x200
2025
2026 cbfs = cbfs_util.CbfsReader(data)
2027 self.assertEqual(size, cbfs.rom_size)
2028
2029 self.assertIn('u-boot', cbfs.files)
2030 cfile = cbfs.files['u-boot']
2031 self.assertEqual(U_BOOT_DATA, cfile.data)
2032 self.assertEqual(0x40, cfile.cbfs_offset)
2033
2034 self.assertIn('u-boot-dtb', cbfs.files)
2035 cfile2 = cbfs.files['u-boot-dtb']
2036 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2037 self.assertEqual(0x140, cfile2.cbfs_offset)
2038
Simon Glass0f621332019-07-08 14:25:27 -06002039 def testFdtmap(self):
2040 """Test an FDT map can be inserted in the image"""
2041 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2042 fdtmap_data = data[len(U_BOOT_DATA):]
2043 magic = fdtmap_data[:8]
2044 self.assertEqual('_FDTMAP_', magic)
2045 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2046
2047 fdt_data = fdtmap_data[16:]
2048 dtb = fdt.Fdt.FromData(fdt_data)
2049 dtb.Scan()
2050 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'],
2051 prefix='/')
2052 self.assertEqual({
2053 'image-pos': 0,
2054 'offset': 0,
2055 'u-boot:offset': 0,
2056 'u-boot:size': len(U_BOOT_DATA),
2057 'u-boot:image-pos': 0,
2058 'fdtmap:image-pos': 4,
2059 'fdtmap:offset': 4,
2060 'fdtmap:size': len(fdtmap_data),
2061 'size': len(data),
2062 }, props)
2063
2064 def testFdtmapNoMatch(self):
2065 """Check handling of an FDT map when the section cannot be found"""
2066 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2067
2068 # Mangle the section name, which should cause a mismatch between the
2069 # correct FDT path and the one expected by the section
2070 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002071 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002072 entries = image.GetEntries()
2073 fdtmap = entries['fdtmap']
2074 with self.assertRaises(ValueError) as e:
2075 fdtmap._GetFdtmap()
2076 self.assertIn("Cannot locate node for path '/binman-suffix'",
2077 str(e.exception))
2078
Simon Glasscec34ba2019-07-08 14:25:28 -06002079 def testFdtmapHeader(self):
2080 """Test an FDT map and image header can be inserted in the image"""
2081 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2082 fdtmap_pos = len(U_BOOT_DATA)
2083 fdtmap_data = data[fdtmap_pos:]
2084 fdt_data = fdtmap_data[16:]
2085 dtb = fdt.Fdt.FromData(fdt_data)
2086 fdt_size = dtb.GetFdtObj().totalsize()
2087 hdr_data = data[-8:]
2088 self.assertEqual('BinM', hdr_data[:4])
2089 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2090 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2091
2092 def testFdtmapHeaderStart(self):
2093 """Test an image header can be inserted at the image start"""
2094 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2095 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2096 hdr_data = data[:8]
2097 self.assertEqual('BinM', hdr_data[:4])
2098 offset = struct.unpack('<I', hdr_data[4:])[0]
2099 self.assertEqual(fdtmap_pos, offset)
2100
2101 def testFdtmapHeaderPos(self):
2102 """Test an image header can be inserted at a chosen position"""
2103 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2104 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2105 hdr_data = data[0x80:0x88]
2106 self.assertEqual('BinM', hdr_data[:4])
2107 offset = struct.unpack('<I', hdr_data[4:])[0]
2108 self.assertEqual(fdtmap_pos, offset)
2109
2110 def testHeaderMissingFdtmap(self):
2111 """Test an image header requires an fdtmap"""
2112 with self.assertRaises(ValueError) as e:
2113 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2114 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2115 str(e.exception))
2116
2117 def testHeaderNoLocation(self):
2118 """Test an image header with a no specified location is detected"""
2119 with self.assertRaises(ValueError) as e:
2120 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2121 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2122 str(e.exception))
2123
Simon Glasse61b6f62019-07-08 14:25:37 -06002124 def testEntryExpand(self):
2125 """Test expanding an entry after it is packed"""
2126 data = self._DoReadFile('121_entry_expand.dts')
2127 self.assertEqual(b'aa', data[:2])
2128 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2129 self.assertEqual(b'aa', data[-2:])
2130
2131 def testEntryExpandBad(self):
2132 """Test expanding an entry after it is packed, twice"""
2133 with self.assertRaises(ValueError) as e:
2134 self._DoReadFile('122_entry_expand_twice.dts')
2135 self.assertIn("Image '/binman': Entries expanded after packing",
2136 str(e.exception))
2137
2138 def testEntryExpandSection(self):
2139 """Test expanding an entry within a section after it is packed"""
2140 data = self._DoReadFile('123_entry_expand_section.dts')
2141 self.assertEqual(b'aa', data[:2])
2142 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2143 self.assertEqual(b'aa', data[-2:])
2144
Simon Glass90d29682019-07-08 14:25:38 -06002145 def testCompressDtb(self):
2146 """Test that compress of device-tree files is supported"""
2147 self._CheckLz4()
2148 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2149 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2150 comp_data = data[len(U_BOOT_DATA):]
2151 orig = self._decompress(comp_data)
2152 dtb = fdt.Fdt.FromData(orig)
2153 dtb.Scan()
2154 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2155 expected = {
2156 'u-boot:size': len(U_BOOT_DATA),
2157 'u-boot-dtb:uncomp-size': len(orig),
2158 'u-boot-dtb:size': len(comp_data),
2159 'size': len(data),
2160 }
2161 self.assertEqual(expected, props)
2162
Simon Glass151bbbf2019-07-08 14:25:41 -06002163 def testCbfsUpdateFdt(self):
2164 """Test that we can update the device tree with CBFS offset/size info"""
2165 self._CheckLz4()
2166 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2167 update_dtb=True)
2168 dtb = fdt.Fdt(out_dtb_fname)
2169 dtb.Scan()
2170 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
2171 'uncomp-size'])
2172 del props['cbfs/u-boot:size']
2173 self.assertEqual({
2174 'offset': 0,
2175 'size': len(data),
2176 'image-pos': 0,
2177 'cbfs:offset': 0,
2178 'cbfs:size': len(data),
2179 'cbfs:image-pos': 0,
2180 'cbfs/u-boot:offset': 0x38,
2181 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2182 'cbfs/u-boot:image-pos': 0x38,
2183 'cbfs/u-boot-dtb:offset': 0xb8,
2184 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2185 'cbfs/u-boot-dtb:image-pos': 0xb8,
2186 }, props)
2187
Simon Glassc2f1aed2019-07-08 13:18:56 -06002188
Simon Glassac599912017-11-12 21:52:22 -07002189if __name__ == "__main__":
2190 unittest.main()