blob: 971fade343285ccf1348de0319a2c2e2d7153dd4 [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 Glasse0e5df92018-09-14 04:57:31 -06009import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070010from optparse import OptionParser
11import os
12import shutil
13import struct
14import sys
15import tempfile
16import unittest
17
18import binman
19import cmdline
20import command
21import control
Simon Glass19790632017-11-13 18:55:01 -070022import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060023import fdt
Simon Glass4f443042016-11-25 20:15:52 -070024import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060025import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060026import test_util
Simon Glassc55a50f2018-09-14 04:57:19 -060027import state
Simon Glass4f443042016-11-25 20:15:52 -070028import tools
29import tout
30
31# Contents of test files, corresponding to different entry types
Simon Glass6b187df2017-11-12 21:52:27 -070032U_BOOT_DATA = '1234'
33U_BOOT_IMG_DATA = 'img'
Simon Glassf6898902017-11-13 18:54:59 -070034U_BOOT_SPL_DATA = '56780123456789abcde'
Simon Glassb8ef5b62018-07-17 13:25:48 -060035U_BOOT_TPL_DATA = 'tpl'
Simon Glass6b187df2017-11-12 21:52:27 -070036BLOB_DATA = '89'
37ME_DATA = '0abcd'
38VGA_DATA = 'vga'
39U_BOOT_DTB_DATA = 'udtb'
Simon Glass47419ea2017-11-13 18:54:55 -070040U_BOOT_SPL_DTB_DATA = 'spldtb'
Simon Glassb8ef5b62018-07-17 13:25:48 -060041U_BOOT_TPL_DTB_DATA = 'tpldtb'
Simon Glass6b187df2017-11-12 21:52:27 -070042X86_START16_DATA = 'start16'
43X86_START16_SPL_DATA = 'start16spl'
Simon Glass35b384c2018-09-14 04:57:10 -060044X86_START16_TPL_DATA = 'start16tpl'
Jagdish Gediya9d368f32018-09-03 21:35:08 +053045PPC_MPC85XX_BR_DATA = 'ppcmpc85xxbr'
Simon Glass6b187df2017-11-12 21:52:27 -070046U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
47U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
Simon Glassf0253632018-09-14 04:57:32 -060048U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here'
Simon Glass6b187df2017-11-12 21:52:27 -070049FSP_DATA = 'fsp'
50CMC_DATA = 'cmc'
51VBT_DATA = 'vbt'
Simon Glassca4f4ff2017-11-12 21:52:28 -070052MRC_DATA = 'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060053TEXT_DATA = 'text'
54TEXT_DATA2 = 'text2'
55TEXT_DATA3 = 'text3'
Simon Glassec127af2018-07-17 13:25:39 -060056CROS_EC_RW_DATA = 'ecrw'
Simon Glass0ef87aa2018-07-17 13:25:44 -060057GBB_DATA = 'gbbd'
58BMPBLK_DATA = 'bmp'
Simon Glass24d0d3c2018-07-17 13:25:47 -060059VBLOCK_DATA = 'vblk'
Simon Glass0a98b282018-09-14 04:57:28 -060060FILES_DATA = ("sorry I'm late\nOh, don't bother apologising, I'm " +
61 "sorry you're alive\n")
Simon Glass83d73c22018-09-14 04:57:26 -060062COMPRESS_DATA = 'data to compress'
Simon Glass3ae192c2018-10-01 12:22:31 -060063REFCODE_DATA = 'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060064
Simon Glass4f443042016-11-25 20:15:52 -070065
66class TestFunctional(unittest.TestCase):
67 """Functional tests for binman
68
69 Most of these use a sample .dts file to build an image and then check
70 that it looks correct. The sample files are in the test/ subdirectory
71 and are numbered.
72
73 For each entry type a very small test file is created using fixed
74 string contents. This makes it easy to test that things look right, and
75 debug problems.
76
77 In some cases a 'real' file must be used - these are also supplied in
78 the test/ diurectory.
79 """
80 @classmethod
81 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070082 global entry
83 import entry
84
Simon Glass4f443042016-11-25 20:15:52 -070085 # Handle the case where argv[0] is 'python'
86 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
87 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
88
89 # Create a temporary directory for input files
90 self._indir = tempfile.mkdtemp(prefix='binmant.')
91
92 # Create some test files
93 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
94 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
95 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060096 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070097 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -070098 TestFunctional._MakeInputFile('me.bin', ME_DATA)
99 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600100 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700101 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530102 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700103 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
104 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600105 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
106 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700107 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700108 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
109 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600110 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
111 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700112 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
113 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700114 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700115 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600116 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600117 TestFunctional._MakeInputDir('devkeys')
118 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600119 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700120
Simon Glasse0ff8552016-11-25 20:15:53 -0700121 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600122 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700123 TestFunctional._MakeInputFile('u-boot', fd.read())
124
125 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600126 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
128
Simon Glass0a98b282018-09-14 04:57:28 -0600129 shutil.copytree(self.TestFile('files'),
130 os.path.join(self._indir, 'files'))
131
Simon Glass83d73c22018-09-14 04:57:26 -0600132 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
133
Simon Glass4f443042016-11-25 20:15:52 -0700134 @classmethod
135 def tearDownClass(self):
136 """Remove the temporary input directory and its contents"""
137 if self._indir:
138 shutil.rmtree(self._indir)
139 self._indir = None
140
141 def setUp(self):
142 # Enable this to turn on debugging output
143 # tout.Init(tout.DEBUG)
144 command.test_result = None
145
146 def tearDown(self):
147 """Remove the temporary output directory"""
148 tools._FinaliseForTest()
149
Simon Glassb8ef5b62018-07-17 13:25:48 -0600150 @classmethod
151 def _ResetDtbs(self):
152 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
153 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
154 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
155
Simon Glass4f443042016-11-25 20:15:52 -0700156 def _RunBinman(self, *args, **kwargs):
157 """Run binman using the command line
158
159 Args:
160 Arguments to pass, as a list of strings
161 kwargs: Arguments to pass to Command.RunPipe()
162 """
163 result = command.RunPipe([[self._binman_pathname] + list(args)],
164 capture=True, capture_stderr=True, raise_on_error=False)
165 if result.return_code and kwargs.get('raise_on_error', True):
166 raise Exception("Error running '%s': %s" % (' '.join(args),
167 result.stdout + result.stderr))
168 return result
169
170 def _DoBinman(self, *args):
171 """Run binman using directly (in the same process)
172
173 Args:
174 Arguments to pass, as a list of strings
175 Returns:
176 Return value (0 for success)
177 """
Simon Glass7fe91732017-11-13 18:55:00 -0700178 args = list(args)
179 if '-D' in sys.argv:
180 args = args + ['-D']
181 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700182 options.pager = 'binman-invalid-pager'
183 options.build_dir = self._indir
184
185 # For testing, you can force an increase in verbosity here
186 # options.verbosity = tout.DEBUG
187 return control.Binman(options, args)
188
Simon Glass53af22a2018-07-17 13:25:32 -0600189 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600190 entry_args=None, images=None, use_real_dtb=False,
191 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700192 """Run binman with a given test file
193
194 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600195 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600196 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600197 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600198 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600199 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600200 entry_args: Dict of entry args to supply to binman
201 key: arg name
202 value: value of that arg
203 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700204 """
Simon Glass7fe91732017-11-13 18:55:00 -0700205 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
206 if debug:
207 args.append('-D')
Simon Glass3b0c3822018-06-01 09:38:20 -0600208 if map:
209 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600210 if update_dtb:
211 args.append('-up')
Simon Glass93d17412018-09-14 04:57:23 -0600212 if not use_real_dtb:
213 args.append('--fake-dtb')
Simon Glasseb833d82019-04-25 21:58:34 -0600214 if verbosity is not None:
215 args.append('-v%d' % verbosity)
Simon Glass53af22a2018-07-17 13:25:32 -0600216 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600217 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600218 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600219 if images:
220 for image in images:
221 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700222 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700223
224 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700225 """Set up a new test device-tree file
226
227 The given file is compiled and set up as the device tree to be used
228 for ths test.
229
230 Args:
231 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600232 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700233
234 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600235 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700236 """
Simon Glasse0e62752018-10-01 21:12:41 -0600237 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700238 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600239 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700240 data = fd.read()
241 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600242 tools.FinaliseOutputDir()
243 return data
Simon Glass4f443042016-11-25 20:15:52 -0700244
Simon Glass6ed45ba2018-09-14 04:57:24 -0600245 def _GetDtbContentsForSplTpl(self, dtb_data, name):
246 """Create a version of the main DTB for SPL or SPL
247
248 For testing we don't actually have different versions of the DTB. With
249 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
250 we don't normally have any unwanted nodes.
251
252 We still want the DTBs for SPL and TPL to be different though, since
253 otherwise it is confusing to know which one we are looking at. So add
254 an 'spl' or 'tpl' property to the top-level node.
255 """
256 dtb = fdt.Fdt.FromData(dtb_data)
257 dtb.Scan()
258 dtb.GetNode('/binman').AddZeroProp(name)
259 dtb.Sync(auto_resize=True)
260 dtb.Pack()
261 return dtb.GetContents()
262
Simon Glass16b8d6b2018-07-06 10:27:42 -0600263 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600264 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700265 """Run binman and return the resulting image
266
267 This runs binman with a given test file and then reads the resulting
268 output file. It is a shortcut function since most tests need to do
269 these steps.
270
271 Raises an assertion failure if binman returns a non-zero exit code.
272
273 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600274 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700275 use_real_dtb: True to use the test file as the contents of
276 the u-boot-dtb entry. Normally this is not needed and the
277 test contents (the U_BOOT_DTB_DATA string) can be used.
278 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600279 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600280 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600281 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700282
283 Returns:
284 Tuple:
285 Resulting image contents
286 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600287 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600288 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700289 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700290 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700291 # Use the compiled test file as the u-boot-dtb input
292 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700293 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600294
295 # For testing purposes, make a copy of the DT for SPL and TPL. Add
296 # a node indicating which it is, so aid verification.
297 for name in ['spl', 'tpl']:
298 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
299 outfile = os.path.join(self._indir, dtb_fname)
300 TestFunctional._MakeInputFile(dtb_fname,
301 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700302
303 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600304 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600305 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700306 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600307 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700308
309 # Find the (only) image, read it and return its contents
310 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600311 image_fname = tools.GetOutputFilename('image.bin')
312 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600313 if map:
314 map_fname = tools.GetOutputFilename('image.map')
315 with open(map_fname) as fd:
316 map_data = fd.read()
317 else:
318 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600319 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600320 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700321 finally:
322 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600323 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600324 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700325
Simon Glasse0ff8552016-11-25 20:15:53 -0700326 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600327 """Helper function which discards the device-tree binary
328
329 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600330 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600331 use_real_dtb: True to use the test file as the contents of
332 the u-boot-dtb entry. Normally this is not needed and the
333 test contents (the U_BOOT_DTB_DATA string) can be used.
334 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600335
336 Returns:
337 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600338 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700339 return self._DoReadFileDtb(fname, use_real_dtb)[0]
340
Simon Glass4f443042016-11-25 20:15:52 -0700341 @classmethod
342 def _MakeInputFile(self, fname, contents):
343 """Create a new test input file, creating directories as needed
344
345 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600346 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700347 contents: File contents to write in to the file
348 Returns:
349 Full pathname of file created
350 """
351 pathname = os.path.join(self._indir, fname)
352 dirname = os.path.dirname(pathname)
353 if dirname and not os.path.exists(dirname):
354 os.makedirs(dirname)
355 with open(pathname, 'wb') as fd:
356 fd.write(contents)
357 return pathname
358
359 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600360 def _MakeInputDir(self, dirname):
361 """Create a new test input directory, creating directories as needed
362
363 Args:
364 dirname: Directory name to create
365
366 Returns:
367 Full pathname of directory created
368 """
369 pathname = os.path.join(self._indir, dirname)
370 if not os.path.exists(pathname):
371 os.makedirs(pathname)
372 return pathname
373
374 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600375 def _SetupSplElf(self, src_fname='bss_data'):
376 """Set up an ELF file with a '_dt_ucode_base_size' symbol
377
378 Args:
379 Filename of ELF file to use as SPL
380 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600381 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600382 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
383
384 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700385 def TestFile(self, fname):
386 return os.path.join(self._binman_dir, 'test', fname)
387
388 def AssertInList(self, grep_list, target):
389 """Assert that at least one of a list of things is in a target
390
391 Args:
392 grep_list: List of strings to check
393 target: Target string
394 """
395 for grep in grep_list:
396 if grep in target:
397 return
398 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
399
400 def CheckNoGaps(self, entries):
401 """Check that all entries fit together without gaps
402
403 Args:
404 entries: List of entries to check
405 """
Simon Glass3ab95982018-08-01 15:22:37 -0600406 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700407 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600408 self.assertEqual(offset, entry.offset)
409 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700410
Simon Glasse0ff8552016-11-25 20:15:53 -0700411 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600412 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700413
414 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600415 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700416
417 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600418 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700419 """
420 return struct.unpack('>L', dtb[4:8])[0]
421
Simon Glasscee02e62018-07-17 13:25:52 -0600422 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600423 def AddNode(node, path):
424 if node.name != '/':
425 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600426 for subnode in node.subnodes:
427 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600428 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600429 prop_path = path + '/' + subnode.name + ':' + prop.name
430 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
431 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600432 AddNode(subnode, path)
433
434 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600435 AddNode(dtb.GetRoot(), '')
436 return tree
437
Simon Glass4f443042016-11-25 20:15:52 -0700438 def testRun(self):
439 """Test a basic run with valid args"""
440 result = self._RunBinman('-h')
441
442 def testFullHelp(self):
443 """Test that the full help is displayed with -H"""
444 result = self._RunBinman('-H')
445 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500446 # Remove possible extraneous strings
447 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
448 gothelp = result.stdout.replace(extra, '')
449 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700450 self.assertEqual(0, len(result.stderr))
451 self.assertEqual(0, result.return_code)
452
453 def testFullHelpInternal(self):
454 """Test that the full help is displayed with -H"""
455 try:
456 command.test_result = command.CommandResult()
457 result = self._DoBinman('-H')
458 help_file = os.path.join(self._binman_dir, 'README')
459 finally:
460 command.test_result = None
461
462 def testHelp(self):
463 """Test that the basic help is displayed with -h"""
464 result = self._RunBinman('-h')
465 self.assertTrue(len(result.stdout) > 200)
466 self.assertEqual(0, len(result.stderr))
467 self.assertEqual(0, result.return_code)
468
Simon Glass4f443042016-11-25 20:15:52 -0700469 def testBoard(self):
470 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600471 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700472 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
473 result = self._DoBinman('-b', 'sandbox')
474 self.assertEqual(0, result)
475
476 def testNeedBoard(self):
477 """Test that we get an error when no board ius supplied"""
478 with self.assertRaises(ValueError) as e:
479 result = self._DoBinman()
480 self.assertIn("Must provide a board to process (use -b <board>)",
481 str(e.exception))
482
483 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600484 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700485 with self.assertRaises(Exception) as e:
486 self._RunBinman('-d', 'missing_file')
487 # We get one error from libfdt, and a different one from fdtget.
488 self.AssertInList(["Couldn't open blob from 'missing_file'",
489 'No such file or directory'], str(e.exception))
490
491 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600492 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700493
494 Since this is a source file it should be compiled and the error
495 will come from the device-tree compiler (dtc).
496 """
497 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600498 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700499 self.assertIn("FATAL ERROR: Unable to parse input tree",
500 str(e.exception))
501
502 def testMissingNode(self):
503 """Test that a device tree without a 'binman' node generates an error"""
504 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600505 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700506 self.assertIn("does not have a 'binman' node", str(e.exception))
507
508 def testEmpty(self):
509 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass741f2d62018-10-01 12:22:30 -0600510 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700511 self.assertEqual(0, len(result.stderr))
512 self.assertEqual(0, result.return_code)
513
514 def testInvalidEntry(self):
515 """Test that an invalid entry is flagged"""
516 with self.assertRaises(Exception) as e:
517 result = self._RunBinman('-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600518 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700519 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
520 "'/binman/not-a-valid-type'", str(e.exception))
521
522 def testSimple(self):
523 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600524 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700525 self.assertEqual(U_BOOT_DATA, data)
526
Simon Glass7fe91732017-11-13 18:55:00 -0700527 def testSimpleDebug(self):
528 """Test a simple binman run with debugging enabled"""
Simon Glass741f2d62018-10-01 12:22:30 -0600529 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700530
Simon Glass4f443042016-11-25 20:15:52 -0700531 def testDual(self):
532 """Test that we can handle creating two images
533
534 This also tests image padding.
535 """
Simon Glass741f2d62018-10-01 12:22:30 -0600536 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700537 self.assertEqual(0, retcode)
538
539 image = control.images['image1']
540 self.assertEqual(len(U_BOOT_DATA), image._size)
541 fname = tools.GetOutputFilename('image1.bin')
542 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600543 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700544 data = fd.read()
545 self.assertEqual(U_BOOT_DATA, data)
546
547 image = control.images['image2']
548 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
549 fname = tools.GetOutputFilename('image2.bin')
550 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600551 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700552 data = fd.read()
553 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600554 self.assertEqual(tools.GetBytes(0, 3), data[:3])
555 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700556
557 def testBadAlign(self):
558 """Test that an invalid alignment value is detected"""
559 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600560 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700561 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
562 "of two", str(e.exception))
563
564 def testPackSimple(self):
565 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600566 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700567 self.assertEqual(0, retcode)
568 self.assertIn('image', control.images)
569 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600570 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700571 self.assertEqual(5, len(entries))
572
573 # First u-boot
574 self.assertIn('u-boot', entries)
575 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600576 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700577 self.assertEqual(len(U_BOOT_DATA), entry.size)
578
579 # Second u-boot, aligned to 16-byte boundary
580 self.assertIn('u-boot-align', entries)
581 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600582 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700583 self.assertEqual(len(U_BOOT_DATA), entry.size)
584
585 # Third u-boot, size 23 bytes
586 self.assertIn('u-boot-size', entries)
587 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600588 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700589 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
590 self.assertEqual(23, entry.size)
591
592 # Fourth u-boot, placed immediate after the above
593 self.assertIn('u-boot-next', entries)
594 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600595 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700596 self.assertEqual(len(U_BOOT_DATA), entry.size)
597
Simon Glass3ab95982018-08-01 15:22:37 -0600598 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700599 self.assertIn('u-boot-fixed', entries)
600 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600601 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700602 self.assertEqual(len(U_BOOT_DATA), entry.size)
603
604 self.assertEqual(65, image._size)
605
606 def testPackExtra(self):
607 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600608 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700609
610 self.assertEqual(0, retcode)
611 self.assertIn('image', control.images)
612 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600613 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700614 self.assertEqual(5, len(entries))
615
616 # First u-boot with padding before and after
617 self.assertIn('u-boot', entries)
618 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600619 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700620 self.assertEqual(3, entry.pad_before)
621 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
622
623 # Second u-boot has an aligned size, but it has no effect
624 self.assertIn('u-boot-align-size-nop', entries)
625 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600626 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700627 self.assertEqual(4, entry.size)
628
629 # Third u-boot has an aligned size too
630 self.assertIn('u-boot-align-size', entries)
631 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600632 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700633 self.assertEqual(32, entry.size)
634
635 # Fourth u-boot has an aligned end
636 self.assertIn('u-boot-align-end', entries)
637 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600638 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700639 self.assertEqual(16, entry.size)
640
641 # Fifth u-boot immediately afterwards
642 self.assertIn('u-boot-align-both', entries)
643 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600644 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700645 self.assertEqual(64, entry.size)
646
647 self.CheckNoGaps(entries)
648 self.assertEqual(128, image._size)
649
650 def testPackAlignPowerOf2(self):
651 """Test that invalid entry alignment is detected"""
652 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600653 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
655 "of two", str(e.exception))
656
657 def testPackAlignSizePowerOf2(self):
658 """Test that invalid entry size alignment is detected"""
659 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600660 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700661 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
662 "power of two", str(e.exception))
663
664 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600665 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700666 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600667 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600668 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700669 "align 0x4 (4)", str(e.exception))
670
671 def testPackInvalidSizeAlign(self):
672 """Test that invalid entry size alignment is detected"""
673 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600674 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700675 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
676 "align-size 0x4 (4)", str(e.exception))
677
678 def testPackOverlap(self):
679 """Test that overlapping regions are detected"""
680 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600681 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600682 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700683 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
684 str(e.exception))
685
686 def testPackEntryOverflow(self):
687 """Test that entries that overflow their size are detected"""
688 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600689 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700690 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
691 "but entry size is 0x3 (3)", str(e.exception))
692
693 def testPackImageOverflow(self):
694 """Test that entries which overflow the image size are detected"""
695 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600696 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600697 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700698 "size 0x3 (3)", str(e.exception))
699
700 def testPackImageSize(self):
701 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600702 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700703 self.assertEqual(0, retcode)
704 self.assertIn('image', control.images)
705 image = control.images['image']
706 self.assertEqual(7, image._size)
707
708 def testPackImageSizeAlign(self):
709 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600710 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700711 self.assertEqual(0, retcode)
712 self.assertIn('image', control.images)
713 image = control.images['image']
714 self.assertEqual(16, image._size)
715
716 def testPackInvalidImageAlign(self):
717 """Test that invalid image alignment is detected"""
718 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600719 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600720 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700721 "align-size 0x8 (8)", str(e.exception))
722
723 def testPackAlignPowerOf2(self):
724 """Test that invalid image alignment is detected"""
725 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600726 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600727 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700728 "two", str(e.exception))
729
730 def testImagePadByte(self):
731 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600732 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600733 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600734 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
735 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700736
737 def testImageName(self):
738 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600739 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700740 self.assertEqual(0, retcode)
741 image = control.images['image1']
742 fname = tools.GetOutputFilename('test-name')
743 self.assertTrue(os.path.exists(fname))
744
745 image = control.images['image2']
746 fname = tools.GetOutputFilename('test-name.xx')
747 self.assertTrue(os.path.exists(fname))
748
749 def testBlobFilename(self):
750 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600751 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertEqual(BLOB_DATA, data)
753
754 def testPackSorted(self):
755 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600756 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600757 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600758 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
759 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700760
Simon Glass3ab95982018-08-01 15:22:37 -0600761 def testPackZeroOffset(self):
762 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700763 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600764 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600765 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700766 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
767 str(e.exception))
768
769 def testPackUbootDtb(self):
770 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600771 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700772 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700773
774 def testPackX86RomNoSize(self):
775 """Test that the end-at-4gb property requires a size property"""
776 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600777 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600778 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700779 "using end-at-4gb", str(e.exception))
780
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530781 def test4gbAndSkipAtStartTogether(self):
782 """Test that the end-at-4gb and skip-at-size property can't be used
783 together"""
784 with self.assertRaises(ValueError) as e:
785 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
786 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
787 "'skip-at-start'", str(e.exception))
788
Simon Glasse0ff8552016-11-25 20:15:53 -0700789 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600790 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700791 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600792 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600793 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600794 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700795 str(e.exception))
796
797 def testPackX86Rom(self):
798 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600799 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600800 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600801 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
802 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700803
804 def testPackX86RomMeNoDesc(self):
805 """Test that an invalid Intel descriptor entry is detected"""
806 TestFunctional._MakeInputFile('descriptor.bin', '')
807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600808 self._DoTestFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700809 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
810 "signature", str(e.exception))
811
812 def testPackX86RomBadDesc(self):
813 """Test that the Intel requires a descriptor entry"""
814 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600815 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600816 self.assertIn("Node '/binman/intel-me': No offset set with "
817 "offset-unset: should another entry provide this correct "
818 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700819
820 def testPackX86RomMe(self):
821 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600822 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700823 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
824
825 def testPackVga(self):
826 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600827 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700828 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
829
830 def testPackStart16(self):
831 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600832 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700833 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
834
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530835 def testPackPowerpcMpc85xxBootpgResetvec(self):
836 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
837 created"""
838 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
839 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
840
Simon Glass736bb0a2018-07-06 10:27:17 -0600841 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600842 """Handle running a test for insertion of microcode
843
844 Args:
845 dts_fname: Name of test .dts file
846 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600847 ucode_second: True if the microsecond entry is second instead of
848 third
Simon Glassadc57012018-07-06 10:27:16 -0600849
850 Returns:
851 Tuple:
852 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600853 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600854 in the above (two 4-byte words)
855 """
Simon Glass6b187df2017-11-12 21:52:27 -0700856 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700857
858 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600859 if ucode_second:
860 ucode_content = data[len(nodtb_data):]
861 ucode_pos = len(nodtb_data)
862 dtb_with_ucode = ucode_content[16:]
863 fdt_len = self.GetFdtLen(dtb_with_ucode)
864 else:
865 dtb_with_ucode = data[len(nodtb_data):]
866 fdt_len = self.GetFdtLen(dtb_with_ucode)
867 ucode_content = dtb_with_ucode[fdt_len:]
868 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700869 fname = tools.GetOutputFilename('test.dtb')
870 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600871 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600872 dtb = fdt.FdtScan(fname)
873 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700874 self.assertTrue(ucode)
875 for node in ucode.subnodes:
876 self.assertFalse(node.props.get('data'))
877
Simon Glasse0ff8552016-11-25 20:15:53 -0700878 # Check that the microcode appears immediately after the Fdt
879 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700880 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700881 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
882 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600883 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700884
885 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600886 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700887 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
888 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600889 u_boot = data[:len(nodtb_data)]
890 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700891
892 def testPackUbootMicrocode(self):
893 """Test that x86 microcode can be handled correctly
894
895 We expect to see the following in the image, in order:
896 u-boot-nodtb.bin with a microcode pointer inserted at the correct
897 place
898 u-boot.dtb with the microcode removed
899 the microcode
900 """
Simon Glass741f2d62018-10-01 12:22:30 -0600901 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700902 U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700903 self.assertEqual('nodtb with microcode' + pos_and_size +
904 ' somewhere in here', first)
905
Simon Glass160a7662017-05-27 07:38:26 -0600906 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700907 """Test that x86 microcode can be handled correctly
908
909 We expect to see the following in the image, in order:
910 u-boot-nodtb.bin with a microcode pointer inserted at the correct
911 place
912 u-boot.dtb with the microcode
913 an empty microcode region
914 """
915 # We need the libfdt library to run this test since only that allows
916 # finding the offset of a property. This is required by
917 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600918 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700919
920 second = data[len(U_BOOT_NODTB_DATA):]
921
922 fdt_len = self.GetFdtLen(second)
923 third = second[fdt_len:]
924 second = second[:fdt_len]
925
Simon Glass160a7662017-05-27 07:38:26 -0600926 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
927 self.assertIn(ucode_data, second)
928 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700929
Simon Glass160a7662017-05-27 07:38:26 -0600930 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600931 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600932 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
933 len(ucode_data))
934 first = data[:len(U_BOOT_NODTB_DATA)]
935 self.assertEqual('nodtb with microcode' + pos_and_size +
936 ' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700937
Simon Glass75db0862016-11-25 20:15:55 -0700938 def testPackUbootSingleMicrocode(self):
939 """Test that x86 microcode can be handled correctly with fdt_normal.
940 """
Simon Glass160a7662017-05-27 07:38:26 -0600941 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700942
Simon Glassc49deb82016-11-25 20:15:54 -0700943 def testUBootImg(self):
944 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600945 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -0700946 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700947
948 def testNoMicrocode(self):
949 """Test that a missing microcode region is detected"""
950 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600951 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700952 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
953 "node found in ", str(e.exception))
954
955 def testMicrocodeWithoutNode(self):
956 """Test that a missing u-boot-dtb-with-ucode node is detected"""
957 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600958 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700959 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
960 "microcode region u-boot-dtb-with-ucode", str(e.exception))
961
962 def testMicrocodeWithoutNode2(self):
963 """Test that a missing u-boot-ucode node is detected"""
964 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600965 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700966 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
967 "microcode region u-boot-ucode", str(e.exception))
968
969 def testMicrocodeWithoutPtrInElf(self):
970 """Test that a U-Boot binary without the microcode symbol is detected"""
971 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700972 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -0600973 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700974 TestFunctional._MakeInputFile('u-boot', fd.read())
975
976 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600977 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700978 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
979 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
980
981 finally:
982 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -0600983 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700984 TestFunctional._MakeInputFile('u-boot', fd.read())
985
986 def testMicrocodeNotInImage(self):
987 """Test that microcode must be placed within the image"""
988 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600989 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700990 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
991 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -0600992 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -0700993
994 def testWithoutMicrocode(self):
995 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -0600996 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700997 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -0600998 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700999
1000 # Now check the device tree has no microcode
1001 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1002 second = data[len(U_BOOT_NODTB_DATA):]
1003
1004 fdt_len = self.GetFdtLen(second)
1005 self.assertEqual(dtb, second[:fdt_len])
1006
1007 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1008 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001009 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001010
1011 def testUnknownPosSize(self):
1012 """Test that microcode must be placed within the image"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001014 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001015 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001016 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001017
1018 def testPackFsp(self):
1019 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001020 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001021 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1022
1023 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001024 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001025 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001026 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001027
1028 def testPackVbt(self):
1029 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001030 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001031 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001032
Simon Glass56509842017-11-12 21:52:25 -07001033 def testSplBssPad(self):
1034 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001035 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001036 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001037 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001038 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1039 data)
Simon Glass56509842017-11-12 21:52:25 -07001040
Simon Glass86af5112018-10-01 21:12:42 -06001041 def testSplBssPadMissing(self):
1042 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001043 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001044 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001045 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001046 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1047 str(e.exception))
1048
Simon Glass87722132017-11-12 21:52:26 -07001049 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001050 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001051 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001052 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1053
Simon Glass736bb0a2018-07-06 10:27:17 -06001054 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1055 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001056
1057 We expect to see the following in the image, in order:
1058 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1059 correct place
1060 u-boot.dtb with the microcode removed
1061 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001062
1063 Args:
1064 dts: Device tree file to use for test
1065 ucode_second: True if the microsecond entry is second instead of
1066 third
Simon Glass6b187df2017-11-12 21:52:27 -07001067 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001068 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001069 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1070 ucode_second=ucode_second)
Simon Glass6b187df2017-11-12 21:52:27 -07001071 self.assertEqual('splnodtb with microc' + pos_and_size +
1072 'ter somewhere in here', first)
1073
Simon Glass736bb0a2018-07-06 10:27:17 -06001074 def testPackUbootSplMicrocode(self):
1075 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001076 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001077
1078 def testPackUbootSplMicrocodeReorder(self):
1079 """Test that order doesn't matter for microcode entries
1080
1081 This is the same as testPackUbootSplMicrocode but when we process the
1082 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1083 entry, so we reply on binman to try later.
1084 """
Simon Glass741f2d62018-10-01 12:22:30 -06001085 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001086 ucode_second=True)
1087
Simon Glassca4f4ff2017-11-12 21:52:28 -07001088 def testPackMrc(self):
1089 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001090 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001091 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1092
Simon Glass47419ea2017-11-13 18:54:55 -07001093 def testSplDtb(self):
1094 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001095 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001096 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1097
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001098 def testSplNoDtb(self):
1099 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001100 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001101 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1102
Simon Glass19790632017-11-13 18:55:01 -07001103 def testSymbols(self):
1104 """Test binman can assign symbols embedded in U-Boot"""
1105 elf_fname = self.TestFile('u_boot_binman_syms')
1106 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1107 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001108 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001109
Simon Glass11ae93e2018-10-01 21:12:47 -06001110 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001111 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001112 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001113 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1114 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1115 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001116 self.assertEqual(expected, data)
1117
Simon Glassdd57c132018-06-01 09:38:11 -06001118 def testPackUnitAddress(self):
1119 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001120 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001121 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1122
Simon Glass18546952018-06-01 09:38:16 -06001123 def testSections(self):
1124 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001125 data = self._DoReadFile('055_sections.dts')
Simon Glass8122f392018-07-17 13:25:28 -06001126 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1127 U_BOOT_DATA + '&' * 4)
Simon Glass18546952018-06-01 09:38:16 -06001128 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001129
Simon Glass3b0c3822018-06-01 09:38:20 -06001130 def testMap(self):
1131 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001132 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001133 self.assertEqual('''ImagePos Offset Size Name
113400000000 00000000 00000028 main-section
113500000000 00000000 00000010 section@0
113600000000 00000000 00000004 u-boot
113700000010 00000010 00000010 section@1
113800000010 00000000 00000004 u-boot
113900000020 00000020 00000004 section@2
114000000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001141''', map_data)
1142
Simon Glassc8d48ef2018-06-01 09:38:21 -06001143 def testNamePrefix(self):
1144 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001145 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001146 self.assertEqual('''ImagePos Offset Size Name
114700000000 00000000 00000028 main-section
114800000000 00000000 00000010 section@0
114900000000 00000000 00000004 ro-u-boot
115000000010 00000010 00000010 section@1
115100000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001152''', map_data)
1153
Simon Glass736bb0a2018-07-06 10:27:17 -06001154 def testUnknownContents(self):
1155 """Test that obtaining the contents works as expected"""
1156 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001157 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-07-06 10:27:17 -06001158 self.assertIn("Section '/binman': Internal error: Could not complete "
1159 "processing of contents: remaining [<_testing.Entry__testing ",
1160 str(e.exception))
1161
Simon Glass5c890232018-07-06 10:27:19 -06001162 def testBadChangeSize(self):
1163 """Test that trying to change the size of an entry fails"""
1164 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001165 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-07-06 10:27:19 -06001166 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1167 '2 to 1', str(e.exception))
1168
Simon Glass16b8d6b2018-07-06 10:27:42 -06001169 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001170 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001171 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001172 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001173 dtb = fdt.Fdt(out_dtb_fname)
1174 dtb.Scan()
1175 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001176 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001177 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001178 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001179 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001180 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001181 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001182 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001183 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001184 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001185 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001186 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001187 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001188
Simon Glass3ab95982018-08-01 15:22:37 -06001189 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001190 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001191 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001192 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001193 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001194 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001195 'size': 40
1196 }, props)
1197
1198 def testUpdateFdtBad(self):
1199 """Test that we detect when ProcessFdt never completes"""
1200 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001201 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001202 self.assertIn('Could not complete processing of Fdt: remaining '
1203 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001204
Simon Glass53af22a2018-07-17 13:25:32 -06001205 def testEntryArgs(self):
1206 """Test passing arguments to entries from the command line"""
1207 entry_args = {
1208 'test-str-arg': 'test1',
1209 'test-int-arg': '456',
1210 }
Simon Glass741f2d62018-10-01 12:22:30 -06001211 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001212 self.assertIn('image', control.images)
1213 entry = control.images['image'].GetEntries()['_testing']
1214 self.assertEqual('test0', entry.test_str_fdt)
1215 self.assertEqual('test1', entry.test_str_arg)
1216 self.assertEqual(123, entry.test_int_fdt)
1217 self.assertEqual(456, entry.test_int_arg)
1218
1219 def testEntryArgsMissing(self):
1220 """Test missing arguments and properties"""
1221 entry_args = {
1222 'test-int-arg': '456',
1223 }
Simon Glass741f2d62018-10-01 12:22:30 -06001224 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001225 entry = control.images['image'].GetEntries()['_testing']
1226 self.assertEqual('test0', entry.test_str_fdt)
1227 self.assertEqual(None, entry.test_str_arg)
1228 self.assertEqual(None, entry.test_int_fdt)
1229 self.assertEqual(456, entry.test_int_arg)
1230
1231 def testEntryArgsRequired(self):
1232 """Test missing arguments and properties"""
1233 entry_args = {
1234 'test-int-arg': '456',
1235 }
1236 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001237 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001238 self.assertIn("Node '/binman/_testing': Missing required "
1239 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1240 str(e.exception))
1241
1242 def testEntryArgsInvalidFormat(self):
1243 """Test that an invalid entry-argument format is detected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001244 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001245 with self.assertRaises(ValueError) as e:
1246 self._DoBinman(*args)
1247 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1248
1249 def testEntryArgsInvalidInteger(self):
1250 """Test that an invalid entry-argument integer is detected"""
1251 entry_args = {
1252 'test-int-arg': 'abc',
1253 }
1254 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001255 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001256 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1257 "'test-int-arg' (value 'abc') to integer",
1258 str(e.exception))
1259
1260 def testEntryArgsInvalidDatatype(self):
1261 """Test that an invalid entry-argument datatype is detected
1262
1263 This test could be written in entry_test.py except that it needs
1264 access to control.entry_args, which seems more than that module should
1265 be able to see.
1266 """
1267 entry_args = {
1268 'test-bad-datatype-arg': '12',
1269 }
1270 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001271 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001272 entry_args=entry_args)
1273 self.assertIn('GetArg() internal error: Unknown data type ',
1274 str(e.exception))
1275
Simon Glassbb748372018-07-17 13:25:33 -06001276 def testText(self):
1277 """Test for a text entry type"""
1278 entry_args = {
1279 'test-id': TEXT_DATA,
1280 'test-id2': TEXT_DATA2,
1281 'test-id3': TEXT_DATA3,
1282 }
Simon Glass741f2d62018-10-01 12:22:30 -06001283 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001284 entry_args=entry_args)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001285 expected = (TEXT_DATA + tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1286 TEXT_DATA2 + TEXT_DATA3 + 'some text')
Simon Glassbb748372018-07-17 13:25:33 -06001287 self.assertEqual(expected, data)
1288
Simon Glassfd8d1f72018-07-17 13:25:36 -06001289 def testEntryDocs(self):
1290 """Test for creation of entry documentation"""
1291 with test_util.capture_sys_output() as (stdout, stderr):
1292 control.WriteEntryDocs(binman.GetEntryModules())
1293 self.assertTrue(len(stdout.getvalue()) > 0)
1294
1295 def testEntryDocsMissing(self):
1296 """Test handling of missing entry documentation"""
1297 with self.assertRaises(ValueError) as e:
1298 with test_util.capture_sys_output() as (stdout, stderr):
1299 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1300 self.assertIn('Documentation is missing for modules: u_boot',
1301 str(e.exception))
1302
Simon Glass11e36cc2018-07-17 13:25:38 -06001303 def testFmap(self):
1304 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001305 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001306 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1307 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1308 self.assertEqual(expected, data[:32])
1309 self.assertEqual('__FMAP__', fhdr.signature)
1310 self.assertEqual(1, fhdr.ver_major)
1311 self.assertEqual(0, fhdr.ver_minor)
1312 self.assertEqual(0, fhdr.base)
1313 self.assertEqual(16 + 16 +
1314 fmap_util.FMAP_HEADER_LEN +
1315 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1316 self.assertEqual('FMAP', fhdr.name)
1317 self.assertEqual(3, fhdr.nareas)
1318 for fentry in fentries:
1319 self.assertEqual(0, fentry.flags)
1320
1321 self.assertEqual(0, fentries[0].offset)
1322 self.assertEqual(4, fentries[0].size)
1323 self.assertEqual('RO_U_BOOT', fentries[0].name)
1324
1325 self.assertEqual(16, fentries[1].offset)
1326 self.assertEqual(4, fentries[1].size)
1327 self.assertEqual('RW_U_BOOT', fentries[1].name)
1328
1329 self.assertEqual(32, fentries[2].offset)
1330 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1331 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1332 self.assertEqual('FMAP', fentries[2].name)
1333
Simon Glassec127af2018-07-17 13:25:39 -06001334 def testBlobNamedByArg(self):
1335 """Test we can add a blob with the filename coming from an entry arg"""
1336 entry_args = {
1337 'cros-ec-rw-path': 'ecrw.bin',
1338 }
Simon Glass741f2d62018-10-01 12:22:30 -06001339 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001340 entry_args=entry_args)
1341
Simon Glass3af8e492018-07-17 13:25:40 -06001342 def testFill(self):
1343 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001344 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001345 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001346 self.assertEqual(expected, data)
1347
1348 def testFillNoSize(self):
1349 """Test for an fill entry type with no size"""
1350 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001351 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001352 self.assertIn("'fill' entry must have a size property",
1353 str(e.exception))
1354
Simon Glass0ef87aa2018-07-17 13:25:44 -06001355 def _HandleGbbCommand(self, pipe_list):
1356 """Fake calls to the futility utility"""
1357 if pipe_list[0][0] == 'futility':
1358 fname = pipe_list[0][-1]
1359 # Append our GBB data to the file, which will happen every time the
1360 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001361 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001362 fd.write(GBB_DATA)
1363 return command.CommandResult()
1364
1365 def testGbb(self):
1366 """Test for the Chromium OS Google Binary Block"""
1367 command.test_result = self._HandleGbbCommand
1368 entry_args = {
1369 'keydir': 'devkeys',
1370 'bmpblk': 'bmpblk.bin',
1371 }
Simon Glass741f2d62018-10-01 12:22:30 -06001372 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001373
1374 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001375 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1376 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001377 self.assertEqual(expected, data)
1378
1379 def testGbbTooSmall(self):
1380 """Test for the Chromium OS Google Binary Block being large enough"""
1381 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001382 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001383 self.assertIn("Node '/binman/gbb': GBB is too small",
1384 str(e.exception))
1385
1386 def testGbbNoSize(self):
1387 """Test for the Chromium OS Google Binary Block having a size"""
1388 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001389 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001390 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1391 str(e.exception))
1392
Simon Glass24d0d3c2018-07-17 13:25:47 -06001393 def _HandleVblockCommand(self, pipe_list):
1394 """Fake calls to the futility utility"""
1395 if pipe_list[0][0] == 'futility':
1396 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001397 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001398 fd.write(VBLOCK_DATA)
1399 return command.CommandResult()
1400
1401 def testVblock(self):
1402 """Test for the Chromium OS Verified Boot Block"""
1403 command.test_result = self._HandleVblockCommand
1404 entry_args = {
1405 'keydir': 'devkeys',
1406 }
Simon Glass741f2d62018-10-01 12:22:30 -06001407 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001408 entry_args=entry_args)
1409 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1410 self.assertEqual(expected, data)
1411
1412 def testVblockNoContent(self):
1413 """Test we detect a vblock which has no content to sign"""
1414 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001415 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001416 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1417 'property', str(e.exception))
1418
1419 def testVblockBadPhandle(self):
1420 """Test that we detect a vblock with an invalid phandle in contents"""
1421 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001422 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001423 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1424 '1000', str(e.exception))
1425
1426 def testVblockBadEntry(self):
1427 """Test that we detect an entry that points to a non-entry"""
1428 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001429 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001430 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1431 "'other'", str(e.exception))
1432
Simon Glassb8ef5b62018-07-17 13:25:48 -06001433 def testTpl(self):
1434 """Test that an image with TPL and ots device tree can be created"""
1435 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001436 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001437 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001438 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001439 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1440
Simon Glass15a587c2018-07-17 13:25:51 -06001441 def testUsesPos(self):
1442 """Test that the 'pos' property cannot be used anymore"""
1443 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001444 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001445 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1446 "'pos'", str(e.exception))
1447
Simon Glassd178eab2018-09-14 04:57:08 -06001448 def testFillZero(self):
1449 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001450 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001451 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001452
Simon Glass0b489362018-09-14 04:57:09 -06001453 def testTextMissing(self):
1454 """Test for a text entry type where there is no text"""
1455 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001456 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001457 self.assertIn("Node '/binman/text': No value provided for text label "
1458 "'test-id'", str(e.exception))
1459
Simon Glass35b384c2018-09-14 04:57:10 -06001460 def testPackStart16Tpl(self):
1461 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001462 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001463 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1464
Simon Glass0bfa7b02018-09-14 04:57:12 -06001465 def testSelectImage(self):
1466 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001467 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001468
Simon Glasseb833d82019-04-25 21:58:34 -06001469 # We should only get the expected message in verbose mode
1470 for verbosity in (None, 2):
1471 with test_util.capture_sys_output() as (stdout, stderr):
1472 retcode = self._DoTestFile('006_dual_image.dts',
1473 verbosity=verbosity,
1474 images=['image2'])
1475 self.assertEqual(0, retcode)
1476 if verbosity:
1477 self.assertIn(expected, stdout.getvalue())
1478 else:
1479 self.assertNotIn(expected, stdout.getvalue())
1480
1481 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1482 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001483
Simon Glass6ed45ba2018-09-14 04:57:24 -06001484 def testUpdateFdtAll(self):
1485 """Test that all device trees are updated with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001486 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001487 use_real_dtb=True, update_dtb=True)
1488
1489 base_expected = {
1490 'section:image-pos': 0,
1491 'u-boot-tpl-dtb:size': 513,
1492 'u-boot-spl-dtb:size': 513,
1493 'u-boot-spl-dtb:offset': 493,
1494 'image-pos': 0,
1495 'section/u-boot-dtb:image-pos': 0,
1496 'u-boot-spl-dtb:image-pos': 493,
1497 'section/u-boot-dtb:size': 493,
1498 'u-boot-tpl-dtb:image-pos': 1006,
1499 'section/u-boot-dtb:offset': 0,
1500 'section:size': 493,
1501 'offset': 0,
1502 'section:offset': 0,
1503 'u-boot-tpl-dtb:offset': 1006,
1504 'size': 1519
1505 }
1506
1507 # We expect three device-tree files in the output, one after the other.
1508 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1509 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1510 # main U-Boot tree. All three should have the same postions and offset.
1511 start = 0
1512 for item in ['', 'spl', 'tpl']:
1513 dtb = fdt.Fdt.FromData(data[start:])
1514 dtb.Scan()
1515 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1516 'spl', 'tpl'])
1517 expected = dict(base_expected)
1518 if item:
1519 expected[item] = 0
1520 self.assertEqual(expected, props)
1521 start += dtb._fdt_obj.totalsize()
1522
1523 def testUpdateFdtOutput(self):
1524 """Test that output DTB files are updated"""
1525 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001526 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001527 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1528
1529 # Unfortunately, compiling a source file always results in a file
1530 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001531 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001532 # binman as a file called u-boot.dtb. To fix this, copy the file
1533 # over to the expected place.
1534 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1535 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1536 start = 0
1537 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1538 'tpl/u-boot-tpl.dtb.out']:
1539 dtb = fdt.Fdt.FromData(data[start:])
1540 size = dtb._fdt_obj.totalsize()
1541 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1542 outdata = tools.ReadFile(pathname)
1543 name = os.path.split(fname)[0]
1544
1545 if name:
1546 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1547 else:
1548 orig_indata = dtb_data
1549 self.assertNotEqual(outdata, orig_indata,
1550 "Expected output file '%s' be updated" % pathname)
1551 self.assertEqual(outdata, data[start:start + size],
1552 "Expected output file '%s' to match output image" %
1553 pathname)
1554 start += size
1555 finally:
1556 self._ResetDtbs()
1557
Simon Glass83d73c22018-09-14 04:57:26 -06001558 def _decompress(self, data):
1559 out = os.path.join(self._indir, 'lz4.tmp')
1560 with open(out, 'wb') as fd:
1561 fd.write(data)
Simon Glassb8f08762019-05-14 15:53:45 -06001562 return tools.Run('lz4', '-dc', out, binary=True)
Simon Glass83d73c22018-09-14 04:57:26 -06001563 '''
1564 try:
1565 orig = lz4.frame.decompress(data)
1566 except AttributeError:
1567 orig = lz4.decompress(data)
1568 '''
1569
1570 def testCompress(self):
1571 """Test compression of blobs"""
Simon Glass741f2d62018-10-01 12:22:30 -06001572 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001573 use_real_dtb=True, update_dtb=True)
1574 dtb = fdt.Fdt(out_dtb_fname)
1575 dtb.Scan()
1576 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1577 orig = self._decompress(data)
1578 self.assertEquals(COMPRESS_DATA, orig)
1579 expected = {
1580 'blob:uncomp-size': len(COMPRESS_DATA),
1581 'blob:size': len(data),
1582 'size': len(data),
1583 }
1584 self.assertEqual(expected, props)
1585
Simon Glass0a98b282018-09-14 04:57:28 -06001586 def testFiles(self):
1587 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001588 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001589 self.assertEqual(FILES_DATA, data)
1590
1591 def testFilesCompress(self):
1592 """Test bringing in multiple files and compressing them"""
Simon Glass741f2d62018-10-01 12:22:30 -06001593 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001594
1595 image = control.images['image']
1596 entries = image.GetEntries()
1597 files = entries['files']
1598 entries = files._section._entries
1599
1600 orig = ''
1601 for i in range(1, 3):
1602 key = '%d.dat' % i
1603 start = entries[key].image_pos
1604 len = entries[key].size
1605 chunk = data[start:start + len]
1606 orig += self._decompress(chunk)
1607
1608 self.assertEqual(FILES_DATA, orig)
1609
1610 def testFilesMissing(self):
1611 """Test missing files"""
1612 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001613 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001614 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1615 'no files', str(e.exception))
1616
1617 def testFilesNoPattern(self):
1618 """Test missing files"""
1619 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001620 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001621 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1622 str(e.exception))
1623
Simon Glassba64a0b2018-09-14 04:57:29 -06001624 def testExpandSize(self):
1625 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001626 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001627 map=True)
1628 expect = ('a' * 8 + U_BOOT_DATA +
1629 MRC_DATA + 'b' * 1 + U_BOOT_DATA +
1630 'c' * 8 + U_BOOT_DATA +
1631 'd' * 8)
1632 self.assertEqual(expect, data)
1633 self.assertEqual('''ImagePos Offset Size Name
163400000000 00000000 00000028 main-section
163500000000 00000000 00000008 fill
163600000008 00000008 00000004 u-boot
16370000000c 0000000c 00000004 section
16380000000c 00000000 00000003 intel-mrc
163900000010 00000010 00000004 u-boot2
164000000014 00000014 0000000c section2
164100000014 00000000 00000008 fill
16420000001c 00000008 00000004 u-boot
164300000020 00000020 00000008 fill2
1644''', map_data)
1645
1646 def testExpandSizeBad(self):
1647 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001648 with test_util.capture_sys_output() as (stdout, stderr):
1649 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001650 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001651 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1652 'expanding entry', str(e.exception))
1653
Simon Glasse0e5df92018-09-14 04:57:31 -06001654 def testHash(self):
1655 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001656 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001657 use_real_dtb=True, update_dtb=True)
1658 dtb = fdt.Fdt(out_dtb_fname)
1659 dtb.Scan()
1660 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1661 m = hashlib.sha256()
1662 m.update(U_BOOT_DATA)
1663 self.assertEqual(m.digest(), ''.join(hash_node.value))
1664
1665 def testHashNoAlgo(self):
1666 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001667 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001668 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1669 'hash node', str(e.exception))
1670
1671 def testHashBadAlgo(self):
1672 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001673 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001674 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1675 str(e.exception))
1676
1677 def testHashSection(self):
1678 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001679 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001680 use_real_dtb=True, update_dtb=True)
1681 dtb = fdt.Fdt(out_dtb_fname)
1682 dtb.Scan()
1683 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1684 m = hashlib.sha256()
1685 m.update(U_BOOT_DATA)
1686 m.update(16 * 'a')
1687 self.assertEqual(m.digest(), ''.join(hash_node.value))
1688
Simon Glassf0253632018-09-14 04:57:32 -06001689 def testPackUBootTplMicrocode(self):
1690 """Test that x86 microcode can be handled correctly in TPL
1691
1692 We expect to see the following in the image, in order:
1693 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1694 place
1695 u-boot-tpl.dtb with the microcode removed
1696 the microcode
1697 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001698 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001699 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001700 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001701 U_BOOT_TPL_NODTB_DATA)
1702 self.assertEqual('tplnodtb with microc' + pos_and_size +
1703 'ter somewhere in here', first)
1704
Simon Glassf8f8df62018-09-14 04:57:34 -06001705 def testFmapX86(self):
1706 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001707 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001708 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1709 expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7)
1710 self.assertEqual(expected, data[:32])
1711 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1712
1713 self.assertEqual(0x100, fhdr.image_size)
1714
1715 self.assertEqual(0, fentries[0].offset)
1716 self.assertEqual(4, fentries[0].size)
1717 self.assertEqual('U_BOOT', fentries[0].name)
1718
1719 self.assertEqual(4, fentries[1].offset)
1720 self.assertEqual(3, fentries[1].size)
1721 self.assertEqual('INTEL_MRC', fentries[1].name)
1722
1723 self.assertEqual(32, fentries[2].offset)
1724 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1725 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1726 self.assertEqual('FMAP', fentries[2].name)
1727
1728 def testFmapX86Section(self):
1729 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001730 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001731 expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7)
1732 self.assertEqual(expected, data[:32])
1733 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1734
1735 self.assertEqual(0x100, fhdr.image_size)
1736
1737 self.assertEqual(0, fentries[0].offset)
1738 self.assertEqual(4, fentries[0].size)
1739 self.assertEqual('U_BOOT', fentries[0].name)
1740
1741 self.assertEqual(4, fentries[1].offset)
1742 self.assertEqual(3, fentries[1].size)
1743 self.assertEqual('INTEL_MRC', fentries[1].name)
1744
1745 self.assertEqual(36, fentries[2].offset)
1746 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1747 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1748 self.assertEqual('FMAP', fentries[2].name)
1749
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001750 def testElf(self):
1751 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001752 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001753 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001754 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001755 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001756
1757 def testElfStripg(self):
1758 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001759 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001760 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001761 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001762 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001763
Simon Glass163ed6c2018-09-14 04:57:36 -06001764 def testPackOverlapMap(self):
1765 """Test that overlapping regions are detected"""
1766 with test_util.capture_sys_output() as (stdout, stderr):
1767 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001768 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001769 map_fname = tools.GetOutputFilename('image.map')
1770 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1771 stdout.getvalue())
1772
1773 # We should not get an inmage, but there should be a map file
1774 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1775 self.assertTrue(os.path.exists(map_fname))
1776 map_data = tools.ReadFile(map_fname)
1777 self.assertEqual('''ImagePos Offset Size Name
1778<none> 00000000 00000007 main-section
1779<none> 00000000 00000004 u-boot
1780<none> 00000003 00000004 u-boot-align
1781''', map_data)
1782
Simon Glass3ae192c2018-10-01 12:22:31 -06001783 def testPacRefCode(self):
1784 """Test that an image with an Intel Reference code binary works"""
1785 data = self._DoReadFile('100_intel_refcode.dts')
1786 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1787
Simon Glass9481c802019-04-25 21:58:39 -06001788 def testSectionOffset(self):
1789 """Tests use of a section with an offset"""
1790 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1791 map=True)
1792 self.assertEqual('''ImagePos Offset Size Name
179300000000 00000000 00000038 main-section
179400000004 00000004 00000010 section@0
179500000004 00000000 00000004 u-boot
179600000018 00000018 00000010 section@1
179700000018 00000000 00000004 u-boot
17980000002c 0000002c 00000004 section@2
17990000002c 00000000 00000004 u-boot
1800''', map_data)
1801 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001802 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1803 tools.GetBytes(0x21, 12) +
1804 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1805 tools.GetBytes(0x61, 12) +
1806 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1807 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001808
Simon Glass53af22a2018-07-17 13:25:32 -06001809
Simon Glass9fc60b42017-11-12 21:52:22 -07001810if __name__ == "__main__":
1811 unittest.main()