blob: 6a40d1fdbb489a24a07a7c69942a089f3e1ab1ed [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 Glasse1925fa2019-07-08 14:25:44 -060027from etype import fdtmap
Simon Glass2d260032019-07-08 14:25:45 -060028from etype import image_header
Simon Glass4f443042016-11-25 20:15:52 -070029import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060030import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060031import test_util
Simon Glassc5ac1382019-07-08 13:18:54 -060032import gzip
Simon Glassffded752019-07-08 14:25:46 -060033from image import Image
Simon Glassc55a50f2018-09-14 04:57:19 -060034import state
Simon Glass4f443042016-11-25 20:15:52 -070035import tools
36import tout
37
38# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
41U_BOOT_SPL_DATA = b'56780123456789abcde'
42U_BOOT_TPL_DATA = b'tpl'
43BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
52PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
53U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
54U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
55U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
56FSP_DATA = b'fsp'
57CMC_DATA = b'cmc'
58VBT_DATA = b'vbt'
59MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060060TEXT_DATA = 'text'
61TEXT_DATA2 = 'text2'
62TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060063CROS_EC_RW_DATA = b'ecrw'
64GBB_DATA = b'gbbd'
65BMPBLK_DATA = b'bmp'
66VBLOCK_DATA = b'vblk'
67FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
68 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060069COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060070REFCODE_DATA = b'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060071
Simon Glassf667e452019-07-08 14:25:50 -060072EXTRACT_DTB_SIZE = 0x3c9
73
Simon Glass4f443042016-11-25 20:15:52 -070074
75class TestFunctional(unittest.TestCase):
76 """Functional tests for binman
77
78 Most of these use a sample .dts file to build an image and then check
79 that it looks correct. The sample files are in the test/ subdirectory
80 and are numbered.
81
82 For each entry type a very small test file is created using fixed
83 string contents. This makes it easy to test that things look right, and
84 debug problems.
85
86 In some cases a 'real' file must be used - these are also supplied in
87 the test/ diurectory.
88 """
89 @classmethod
90 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070091 global entry
92 import entry
93
Simon Glass4f443042016-11-25 20:15:52 -070094 # Handle the case where argv[0] is 'python'
95 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
96 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
97
98 # Create a temporary directory for input files
99 self._indir = tempfile.mkdtemp(prefix='binmant.')
100
101 # Create some test files
102 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
103 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
104 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600105 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700106 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700107 TestFunctional._MakeInputFile('me.bin', ME_DATA)
108 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600109 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700110 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530111 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700112 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
113 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600114 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
115 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700116 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700117 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
118 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600119 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
120 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700121 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
122 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700123 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700124 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600125 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600126 TestFunctional._MakeInputDir('devkeys')
127 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600128 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700129
Simon Glasse0ff8552016-11-25 20:15:53 -0700130 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600131 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700132 TestFunctional._MakeInputFile('u-boot', fd.read())
133
134 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600135 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700136 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
137
Simon Glass0a98b282018-09-14 04:57:28 -0600138 shutil.copytree(self.TestFile('files'),
139 os.path.join(self._indir, 'files'))
140
Simon Glass83d73c22018-09-14 04:57:26 -0600141 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
142
Simon Glassac62fba2019-07-08 13:18:53 -0600143 # Travis-CI may have an old lz4
144 self.have_lz4 = True
145 try:
146 tools.Run('lz4', '--no-frame-crc', '-c',
147 os.path.join(self._indir, 'u-boot.bin'))
148 except:
149 self.have_lz4 = False
150
Simon Glass4f443042016-11-25 20:15:52 -0700151 @classmethod
152 def tearDownClass(self):
153 """Remove the temporary input directory and its contents"""
Simon Glassd5164a72019-07-08 13:18:49 -0600154 if self.preserve_indir:
155 print('Preserving input dir: %s' % self._indir)
156 else:
157 if self._indir:
158 shutil.rmtree(self._indir)
Simon Glass4f443042016-11-25 20:15:52 -0700159 self._indir = None
160
Simon Glassd5164a72019-07-08 13:18:49 -0600161 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600162 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600163 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600164 """Accept arguments controlling test execution
165
166 Args:
167 preserve_indir: Preserve the shared input directory used by all
168 tests in this class.
169 preserve_outdir: Preserve the output directories used by tests. Each
170 test has its own, so this is normally only useful when running a
171 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600172 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600173 """
174 cls.preserve_indir = preserve_indir
175 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600176 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600177 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600178
Simon Glassac62fba2019-07-08 13:18:53 -0600179 def _CheckLz4(self):
180 if not self.have_lz4:
181 self.skipTest('lz4 --no-frame-crc not available')
182
Simon Glass4f443042016-11-25 20:15:52 -0700183 def setUp(self):
184 # Enable this to turn on debugging output
185 # tout.Init(tout.DEBUG)
186 command.test_result = None
187
188 def tearDown(self):
189 """Remove the temporary output directory"""
Simon Glassd5164a72019-07-08 13:18:49 -0600190 if self.preserve_outdirs:
191 print('Preserving output dir: %s' % tools.outdir)
192 else:
193 tools._FinaliseForTest()
Simon Glass4f443042016-11-25 20:15:52 -0700194
Simon Glassb8ef5b62018-07-17 13:25:48 -0600195 @classmethod
196 def _ResetDtbs(self):
197 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
198 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
199 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
200
Simon Glass4f443042016-11-25 20:15:52 -0700201 def _RunBinman(self, *args, **kwargs):
202 """Run binman using the command line
203
204 Args:
205 Arguments to pass, as a list of strings
206 kwargs: Arguments to pass to Command.RunPipe()
207 """
208 result = command.RunPipe([[self._binman_pathname] + list(args)],
209 capture=True, capture_stderr=True, raise_on_error=False)
210 if result.return_code and kwargs.get('raise_on_error', True):
211 raise Exception("Error running '%s': %s" % (' '.join(args),
212 result.stdout + result.stderr))
213 return result
214
Simon Glass53cd5d92019-07-08 14:25:29 -0600215 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700216 """Run binman using directly (in the same process)
217
218 Args:
219 Arguments to pass, as a list of strings
220 Returns:
221 Return value (0 for success)
222 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600223 argv = list(argv)
224 args = cmdline.ParseArgs(argv)
225 args.pager = 'binman-invalid-pager'
226 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700227
228 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600229 # args.verbosity = tout.DEBUG
230 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700231
Simon Glass53af22a2018-07-17 13:25:32 -0600232 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600233 entry_args=None, images=None, use_real_dtb=False,
234 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700235 """Run binman with a given test file
236
237 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600238 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600239 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600240 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600241 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600242 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600243 entry_args: Dict of entry args to supply to binman
244 key: arg name
245 value: value of that arg
246 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700247 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600248 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700249 if debug:
250 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600251 if verbosity is not None:
252 args.append('-v%d' % verbosity)
253 elif self.verbosity:
254 args.append('-v%d' % self.verbosity)
255 if self.toolpath:
256 for path in self.toolpath:
257 args += ['--toolpath', path]
258 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600259 if map:
260 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600261 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600262 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600263 if not use_real_dtb:
264 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600265 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600266 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600267 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600268 if images:
269 for image in images:
270 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700271 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700272
273 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700274 """Set up a new test device-tree file
275
276 The given file is compiled and set up as the device tree to be used
277 for ths test.
278
279 Args:
280 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600281 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700282
283 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600284 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700285 """
Simon Glasse0e62752018-10-01 21:12:41 -0600286 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700287 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600288 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700289 data = fd.read()
290 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600291 tools.FinaliseOutputDir()
292 return data
Simon Glass4f443042016-11-25 20:15:52 -0700293
Simon Glass6ed45ba2018-09-14 04:57:24 -0600294 def _GetDtbContentsForSplTpl(self, dtb_data, name):
295 """Create a version of the main DTB for SPL or SPL
296
297 For testing we don't actually have different versions of the DTB. With
298 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
299 we don't normally have any unwanted nodes.
300
301 We still want the DTBs for SPL and TPL to be different though, since
302 otherwise it is confusing to know which one we are looking at. So add
303 an 'spl' or 'tpl' property to the top-level node.
304 """
305 dtb = fdt.Fdt.FromData(dtb_data)
306 dtb.Scan()
307 dtb.GetNode('/binman').AddZeroProp(name)
308 dtb.Sync(auto_resize=True)
309 dtb.Pack()
310 return dtb.GetContents()
311
Simon Glass16b8d6b2018-07-06 10:27:42 -0600312 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600313 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700314 """Run binman and return the resulting image
315
316 This runs binman with a given test file and then reads the resulting
317 output file. It is a shortcut function since most tests need to do
318 these steps.
319
320 Raises an assertion failure if binman returns a non-zero exit code.
321
322 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600323 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700324 use_real_dtb: True to use the test file as the contents of
325 the u-boot-dtb entry. Normally this is not needed and the
326 test contents (the U_BOOT_DTB_DATA string) can be used.
327 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600328 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600329 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600330 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700331
332 Returns:
333 Tuple:
334 Resulting image contents
335 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600336 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600337 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700338 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700339 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700340 # Use the compiled test file as the u-boot-dtb input
341 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700342 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600343
344 # For testing purposes, make a copy of the DT for SPL and TPL. Add
345 # a node indicating which it is, so aid verification.
346 for name in ['spl', 'tpl']:
347 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
348 outfile = os.path.join(self._indir, dtb_fname)
349 TestFunctional._MakeInputFile(dtb_fname,
350 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700351
352 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600353 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600354 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700355 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600356 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700357
358 # Find the (only) image, read it and return its contents
359 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600360 image_fname = tools.GetOutputFilename('image.bin')
361 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600362 if map:
363 map_fname = tools.GetOutputFilename('image.map')
364 with open(map_fname) as fd:
365 map_data = fd.read()
366 else:
367 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600368 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600369 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700370 finally:
371 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600372 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600373 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700374
Simon Glass3c081312019-07-08 14:25:26 -0600375 def _DoReadFileRealDtb(self, fname):
376 """Run binman with a real .dtb file and return the resulting data
377
378 Args:
379 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
380
381 Returns:
382 Resulting image contents
383 """
384 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
385
Simon Glasse0ff8552016-11-25 20:15:53 -0700386 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600387 """Helper function which discards the device-tree binary
388
389 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600390 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600391 use_real_dtb: True to use the test file as the contents of
392 the u-boot-dtb entry. Normally this is not needed and the
393 test contents (the U_BOOT_DTB_DATA string) can be used.
394 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600395
396 Returns:
397 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600398 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700399 return self._DoReadFileDtb(fname, use_real_dtb)[0]
400
Simon Glass4f443042016-11-25 20:15:52 -0700401 @classmethod
402 def _MakeInputFile(self, fname, contents):
403 """Create a new test input file, creating directories as needed
404
405 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600406 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700407 contents: File contents to write in to the file
408 Returns:
409 Full pathname of file created
410 """
411 pathname = os.path.join(self._indir, fname)
412 dirname = os.path.dirname(pathname)
413 if dirname and not os.path.exists(dirname):
414 os.makedirs(dirname)
415 with open(pathname, 'wb') as fd:
416 fd.write(contents)
417 return pathname
418
419 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600420 def _MakeInputDir(self, dirname):
421 """Create a new test input directory, creating directories as needed
422
423 Args:
424 dirname: Directory name to create
425
426 Returns:
427 Full pathname of directory created
428 """
429 pathname = os.path.join(self._indir, dirname)
430 if not os.path.exists(pathname):
431 os.makedirs(pathname)
432 return pathname
433
434 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600435 def _SetupSplElf(self, src_fname='bss_data'):
436 """Set up an ELF file with a '_dt_ucode_base_size' symbol
437
438 Args:
439 Filename of ELF file to use as SPL
440 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600441 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600442 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
443
444 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700445 def TestFile(self, fname):
446 return os.path.join(self._binman_dir, 'test', fname)
447
448 def AssertInList(self, grep_list, target):
449 """Assert that at least one of a list of things is in a target
450
451 Args:
452 grep_list: List of strings to check
453 target: Target string
454 """
455 for grep in grep_list:
456 if grep in target:
457 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600458 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700459
460 def CheckNoGaps(self, entries):
461 """Check that all entries fit together without gaps
462
463 Args:
464 entries: List of entries to check
465 """
Simon Glass3ab95982018-08-01 15:22:37 -0600466 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700467 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600468 self.assertEqual(offset, entry.offset)
469 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700470
Simon Glasse0ff8552016-11-25 20:15:53 -0700471 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600472 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700473
474 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600475 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700476
477 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600478 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700479 """
480 return struct.unpack('>L', dtb[4:8])[0]
481
Simon Glass086cec92019-07-08 14:25:27 -0600482 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600483 def AddNode(node, path):
484 if node.name != '/':
485 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600486 for prop in node.props.values():
487 if prop.name in prop_names:
488 prop_path = path + ':' + prop.name
489 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
490 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600491 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600492 AddNode(subnode, path)
493
494 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600495 AddNode(dtb.GetRoot(), '')
496 return tree
497
Simon Glass4f443042016-11-25 20:15:52 -0700498 def testRun(self):
499 """Test a basic run with valid args"""
500 result = self._RunBinman('-h')
501
502 def testFullHelp(self):
503 """Test that the full help is displayed with -H"""
504 result = self._RunBinman('-H')
505 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500506 # Remove possible extraneous strings
507 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
508 gothelp = result.stdout.replace(extra, '')
509 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700510 self.assertEqual(0, len(result.stderr))
511 self.assertEqual(0, result.return_code)
512
513 def testFullHelpInternal(self):
514 """Test that the full help is displayed with -H"""
515 try:
516 command.test_result = command.CommandResult()
517 result = self._DoBinman('-H')
518 help_file = os.path.join(self._binman_dir, 'README')
519 finally:
520 command.test_result = None
521
522 def testHelp(self):
523 """Test that the basic help is displayed with -h"""
524 result = self._RunBinman('-h')
525 self.assertTrue(len(result.stdout) > 200)
526 self.assertEqual(0, len(result.stderr))
527 self.assertEqual(0, result.return_code)
528
Simon Glass4f443042016-11-25 20:15:52 -0700529 def testBoard(self):
530 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600531 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700532 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600533 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700534 self.assertEqual(0, result)
535
536 def testNeedBoard(self):
537 """Test that we get an error when no board ius supplied"""
538 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600539 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700540 self.assertIn("Must provide a board to process (use -b <board>)",
541 str(e.exception))
542
543 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600544 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700545 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600546 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700547 # We get one error from libfdt, and a different one from fdtget.
548 self.AssertInList(["Couldn't open blob from 'missing_file'",
549 'No such file or directory'], str(e.exception))
550
551 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600552 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700553
554 Since this is a source file it should be compiled and the error
555 will come from the device-tree compiler (dtc).
556 """
557 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600558 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700559 self.assertIn("FATAL ERROR: Unable to parse input tree",
560 str(e.exception))
561
562 def testMissingNode(self):
563 """Test that a device tree without a 'binman' node generates an error"""
564 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600565 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700566 self.assertIn("does not have a 'binman' node", str(e.exception))
567
568 def testEmpty(self):
569 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600570 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700571 self.assertEqual(0, len(result.stderr))
572 self.assertEqual(0, result.return_code)
573
574 def testInvalidEntry(self):
575 """Test that an invalid entry is flagged"""
576 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600577 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600578 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700579 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
580 "'/binman/not-a-valid-type'", str(e.exception))
581
582 def testSimple(self):
583 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600584 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700585 self.assertEqual(U_BOOT_DATA, data)
586
Simon Glass7fe91732017-11-13 18:55:00 -0700587 def testSimpleDebug(self):
588 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600589 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700590
Simon Glass4f443042016-11-25 20:15:52 -0700591 def testDual(self):
592 """Test that we can handle creating two images
593
594 This also tests image padding.
595 """
Simon Glass741f2d62018-10-01 12:22:30 -0600596 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700597 self.assertEqual(0, retcode)
598
599 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600600 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700601 fname = tools.GetOutputFilename('image1.bin')
602 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600603 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700604 data = fd.read()
605 self.assertEqual(U_BOOT_DATA, data)
606
607 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600608 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700609 fname = tools.GetOutputFilename('image2.bin')
610 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600611 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700612 data = fd.read()
613 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600614 self.assertEqual(tools.GetBytes(0, 3), data[:3])
615 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700616
617 def testBadAlign(self):
618 """Test that an invalid alignment value is detected"""
619 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600620 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700621 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
622 "of two", str(e.exception))
623
624 def testPackSimple(self):
625 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600626 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700627 self.assertEqual(0, retcode)
628 self.assertIn('image', control.images)
629 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600630 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700631 self.assertEqual(5, len(entries))
632
633 # First u-boot
634 self.assertIn('u-boot', entries)
635 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600636 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700637 self.assertEqual(len(U_BOOT_DATA), entry.size)
638
639 # Second u-boot, aligned to 16-byte boundary
640 self.assertIn('u-boot-align', entries)
641 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600642 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700643 self.assertEqual(len(U_BOOT_DATA), entry.size)
644
645 # Third u-boot, size 23 bytes
646 self.assertIn('u-boot-size', entries)
647 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600648 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700649 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
650 self.assertEqual(23, entry.size)
651
652 # Fourth u-boot, placed immediate after the above
653 self.assertIn('u-boot-next', entries)
654 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600655 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700656 self.assertEqual(len(U_BOOT_DATA), entry.size)
657
Simon Glass3ab95982018-08-01 15:22:37 -0600658 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700659 self.assertIn('u-boot-fixed', entries)
660 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600661 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700662 self.assertEqual(len(U_BOOT_DATA), entry.size)
663
Simon Glass8beb11e2019-07-08 14:25:47 -0600664 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700665
666 def testPackExtra(self):
667 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600668 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700669
670 self.assertEqual(0, retcode)
671 self.assertIn('image', control.images)
672 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600673 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700674 self.assertEqual(5, len(entries))
675
676 # First u-boot with padding before and after
677 self.assertIn('u-boot', entries)
678 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600679 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700680 self.assertEqual(3, entry.pad_before)
681 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
682
683 # Second u-boot has an aligned size, but it has no effect
684 self.assertIn('u-boot-align-size-nop', entries)
685 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600686 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700687 self.assertEqual(4, entry.size)
688
689 # Third u-boot has an aligned size too
690 self.assertIn('u-boot-align-size', entries)
691 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600692 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700693 self.assertEqual(32, entry.size)
694
695 # Fourth u-boot has an aligned end
696 self.assertIn('u-boot-align-end', entries)
697 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600698 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700699 self.assertEqual(16, entry.size)
700
701 # Fifth u-boot immediately afterwards
702 self.assertIn('u-boot-align-both', entries)
703 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600704 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700705 self.assertEqual(64, entry.size)
706
707 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600708 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700709
710 def testPackAlignPowerOf2(self):
711 """Test that invalid entry alignment is detected"""
712 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600713 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700714 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
715 "of two", str(e.exception))
716
717 def testPackAlignSizePowerOf2(self):
718 """Test that invalid entry size alignment is detected"""
719 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600720 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700721 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
722 "power of two", str(e.exception))
723
724 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600725 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700726 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600727 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600728 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700729 "align 0x4 (4)", str(e.exception))
730
731 def testPackInvalidSizeAlign(self):
732 """Test that invalid entry size alignment is detected"""
733 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600734 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700735 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
736 "align-size 0x4 (4)", str(e.exception))
737
738 def testPackOverlap(self):
739 """Test that overlapping regions are detected"""
740 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600741 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600742 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700743 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
744 str(e.exception))
745
746 def testPackEntryOverflow(self):
747 """Test that entries that overflow their size are detected"""
748 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600749 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700750 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
751 "but entry size is 0x3 (3)", str(e.exception))
752
753 def testPackImageOverflow(self):
754 """Test that entries which overflow the image size are detected"""
755 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600756 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600757 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700758 "size 0x3 (3)", str(e.exception))
759
760 def testPackImageSize(self):
761 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600762 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700763 self.assertEqual(0, retcode)
764 self.assertIn('image', control.images)
765 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600766 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700767
768 def testPackImageSizeAlign(self):
769 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600770 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700771 self.assertEqual(0, retcode)
772 self.assertIn('image', control.images)
773 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600774 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700775
776 def testPackInvalidImageAlign(self):
777 """Test that invalid image alignment is detected"""
778 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600779 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600780 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700781 "align-size 0x8 (8)", str(e.exception))
782
783 def testPackAlignPowerOf2(self):
784 """Test that invalid image alignment is detected"""
785 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600786 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600787 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700788 "two", str(e.exception))
789
790 def testImagePadByte(self):
791 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600792 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600793 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600794 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
795 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700796
797 def testImageName(self):
798 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600799 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700800 self.assertEqual(0, retcode)
801 image = control.images['image1']
802 fname = tools.GetOutputFilename('test-name')
803 self.assertTrue(os.path.exists(fname))
804
805 image = control.images['image2']
806 fname = tools.GetOutputFilename('test-name.xx')
807 self.assertTrue(os.path.exists(fname))
808
809 def testBlobFilename(self):
810 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600811 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700812 self.assertEqual(BLOB_DATA, data)
813
814 def testPackSorted(self):
815 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600816 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600817 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600818 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
819 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700820
Simon Glass3ab95982018-08-01 15:22:37 -0600821 def testPackZeroOffset(self):
822 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700823 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600824 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600825 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700826 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
827 str(e.exception))
828
829 def testPackUbootDtb(self):
830 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600831 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700832 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700833
834 def testPackX86RomNoSize(self):
835 """Test that the end-at-4gb property requires a size property"""
836 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600837 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600838 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700839 "using end-at-4gb", str(e.exception))
840
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530841 def test4gbAndSkipAtStartTogether(self):
842 """Test that the end-at-4gb and skip-at-size property can't be used
843 together"""
844 with self.assertRaises(ValueError) as e:
845 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600846 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530847 "'skip-at-start'", str(e.exception))
848
Simon Glasse0ff8552016-11-25 20:15:53 -0700849 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600850 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700851 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600852 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600853 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600854 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700855 str(e.exception))
856
857 def testPackX86Rom(self):
858 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600859 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600860 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600861 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
862 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700863
864 def testPackX86RomMeNoDesc(self):
865 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600866 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700867 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600868 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600869 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
870 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700871
872 def testPackX86RomBadDesc(self):
873 """Test that the Intel requires a descriptor entry"""
874 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600875 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600876 self.assertIn("Node '/binman/intel-me': No offset set with "
877 "offset-unset: should another entry provide this correct "
878 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700879
880 def testPackX86RomMe(self):
881 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600882 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600883 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
884 if data[:0x1000] != expected_desc:
885 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700886 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
887
888 def testPackVga(self):
889 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600890 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700891 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
892
893 def testPackStart16(self):
894 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600895 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700896 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
897
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530898 def testPackPowerpcMpc85xxBootpgResetvec(self):
899 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
900 created"""
901 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
902 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
903
Simon Glass736bb0a2018-07-06 10:27:17 -0600904 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600905 """Handle running a test for insertion of microcode
906
907 Args:
908 dts_fname: Name of test .dts file
909 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600910 ucode_second: True if the microsecond entry is second instead of
911 third
Simon Glassadc57012018-07-06 10:27:16 -0600912
913 Returns:
914 Tuple:
915 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600916 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600917 in the above (two 4-byte words)
918 """
Simon Glass6b187df2017-11-12 21:52:27 -0700919 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700920
921 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600922 if ucode_second:
923 ucode_content = data[len(nodtb_data):]
924 ucode_pos = len(nodtb_data)
925 dtb_with_ucode = ucode_content[16:]
926 fdt_len = self.GetFdtLen(dtb_with_ucode)
927 else:
928 dtb_with_ucode = data[len(nodtb_data):]
929 fdt_len = self.GetFdtLen(dtb_with_ucode)
930 ucode_content = dtb_with_ucode[fdt_len:]
931 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700932 fname = tools.GetOutputFilename('test.dtb')
933 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600934 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600935 dtb = fdt.FdtScan(fname)
936 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700937 self.assertTrue(ucode)
938 for node in ucode.subnodes:
939 self.assertFalse(node.props.get('data'))
940
Simon Glasse0ff8552016-11-25 20:15:53 -0700941 # Check that the microcode appears immediately after the Fdt
942 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700943 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700944 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
945 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600946 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700947
948 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600949 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700950 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
951 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600952 u_boot = data[:len(nodtb_data)]
953 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700954
955 def testPackUbootMicrocode(self):
956 """Test that x86 microcode can be handled correctly
957
958 We expect to see the following in the image, in order:
959 u-boot-nodtb.bin with a microcode pointer inserted at the correct
960 place
961 u-boot.dtb with the microcode removed
962 the microcode
963 """
Simon Glass741f2d62018-10-01 12:22:30 -0600964 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700965 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600966 self.assertEqual(b'nodtb with microcode' + pos_and_size +
967 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700968
Simon Glass160a7662017-05-27 07:38:26 -0600969 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700970 """Test that x86 microcode can be handled correctly
971
972 We expect to see the following in the image, in order:
973 u-boot-nodtb.bin with a microcode pointer inserted at the correct
974 place
975 u-boot.dtb with the microcode
976 an empty microcode region
977 """
978 # We need the libfdt library to run this test since only that allows
979 # finding the offset of a property. This is required by
980 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600981 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700982
983 second = data[len(U_BOOT_NODTB_DATA):]
984
985 fdt_len = self.GetFdtLen(second)
986 third = second[fdt_len:]
987 second = second[:fdt_len]
988
Simon Glass160a7662017-05-27 07:38:26 -0600989 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
990 self.assertIn(ucode_data, second)
991 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700992
Simon Glass160a7662017-05-27 07:38:26 -0600993 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600994 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600995 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
996 len(ucode_data))
997 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -0600998 self.assertEqual(b'nodtb with microcode' + pos_and_size +
999 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001000
Simon Glass75db0862016-11-25 20:15:55 -07001001 def testPackUbootSingleMicrocode(self):
1002 """Test that x86 microcode can be handled correctly with fdt_normal.
1003 """
Simon Glass160a7662017-05-27 07:38:26 -06001004 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001005
Simon Glassc49deb82016-11-25 20:15:54 -07001006 def testUBootImg(self):
1007 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001008 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001009 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001010
1011 def testNoMicrocode(self):
1012 """Test that a missing microcode region is detected"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001014 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001015 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1016 "node found in ", str(e.exception))
1017
1018 def testMicrocodeWithoutNode(self):
1019 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1020 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001021 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001022 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1023 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1024
1025 def testMicrocodeWithoutNode2(self):
1026 """Test that a missing u-boot-ucode node is detected"""
1027 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001028 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001029 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1030 "microcode region u-boot-ucode", str(e.exception))
1031
1032 def testMicrocodeWithoutPtrInElf(self):
1033 """Test that a U-Boot binary without the microcode symbol is detected"""
1034 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001035 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001036 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001037 TestFunctional._MakeInputFile('u-boot', fd.read())
1038
1039 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001040 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001041 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1042 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1043
1044 finally:
1045 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -06001046 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001047 TestFunctional._MakeInputFile('u-boot', fd.read())
1048
1049 def testMicrocodeNotInImage(self):
1050 """Test that microcode must be placed within the image"""
1051 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001052 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001053 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1054 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001055 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001056
1057 def testWithoutMicrocode(self):
1058 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001059 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001060 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001061 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001062
1063 # Now check the device tree has no microcode
1064 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1065 second = data[len(U_BOOT_NODTB_DATA):]
1066
1067 fdt_len = self.GetFdtLen(second)
1068 self.assertEqual(dtb, second[:fdt_len])
1069
1070 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1071 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001072 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001073
1074 def testUnknownPosSize(self):
1075 """Test that microcode must be placed within the image"""
1076 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001077 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001078 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001079 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001080
1081 def testPackFsp(self):
1082 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001083 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001084 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1085
1086 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001087 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001088 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001089 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001090
1091 def testPackVbt(self):
1092 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001093 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001094 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001095
Simon Glass56509842017-11-12 21:52:25 -07001096 def testSplBssPad(self):
1097 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001098 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001099 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001100 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001101 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1102 data)
Simon Glass56509842017-11-12 21:52:25 -07001103
Simon Glass86af5112018-10-01 21:12:42 -06001104 def testSplBssPadMissing(self):
1105 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001106 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001107 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001108 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001109 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1110 str(e.exception))
1111
Simon Glass87722132017-11-12 21:52:26 -07001112 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001113 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001114 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001115 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1116
Simon Glass736bb0a2018-07-06 10:27:17 -06001117 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1118 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001119
1120 We expect to see the following in the image, in order:
1121 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1122 correct place
1123 u-boot.dtb with the microcode removed
1124 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001125
1126 Args:
1127 dts: Device tree file to use for test
1128 ucode_second: True if the microsecond entry is second instead of
1129 third
Simon Glass6b187df2017-11-12 21:52:27 -07001130 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001131 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001132 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1133 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001134 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1135 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001136
Simon Glass736bb0a2018-07-06 10:27:17 -06001137 def testPackUbootSplMicrocode(self):
1138 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001139 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001140
1141 def testPackUbootSplMicrocodeReorder(self):
1142 """Test that order doesn't matter for microcode entries
1143
1144 This is the same as testPackUbootSplMicrocode but when we process the
1145 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1146 entry, so we reply on binman to try later.
1147 """
Simon Glass741f2d62018-10-01 12:22:30 -06001148 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001149 ucode_second=True)
1150
Simon Glassca4f4ff2017-11-12 21:52:28 -07001151 def testPackMrc(self):
1152 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001153 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001154 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1155
Simon Glass47419ea2017-11-13 18:54:55 -07001156 def testSplDtb(self):
1157 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001158 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001159 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1160
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001161 def testSplNoDtb(self):
1162 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001163 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001164 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1165
Simon Glass19790632017-11-13 18:55:01 -07001166 def testSymbols(self):
1167 """Test binman can assign symbols embedded in U-Boot"""
1168 elf_fname = self.TestFile('u_boot_binman_syms')
1169 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1170 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001171 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001172
Simon Glass11ae93e2018-10-01 21:12:47 -06001173 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001174 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001175 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001176 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1177 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1178 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001179 self.assertEqual(expected, data)
1180
Simon Glassdd57c132018-06-01 09:38:11 -06001181 def testPackUnitAddress(self):
1182 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001183 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001184 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1185
Simon Glass18546952018-06-01 09:38:16 -06001186 def testSections(self):
1187 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001188 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001189 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1190 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1191 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001192 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001193
Simon Glass3b0c3822018-06-01 09:38:20 -06001194 def testMap(self):
1195 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001196 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001197 self.assertEqual('''ImagePos Offset Size Name
119800000000 00000000 00000028 main-section
119900000000 00000000 00000010 section@0
120000000000 00000000 00000004 u-boot
120100000010 00000010 00000010 section@1
120200000010 00000000 00000004 u-boot
120300000020 00000020 00000004 section@2
120400000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001205''', map_data)
1206
Simon Glassc8d48ef2018-06-01 09:38:21 -06001207 def testNamePrefix(self):
1208 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001209 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001210 self.assertEqual('''ImagePos Offset Size Name
121100000000 00000000 00000028 main-section
121200000000 00000000 00000010 section@0
121300000000 00000000 00000004 ro-u-boot
121400000010 00000010 00000010 section@1
121500000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001216''', map_data)
1217
Simon Glass736bb0a2018-07-06 10:27:17 -06001218 def testUnknownContents(self):
1219 """Test that obtaining the contents works as expected"""
1220 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001221 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001222 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass736bb0a2018-07-06 10:27:17 -06001223 "processing of contents: remaining [<_testing.Entry__testing ",
1224 str(e.exception))
1225
Simon Glass5c890232018-07-06 10:27:19 -06001226 def testBadChangeSize(self):
1227 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001228 try:
1229 state.SetAllowEntryExpansion(False)
1230 with self.assertRaises(ValueError) as e:
1231 self._DoReadFile('059_change_size.dts', True)
1232 self.assertIn("Node '/binman/_testing': Cannot update entry size from 1 to 2",
1233 str(e.exception))
1234 finally:
1235 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001236
Simon Glass16b8d6b2018-07-06 10:27:42 -06001237 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001238 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001239 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001240 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001241 dtb = fdt.Fdt(out_dtb_fname)
1242 dtb.Scan()
1243 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001244 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001245 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001246 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001247 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001248 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001249 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001250 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001251 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001252 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001253 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001254 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001255 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001256
Simon Glass3ab95982018-08-01 15:22:37 -06001257 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001258 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001259 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001260 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001261 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001262 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001263 'size': 40
1264 }, props)
1265
1266 def testUpdateFdtBad(self):
1267 """Test that we detect when ProcessFdt never completes"""
1268 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001269 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001270 self.assertIn('Could not complete processing of Fdt: remaining '
1271 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001272
Simon Glass53af22a2018-07-17 13:25:32 -06001273 def testEntryArgs(self):
1274 """Test passing arguments to entries from the command line"""
1275 entry_args = {
1276 'test-str-arg': 'test1',
1277 'test-int-arg': '456',
1278 }
Simon Glass741f2d62018-10-01 12:22:30 -06001279 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001280 self.assertIn('image', control.images)
1281 entry = control.images['image'].GetEntries()['_testing']
1282 self.assertEqual('test0', entry.test_str_fdt)
1283 self.assertEqual('test1', entry.test_str_arg)
1284 self.assertEqual(123, entry.test_int_fdt)
1285 self.assertEqual(456, entry.test_int_arg)
1286
1287 def testEntryArgsMissing(self):
1288 """Test missing arguments and properties"""
1289 entry_args = {
1290 'test-int-arg': '456',
1291 }
Simon Glass741f2d62018-10-01 12:22:30 -06001292 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001293 entry = control.images['image'].GetEntries()['_testing']
1294 self.assertEqual('test0', entry.test_str_fdt)
1295 self.assertEqual(None, entry.test_str_arg)
1296 self.assertEqual(None, entry.test_int_fdt)
1297 self.assertEqual(456, entry.test_int_arg)
1298
1299 def testEntryArgsRequired(self):
1300 """Test missing arguments and properties"""
1301 entry_args = {
1302 'test-int-arg': '456',
1303 }
1304 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001305 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001306 self.assertIn("Node '/binman/_testing': Missing required "
1307 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1308 str(e.exception))
1309
1310 def testEntryArgsInvalidFormat(self):
1311 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001312 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1313 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001314 with self.assertRaises(ValueError) as e:
1315 self._DoBinman(*args)
1316 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1317
1318 def testEntryArgsInvalidInteger(self):
1319 """Test that an invalid entry-argument integer is detected"""
1320 entry_args = {
1321 'test-int-arg': 'abc',
1322 }
1323 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001324 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001325 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1326 "'test-int-arg' (value 'abc') to integer",
1327 str(e.exception))
1328
1329 def testEntryArgsInvalidDatatype(self):
1330 """Test that an invalid entry-argument datatype is detected
1331
1332 This test could be written in entry_test.py except that it needs
1333 access to control.entry_args, which seems more than that module should
1334 be able to see.
1335 """
1336 entry_args = {
1337 'test-bad-datatype-arg': '12',
1338 }
1339 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001340 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001341 entry_args=entry_args)
1342 self.assertIn('GetArg() internal error: Unknown data type ',
1343 str(e.exception))
1344
Simon Glassbb748372018-07-17 13:25:33 -06001345 def testText(self):
1346 """Test for a text entry type"""
1347 entry_args = {
1348 'test-id': TEXT_DATA,
1349 'test-id2': TEXT_DATA2,
1350 'test-id3': TEXT_DATA3,
1351 }
Simon Glass741f2d62018-10-01 12:22:30 -06001352 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001353 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001354 expected = (tools.ToBytes(TEXT_DATA) +
1355 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1356 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001357 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001358 self.assertEqual(expected, data)
1359
Simon Glassfd8d1f72018-07-17 13:25:36 -06001360 def testEntryDocs(self):
1361 """Test for creation of entry documentation"""
1362 with test_util.capture_sys_output() as (stdout, stderr):
1363 control.WriteEntryDocs(binman.GetEntryModules())
1364 self.assertTrue(len(stdout.getvalue()) > 0)
1365
1366 def testEntryDocsMissing(self):
1367 """Test handling of missing entry documentation"""
1368 with self.assertRaises(ValueError) as e:
1369 with test_util.capture_sys_output() as (stdout, stderr):
1370 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1371 self.assertIn('Documentation is missing for modules: u_boot',
1372 str(e.exception))
1373
Simon Glass11e36cc2018-07-17 13:25:38 -06001374 def testFmap(self):
1375 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001376 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001377 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001378 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1379 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001380 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001381 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001382 self.assertEqual(1, fhdr.ver_major)
1383 self.assertEqual(0, fhdr.ver_minor)
1384 self.assertEqual(0, fhdr.base)
1385 self.assertEqual(16 + 16 +
1386 fmap_util.FMAP_HEADER_LEN +
1387 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001388 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001389 self.assertEqual(3, fhdr.nareas)
1390 for fentry in fentries:
1391 self.assertEqual(0, fentry.flags)
1392
1393 self.assertEqual(0, fentries[0].offset)
1394 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001395 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001396
1397 self.assertEqual(16, fentries[1].offset)
1398 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001399 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001400
1401 self.assertEqual(32, fentries[2].offset)
1402 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1403 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001404 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001405
Simon Glassec127af2018-07-17 13:25:39 -06001406 def testBlobNamedByArg(self):
1407 """Test we can add a blob with the filename coming from an entry arg"""
1408 entry_args = {
1409 'cros-ec-rw-path': 'ecrw.bin',
1410 }
Simon Glass741f2d62018-10-01 12:22:30 -06001411 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001412 entry_args=entry_args)
1413
Simon Glass3af8e492018-07-17 13:25:40 -06001414 def testFill(self):
1415 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001416 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001417 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001418 self.assertEqual(expected, data)
1419
1420 def testFillNoSize(self):
1421 """Test for an fill entry type with no size"""
1422 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001423 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001424 self.assertIn("'fill' entry must have a size property",
1425 str(e.exception))
1426
Simon Glass0ef87aa2018-07-17 13:25:44 -06001427 def _HandleGbbCommand(self, pipe_list):
1428 """Fake calls to the futility utility"""
1429 if pipe_list[0][0] == 'futility':
1430 fname = pipe_list[0][-1]
1431 # Append our GBB data to the file, which will happen every time the
1432 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001433 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001434 fd.write(GBB_DATA)
1435 return command.CommandResult()
1436
1437 def testGbb(self):
1438 """Test for the Chromium OS Google Binary Block"""
1439 command.test_result = self._HandleGbbCommand
1440 entry_args = {
1441 'keydir': 'devkeys',
1442 'bmpblk': 'bmpblk.bin',
1443 }
Simon Glass741f2d62018-10-01 12:22:30 -06001444 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001445
1446 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001447 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1448 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001449 self.assertEqual(expected, data)
1450
1451 def testGbbTooSmall(self):
1452 """Test for the Chromium OS Google Binary Block being large enough"""
1453 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001454 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001455 self.assertIn("Node '/binman/gbb': GBB is too small",
1456 str(e.exception))
1457
1458 def testGbbNoSize(self):
1459 """Test for the Chromium OS Google Binary Block having a size"""
1460 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001461 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001462 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1463 str(e.exception))
1464
Simon Glass24d0d3c2018-07-17 13:25:47 -06001465 def _HandleVblockCommand(self, pipe_list):
1466 """Fake calls to the futility utility"""
1467 if pipe_list[0][0] == 'futility':
1468 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001469 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001470 fd.write(VBLOCK_DATA)
1471 return command.CommandResult()
1472
1473 def testVblock(self):
1474 """Test for the Chromium OS Verified Boot Block"""
1475 command.test_result = self._HandleVblockCommand
1476 entry_args = {
1477 'keydir': 'devkeys',
1478 }
Simon Glass741f2d62018-10-01 12:22:30 -06001479 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001480 entry_args=entry_args)
1481 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1482 self.assertEqual(expected, data)
1483
1484 def testVblockNoContent(self):
1485 """Test we detect a vblock which has no content to sign"""
1486 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001487 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001488 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1489 'property', str(e.exception))
1490
1491 def testVblockBadPhandle(self):
1492 """Test that we detect a vblock with an invalid phandle in contents"""
1493 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001494 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001495 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1496 '1000', str(e.exception))
1497
1498 def testVblockBadEntry(self):
1499 """Test that we detect an entry that points to a non-entry"""
1500 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001501 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001502 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1503 "'other'", str(e.exception))
1504
Simon Glassb8ef5b62018-07-17 13:25:48 -06001505 def testTpl(self):
1506 """Test that an image with TPL and ots device tree can be created"""
1507 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001508 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001509 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001510 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001511 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1512
Simon Glass15a587c2018-07-17 13:25:51 -06001513 def testUsesPos(self):
1514 """Test that the 'pos' property cannot be used anymore"""
1515 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001516 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001517 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1518 "'pos'", str(e.exception))
1519
Simon Glassd178eab2018-09-14 04:57:08 -06001520 def testFillZero(self):
1521 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001522 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001523 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001524
Simon Glass0b489362018-09-14 04:57:09 -06001525 def testTextMissing(self):
1526 """Test for a text entry type where there is no text"""
1527 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001528 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001529 self.assertIn("Node '/binman/text': No value provided for text label "
1530 "'test-id'", str(e.exception))
1531
Simon Glass35b384c2018-09-14 04:57:10 -06001532 def testPackStart16Tpl(self):
1533 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001534 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001535 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1536
Simon Glass0bfa7b02018-09-14 04:57:12 -06001537 def testSelectImage(self):
1538 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001539 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001540
Simon Glasseb833d82019-04-25 21:58:34 -06001541 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001542 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001543 with test_util.capture_sys_output() as (stdout, stderr):
1544 retcode = self._DoTestFile('006_dual_image.dts',
1545 verbosity=verbosity,
1546 images=['image2'])
1547 self.assertEqual(0, retcode)
1548 if verbosity:
1549 self.assertIn(expected, stdout.getvalue())
1550 else:
1551 self.assertNotIn(expected, stdout.getvalue())
1552
1553 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1554 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001555
Simon Glass6ed45ba2018-09-14 04:57:24 -06001556 def testUpdateFdtAll(self):
1557 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001558 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001559
1560 base_expected = {
1561 'section:image-pos': 0,
1562 'u-boot-tpl-dtb:size': 513,
1563 'u-boot-spl-dtb:size': 513,
1564 'u-boot-spl-dtb:offset': 493,
1565 'image-pos': 0,
1566 'section/u-boot-dtb:image-pos': 0,
1567 'u-boot-spl-dtb:image-pos': 493,
1568 'section/u-boot-dtb:size': 493,
1569 'u-boot-tpl-dtb:image-pos': 1006,
1570 'section/u-boot-dtb:offset': 0,
1571 'section:size': 493,
1572 'offset': 0,
1573 'section:offset': 0,
1574 'u-boot-tpl-dtb:offset': 1006,
1575 'size': 1519
1576 }
1577
1578 # We expect three device-tree files in the output, one after the other.
1579 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1580 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1581 # main U-Boot tree. All three should have the same postions and offset.
1582 start = 0
1583 for item in ['', 'spl', 'tpl']:
1584 dtb = fdt.Fdt.FromData(data[start:])
1585 dtb.Scan()
1586 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1587 'spl', 'tpl'])
1588 expected = dict(base_expected)
1589 if item:
1590 expected[item] = 0
1591 self.assertEqual(expected, props)
1592 start += dtb._fdt_obj.totalsize()
1593
1594 def testUpdateFdtOutput(self):
1595 """Test that output DTB files are updated"""
1596 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001597 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001598 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1599
1600 # Unfortunately, compiling a source file always results in a file
1601 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001602 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001603 # binman as a file called u-boot.dtb. To fix this, copy the file
1604 # over to the expected place.
1605 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1606 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1607 start = 0
1608 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1609 'tpl/u-boot-tpl.dtb.out']:
1610 dtb = fdt.Fdt.FromData(data[start:])
1611 size = dtb._fdt_obj.totalsize()
1612 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1613 outdata = tools.ReadFile(pathname)
1614 name = os.path.split(fname)[0]
1615
1616 if name:
1617 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1618 else:
1619 orig_indata = dtb_data
1620 self.assertNotEqual(outdata, orig_indata,
1621 "Expected output file '%s' be updated" % pathname)
1622 self.assertEqual(outdata, data[start:start + size],
1623 "Expected output file '%s' to match output image" %
1624 pathname)
1625 start += size
1626 finally:
1627 self._ResetDtbs()
1628
Simon Glass83d73c22018-09-14 04:57:26 -06001629 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001630 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001631
1632 def testCompress(self):
1633 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001634 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001635 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001636 use_real_dtb=True, update_dtb=True)
1637 dtb = fdt.Fdt(out_dtb_fname)
1638 dtb.Scan()
1639 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1640 orig = self._decompress(data)
1641 self.assertEquals(COMPRESS_DATA, orig)
1642 expected = {
1643 'blob:uncomp-size': len(COMPRESS_DATA),
1644 'blob:size': len(data),
1645 'size': len(data),
1646 }
1647 self.assertEqual(expected, props)
1648
Simon Glass0a98b282018-09-14 04:57:28 -06001649 def testFiles(self):
1650 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001651 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001652 self.assertEqual(FILES_DATA, data)
1653
1654 def testFilesCompress(self):
1655 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001656 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001657 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001658
1659 image = control.images['image']
1660 entries = image.GetEntries()
1661 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001662 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001663
Simon Glassc6c10e72019-05-17 22:00:46 -06001664 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001665 for i in range(1, 3):
1666 key = '%d.dat' % i
1667 start = entries[key].image_pos
1668 len = entries[key].size
1669 chunk = data[start:start + len]
1670 orig += self._decompress(chunk)
1671
1672 self.assertEqual(FILES_DATA, orig)
1673
1674 def testFilesMissing(self):
1675 """Test missing files"""
1676 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001677 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001678 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1679 'no files', str(e.exception))
1680
1681 def testFilesNoPattern(self):
1682 """Test missing files"""
1683 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001684 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001685 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1686 str(e.exception))
1687
Simon Glassba64a0b2018-09-14 04:57:29 -06001688 def testExpandSize(self):
1689 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001690 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001691 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001692 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1693 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1694 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1695 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001696 self.assertEqual(expect, data)
1697 self.assertEqual('''ImagePos Offset Size Name
169800000000 00000000 00000028 main-section
169900000000 00000000 00000008 fill
170000000008 00000008 00000004 u-boot
17010000000c 0000000c 00000004 section
17020000000c 00000000 00000003 intel-mrc
170300000010 00000010 00000004 u-boot2
170400000014 00000014 0000000c section2
170500000014 00000000 00000008 fill
17060000001c 00000008 00000004 u-boot
170700000020 00000020 00000008 fill2
1708''', map_data)
1709
1710 def testExpandSizeBad(self):
1711 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001712 with test_util.capture_sys_output() as (stdout, stderr):
1713 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001714 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001715 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1716 'expanding entry', str(e.exception))
1717
Simon Glasse0e5df92018-09-14 04:57:31 -06001718 def testHash(self):
1719 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001720 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001721 use_real_dtb=True, update_dtb=True)
1722 dtb = fdt.Fdt(out_dtb_fname)
1723 dtb.Scan()
1724 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1725 m = hashlib.sha256()
1726 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001727 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001728
1729 def testHashNoAlgo(self):
1730 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001731 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001732 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1733 'hash node', str(e.exception))
1734
1735 def testHashBadAlgo(self):
1736 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001737 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001738 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1739 str(e.exception))
1740
1741 def testHashSection(self):
1742 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001743 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001744 use_real_dtb=True, update_dtb=True)
1745 dtb = fdt.Fdt(out_dtb_fname)
1746 dtb.Scan()
1747 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1748 m = hashlib.sha256()
1749 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001750 m.update(tools.GetBytes(ord('a'), 16))
1751 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001752
Simon Glassf0253632018-09-14 04:57:32 -06001753 def testPackUBootTplMicrocode(self):
1754 """Test that x86 microcode can be handled correctly in TPL
1755
1756 We expect to see the following in the image, in order:
1757 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1758 place
1759 u-boot-tpl.dtb with the microcode removed
1760 the microcode
1761 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001762 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001763 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001764 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001765 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001766 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1767 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001768
Simon Glassf8f8df62018-09-14 04:57:34 -06001769 def testFmapX86(self):
1770 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001771 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001772 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001773 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001774 self.assertEqual(expected, data[:32])
1775 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1776
1777 self.assertEqual(0x100, fhdr.image_size)
1778
1779 self.assertEqual(0, fentries[0].offset)
1780 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001781 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001782
1783 self.assertEqual(4, fentries[1].offset)
1784 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001785 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001786
1787 self.assertEqual(32, fentries[2].offset)
1788 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1789 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001790 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001791
1792 def testFmapX86Section(self):
1793 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001794 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001795 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001796 self.assertEqual(expected, data[:32])
1797 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1798
1799 self.assertEqual(0x100, fhdr.image_size)
1800
1801 self.assertEqual(0, fentries[0].offset)
1802 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001803 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001804
1805 self.assertEqual(4, fentries[1].offset)
1806 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001807 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001808
1809 self.assertEqual(36, fentries[2].offset)
1810 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1811 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001812 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001813
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001814 def testElf(self):
1815 """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 Glass4c650252019-07-08 13:18:46 -06001818 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1819 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001820 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001821 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001822
Simon Glass093d1682019-07-08 13:18:25 -06001823 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001824 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001825 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001826 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001827 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001828 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001829
Simon Glass163ed6c2018-09-14 04:57:36 -06001830 def testPackOverlapMap(self):
1831 """Test that overlapping regions are detected"""
1832 with test_util.capture_sys_output() as (stdout, stderr):
1833 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001834 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001835 map_fname = tools.GetOutputFilename('image.map')
1836 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1837 stdout.getvalue())
1838
1839 # We should not get an inmage, but there should be a map file
1840 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1841 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001842 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001843 self.assertEqual('''ImagePos Offset Size Name
1844<none> 00000000 00000007 main-section
1845<none> 00000000 00000004 u-boot
1846<none> 00000003 00000004 u-boot-align
1847''', map_data)
1848
Simon Glass093d1682019-07-08 13:18:25 -06001849 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001850 """Test that an image with an Intel Reference code binary works"""
1851 data = self._DoReadFile('100_intel_refcode.dts')
1852 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1853
Simon Glass9481c802019-04-25 21:58:39 -06001854 def testSectionOffset(self):
1855 """Tests use of a section with an offset"""
1856 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1857 map=True)
1858 self.assertEqual('''ImagePos Offset Size Name
185900000000 00000000 00000038 main-section
186000000004 00000004 00000010 section@0
186100000004 00000000 00000004 u-boot
186200000018 00000018 00000010 section@1
186300000018 00000000 00000004 u-boot
18640000002c 0000002c 00000004 section@2
18650000002c 00000000 00000004 u-boot
1866''', map_data)
1867 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001868 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1869 tools.GetBytes(0x21, 12) +
1870 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1871 tools.GetBytes(0x61, 12) +
1872 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1873 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001874
Simon Glassac62fba2019-07-08 13:18:53 -06001875 def testCbfsRaw(self):
1876 """Test base handling of a Coreboot Filesystem (CBFS)
1877
1878 The exact contents of the CBFS is verified by similar tests in
1879 cbfs_util_test.py. The tests here merely check that the files added to
1880 the CBFS can be found in the final image.
1881 """
1882 data = self._DoReadFile('102_cbfs_raw.dts')
1883 size = 0xb0
1884
1885 cbfs = cbfs_util.CbfsReader(data)
1886 self.assertEqual(size, cbfs.rom_size)
1887
1888 self.assertIn('u-boot-dtb', cbfs.files)
1889 cfile = cbfs.files['u-boot-dtb']
1890 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1891
1892 def testCbfsArch(self):
1893 """Test on non-x86 architecture"""
1894 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1895 size = 0x100
1896
1897 cbfs = cbfs_util.CbfsReader(data)
1898 self.assertEqual(size, cbfs.rom_size)
1899
1900 self.assertIn('u-boot-dtb', cbfs.files)
1901 cfile = cbfs.files['u-boot-dtb']
1902 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1903
1904 def testCbfsStage(self):
1905 """Tests handling of a Coreboot Filesystem (CBFS)"""
1906 if not elf.ELF_TOOLS:
1907 self.skipTest('Python elftools not available')
1908 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1909 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1910 size = 0xb0
1911
1912 data = self._DoReadFile('104_cbfs_stage.dts')
1913 cbfs = cbfs_util.CbfsReader(data)
1914 self.assertEqual(size, cbfs.rom_size)
1915
1916 self.assertIn('u-boot', cbfs.files)
1917 cfile = cbfs.files['u-boot']
1918 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1919
1920 def testCbfsRawCompress(self):
1921 """Test handling of compressing raw files"""
1922 self._CheckLz4()
1923 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1924 size = 0x140
1925
1926 cbfs = cbfs_util.CbfsReader(data)
1927 self.assertIn('u-boot', cbfs.files)
1928 cfile = cbfs.files['u-boot']
1929 self.assertEqual(COMPRESS_DATA, cfile.data)
1930
1931 def testCbfsBadArch(self):
1932 """Test handling of a bad architecture"""
1933 with self.assertRaises(ValueError) as e:
1934 self._DoReadFile('106_cbfs_bad_arch.dts')
1935 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1936
1937 def testCbfsNoSize(self):
1938 """Test handling of a missing size property"""
1939 with self.assertRaises(ValueError) as e:
1940 self._DoReadFile('107_cbfs_no_size.dts')
1941 self.assertIn('entry must have a size property', str(e.exception))
1942
1943 def testCbfsNoCOntents(self):
1944 """Test handling of a CBFS entry which does not provide contentsy"""
1945 with self.assertRaises(ValueError) as e:
1946 self._DoReadFile('108_cbfs_no_contents.dts')
1947 self.assertIn('Could not complete processing of contents',
1948 str(e.exception))
1949
1950 def testCbfsBadCompress(self):
1951 """Test handling of a bad architecture"""
1952 with self.assertRaises(ValueError) as e:
1953 self._DoReadFile('109_cbfs_bad_compress.dts')
1954 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1955 str(e.exception))
1956
1957 def testCbfsNamedEntries(self):
1958 """Test handling of named entries"""
1959 data = self._DoReadFile('110_cbfs_name.dts')
1960
1961 cbfs = cbfs_util.CbfsReader(data)
1962 self.assertIn('FRED', cbfs.files)
1963 cfile1 = cbfs.files['FRED']
1964 self.assertEqual(U_BOOT_DATA, cfile1.data)
1965
1966 self.assertIn('hello', cbfs.files)
1967 cfile2 = cbfs.files['hello']
1968 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1969
Simon Glassc5ac1382019-07-08 13:18:54 -06001970 def _SetupIfwi(self, fname):
1971 """Set up to run an IFWI test
1972
1973 Args:
1974 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1975 """
1976 self._SetupSplElf()
1977
1978 # Intel Integrated Firmware Image (IFWI) file
1979 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1980 data = fd.read()
1981 TestFunctional._MakeInputFile(fname,data)
1982
1983 def _CheckIfwi(self, data):
1984 """Check that an image with an IFWI contains the correct output
1985
1986 Args:
1987 data: Conents of output file
1988 """
1989 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1990 if data[:0x1000] != expected_desc:
1991 self.fail('Expected descriptor binary at start of image')
1992
1993 # We expect to find the TPL wil in subpart IBBP entry IBBL
1994 image_fname = tools.GetOutputFilename('image.bin')
1995 tpl_fname = tools.GetOutputFilename('tpl.out')
1996 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
1997 subpart='IBBP', entry_name='IBBL')
1998
1999 tpl_data = tools.ReadFile(tpl_fname)
2000 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2001
2002 def testPackX86RomIfwi(self):
2003 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2004 self._SetupIfwi('fitimage.bin')
2005 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2006 self._CheckIfwi(data)
2007
2008 def testPackX86RomIfwiNoDesc(self):
2009 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2010 self._SetupIfwi('ifwi.bin')
2011 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2012 self._CheckIfwi(data)
2013
2014 def testPackX86RomIfwiNoData(self):
2015 """Test that an x86 ROM with IFWI handles missing data"""
2016 self._SetupIfwi('ifwi.bin')
2017 with self.assertRaises(ValueError) as e:
2018 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2019 self.assertIn('Could not complete processing of contents',
2020 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002021
Simon Glasse073d4e2019-07-08 13:18:56 -06002022 def testCbfsOffset(self):
2023 """Test a CBFS with files at particular offsets
2024
2025 Like all CFBS tests, this is just checking the logic that calls
2026 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2027 """
2028 data = self._DoReadFile('114_cbfs_offset.dts')
2029 size = 0x200
2030
2031 cbfs = cbfs_util.CbfsReader(data)
2032 self.assertEqual(size, cbfs.rom_size)
2033
2034 self.assertIn('u-boot', cbfs.files)
2035 cfile = cbfs.files['u-boot']
2036 self.assertEqual(U_BOOT_DATA, cfile.data)
2037 self.assertEqual(0x40, cfile.cbfs_offset)
2038
2039 self.assertIn('u-boot-dtb', cbfs.files)
2040 cfile2 = cbfs.files['u-boot-dtb']
2041 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2042 self.assertEqual(0x140, cfile2.cbfs_offset)
2043
Simon Glass086cec92019-07-08 14:25:27 -06002044 def testFdtmap(self):
2045 """Test an FDT map can be inserted in the image"""
2046 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2047 fdtmap_data = data[len(U_BOOT_DATA):]
2048 magic = fdtmap_data[:8]
2049 self.assertEqual('_FDTMAP_', magic)
2050 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2051
2052 fdt_data = fdtmap_data[16:]
2053 dtb = fdt.Fdt.FromData(fdt_data)
2054 dtb.Scan()
2055 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'],
2056 prefix='/')
2057 self.assertEqual({
2058 'image-pos': 0,
2059 'offset': 0,
2060 'u-boot:offset': 0,
2061 'u-boot:size': len(U_BOOT_DATA),
2062 'u-boot:image-pos': 0,
2063 'fdtmap:image-pos': 4,
2064 'fdtmap:offset': 4,
2065 'fdtmap:size': len(fdtmap_data),
2066 'size': len(data),
2067 }, props)
2068
2069 def testFdtmapNoMatch(self):
2070 """Check handling of an FDT map when the section cannot be found"""
2071 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2072
2073 # Mangle the section name, which should cause a mismatch between the
2074 # correct FDT path and the one expected by the section
2075 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002076 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002077 entries = image.GetEntries()
2078 fdtmap = entries['fdtmap']
2079 with self.assertRaises(ValueError) as e:
2080 fdtmap._GetFdtmap()
2081 self.assertIn("Cannot locate node for path '/binman-suffix'",
2082 str(e.exception))
2083
Simon Glasscf228942019-07-08 14:25:28 -06002084 def testFdtmapHeader(self):
2085 """Test an FDT map and image header can be inserted in the image"""
2086 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2087 fdtmap_pos = len(U_BOOT_DATA)
2088 fdtmap_data = data[fdtmap_pos:]
2089 fdt_data = fdtmap_data[16:]
2090 dtb = fdt.Fdt.FromData(fdt_data)
2091 fdt_size = dtb.GetFdtObj().totalsize()
2092 hdr_data = data[-8:]
2093 self.assertEqual('BinM', hdr_data[:4])
2094 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2095 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2096
2097 def testFdtmapHeaderStart(self):
2098 """Test an image header can be inserted at the image start"""
2099 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2100 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2101 hdr_data = data[:8]
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 testFdtmapHeaderPos(self):
2107 """Test an image header can be inserted at a chosen position"""
2108 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2109 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2110 hdr_data = data[0x80:0x88]
2111 self.assertEqual('BinM', hdr_data[:4])
2112 offset = struct.unpack('<I', hdr_data[4:])[0]
2113 self.assertEqual(fdtmap_pos, offset)
2114
2115 def testHeaderMissingFdtmap(self):
2116 """Test an image header requires an fdtmap"""
2117 with self.assertRaises(ValueError) as e:
2118 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2119 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2120 str(e.exception))
2121
2122 def testHeaderNoLocation(self):
2123 """Test an image header with a no specified location is detected"""
2124 with self.assertRaises(ValueError) as e:
2125 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2126 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2127 str(e.exception))
2128
Simon Glassc52c9e72019-07-08 14:25:37 -06002129 def testEntryExpand(self):
2130 """Test expanding an entry after it is packed"""
2131 data = self._DoReadFile('121_entry_expand.dts')
2132 self.assertEqual(b'aa', data[:2])
2133 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2134 self.assertEqual(b'aa', data[-2:])
2135
2136 def testEntryExpandBad(self):
2137 """Test expanding an entry after it is packed, twice"""
2138 with self.assertRaises(ValueError) as e:
2139 self._DoReadFile('122_entry_expand_twice.dts')
2140 self.assertIn("Image '/binman': Entries expanded after packing",
2141 str(e.exception))
2142
2143 def testEntryExpandSection(self):
2144 """Test expanding an entry within a section after it is packed"""
2145 data = self._DoReadFile('123_entry_expand_section.dts')
2146 self.assertEqual(b'aa', data[:2])
2147 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2148 self.assertEqual(b'aa', data[-2:])
2149
Simon Glass6c223fd2019-07-08 14:25:38 -06002150 def testCompressDtb(self):
2151 """Test that compress of device-tree files is supported"""
2152 self._CheckLz4()
2153 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2154 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2155 comp_data = data[len(U_BOOT_DATA):]
2156 orig = self._decompress(comp_data)
2157 dtb = fdt.Fdt.FromData(orig)
2158 dtb.Scan()
2159 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2160 expected = {
2161 'u-boot:size': len(U_BOOT_DATA),
2162 'u-boot-dtb:uncomp-size': len(orig),
2163 'u-boot-dtb:size': len(comp_data),
2164 'size': len(data),
2165 }
2166 self.assertEqual(expected, props)
2167
Simon Glass69f7cb32019-07-08 14:25:41 -06002168 def testCbfsUpdateFdt(self):
2169 """Test that we can update the device tree with CBFS offset/size info"""
2170 self._CheckLz4()
2171 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2172 update_dtb=True)
2173 dtb = fdt.Fdt(out_dtb_fname)
2174 dtb.Scan()
2175 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
2176 'uncomp-size'])
2177 del props['cbfs/u-boot:size']
2178 self.assertEqual({
2179 'offset': 0,
2180 'size': len(data),
2181 'image-pos': 0,
2182 'cbfs:offset': 0,
2183 'cbfs:size': len(data),
2184 'cbfs:image-pos': 0,
2185 'cbfs/u-boot:offset': 0x38,
2186 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2187 'cbfs/u-boot:image-pos': 0x38,
2188 'cbfs/u-boot-dtb:offset': 0xb8,
2189 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2190 'cbfs/u-boot-dtb:image-pos': 0xb8,
2191 }, props)
2192
Simon Glass8a1ad062019-07-08 14:25:42 -06002193 def testCbfsBadType(self):
2194 """Test an image header with a no specified location is detected"""
2195 with self.assertRaises(ValueError) as e:
2196 self._DoReadFile('126_cbfs_bad_type.dts')
2197 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2198
Simon Glass41b8ba02019-07-08 14:25:43 -06002199 def testList(self):
2200 """Test listing the files in an image"""
2201 self._CheckLz4()
2202 data = self._DoReadFile('127_list.dts')
2203 image = control.images['image']
2204 entries = image.BuildEntryList()
2205 self.assertEqual(7, len(entries))
2206
2207 ent = entries[0]
2208 self.assertEqual(0, ent.indent)
2209 self.assertEqual('main-section', ent.name)
2210 self.assertEqual('section', ent.etype)
2211 self.assertEqual(len(data), ent.size)
2212 self.assertEqual(0, ent.image_pos)
2213 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002214 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002215
2216 ent = entries[1]
2217 self.assertEqual(1, ent.indent)
2218 self.assertEqual('u-boot', ent.name)
2219 self.assertEqual('u-boot', ent.etype)
2220 self.assertEqual(len(U_BOOT_DATA), ent.size)
2221 self.assertEqual(0, ent.image_pos)
2222 self.assertEqual(None, ent.uncomp_size)
2223 self.assertEqual(0, ent.offset)
2224
2225 ent = entries[2]
2226 self.assertEqual(1, ent.indent)
2227 self.assertEqual('section', ent.name)
2228 self.assertEqual('section', ent.etype)
2229 section_size = ent.size
2230 self.assertEqual(0x100, ent.image_pos)
2231 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002232 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002233
2234 ent = entries[3]
2235 self.assertEqual(2, ent.indent)
2236 self.assertEqual('cbfs', ent.name)
2237 self.assertEqual('cbfs', ent.etype)
2238 self.assertEqual(0x400, ent.size)
2239 self.assertEqual(0x100, ent.image_pos)
2240 self.assertEqual(None, ent.uncomp_size)
2241 self.assertEqual(0, ent.offset)
2242
2243 ent = entries[4]
2244 self.assertEqual(3, ent.indent)
2245 self.assertEqual('u-boot', ent.name)
2246 self.assertEqual('u-boot', ent.etype)
2247 self.assertEqual(len(U_BOOT_DATA), ent.size)
2248 self.assertEqual(0x138, ent.image_pos)
2249 self.assertEqual(None, ent.uncomp_size)
2250 self.assertEqual(0x38, ent.offset)
2251
2252 ent = entries[5]
2253 self.assertEqual(3, ent.indent)
2254 self.assertEqual('u-boot-dtb', ent.name)
2255 self.assertEqual('text', ent.etype)
2256 self.assertGreater(len(COMPRESS_DATA), ent.size)
2257 self.assertEqual(0x178, ent.image_pos)
2258 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2259 self.assertEqual(0x78, ent.offset)
2260
2261 ent = entries[6]
2262 self.assertEqual(2, ent.indent)
2263 self.assertEqual('u-boot-dtb', ent.name)
2264 self.assertEqual('u-boot-dtb', ent.etype)
2265 self.assertEqual(0x500, ent.image_pos)
2266 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2267 dtb_size = ent.size
2268 # Compressing this data expands it since headers are added
2269 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2270 self.assertEqual(0x400, ent.offset)
2271
2272 self.assertEqual(len(data), 0x100 + section_size)
2273 self.assertEqual(section_size, 0x400 + dtb_size)
2274
Simon Glasse1925fa2019-07-08 14:25:44 -06002275 def testFindFdtmap(self):
2276 """Test locating an FDT map in an image"""
2277 self._CheckLz4()
2278 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2279 image = control.images['image']
2280 entries = image.GetEntries()
2281 entry = entries['fdtmap']
2282 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2283
2284 def testFindFdtmapMissing(self):
2285 """Test failing to locate an FDP map"""
2286 data = self._DoReadFile('005_simple.dts')
2287 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2288
Simon Glass2d260032019-07-08 14:25:45 -06002289 def testFindImageHeader(self):
2290 """Test locating a image header"""
2291 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002292 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002293 image = control.images['image']
2294 entries = image.GetEntries()
2295 entry = entries['fdtmap']
2296 # The header should point to the FDT map
2297 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2298
2299 def testFindImageHeaderStart(self):
2300 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002301 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002302 image = control.images['image']
2303 entries = image.GetEntries()
2304 entry = entries['fdtmap']
2305 # The header should point to the FDT map
2306 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2307
2308 def testFindImageHeaderMissing(self):
2309 """Test failing to locate an image header"""
2310 data = self._DoReadFile('005_simple.dts')
2311 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2312
Simon Glassffded752019-07-08 14:25:46 -06002313 def testReadImage(self):
2314 """Test reading an image and accessing its FDT map"""
2315 self._CheckLz4()
2316 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2317 image_fname = tools.GetOutputFilename('image.bin')
2318 orig_image = control.images['image']
2319 image = Image.FromFile(image_fname)
2320 self.assertEqual(orig_image.GetEntries().keys(),
2321 image.GetEntries().keys())
2322
2323 orig_entry = orig_image.GetEntries()['fdtmap']
2324 entry = image.GetEntries()['fdtmap']
2325 self.assertEquals(orig_entry.offset, entry.offset)
2326 self.assertEquals(orig_entry.size, entry.size)
2327 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2328
2329 def testReadImageNoHeader(self):
2330 """Test accessing an image's FDT map without an image header"""
2331 self._CheckLz4()
2332 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2333 image_fname = tools.GetOutputFilename('image.bin')
2334 image = Image.FromFile(image_fname)
2335 self.assertTrue(isinstance(image, Image))
Simon Glass8beb11e2019-07-08 14:25:47 -06002336 self.assertEqual('image', image.image_name)
Simon Glassffded752019-07-08 14:25:46 -06002337
2338 def testReadImageFail(self):
2339 """Test failing to read an image image's FDT map"""
2340 self._DoReadFile('005_simple.dts')
2341 image_fname = tools.GetOutputFilename('image.bin')
2342 with self.assertRaises(ValueError) as e:
2343 image = Image.FromFile(image_fname)
2344 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002345
Simon Glass61f564d2019-07-08 14:25:48 -06002346 def testListCmd(self):
2347 """Test listing the files in an image using an Fdtmap"""
2348 self._CheckLz4()
2349 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2350
2351 # lz4 compression size differs depending on the version
2352 image = control.images['image']
2353 entries = image.GetEntries()
2354 section_size = entries['section'].size
2355 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2356 fdtmap_offset = entries['fdtmap'].offset
2357
2358 image_fname = tools.GetOutputFilename('image.bin')
2359 with test_util.capture_sys_output() as (stdout, stderr):
2360 self._DoBinman('ls', '-i', image_fname)
2361 lines = stdout.getvalue().splitlines()
2362 expected = [
2363'Name Image-pos Size Entry-type Offset Uncomp-size',
2364'----------------------------------------------------------------------',
2365'main-section 0 c00 section 0',
2366' u-boot 0 4 u-boot 0',
2367' section 100 %x section 100' % section_size,
2368' cbfs 100 400 cbfs 0',
2369' u-boot 138 4 u-boot 38',
2370' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2371' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
2372' fdtmap %x 395 fdtmap %x' %
2373 (fdtmap_offset, fdtmap_offset),
2374' image-header bf8 8 image-header bf8',
2375 ]
2376 self.assertEqual(expected, lines)
2377
2378 def testListCmdFail(self):
2379 """Test failing to list an image"""
2380 self._DoReadFile('005_simple.dts')
2381 image_fname = tools.GetOutputFilename('image.bin')
2382 with self.assertRaises(ValueError) as e:
2383 self._DoBinman('ls', '-i', image_fname)
2384 self.assertIn("Cannot find FDT map in image", str(e.exception))
2385
2386 def _RunListCmd(self, paths, expected):
2387 """List out entries and check the result
2388
2389 Args:
2390 paths: List of paths to pass to the list command
2391 expected: Expected list of filenames to be returned, in order
2392 """
2393 self._CheckLz4()
2394 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2395 image_fname = tools.GetOutputFilename('image.bin')
2396 image = Image.FromFile(image_fname)
2397 lines = image.GetListEntries(paths)[1]
2398 files = [line[0].strip() for line in lines[1:]]
2399 self.assertEqual(expected, files)
2400
2401 def testListCmdSection(self):
2402 """Test listing the files in a section"""
2403 self._RunListCmd(['section'],
2404 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2405
2406 def testListCmdFile(self):
2407 """Test listing a particular file"""
2408 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2409
2410 def testListCmdWildcard(self):
2411 """Test listing a wildcarded file"""
2412 self._RunListCmd(['*boot*'],
2413 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2414
2415 def testListCmdWildcardMulti(self):
2416 """Test listing a wildcarded file"""
2417 self._RunListCmd(['*cb*', '*head*'],
2418 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2419
2420 def testListCmdEmpty(self):
2421 """Test listing a wildcarded file"""
2422 self._RunListCmd(['nothing'], [])
2423
2424 def testListCmdPath(self):
2425 """Test listing the files in a sub-entry of a section"""
2426 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2427
Simon Glassf667e452019-07-08 14:25:50 -06002428 def _RunExtractCmd(self, entry_name, decomp=True):
2429 """Extract an entry from an image
2430
2431 Args:
2432 entry_name: Entry name to extract
2433 decomp: True to decompress the data if compressed, False to leave
2434 it in its raw uncompressed format
2435
2436 Returns:
2437 data from entry
2438 """
2439 self._CheckLz4()
2440 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2441 image_fname = tools.GetOutputFilename('image.bin')
2442 return control.ReadEntry(image_fname, entry_name, decomp)
2443
2444 def testExtractSimple(self):
2445 """Test extracting a single file"""
2446 data = self._RunExtractCmd('u-boot')
2447 self.assertEqual(U_BOOT_DATA, data)
2448
Simon Glass71ce0ba2019-07-08 14:25:52 -06002449 def testExtractSection(self):
2450 """Test extracting the files in a section"""
2451 data = self._RunExtractCmd('section')
2452 cbfs_data = data[:0x400]
2453 cbfs = cbfs_util.CbfsReader(cbfs_data)
2454 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2455 dtb_data = data[0x400:]
2456 dtb = self._decompress(dtb_data)
2457 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2458
2459 def testExtractCompressed(self):
2460 """Test extracting compressed data"""
2461 data = self._RunExtractCmd('section/u-boot-dtb')
2462 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2463
2464 def testExtractRaw(self):
2465 """Test extracting compressed data without decompressing it"""
2466 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2467 dtb = self._decompress(data)
2468 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2469
2470 def testExtractCbfs(self):
2471 """Test extracting CBFS data"""
2472 data = self._RunExtractCmd('section/cbfs/u-boot')
2473 self.assertEqual(U_BOOT_DATA, data)
2474
2475 def testExtractCbfsCompressed(self):
2476 """Test extracting CBFS compressed data"""
2477 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2478 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2479
2480 def testExtractCbfsRaw(self):
2481 """Test extracting CBFS compressed data without decompressing it"""
2482 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2483 dtb = tools.Decompress(data, 'lzma')
2484 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2485
Simon Glassf667e452019-07-08 14:25:50 -06002486 def testExtractBadEntry(self):
2487 """Test extracting a bad section path"""
2488 with self.assertRaises(ValueError) as e:
2489 self._RunExtractCmd('section/does-not-exist')
2490 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2491 str(e.exception))
2492
2493 def testExtractMissingFile(self):
2494 """Test extracting file that does not exist"""
2495 with self.assertRaises(IOError) as e:
2496 control.ReadEntry('missing-file', 'name')
2497
2498 def testExtractBadFile(self):
2499 """Test extracting an invalid file"""
2500 fname = os.path.join(self._indir, 'badfile')
2501 tools.WriteFile(fname, b'')
2502 with self.assertRaises(ValueError) as e:
2503 control.ReadEntry(fname, 'name')
2504
Simon Glass71ce0ba2019-07-08 14:25:52 -06002505 def testExtractCmd(self):
2506 """Test extracting a file fron an image on the command line"""
2507 self._CheckLz4()
2508 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2509 image_fname = tools.GetOutputFilename('image.bin')
2510 fname = os.path.join(self._indir, 'output.extact')
2511 with test_util.capture_sys_output() as (stdout, stderr):
2512 self._DoBinman('extract', '-i', image_fname, 'u-boot', '-f', fname)
2513 data = tools.ReadFile(fname)
2514 self.assertEqual(U_BOOT_DATA, data)
2515
2516 def testExtractOneEntry(self):
2517 """Test extracting a single entry fron an image """
2518 self._CheckLz4()
2519 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2520 image_fname = tools.GetOutputFilename('image.bin')
2521 fname = os.path.join(self._indir, 'output.extact')
2522 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2523 data = tools.ReadFile(fname)
2524 self.assertEqual(U_BOOT_DATA, data)
2525
2526 def _CheckExtractOutput(self, decomp):
2527 """Helper to test file output with and without decompression
2528
2529 Args:
2530 decomp: True to decompress entry data, False to output it raw
2531 """
2532 def _CheckPresent(entry_path, expect_data, expect_size=None):
2533 """Check and remove expected file
2534
2535 This checks the data/size of a file and removes the file both from
2536 the outfiles set and from the output directory. Once all files are
2537 processed, both the set and directory should be empty.
2538
2539 Args:
2540 entry_path: Entry path
2541 expect_data: Data to expect in file, or None to skip check
2542 expect_size: Size of data to expect in file, or None to skip
2543 """
2544 path = os.path.join(outdir, entry_path)
2545 data = tools.ReadFile(path)
2546 os.remove(path)
2547 if expect_data:
2548 self.assertEqual(expect_data, data)
2549 elif expect_size:
2550 self.assertEqual(expect_size, len(data))
2551 outfiles.remove(path)
2552
2553 def _CheckDirPresent(name):
2554 """Remove expected directory
2555
2556 This gives an error if the directory does not exist as expected
2557
2558 Args:
2559 name: Name of directory to remove
2560 """
2561 path = os.path.join(outdir, name)
2562 os.rmdir(path)
2563
2564 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2565 image_fname = tools.GetOutputFilename('image.bin')
2566 outdir = os.path.join(self._indir, 'extract')
2567 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2568
2569 # Create a set of all file that were output (should be 9)
2570 outfiles = set()
2571 for root, dirs, files in os.walk(outdir):
2572 outfiles |= set([os.path.join(root, fname) for fname in files])
2573 self.assertEqual(9, len(outfiles))
2574 self.assertEqual(9, len(einfos))
2575
2576 image = control.images['image']
2577 entries = image.GetEntries()
2578
2579 # Check the 9 files in various ways
2580 section = entries['section']
2581 section_entries = section.GetEntries()
2582 cbfs_entries = section_entries['cbfs'].GetEntries()
2583 _CheckPresent('u-boot', U_BOOT_DATA)
2584 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2585 dtb_len = EXTRACT_DTB_SIZE
2586 if not decomp:
2587 dtb_len = cbfs_entries['u-boot-dtb'].size
2588 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2589 if not decomp:
2590 dtb_len = section_entries['u-boot-dtb'].size
2591 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2592
2593 fdtmap = entries['fdtmap']
2594 _CheckPresent('fdtmap', fdtmap.data)
2595 hdr = entries['image-header']
2596 _CheckPresent('image-header', hdr.data)
2597
2598 _CheckPresent('section/root', section.data)
2599 cbfs = section_entries['cbfs']
2600 _CheckPresent('section/cbfs/root', cbfs.data)
2601 data = tools.ReadFile(image_fname)
2602 _CheckPresent('root', data)
2603
2604 # There should be no files left. Remove all the directories to check.
2605 # If there are any files/dirs remaining, one of these checks will fail.
2606 self.assertEqual(0, len(outfiles))
2607 _CheckDirPresent('section/cbfs')
2608 _CheckDirPresent('section')
2609 _CheckDirPresent('')
2610 self.assertFalse(os.path.exists(outdir))
2611
2612 def testExtractAllEntries(self):
2613 """Test extracting all entries"""
2614 self._CheckLz4()
2615 self._CheckExtractOutput(decomp=True)
2616
2617 def testExtractAllEntriesRaw(self):
2618 """Test extracting all entries without decompressing them"""
2619 self._CheckLz4()
2620 self._CheckExtractOutput(decomp=False)
2621
2622 def testExtractSelectedEntries(self):
2623 """Test extracting some entries"""
2624 self._CheckLz4()
2625 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2626 image_fname = tools.GetOutputFilename('image.bin')
2627 outdir = os.path.join(self._indir, 'extract')
2628 einfos = control.ExtractEntries(image_fname, None, outdir,
2629 ['*cb*', '*head*'])
2630
2631 # File output is tested by testExtractAllEntries(), so just check that
2632 # the expected entries are selected
2633 names = [einfo.name for einfo in einfos]
2634 self.assertEqual(names,
2635 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2636
2637 def testExtractNoEntryPaths(self):
2638 """Test extracting some entries"""
2639 self._CheckLz4()
2640 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2641 image_fname = tools.GetOutputFilename('image.bin')
2642 with self.assertRaises(ValueError) as e:
2643 control.ExtractEntries(image_fname, 'fname', None, [])
2644 self.assertIn('Must specify an entry path to write with -o',
2645 str(e.exception))
2646
2647 def testExtractTooManyEntryPaths(self):
2648 """Test extracting some entries"""
2649 self._CheckLz4()
2650 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2651 image_fname = tools.GetOutputFilename('image.bin')
2652 with self.assertRaises(ValueError) as e:
2653 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2654 self.assertIn('Must specify exactly one entry path to write with -o',
2655 str(e.exception))
2656
Simon Glasse2705fa2019-07-08 14:25:53 -06002657 def testPackAlignSection(self):
2658 """Test that sections can have alignment"""
2659 self._DoReadFile('131_pack_align_section.dts')
2660
2661 self.assertIn('image', control.images)
2662 image = control.images['image']
2663 entries = image.GetEntries()
2664 self.assertEqual(3, len(entries))
2665
2666 # First u-boot
2667 self.assertIn('u-boot', entries)
2668 entry = entries['u-boot']
2669 self.assertEqual(0, entry.offset)
2670 self.assertEqual(0, entry.image_pos)
2671 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2672 self.assertEqual(len(U_BOOT_DATA), entry.size)
2673
2674 # Section0
2675 self.assertIn('section0', entries)
2676 section0 = entries['section0']
2677 self.assertEqual(0x10, section0.offset)
2678 self.assertEqual(0x10, section0.image_pos)
2679 self.assertEqual(len(U_BOOT_DATA), section0.size)
2680
2681 # Second u-boot
2682 section_entries = section0.GetEntries()
2683 self.assertIn('u-boot', section_entries)
2684 entry = section_entries['u-boot']
2685 self.assertEqual(0, entry.offset)
2686 self.assertEqual(0x10, entry.image_pos)
2687 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2688 self.assertEqual(len(U_BOOT_DATA), entry.size)
2689
2690 # Section1
2691 self.assertIn('section1', entries)
2692 section1 = entries['section1']
2693 self.assertEqual(0x14, section1.offset)
2694 self.assertEqual(0x14, section1.image_pos)
2695 self.assertEqual(0x20, section1.size)
2696
2697 # Second u-boot
2698 section_entries = section1.GetEntries()
2699 self.assertIn('u-boot', section_entries)
2700 entry = section_entries['u-boot']
2701 self.assertEqual(0, entry.offset)
2702 self.assertEqual(0x14, entry.image_pos)
2703 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2704 self.assertEqual(len(U_BOOT_DATA), entry.size)
2705
2706 # Section2
2707 self.assertIn('section2', section_entries)
2708 section2 = section_entries['section2']
2709 self.assertEqual(0x4, section2.offset)
2710 self.assertEqual(0x18, section2.image_pos)
2711 self.assertEqual(4, section2.size)
2712
2713 # Third u-boot
2714 section_entries = section2.GetEntries()
2715 self.assertIn('u-boot', section_entries)
2716 entry = section_entries['u-boot']
2717 self.assertEqual(0, entry.offset)
2718 self.assertEqual(0x18, entry.image_pos)
2719 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2720 self.assertEqual(len(U_BOOT_DATA), entry.size)
2721
Simon Glass8beb11e2019-07-08 14:25:47 -06002722
Simon Glass9fc60b42017-11-12 21:52:22 -07002723if __name__ == "__main__":
2724 unittest.main()