blob: 1c917345f2a343f0ba057cc737ea2023ff1a7d2c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassd5164a72019-07-08 13:18:49 -06009from __future__ import print_function
10
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
14import shutil
15import struct
16import sys
17import tempfile
18import unittest
19
20import binman
Simon Glassac62fba2019-07-08 13:18:53 -060021import cbfs_util
Simon Glass4f443042016-11-25 20:15:52 -070022import cmdline
23import command
24import control
Simon Glass19790632017-11-13 18:55:01 -070025import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060026import fdt
Simon Glass4f443042016-11-25 20:15:52 -070027import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060028import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060029import test_util
Simon Glassc5ac1382019-07-08 13:18:54 -060030import gzip
Simon Glassc55a50f2018-09-14 04:57:19 -060031import state
Simon Glass4f443042016-11-25 20:15:52 -070032import tools
33import tout
34
35# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-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 Glassbb748372018-07-17 13:25:33 -060057TEXT_DATA = 'text'
58TEXT_DATA2 = 'text2'
59TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-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 Glassff5c7e32019-07-08 13:18:42 -060066COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060067REFCODE_DATA = b'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060068
Simon Glass4f443042016-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 Glass4d5994f2017-11-12 21:52:20 -070086 global entry
87 import entry
88
Simon Glass4f443042016-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 Glassb8ef5b62018-07-17 13:25:48 -0600100 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700101 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700102 TestFunctional._MakeInputFile('me.bin', ME_DATA)
103 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600104 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700105 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530106 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700107 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
108 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600109 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
110 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700111 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700112 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
113 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600114 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
115 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700116 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
117 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700118 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700119 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600120 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600121 TestFunctional._MakeInputDir('devkeys')
122 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600123 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700124
Simon Glasse0ff8552016-11-25 20:15:53 -0700125 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600126 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('u-boot', fd.read())
128
129 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600130 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700131 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
132
Simon Glass0a98b282018-09-14 04:57:28 -0600133 shutil.copytree(self.TestFile('files'),
134 os.path.join(self._indir, 'files'))
135
Simon Glass83d73c22018-09-14 04:57:26 -0600136 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
137
Simon Glassac62fba2019-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 Glass4f443042016-11-25 20:15:52 -0700146 @classmethod
147 def tearDownClass(self):
148 """Remove the temporary input directory and its contents"""
Simon Glassd5164a72019-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 Glass4f443042016-11-25 20:15:52 -0700154 self._indir = None
155
Simon Glassd5164a72019-07-08 13:18:49 -0600156 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600157 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600158 toolpath=None, verbosity=None):
Simon Glassd5164a72019-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 Glass8acce602019-07-08 13:18:50 -0600167 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600168 """
169 cls.preserve_indir = preserve_indir
170 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600171 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600172 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600173
Simon Glassac62fba2019-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 Glass4f443042016-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 Glassd5164a72019-07-08 13:18:49 -0600185 if self.preserve_outdirs:
186 print('Preserving output dir: %s' % tools.outdir)
187 else:
188 tools._FinaliseForTest()
Simon Glass4f443042016-11-25 20:15:52 -0700189
Simon Glassb8ef5b62018-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 Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600210 def _DoBinman(self, *argv):
Simon Glass4f443042016-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 Glass53cd5d92019-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 Glass4f443042016-11-25 20:15:52 -0700222
223 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600224 # args.verbosity = tout.DEBUG
225 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700226
Simon Glass53af22a2018-07-17 13:25:32 -0600227 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600228 entry_args=None, images=None, use_real_dtb=False,
229 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700230 """Run binman with a given test file
231
232 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600233 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600234 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600235 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600236 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600237 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600238 entry_args: Dict of entry args to supply to binman
239 key: arg name
240 value: value of that arg
241 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700242 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600243 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700244 if debug:
245 args.append('-D')
Simon Glass53cd5d92019-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 Glass3b0c3822018-06-01 09:38:20 -0600254 if map:
255 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600256 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600257 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600258 if not use_real_dtb:
259 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600260 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600261 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600262 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600263 if images:
264 for image in images:
265 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700266 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700267
268 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-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 Glass7ae5f312018-06-01 09:38:19 -0600276 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700277
278 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600279 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700280 """
Simon Glasse0e62752018-10-01 21:12:41 -0600281 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700282 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600283 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700284 data = fd.read()
285 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600286 tools.FinaliseOutputDir()
287 return data
Simon Glass4f443042016-11-25 20:15:52 -0700288
Simon Glass6ed45ba2018-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 Glass16b8d6b2018-07-06 10:27:42 -0600307 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600308 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600318 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-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 Glass3b0c3822018-06-01 09:38:20 -0600323 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600324 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600325 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700326
327 Returns:
328 Tuple:
329 Resulting image contents
330 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600331 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600332 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700333 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700334 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700335 # Use the compiled test file as the u-boot-dtb input
336 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700337 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-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 Glass4f443042016-11-25 20:15:52 -0700346
347 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600348 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600349 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700350 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600351 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700352
353 # Find the (only) image, read it and return its contents
354 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600355 image_fname = tools.GetOutputFilename('image.bin')
356 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-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 Glass1d0ebf72019-05-14 15:53:42 -0600363 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600364 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700365 finally:
366 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600367 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600368 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700369
Simon Glass3c081312019-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 Glasse0ff8552016-11-25 20:15:53 -0700381 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600382 """Helper function which discards the device-tree binary
383
384 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600385 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-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 Glassea6922e2018-07-17 13:25:27 -0600390
391 Returns:
392 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600393 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700394 return self._DoReadFileDtb(fname, use_real_dtb)[0]
395
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600401 fname: Filename to create
Simon Glass4f443042016-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 Glass0ef87aa2018-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 Glass11ae93e2018-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 Glass1d0ebf72019-05-14 15:53:42 -0600436 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600437 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
438
439 @classmethod
Simon Glass4f443042016-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 Glass1fc62de2019-05-17 22:00:50 -0600453 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600461 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700462 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600463 self.assertEqual(offset, entry.offset)
464 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700465
Simon Glasse0ff8552016-11-25 20:15:53 -0700466 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600467 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700468
469 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600470 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700471
472 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600473 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700474 """
475 return struct.unpack('>L', dtb[4:8])[0]
476
Simon Glass086cec92019-07-08 14:25:27 -0600477 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600478 def AddNode(node, path):
479 if node.name != '/':
480 path += '/' + node.name
Simon Glass086cec92019-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 Glass16b8d6b2018-07-06 10:27:42 -0600486 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600487 AddNode(subnode, path)
488
489 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600490 AddNode(dtb.GetRoot(), '')
491 return tree
492
Simon Glass4f443042016-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 Rini3759df02018-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 Glass4f443042016-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 Glass4f443042016-11-25 20:15:52 -0700524 def testBoard(self):
525 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600526 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700527 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600528 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600534 result = self._DoBinman('build')
Simon Glass4f443042016-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 Glass7ae5f312018-06-01 09:38:19 -0600539 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700540 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600541 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-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 Glass7ae5f312018-06-01 09:38:19 -0600547 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600553 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600560 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600565 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-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 Glass53cd5d92019-07-08 14:25:29 -0600572 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600573 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600579 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700580 self.assertEqual(U_BOOT_DATA, data)
581
Simon Glass7fe91732017-11-13 18:55:00 -0700582 def testSimpleDebug(self):
583 """Test a simple binman run with debugging enabled"""
Simon Glass741f2d62018-10-01 12:22:30 -0600584 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700585
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600591 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-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 Glass1d0ebf72019-05-14 15:53:42 -0600598 with open(fname, 'rb') as fd:
Simon Glass4f443042016-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 Glass1d0ebf72019-05-14 15:53:42 -0600606 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700607 data = fd.read()
608 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600609 self.assertEqual(tools.GetBytes(0, 3), data[:3])
610 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600615 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600621 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700622 self.assertEqual(0, retcode)
623 self.assertIn('image', control.images)
624 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600625 entries = image.GetEntries()
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600631 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600637 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600643 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600650 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700651 self.assertEqual(len(U_BOOT_DATA), entry.size)
652
Simon Glass3ab95982018-08-01 15:22:37 -0600653 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertIn('u-boot-fixed', entries)
655 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600656 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600663 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700664
665 self.assertEqual(0, retcode)
666 self.assertIn('image', control.images)
667 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600668 entries = image.GetEntries()
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600674 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600681 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600687 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600693 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600699 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600708 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600715 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600720 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700721 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600722 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600723 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600729 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600736 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600737 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600744 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600751 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600752 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600757 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600765 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600774 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600775 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600781 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600782 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-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 Glass11ae93e2018-10-01 21:12:47 -0600787 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600788 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600789 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
790 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700791
792 def testImageName(self):
793 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600794 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600806 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700807 self.assertEqual(BLOB_DATA, data)
808
809 def testPackSorted(self):
810 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600811 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600812 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-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 Glass4f443042016-11-25 20:15:52 -0700815
Simon Glass3ab95982018-08-01 15:22:37 -0600816 def testPackZeroOffset(self):
817 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700818 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600819 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600820 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-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 Glass741f2d62018-10-01 12:22:30 -0600826 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700827 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-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 Glass741f2d62018-10-01 12:22:30 -0600832 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600833 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700834 "using end-at-4gb", str(e.exception))
835
Jagdish Gediya94b57db2018-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 Glasse0ff8552016-11-25 20:15:53 -0700844 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600845 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700846 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600847 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600848 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600849 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-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 Glass11ae93e2018-10-01 21:12:47 -0600854 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600855 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-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 Glasse0ff8552016-11-25 20:15:53 -0700858
859 def testPackX86RomMeNoDesc(self):
860 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600861 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700862 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600863 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600864 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
865 str(e.exception))
Simon Glasse0ff8552016-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 Glass741f2d62018-10-01 12:22:30 -0600870 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-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 Glasse0ff8552016-11-25 20:15:53 -0700874
875 def testPackX86RomMe(self):
876 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600877 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glassc5ac1382019-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 Glasse0ff8552016-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 Glass741f2d62018-10-01 12:22:30 -0600885 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-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 Glass741f2d62018-10-01 12:22:30 -0600890 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700891 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
892
Jagdish Gediya9d368f32018-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 Glass736bb0a2018-07-06 10:27:17 -0600899 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-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 Glass736bb0a2018-07-06 10:27:17 -0600905 ucode_second: True if the microsecond entry is second instead of
906 third
Simon Glassadc57012018-07-06 10:27:16 -0600907
908 Returns:
909 Tuple:
910 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600911 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600912 in the above (two 4-byte words)
913 """
Simon Glass6b187df2017-11-12 21:52:27 -0700914 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700915
916 # Now check the device tree has no microcode
Simon Glass736bb0a2018-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 Glasse0ff8552016-11-25 20:15:53 -0700927 fname = tools.GetOutputFilename('test.dtb')
928 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600929 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600930 dtb = fdt.FdtScan(fname)
931 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700932 self.assertTrue(ucode)
933 for node in ucode.subnodes:
934 self.assertFalse(node.props.get('data'))
935
Simon Glasse0ff8552016-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 Glass87722132017-11-12 21:52:26 -0700938 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700939 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
940 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600941 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700942
943 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600944 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700945 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
946 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600947 u_boot = data[:len(nodtb_data)]
948 return u_boot, pos_and_size
Simon Glass6b187df2017-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 Glass741f2d62018-10-01 12:22:30 -0600959 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700960 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600961 self.assertEqual(b'nodtb with microcode' + pos_and_size +
962 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700963
Simon Glass160a7662017-05-27 07:38:26 -0600964 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-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 Glass741f2d62018-10-01 12:22:30 -0600976 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-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 Glass160a7662017-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 Glasse0ff8552016-11-25 20:15:53 -0700987
Simon Glass160a7662017-05-27 07:38:26 -0600988 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600989 # expected offset and size
Simon Glass160a7662017-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 Glassc6c10e72019-05-17 22:00:46 -0600993 self.assertEqual(b'nodtb with microcode' + pos_and_size +
994 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700995
Simon Glass75db0862016-11-25 20:15:55 -0700996 def testPackUbootSingleMicrocode(self):
997 """Test that x86 microcode can be handled correctly with fdt_normal.
998 """
Simon Glass160a7662017-05-27 07:38:26 -0600999 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001000
Simon Glassc49deb82016-11-25 20:15:54 -07001001 def testUBootImg(self):
1002 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001003 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001004 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001009 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001016 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001023 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-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 Glass75db0862016-11-25 20:15:55 -07001030 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001031 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001032 TestFunctional._MakeInputFile('u-boot', fd.read())
1033
1034 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001035 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-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 Glass1d0ebf72019-05-14 15:53:42 -06001041 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001047 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-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 Glass25ac0e62018-06-01 09:38:14 -06001050 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-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 Glass1d0ebf72019-05-14 15:53:42 -06001054 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001055 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001056 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-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 Glasse6d85ff2019-05-14 15:53:47 -06001067 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-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 Glass741f2d62018-10-01 12:22:30 -06001072 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001073 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001074 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001075
1076 def testPackFsp(self):
1077 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001078 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001079 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1080
1081 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001082 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001083 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001084 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001085
1086 def testPackVbt(self):
1087 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001088 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001089 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001090
Simon Glass56509842017-11-12 21:52:25 -07001091 def testSplBssPad(self):
1092 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001093 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001094 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001095 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001096 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1097 data)
Simon Glass56509842017-11-12 21:52:25 -07001098
Simon Glass86af5112018-10-01 21:12:42 -06001099 def testSplBssPadMissing(self):
1100 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001101 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001102 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001103 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001104 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1105 str(e.exception))
1106
Simon Glass87722132017-11-12 21:52:26 -07001107 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001108 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001109 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001110 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1111
Simon Glass736bb0a2018-07-06 10:27:17 -06001112 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1113 """Helper function for microcode tests
Simon Glass6b187df2017-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 Glass736bb0a2018-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 Glass6b187df2017-11-12 21:52:27 -07001125 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001126 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001127 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1128 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001129 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1130 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001131
Simon Glass736bb0a2018-07-06 10:27:17 -06001132 def testPackUbootSplMicrocode(self):
1133 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001134 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-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 Glass741f2d62018-10-01 12:22:30 -06001143 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001144 ucode_second=True)
1145
Simon Glassca4f4ff2017-11-12 21:52:28 -07001146 def testPackMrc(self):
1147 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001148 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001149 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1150
Simon Glass47419ea2017-11-13 18:54:55 -07001151 def testSplDtb(self):
1152 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001153 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001154 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1155
Simon Glass4e6fdbe2017-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 Glass741f2d62018-10-01 12:22:30 -06001158 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001159 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1160
Simon Glass19790632017-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 Glass3ab95982018-08-01 15:22:37 -06001166 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001167
Simon Glass11ae93e2018-10-01 21:12:47 -06001168 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001169 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001170 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-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 Glass19790632017-11-13 18:55:01 -07001174 self.assertEqual(expected, data)
1175
Simon Glassdd57c132018-06-01 09:38:11 -06001176 def testPackUnitAddress(self):
1177 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001178 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001179 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1180
Simon Glass18546952018-06-01 09:38:16 -06001181 def testSections(self):
1182 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001183 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-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 Glass18546952018-06-01 09:38:16 -06001187 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001188
Simon Glass3b0c3822018-06-01 09:38:20 -06001189 def testMap(self):
1190 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001191 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-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 Glass3b0c3822018-06-01 09:38:20 -06001200''', map_data)
1201
Simon Glassc8d48ef2018-06-01 09:38:21 -06001202 def testNamePrefix(self):
1203 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001204 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-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 Glassc8d48ef2018-06-01 09:38:21 -06001211''', map_data)
1212
Simon Glass736bb0a2018-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 Glass741f2d62018-10-01 12:22:30 -06001216 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-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 Glass5c890232018-07-06 10:27:19 -06001221 def testBadChangeSize(self):
1222 """Test that trying to change the size of an entry fails"""
1223 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001224 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-07-06 10:27:19 -06001225 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
Simon Glass5b463fc2019-07-08 14:25:33 -06001226 '1 to 2', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001227
Simon Glass16b8d6b2018-07-06 10:27:42 -06001228 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001229 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001230 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001231 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001232 dtb = fdt.Fdt(out_dtb_fname)
1233 dtb.Scan()
1234 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001235 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001236 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001237 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001238 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001239 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001240 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001241 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001242 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001243 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001244 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001245 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001246 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001247
Simon Glass3ab95982018-08-01 15:22:37 -06001248 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001249 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001250 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001251 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001252 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001253 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001254 'size': 40
1255 }, props)
1256
1257 def testUpdateFdtBad(self):
1258 """Test that we detect when ProcessFdt never completes"""
1259 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001260 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001261 self.assertIn('Could not complete processing of Fdt: remaining '
1262 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001263
Simon Glass53af22a2018-07-17 13:25:32 -06001264 def testEntryArgs(self):
1265 """Test passing arguments to entries from the command line"""
1266 entry_args = {
1267 'test-str-arg': 'test1',
1268 'test-int-arg': '456',
1269 }
Simon Glass741f2d62018-10-01 12:22:30 -06001270 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001271 self.assertIn('image', control.images)
1272 entry = control.images['image'].GetEntries()['_testing']
1273 self.assertEqual('test0', entry.test_str_fdt)
1274 self.assertEqual('test1', entry.test_str_arg)
1275 self.assertEqual(123, entry.test_int_fdt)
1276 self.assertEqual(456, entry.test_int_arg)
1277
1278 def testEntryArgsMissing(self):
1279 """Test missing arguments and properties"""
1280 entry_args = {
1281 'test-int-arg': '456',
1282 }
Simon Glass741f2d62018-10-01 12:22:30 -06001283 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001284 entry = control.images['image'].GetEntries()['_testing']
1285 self.assertEqual('test0', entry.test_str_fdt)
1286 self.assertEqual(None, entry.test_str_arg)
1287 self.assertEqual(None, entry.test_int_fdt)
1288 self.assertEqual(456, entry.test_int_arg)
1289
1290 def testEntryArgsRequired(self):
1291 """Test missing arguments and properties"""
1292 entry_args = {
1293 'test-int-arg': '456',
1294 }
1295 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001296 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001297 self.assertIn("Node '/binman/_testing': Missing required "
1298 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1299 str(e.exception))
1300
1301 def testEntryArgsInvalidFormat(self):
1302 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001303 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1304 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001305 with self.assertRaises(ValueError) as e:
1306 self._DoBinman(*args)
1307 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1308
1309 def testEntryArgsInvalidInteger(self):
1310 """Test that an invalid entry-argument integer is detected"""
1311 entry_args = {
1312 'test-int-arg': 'abc',
1313 }
1314 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001315 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001316 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1317 "'test-int-arg' (value 'abc') to integer",
1318 str(e.exception))
1319
1320 def testEntryArgsInvalidDatatype(self):
1321 """Test that an invalid entry-argument datatype is detected
1322
1323 This test could be written in entry_test.py except that it needs
1324 access to control.entry_args, which seems more than that module should
1325 be able to see.
1326 """
1327 entry_args = {
1328 'test-bad-datatype-arg': '12',
1329 }
1330 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001331 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001332 entry_args=entry_args)
1333 self.assertIn('GetArg() internal error: Unknown data type ',
1334 str(e.exception))
1335
Simon Glassbb748372018-07-17 13:25:33 -06001336 def testText(self):
1337 """Test for a text entry type"""
1338 entry_args = {
1339 'test-id': TEXT_DATA,
1340 'test-id2': TEXT_DATA2,
1341 'test-id3': TEXT_DATA3,
1342 }
Simon Glass741f2d62018-10-01 12:22:30 -06001343 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001344 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001345 expected = (tools.ToBytes(TEXT_DATA) +
1346 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1347 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001348 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001349 self.assertEqual(expected, data)
1350
Simon Glassfd8d1f72018-07-17 13:25:36 -06001351 def testEntryDocs(self):
1352 """Test for creation of entry documentation"""
1353 with test_util.capture_sys_output() as (stdout, stderr):
1354 control.WriteEntryDocs(binman.GetEntryModules())
1355 self.assertTrue(len(stdout.getvalue()) > 0)
1356
1357 def testEntryDocsMissing(self):
1358 """Test handling of missing entry documentation"""
1359 with self.assertRaises(ValueError) as e:
1360 with test_util.capture_sys_output() as (stdout, stderr):
1361 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1362 self.assertIn('Documentation is missing for modules: u_boot',
1363 str(e.exception))
1364
Simon Glass11e36cc2018-07-17 13:25:38 -06001365 def testFmap(self):
1366 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001367 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001368 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001369 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1370 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001371 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001372 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001373 self.assertEqual(1, fhdr.ver_major)
1374 self.assertEqual(0, fhdr.ver_minor)
1375 self.assertEqual(0, fhdr.base)
1376 self.assertEqual(16 + 16 +
1377 fmap_util.FMAP_HEADER_LEN +
1378 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001379 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001380 self.assertEqual(3, fhdr.nareas)
1381 for fentry in fentries:
1382 self.assertEqual(0, fentry.flags)
1383
1384 self.assertEqual(0, fentries[0].offset)
1385 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001386 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001387
1388 self.assertEqual(16, fentries[1].offset)
1389 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001390 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001391
1392 self.assertEqual(32, fentries[2].offset)
1393 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1394 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001395 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001396
Simon Glassec127af2018-07-17 13:25:39 -06001397 def testBlobNamedByArg(self):
1398 """Test we can add a blob with the filename coming from an entry arg"""
1399 entry_args = {
1400 'cros-ec-rw-path': 'ecrw.bin',
1401 }
Simon Glass741f2d62018-10-01 12:22:30 -06001402 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001403 entry_args=entry_args)
1404
Simon Glass3af8e492018-07-17 13:25:40 -06001405 def testFill(self):
1406 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001407 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001408 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001409 self.assertEqual(expected, data)
1410
1411 def testFillNoSize(self):
1412 """Test for an fill entry type with no size"""
1413 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001414 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001415 self.assertIn("'fill' entry must have a size property",
1416 str(e.exception))
1417
Simon Glass0ef87aa2018-07-17 13:25:44 -06001418 def _HandleGbbCommand(self, pipe_list):
1419 """Fake calls to the futility utility"""
1420 if pipe_list[0][0] == 'futility':
1421 fname = pipe_list[0][-1]
1422 # Append our GBB data to the file, which will happen every time the
1423 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001424 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001425 fd.write(GBB_DATA)
1426 return command.CommandResult()
1427
1428 def testGbb(self):
1429 """Test for the Chromium OS Google Binary Block"""
1430 command.test_result = self._HandleGbbCommand
1431 entry_args = {
1432 'keydir': 'devkeys',
1433 'bmpblk': 'bmpblk.bin',
1434 }
Simon Glass741f2d62018-10-01 12:22:30 -06001435 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001436
1437 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001438 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1439 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001440 self.assertEqual(expected, data)
1441
1442 def testGbbTooSmall(self):
1443 """Test for the Chromium OS Google Binary Block being large enough"""
1444 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001445 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001446 self.assertIn("Node '/binman/gbb': GBB is too small",
1447 str(e.exception))
1448
1449 def testGbbNoSize(self):
1450 """Test for the Chromium OS Google Binary Block having a size"""
1451 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001452 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001453 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1454 str(e.exception))
1455
Simon Glass24d0d3c2018-07-17 13:25:47 -06001456 def _HandleVblockCommand(self, pipe_list):
1457 """Fake calls to the futility utility"""
1458 if pipe_list[0][0] == 'futility':
1459 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001460 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001461 fd.write(VBLOCK_DATA)
1462 return command.CommandResult()
1463
1464 def testVblock(self):
1465 """Test for the Chromium OS Verified Boot Block"""
1466 command.test_result = self._HandleVblockCommand
1467 entry_args = {
1468 'keydir': 'devkeys',
1469 }
Simon Glass741f2d62018-10-01 12:22:30 -06001470 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001471 entry_args=entry_args)
1472 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1473 self.assertEqual(expected, data)
1474
1475 def testVblockNoContent(self):
1476 """Test we detect a vblock which has no content to sign"""
1477 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001478 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001479 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1480 'property', str(e.exception))
1481
1482 def testVblockBadPhandle(self):
1483 """Test that we detect a vblock with an invalid phandle in contents"""
1484 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001485 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001486 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1487 '1000', str(e.exception))
1488
1489 def testVblockBadEntry(self):
1490 """Test that we detect an entry that points to a non-entry"""
1491 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001492 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001493 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1494 "'other'", str(e.exception))
1495
Simon Glassb8ef5b62018-07-17 13:25:48 -06001496 def testTpl(self):
1497 """Test that an image with TPL and ots device tree can be created"""
1498 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001499 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001500 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001501 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001502 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1503
Simon Glass15a587c2018-07-17 13:25:51 -06001504 def testUsesPos(self):
1505 """Test that the 'pos' property cannot be used anymore"""
1506 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001507 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001508 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1509 "'pos'", str(e.exception))
1510
Simon Glassd178eab2018-09-14 04:57:08 -06001511 def testFillZero(self):
1512 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001513 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001514 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001515
Simon Glass0b489362018-09-14 04:57:09 -06001516 def testTextMissing(self):
1517 """Test for a text entry type where there is no text"""
1518 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001519 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001520 self.assertIn("Node '/binman/text': No value provided for text label "
1521 "'test-id'", str(e.exception))
1522
Simon Glass35b384c2018-09-14 04:57:10 -06001523 def testPackStart16Tpl(self):
1524 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001525 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001526 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1527
Simon Glass0bfa7b02018-09-14 04:57:12 -06001528 def testSelectImage(self):
1529 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001530 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001531
Simon Glasseb833d82019-04-25 21:58:34 -06001532 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001533 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001534 with test_util.capture_sys_output() as (stdout, stderr):
1535 retcode = self._DoTestFile('006_dual_image.dts',
1536 verbosity=verbosity,
1537 images=['image2'])
1538 self.assertEqual(0, retcode)
1539 if verbosity:
1540 self.assertIn(expected, stdout.getvalue())
1541 else:
1542 self.assertNotIn(expected, stdout.getvalue())
1543
1544 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1545 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001546
Simon Glass6ed45ba2018-09-14 04:57:24 -06001547 def testUpdateFdtAll(self):
1548 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001549 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001550
1551 base_expected = {
1552 'section:image-pos': 0,
1553 'u-boot-tpl-dtb:size': 513,
1554 'u-boot-spl-dtb:size': 513,
1555 'u-boot-spl-dtb:offset': 493,
1556 'image-pos': 0,
1557 'section/u-boot-dtb:image-pos': 0,
1558 'u-boot-spl-dtb:image-pos': 493,
1559 'section/u-boot-dtb:size': 493,
1560 'u-boot-tpl-dtb:image-pos': 1006,
1561 'section/u-boot-dtb:offset': 0,
1562 'section:size': 493,
1563 'offset': 0,
1564 'section:offset': 0,
1565 'u-boot-tpl-dtb:offset': 1006,
1566 'size': 1519
1567 }
1568
1569 # We expect three device-tree files in the output, one after the other.
1570 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1571 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1572 # main U-Boot tree. All three should have the same postions and offset.
1573 start = 0
1574 for item in ['', 'spl', 'tpl']:
1575 dtb = fdt.Fdt.FromData(data[start:])
1576 dtb.Scan()
1577 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1578 'spl', 'tpl'])
1579 expected = dict(base_expected)
1580 if item:
1581 expected[item] = 0
1582 self.assertEqual(expected, props)
1583 start += dtb._fdt_obj.totalsize()
1584
1585 def testUpdateFdtOutput(self):
1586 """Test that output DTB files are updated"""
1587 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001588 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001589 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1590
1591 # Unfortunately, compiling a source file always results in a file
1592 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001593 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001594 # binman as a file called u-boot.dtb. To fix this, copy the file
1595 # over to the expected place.
1596 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1597 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1598 start = 0
1599 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1600 'tpl/u-boot-tpl.dtb.out']:
1601 dtb = fdt.Fdt.FromData(data[start:])
1602 size = dtb._fdt_obj.totalsize()
1603 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1604 outdata = tools.ReadFile(pathname)
1605 name = os.path.split(fname)[0]
1606
1607 if name:
1608 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1609 else:
1610 orig_indata = dtb_data
1611 self.assertNotEqual(outdata, orig_indata,
1612 "Expected output file '%s' be updated" % pathname)
1613 self.assertEqual(outdata, data[start:start + size],
1614 "Expected output file '%s' to match output image" %
1615 pathname)
1616 start += size
1617 finally:
1618 self._ResetDtbs()
1619
Simon Glass83d73c22018-09-14 04:57:26 -06001620 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001621 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001622
1623 def testCompress(self):
1624 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001625 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001626 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001627 use_real_dtb=True, update_dtb=True)
1628 dtb = fdt.Fdt(out_dtb_fname)
1629 dtb.Scan()
1630 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1631 orig = self._decompress(data)
1632 self.assertEquals(COMPRESS_DATA, orig)
1633 expected = {
1634 'blob:uncomp-size': len(COMPRESS_DATA),
1635 'blob:size': len(data),
1636 'size': len(data),
1637 }
1638 self.assertEqual(expected, props)
1639
Simon Glass0a98b282018-09-14 04:57:28 -06001640 def testFiles(self):
1641 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001642 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001643 self.assertEqual(FILES_DATA, data)
1644
1645 def testFilesCompress(self):
1646 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001647 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001648 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001649
1650 image = control.images['image']
1651 entries = image.GetEntries()
1652 files = entries['files']
1653 entries = files._section._entries
1654
Simon Glassc6c10e72019-05-17 22:00:46 -06001655 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001656 for i in range(1, 3):
1657 key = '%d.dat' % i
1658 start = entries[key].image_pos
1659 len = entries[key].size
1660 chunk = data[start:start + len]
1661 orig += self._decompress(chunk)
1662
1663 self.assertEqual(FILES_DATA, orig)
1664
1665 def testFilesMissing(self):
1666 """Test missing files"""
1667 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001668 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001669 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1670 'no files', str(e.exception))
1671
1672 def testFilesNoPattern(self):
1673 """Test missing files"""
1674 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001675 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001676 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1677 str(e.exception))
1678
Simon Glassba64a0b2018-09-14 04:57:29 -06001679 def testExpandSize(self):
1680 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001681 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001682 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001683 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1684 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1685 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1686 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001687 self.assertEqual(expect, data)
1688 self.assertEqual('''ImagePos Offset Size Name
168900000000 00000000 00000028 main-section
169000000000 00000000 00000008 fill
169100000008 00000008 00000004 u-boot
16920000000c 0000000c 00000004 section
16930000000c 00000000 00000003 intel-mrc
169400000010 00000010 00000004 u-boot2
169500000014 00000014 0000000c section2
169600000014 00000000 00000008 fill
16970000001c 00000008 00000004 u-boot
169800000020 00000020 00000008 fill2
1699''', map_data)
1700
1701 def testExpandSizeBad(self):
1702 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001703 with test_util.capture_sys_output() as (stdout, stderr):
1704 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001705 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001706 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1707 'expanding entry', str(e.exception))
1708
Simon Glasse0e5df92018-09-14 04:57:31 -06001709 def testHash(self):
1710 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001711 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001712 use_real_dtb=True, update_dtb=True)
1713 dtb = fdt.Fdt(out_dtb_fname)
1714 dtb.Scan()
1715 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1716 m = hashlib.sha256()
1717 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001718 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001719
1720 def testHashNoAlgo(self):
1721 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001722 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001723 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1724 'hash node', str(e.exception))
1725
1726 def testHashBadAlgo(self):
1727 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001728 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001729 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1730 str(e.exception))
1731
1732 def testHashSection(self):
1733 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001734 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001735 use_real_dtb=True, update_dtb=True)
1736 dtb = fdt.Fdt(out_dtb_fname)
1737 dtb.Scan()
1738 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1739 m = hashlib.sha256()
1740 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001741 m.update(tools.GetBytes(ord('a'), 16))
1742 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001743
Simon Glassf0253632018-09-14 04:57:32 -06001744 def testPackUBootTplMicrocode(self):
1745 """Test that x86 microcode can be handled correctly in TPL
1746
1747 We expect to see the following in the image, in order:
1748 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1749 place
1750 u-boot-tpl.dtb with the microcode removed
1751 the microcode
1752 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001753 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001754 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001755 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001756 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001757 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1758 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001759
Simon Glassf8f8df62018-09-14 04:57:34 -06001760 def testFmapX86(self):
1761 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001762 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001763 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001764 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001765 self.assertEqual(expected, data[:32])
1766 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1767
1768 self.assertEqual(0x100, fhdr.image_size)
1769
1770 self.assertEqual(0, fentries[0].offset)
1771 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001772 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001773
1774 self.assertEqual(4, fentries[1].offset)
1775 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001776 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001777
1778 self.assertEqual(32, fentries[2].offset)
1779 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1780 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001781 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001782
1783 def testFmapX86Section(self):
1784 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001785 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001786 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001787 self.assertEqual(expected, data[:32])
1788 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1789
1790 self.assertEqual(0x100, fhdr.image_size)
1791
1792 self.assertEqual(0, fentries[0].offset)
1793 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001794 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001795
1796 self.assertEqual(4, fentries[1].offset)
1797 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001798 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001799
1800 self.assertEqual(36, fentries[2].offset)
1801 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1802 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001803 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001804
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001805 def testElf(self):
1806 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001807 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001808 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001809 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1810 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001811 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001812 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001813
Simon Glass093d1682019-07-08 13:18:25 -06001814 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001815 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001816 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001817 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001818 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001819 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001820
Simon Glass163ed6c2018-09-14 04:57:36 -06001821 def testPackOverlapMap(self):
1822 """Test that overlapping regions are detected"""
1823 with test_util.capture_sys_output() as (stdout, stderr):
1824 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001825 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001826 map_fname = tools.GetOutputFilename('image.map')
1827 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1828 stdout.getvalue())
1829
1830 # We should not get an inmage, but there should be a map file
1831 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1832 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001833 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001834 self.assertEqual('''ImagePos Offset Size Name
1835<none> 00000000 00000007 main-section
1836<none> 00000000 00000004 u-boot
1837<none> 00000003 00000004 u-boot-align
1838''', map_data)
1839
Simon Glass093d1682019-07-08 13:18:25 -06001840 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001841 """Test that an image with an Intel Reference code binary works"""
1842 data = self._DoReadFile('100_intel_refcode.dts')
1843 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1844
Simon Glass9481c802019-04-25 21:58:39 -06001845 def testSectionOffset(self):
1846 """Tests use of a section with an offset"""
1847 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1848 map=True)
1849 self.assertEqual('''ImagePos Offset Size Name
185000000000 00000000 00000038 main-section
185100000004 00000004 00000010 section@0
185200000004 00000000 00000004 u-boot
185300000018 00000018 00000010 section@1
185400000018 00000000 00000004 u-boot
18550000002c 0000002c 00000004 section@2
18560000002c 00000000 00000004 u-boot
1857''', map_data)
1858 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001859 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1860 tools.GetBytes(0x21, 12) +
1861 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1862 tools.GetBytes(0x61, 12) +
1863 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1864 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001865
Simon Glassac62fba2019-07-08 13:18:53 -06001866 def testCbfsRaw(self):
1867 """Test base handling of a Coreboot Filesystem (CBFS)
1868
1869 The exact contents of the CBFS is verified by similar tests in
1870 cbfs_util_test.py. The tests here merely check that the files added to
1871 the CBFS can be found in the final image.
1872 """
1873 data = self._DoReadFile('102_cbfs_raw.dts')
1874 size = 0xb0
1875
1876 cbfs = cbfs_util.CbfsReader(data)
1877 self.assertEqual(size, cbfs.rom_size)
1878
1879 self.assertIn('u-boot-dtb', cbfs.files)
1880 cfile = cbfs.files['u-boot-dtb']
1881 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1882
1883 def testCbfsArch(self):
1884 """Test on non-x86 architecture"""
1885 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1886 size = 0x100
1887
1888 cbfs = cbfs_util.CbfsReader(data)
1889 self.assertEqual(size, cbfs.rom_size)
1890
1891 self.assertIn('u-boot-dtb', cbfs.files)
1892 cfile = cbfs.files['u-boot-dtb']
1893 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1894
1895 def testCbfsStage(self):
1896 """Tests handling of a Coreboot Filesystem (CBFS)"""
1897 if not elf.ELF_TOOLS:
1898 self.skipTest('Python elftools not available')
1899 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1900 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1901 size = 0xb0
1902
1903 data = self._DoReadFile('104_cbfs_stage.dts')
1904 cbfs = cbfs_util.CbfsReader(data)
1905 self.assertEqual(size, cbfs.rom_size)
1906
1907 self.assertIn('u-boot', cbfs.files)
1908 cfile = cbfs.files['u-boot']
1909 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1910
1911 def testCbfsRawCompress(self):
1912 """Test handling of compressing raw files"""
1913 self._CheckLz4()
1914 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1915 size = 0x140
1916
1917 cbfs = cbfs_util.CbfsReader(data)
1918 self.assertIn('u-boot', cbfs.files)
1919 cfile = cbfs.files['u-boot']
1920 self.assertEqual(COMPRESS_DATA, cfile.data)
1921
1922 def testCbfsBadArch(self):
1923 """Test handling of a bad architecture"""
1924 with self.assertRaises(ValueError) as e:
1925 self._DoReadFile('106_cbfs_bad_arch.dts')
1926 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1927
1928 def testCbfsNoSize(self):
1929 """Test handling of a missing size property"""
1930 with self.assertRaises(ValueError) as e:
1931 self._DoReadFile('107_cbfs_no_size.dts')
1932 self.assertIn('entry must have a size property', str(e.exception))
1933
1934 def testCbfsNoCOntents(self):
1935 """Test handling of a CBFS entry which does not provide contentsy"""
1936 with self.assertRaises(ValueError) as e:
1937 self._DoReadFile('108_cbfs_no_contents.dts')
1938 self.assertIn('Could not complete processing of contents',
1939 str(e.exception))
1940
1941 def testCbfsBadCompress(self):
1942 """Test handling of a bad architecture"""
1943 with self.assertRaises(ValueError) as e:
1944 self._DoReadFile('109_cbfs_bad_compress.dts')
1945 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1946 str(e.exception))
1947
1948 def testCbfsNamedEntries(self):
1949 """Test handling of named entries"""
1950 data = self._DoReadFile('110_cbfs_name.dts')
1951
1952 cbfs = cbfs_util.CbfsReader(data)
1953 self.assertIn('FRED', cbfs.files)
1954 cfile1 = cbfs.files['FRED']
1955 self.assertEqual(U_BOOT_DATA, cfile1.data)
1956
1957 self.assertIn('hello', cbfs.files)
1958 cfile2 = cbfs.files['hello']
1959 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1960
Simon Glassc5ac1382019-07-08 13:18:54 -06001961 def _SetupIfwi(self, fname):
1962 """Set up to run an IFWI test
1963
1964 Args:
1965 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1966 """
1967 self._SetupSplElf()
1968
1969 # Intel Integrated Firmware Image (IFWI) file
1970 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1971 data = fd.read()
1972 TestFunctional._MakeInputFile(fname,data)
1973
1974 def _CheckIfwi(self, data):
1975 """Check that an image with an IFWI contains the correct output
1976
1977 Args:
1978 data: Conents of output file
1979 """
1980 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1981 if data[:0x1000] != expected_desc:
1982 self.fail('Expected descriptor binary at start of image')
1983
1984 # We expect to find the TPL wil in subpart IBBP entry IBBL
1985 image_fname = tools.GetOutputFilename('image.bin')
1986 tpl_fname = tools.GetOutputFilename('tpl.out')
1987 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
1988 subpart='IBBP', entry_name='IBBL')
1989
1990 tpl_data = tools.ReadFile(tpl_fname)
1991 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
1992
1993 def testPackX86RomIfwi(self):
1994 """Test that an x86 ROM with Integrated Firmware Image can be created"""
1995 self._SetupIfwi('fitimage.bin')
1996 data = self._DoReadFile('111_x86-rom-ifwi.dts')
1997 self._CheckIfwi(data)
1998
1999 def testPackX86RomIfwiNoDesc(self):
2000 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2001 self._SetupIfwi('ifwi.bin')
2002 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2003 self._CheckIfwi(data)
2004
2005 def testPackX86RomIfwiNoData(self):
2006 """Test that an x86 ROM with IFWI handles missing data"""
2007 self._SetupIfwi('ifwi.bin')
2008 with self.assertRaises(ValueError) as e:
2009 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2010 self.assertIn('Could not complete processing of contents',
2011 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002012
Simon Glasse073d4e2019-07-08 13:18:56 -06002013 def testCbfsOffset(self):
2014 """Test a CBFS with files at particular offsets
2015
2016 Like all CFBS tests, this is just checking the logic that calls
2017 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2018 """
2019 data = self._DoReadFile('114_cbfs_offset.dts')
2020 size = 0x200
2021
2022 cbfs = cbfs_util.CbfsReader(data)
2023 self.assertEqual(size, cbfs.rom_size)
2024
2025 self.assertIn('u-boot', cbfs.files)
2026 cfile = cbfs.files['u-boot']
2027 self.assertEqual(U_BOOT_DATA, cfile.data)
2028 self.assertEqual(0x40, cfile.cbfs_offset)
2029
2030 self.assertIn('u-boot-dtb', cbfs.files)
2031 cfile2 = cbfs.files['u-boot-dtb']
2032 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2033 self.assertEqual(0x140, cfile2.cbfs_offset)
2034
Simon Glass086cec92019-07-08 14:25:27 -06002035 def testFdtmap(self):
2036 """Test an FDT map can be inserted in the image"""
2037 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2038 fdtmap_data = data[len(U_BOOT_DATA):]
2039 magic = fdtmap_data[:8]
2040 self.assertEqual('_FDTMAP_', magic)
2041 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2042
2043 fdt_data = fdtmap_data[16:]
2044 dtb = fdt.Fdt.FromData(fdt_data)
2045 dtb.Scan()
2046 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'],
2047 prefix='/')
2048 self.assertEqual({
2049 'image-pos': 0,
2050 'offset': 0,
2051 'u-boot:offset': 0,
2052 'u-boot:size': len(U_BOOT_DATA),
2053 'u-boot:image-pos': 0,
2054 'fdtmap:image-pos': 4,
2055 'fdtmap:offset': 4,
2056 'fdtmap:size': len(fdtmap_data),
2057 'size': len(data),
2058 }, props)
2059
2060 def testFdtmapNoMatch(self):
2061 """Check handling of an FDT map when the section cannot be found"""
2062 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2063
2064 # Mangle the section name, which should cause a mismatch between the
2065 # correct FDT path and the one expected by the section
2066 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002067 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002068 entries = image.GetEntries()
2069 fdtmap = entries['fdtmap']
2070 with self.assertRaises(ValueError) as e:
2071 fdtmap._GetFdtmap()
2072 self.assertIn("Cannot locate node for path '/binman-suffix'",
2073 str(e.exception))
2074
Simon Glasscf228942019-07-08 14:25:28 -06002075 def testFdtmapHeader(self):
2076 """Test an FDT map and image header can be inserted in the image"""
2077 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2078 fdtmap_pos = len(U_BOOT_DATA)
2079 fdtmap_data = data[fdtmap_pos:]
2080 fdt_data = fdtmap_data[16:]
2081 dtb = fdt.Fdt.FromData(fdt_data)
2082 fdt_size = dtb.GetFdtObj().totalsize()
2083 hdr_data = data[-8:]
2084 self.assertEqual('BinM', hdr_data[:4])
2085 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2086 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2087
2088 def testFdtmapHeaderStart(self):
2089 """Test an image header can be inserted at the image start"""
2090 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2091 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2092 hdr_data = data[:8]
2093 self.assertEqual('BinM', hdr_data[:4])
2094 offset = struct.unpack('<I', hdr_data[4:])[0]
2095 self.assertEqual(fdtmap_pos, offset)
2096
2097 def testFdtmapHeaderPos(self):
2098 """Test an image header can be inserted at a chosen position"""
2099 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2100 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2101 hdr_data = data[0x80:0x88]
2102 self.assertEqual('BinM', hdr_data[:4])
2103 offset = struct.unpack('<I', hdr_data[4:])[0]
2104 self.assertEqual(fdtmap_pos, offset)
2105
2106 def testHeaderMissingFdtmap(self):
2107 """Test an image header requires an fdtmap"""
2108 with self.assertRaises(ValueError) as e:
2109 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2110 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2111 str(e.exception))
2112
2113 def testHeaderNoLocation(self):
2114 """Test an image header with a no specified location is detected"""
2115 with self.assertRaises(ValueError) as e:
2116 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2117 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2118 str(e.exception))
2119
Simon Glasse073d4e2019-07-08 13:18:56 -06002120
Simon Glass9fc60b42017-11-12 21:52:22 -07002121if __name__ == "__main__":
2122 unittest.main()