blob: e1fc9e8e9e8f19c82338042ade2d9c45ca6d2f75 [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])
554 self.assertEqual(chr(0) * 3, data[:3])
555 self.assertEqual(chr(0) * 5, data[7:])
556
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 Glassf6898902017-11-13 18:54:59 -0700734 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700735
736 def testImageName(self):
737 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600738 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700739 self.assertEqual(0, retcode)
740 image = control.images['image1']
741 fname = tools.GetOutputFilename('test-name')
742 self.assertTrue(os.path.exists(fname))
743
744 image = control.images['image2']
745 fname = tools.GetOutputFilename('test-name.xx')
746 self.assertTrue(os.path.exists(fname))
747
748 def testBlobFilename(self):
749 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600750 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700751 self.assertEqual(BLOB_DATA, data)
752
753 def testPackSorted(self):
754 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600755 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600756 data = self._DoReadFile('024_sorted.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700757 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
Simon Glass4f443042016-11-25 20:15:52 -0700758 U_BOOT_DATA, data)
759
Simon Glass3ab95982018-08-01 15:22:37 -0600760 def testPackZeroOffset(self):
761 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700762 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600763 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600764 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700765 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
766 str(e.exception))
767
768 def testPackUbootDtb(self):
769 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600770 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700771 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700772
773 def testPackX86RomNoSize(self):
774 """Test that the end-at-4gb property requires a size property"""
775 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600776 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600777 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700778 "using end-at-4gb", str(e.exception))
779
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530780 def test4gbAndSkipAtStartTogether(self):
781 """Test that the end-at-4gb and skip-at-size property can't be used
782 together"""
783 with self.assertRaises(ValueError) as e:
784 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
785 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
786 "'skip-at-start'", str(e.exception))
787
Simon Glasse0ff8552016-11-25 20:15:53 -0700788 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600789 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700790 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600791 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600792 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600793 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700794 str(e.exception))
795
796 def testPackX86Rom(self):
797 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600798 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600799 data = self._DoReadFile('029_x86-rom.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700800 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
801 chr(0) * 2, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700802
803 def testPackX86RomMeNoDesc(self):
804 """Test that an invalid Intel descriptor entry is detected"""
805 TestFunctional._MakeInputFile('descriptor.bin', '')
806 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600807 self._DoTestFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700808 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
809 "signature", str(e.exception))
810
811 def testPackX86RomBadDesc(self):
812 """Test that the Intel requires a descriptor entry"""
813 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600814 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600815 self.assertIn("Node '/binman/intel-me': No offset set with "
816 "offset-unset: should another entry provide this correct "
817 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700818
819 def testPackX86RomMe(self):
820 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600821 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700822 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
823
824 def testPackVga(self):
825 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600826 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700827 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
828
829 def testPackStart16(self):
830 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600831 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700832 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
833
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530834 def testPackPowerpcMpc85xxBootpgResetvec(self):
835 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
836 created"""
837 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
838 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
839
Simon Glass736bb0a2018-07-06 10:27:17 -0600840 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600841 """Handle running a test for insertion of microcode
842
843 Args:
844 dts_fname: Name of test .dts file
845 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600846 ucode_second: True if the microsecond entry is second instead of
847 third
Simon Glassadc57012018-07-06 10:27:16 -0600848
849 Returns:
850 Tuple:
851 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600852 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600853 in the above (two 4-byte words)
854 """
Simon Glass6b187df2017-11-12 21:52:27 -0700855 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700856
857 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600858 if ucode_second:
859 ucode_content = data[len(nodtb_data):]
860 ucode_pos = len(nodtb_data)
861 dtb_with_ucode = ucode_content[16:]
862 fdt_len = self.GetFdtLen(dtb_with_ucode)
863 else:
864 dtb_with_ucode = data[len(nodtb_data):]
865 fdt_len = self.GetFdtLen(dtb_with_ucode)
866 ucode_content = dtb_with_ucode[fdt_len:]
867 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700868 fname = tools.GetOutputFilename('test.dtb')
869 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600870 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600871 dtb = fdt.FdtScan(fname)
872 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700873 self.assertTrue(ucode)
874 for node in ucode.subnodes:
875 self.assertFalse(node.props.get('data'))
876
Simon Glasse0ff8552016-11-25 20:15:53 -0700877 # Check that the microcode appears immediately after the Fdt
878 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700879 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700880 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
881 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600882 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700883
884 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600885 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700886 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
887 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600888 u_boot = data[:len(nodtb_data)]
889 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700890
891 def testPackUbootMicrocode(self):
892 """Test that x86 microcode can be handled correctly
893
894 We expect to see the following in the image, in order:
895 u-boot-nodtb.bin with a microcode pointer inserted at the correct
896 place
897 u-boot.dtb with the microcode removed
898 the microcode
899 """
Simon Glass741f2d62018-10-01 12:22:30 -0600900 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700901 U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700902 self.assertEqual('nodtb with microcode' + pos_and_size +
903 ' somewhere in here', first)
904
Simon Glass160a7662017-05-27 07:38:26 -0600905 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700906 """Test that x86 microcode can be handled correctly
907
908 We expect to see the following in the image, in order:
909 u-boot-nodtb.bin with a microcode pointer inserted at the correct
910 place
911 u-boot.dtb with the microcode
912 an empty microcode region
913 """
914 # We need the libfdt library to run this test since only that allows
915 # finding the offset of a property. This is required by
916 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600917 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700918
919 second = data[len(U_BOOT_NODTB_DATA):]
920
921 fdt_len = self.GetFdtLen(second)
922 third = second[fdt_len:]
923 second = second[:fdt_len]
924
Simon Glass160a7662017-05-27 07:38:26 -0600925 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
926 self.assertIn(ucode_data, second)
927 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700928
Simon Glass160a7662017-05-27 07:38:26 -0600929 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600930 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600931 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
932 len(ucode_data))
933 first = data[:len(U_BOOT_NODTB_DATA)]
934 self.assertEqual('nodtb with microcode' + pos_and_size +
935 ' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700936
Simon Glass75db0862016-11-25 20:15:55 -0700937 def testPackUbootSingleMicrocode(self):
938 """Test that x86 microcode can be handled correctly with fdt_normal.
939 """
Simon Glass160a7662017-05-27 07:38:26 -0600940 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700941
Simon Glassc49deb82016-11-25 20:15:54 -0700942 def testUBootImg(self):
943 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600944 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -0700945 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700946
947 def testNoMicrocode(self):
948 """Test that a missing microcode region is detected"""
949 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600950 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700951 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
952 "node found in ", str(e.exception))
953
954 def testMicrocodeWithoutNode(self):
955 """Test that a missing u-boot-dtb-with-ucode node is detected"""
956 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600957 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700958 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
959 "microcode region u-boot-dtb-with-ucode", str(e.exception))
960
961 def testMicrocodeWithoutNode2(self):
962 """Test that a missing u-boot-ucode node is detected"""
963 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600964 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700965 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
966 "microcode region u-boot-ucode", str(e.exception))
967
968 def testMicrocodeWithoutPtrInElf(self):
969 """Test that a U-Boot binary without the microcode symbol is detected"""
970 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700971 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -0600972 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700973 TestFunctional._MakeInputFile('u-boot', fd.read())
974
975 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600976 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700977 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
978 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
979
980 finally:
981 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -0600982 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700983 TestFunctional._MakeInputFile('u-boot', fd.read())
984
985 def testMicrocodeNotInImage(self):
986 """Test that microcode must be placed within the image"""
987 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600988 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700989 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
990 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -0600991 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -0700992
993 def testWithoutMicrocode(self):
994 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -0600995 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700996 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -0600997 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700998
999 # Now check the device tree has no microcode
1000 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1001 second = data[len(U_BOOT_NODTB_DATA):]
1002
1003 fdt_len = self.GetFdtLen(second)
1004 self.assertEqual(dtb, second[:fdt_len])
1005
1006 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1007 third = data[used_len:]
1008 self.assertEqual(chr(0) * (0x200 - used_len), third)
1009
1010 def testUnknownPosSize(self):
1011 """Test that microcode must be placed within the image"""
1012 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001013 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001014 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001015 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001016
1017 def testPackFsp(self):
1018 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001019 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001020 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1021
1022 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001023 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001024 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001025 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001026
1027 def testPackVbt(self):
1028 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001029 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001030 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001031
Simon Glass56509842017-11-12 21:52:25 -07001032 def testSplBssPad(self):
1033 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001034 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001035 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001036 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass56509842017-11-12 21:52:25 -07001037 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
1038
Simon Glass86af5112018-10-01 21:12:42 -06001039 def testSplBssPadMissing(self):
1040 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001041 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001042 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001043 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001044 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1045 str(e.exception))
1046
Simon Glass87722132017-11-12 21:52:26 -07001047 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001048 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001049 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001050 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1051
Simon Glass736bb0a2018-07-06 10:27:17 -06001052 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1053 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001054
1055 We expect to see the following in the image, in order:
1056 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1057 correct place
1058 u-boot.dtb with the microcode removed
1059 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001060
1061 Args:
1062 dts: Device tree file to use for test
1063 ucode_second: True if the microsecond entry is second instead of
1064 third
Simon Glass6b187df2017-11-12 21:52:27 -07001065 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001066 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001067 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1068 ucode_second=ucode_second)
Simon Glass6b187df2017-11-12 21:52:27 -07001069 self.assertEqual('splnodtb with microc' + pos_and_size +
1070 'ter somewhere in here', first)
1071
Simon Glass736bb0a2018-07-06 10:27:17 -06001072 def testPackUbootSplMicrocode(self):
1073 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001074 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001075
1076 def testPackUbootSplMicrocodeReorder(self):
1077 """Test that order doesn't matter for microcode entries
1078
1079 This is the same as testPackUbootSplMicrocode but when we process the
1080 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1081 entry, so we reply on binman to try later.
1082 """
Simon Glass741f2d62018-10-01 12:22:30 -06001083 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001084 ucode_second=True)
1085
Simon Glassca4f4ff2017-11-12 21:52:28 -07001086 def testPackMrc(self):
1087 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001088 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001089 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1090
Simon Glass47419ea2017-11-13 18:54:55 -07001091 def testSplDtb(self):
1092 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001093 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001094 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1095
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001096 def testSplNoDtb(self):
1097 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001098 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001099 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1100
Simon Glass19790632017-11-13 18:55:01 -07001101 def testSymbols(self):
1102 """Test binman can assign symbols embedded in U-Boot"""
1103 elf_fname = self.TestFile('u_boot_binman_syms')
1104 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1105 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001106 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001107
Simon Glass11ae93e2018-10-01 21:12:47 -06001108 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001109 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001110 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1111 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1112 U_BOOT_DATA +
1113 sym_values + U_BOOT_SPL_DATA[16:])
1114 self.assertEqual(expected, data)
1115
Simon Glassdd57c132018-06-01 09:38:11 -06001116 def testPackUnitAddress(self):
1117 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001118 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001119 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1120
Simon Glass18546952018-06-01 09:38:16 -06001121 def testSections(self):
1122 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001123 data = self._DoReadFile('055_sections.dts')
Simon Glass8122f392018-07-17 13:25:28 -06001124 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1125 U_BOOT_DATA + '&' * 4)
Simon Glass18546952018-06-01 09:38:16 -06001126 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001127
Simon Glass3b0c3822018-06-01 09:38:20 -06001128 def testMap(self):
1129 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001130 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001131 self.assertEqual('''ImagePos Offset Size Name
113200000000 00000000 00000028 main-section
113300000000 00000000 00000010 section@0
113400000000 00000000 00000004 u-boot
113500000010 00000010 00000010 section@1
113600000010 00000000 00000004 u-boot
113700000020 00000020 00000004 section@2
113800000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001139''', map_data)
1140
Simon Glassc8d48ef2018-06-01 09:38:21 -06001141 def testNamePrefix(self):
1142 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001143 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001144 self.assertEqual('''ImagePos Offset Size Name
114500000000 00000000 00000028 main-section
114600000000 00000000 00000010 section@0
114700000000 00000000 00000004 ro-u-boot
114800000010 00000010 00000010 section@1
114900000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001150''', map_data)
1151
Simon Glass736bb0a2018-07-06 10:27:17 -06001152 def testUnknownContents(self):
1153 """Test that obtaining the contents works as expected"""
1154 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001155 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-07-06 10:27:17 -06001156 self.assertIn("Section '/binman': Internal error: Could not complete "
1157 "processing of contents: remaining [<_testing.Entry__testing ",
1158 str(e.exception))
1159
Simon Glass5c890232018-07-06 10:27:19 -06001160 def testBadChangeSize(self):
1161 """Test that trying to change the size of an entry fails"""
1162 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001163 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-07-06 10:27:19 -06001164 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1165 '2 to 1', str(e.exception))
1166
Simon Glass16b8d6b2018-07-06 10:27:42 -06001167 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001168 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001169 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001170 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001171 dtb = fdt.Fdt(out_dtb_fname)
1172 dtb.Scan()
1173 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001174 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001175 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001176 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001177 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001178 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001179 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001180 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001181 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001182 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001183 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001184 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001185 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001186
Simon Glass3ab95982018-08-01 15:22:37 -06001187 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001188 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001189 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001190 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001191 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001192 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001193 'size': 40
1194 }, props)
1195
1196 def testUpdateFdtBad(self):
1197 """Test that we detect when ProcessFdt never completes"""
1198 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001199 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001200 self.assertIn('Could not complete processing of Fdt: remaining '
1201 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001202
Simon Glass53af22a2018-07-17 13:25:32 -06001203 def testEntryArgs(self):
1204 """Test passing arguments to entries from the command line"""
1205 entry_args = {
1206 'test-str-arg': 'test1',
1207 'test-int-arg': '456',
1208 }
Simon Glass741f2d62018-10-01 12:22:30 -06001209 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001210 self.assertIn('image', control.images)
1211 entry = control.images['image'].GetEntries()['_testing']
1212 self.assertEqual('test0', entry.test_str_fdt)
1213 self.assertEqual('test1', entry.test_str_arg)
1214 self.assertEqual(123, entry.test_int_fdt)
1215 self.assertEqual(456, entry.test_int_arg)
1216
1217 def testEntryArgsMissing(self):
1218 """Test missing arguments and properties"""
1219 entry_args = {
1220 'test-int-arg': '456',
1221 }
Simon Glass741f2d62018-10-01 12:22:30 -06001222 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001223 entry = control.images['image'].GetEntries()['_testing']
1224 self.assertEqual('test0', entry.test_str_fdt)
1225 self.assertEqual(None, entry.test_str_arg)
1226 self.assertEqual(None, entry.test_int_fdt)
1227 self.assertEqual(456, entry.test_int_arg)
1228
1229 def testEntryArgsRequired(self):
1230 """Test missing arguments and properties"""
1231 entry_args = {
1232 'test-int-arg': '456',
1233 }
1234 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001235 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001236 self.assertIn("Node '/binman/_testing': Missing required "
1237 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1238 str(e.exception))
1239
1240 def testEntryArgsInvalidFormat(self):
1241 """Test that an invalid entry-argument format is detected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001242 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001243 with self.assertRaises(ValueError) as e:
1244 self._DoBinman(*args)
1245 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1246
1247 def testEntryArgsInvalidInteger(self):
1248 """Test that an invalid entry-argument integer is detected"""
1249 entry_args = {
1250 'test-int-arg': 'abc',
1251 }
1252 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001253 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001254 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1255 "'test-int-arg' (value 'abc') to integer",
1256 str(e.exception))
1257
1258 def testEntryArgsInvalidDatatype(self):
1259 """Test that an invalid entry-argument datatype is detected
1260
1261 This test could be written in entry_test.py except that it needs
1262 access to control.entry_args, which seems more than that module should
1263 be able to see.
1264 """
1265 entry_args = {
1266 'test-bad-datatype-arg': '12',
1267 }
1268 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001269 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001270 entry_args=entry_args)
1271 self.assertIn('GetArg() internal error: Unknown data type ',
1272 str(e.exception))
1273
Simon Glassbb748372018-07-17 13:25:33 -06001274 def testText(self):
1275 """Test for a text entry type"""
1276 entry_args = {
1277 'test-id': TEXT_DATA,
1278 'test-id2': TEXT_DATA2,
1279 'test-id3': TEXT_DATA3,
1280 }
Simon Glass741f2d62018-10-01 12:22:30 -06001281 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001282 entry_args=entry_args)
1283 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1284 TEXT_DATA3 + 'some text')
1285 self.assertEqual(expected, data)
1286
Simon Glassfd8d1f72018-07-17 13:25:36 -06001287 def testEntryDocs(self):
1288 """Test for creation of entry documentation"""
1289 with test_util.capture_sys_output() as (stdout, stderr):
1290 control.WriteEntryDocs(binman.GetEntryModules())
1291 self.assertTrue(len(stdout.getvalue()) > 0)
1292
1293 def testEntryDocsMissing(self):
1294 """Test handling of missing entry documentation"""
1295 with self.assertRaises(ValueError) as e:
1296 with test_util.capture_sys_output() as (stdout, stderr):
1297 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1298 self.assertIn('Documentation is missing for modules: u_boot',
1299 str(e.exception))
1300
Simon Glass11e36cc2018-07-17 13:25:38 -06001301 def testFmap(self):
1302 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001303 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001304 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1305 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1306 self.assertEqual(expected, data[:32])
1307 self.assertEqual('__FMAP__', fhdr.signature)
1308 self.assertEqual(1, fhdr.ver_major)
1309 self.assertEqual(0, fhdr.ver_minor)
1310 self.assertEqual(0, fhdr.base)
1311 self.assertEqual(16 + 16 +
1312 fmap_util.FMAP_HEADER_LEN +
1313 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1314 self.assertEqual('FMAP', fhdr.name)
1315 self.assertEqual(3, fhdr.nareas)
1316 for fentry in fentries:
1317 self.assertEqual(0, fentry.flags)
1318
1319 self.assertEqual(0, fentries[0].offset)
1320 self.assertEqual(4, fentries[0].size)
1321 self.assertEqual('RO_U_BOOT', fentries[0].name)
1322
1323 self.assertEqual(16, fentries[1].offset)
1324 self.assertEqual(4, fentries[1].size)
1325 self.assertEqual('RW_U_BOOT', fentries[1].name)
1326
1327 self.assertEqual(32, fentries[2].offset)
1328 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1329 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1330 self.assertEqual('FMAP', fentries[2].name)
1331
Simon Glassec127af2018-07-17 13:25:39 -06001332 def testBlobNamedByArg(self):
1333 """Test we can add a blob with the filename coming from an entry arg"""
1334 entry_args = {
1335 'cros-ec-rw-path': 'ecrw.bin',
1336 }
Simon Glass741f2d62018-10-01 12:22:30 -06001337 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001338 entry_args=entry_args)
1339
Simon Glass3af8e492018-07-17 13:25:40 -06001340 def testFill(self):
1341 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001342 data = self._DoReadFile('069_fill.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001343 expected = 8 * chr(0xff) + 8 * chr(0)
1344 self.assertEqual(expected, data)
1345
1346 def testFillNoSize(self):
1347 """Test for an fill entry type with no size"""
1348 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001349 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001350 self.assertIn("'fill' entry must have a size property",
1351 str(e.exception))
1352
Simon Glass0ef87aa2018-07-17 13:25:44 -06001353 def _HandleGbbCommand(self, pipe_list):
1354 """Fake calls to the futility utility"""
1355 if pipe_list[0][0] == 'futility':
1356 fname = pipe_list[0][-1]
1357 # Append our GBB data to the file, which will happen every time the
1358 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001359 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001360 fd.write(GBB_DATA)
1361 return command.CommandResult()
1362
1363 def testGbb(self):
1364 """Test for the Chromium OS Google Binary Block"""
1365 command.test_result = self._HandleGbbCommand
1366 entry_args = {
1367 'keydir': 'devkeys',
1368 'bmpblk': 'bmpblk.bin',
1369 }
Simon Glass741f2d62018-10-01 12:22:30 -06001370 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001371
1372 # Since futility
1373 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1374 self.assertEqual(expected, data)
1375
1376 def testGbbTooSmall(self):
1377 """Test for the Chromium OS Google Binary Block being large enough"""
1378 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001379 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001380 self.assertIn("Node '/binman/gbb': GBB is too small",
1381 str(e.exception))
1382
1383 def testGbbNoSize(self):
1384 """Test for the Chromium OS Google Binary Block having a size"""
1385 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001386 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001387 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1388 str(e.exception))
1389
Simon Glass24d0d3c2018-07-17 13:25:47 -06001390 def _HandleVblockCommand(self, pipe_list):
1391 """Fake calls to the futility utility"""
1392 if pipe_list[0][0] == 'futility':
1393 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001394 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001395 fd.write(VBLOCK_DATA)
1396 return command.CommandResult()
1397
1398 def testVblock(self):
1399 """Test for the Chromium OS Verified Boot Block"""
1400 command.test_result = self._HandleVblockCommand
1401 entry_args = {
1402 'keydir': 'devkeys',
1403 }
Simon Glass741f2d62018-10-01 12:22:30 -06001404 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001405 entry_args=entry_args)
1406 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1407 self.assertEqual(expected, data)
1408
1409 def testVblockNoContent(self):
1410 """Test we detect a vblock which has no content to sign"""
1411 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001412 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001413 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1414 'property', str(e.exception))
1415
1416 def testVblockBadPhandle(self):
1417 """Test that we detect a vblock with an invalid phandle in contents"""
1418 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001419 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001420 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1421 '1000', str(e.exception))
1422
1423 def testVblockBadEntry(self):
1424 """Test that we detect an entry that points to a non-entry"""
1425 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001426 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001427 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1428 "'other'", str(e.exception))
1429
Simon Glassb8ef5b62018-07-17 13:25:48 -06001430 def testTpl(self):
1431 """Test that an image with TPL and ots device tree can be created"""
1432 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001433 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001434 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001435 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001436 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1437
Simon Glass15a587c2018-07-17 13:25:51 -06001438 def testUsesPos(self):
1439 """Test that the 'pos' property cannot be used anymore"""
1440 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001441 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001442 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1443 "'pos'", str(e.exception))
1444
Simon Glassd178eab2018-09-14 04:57:08 -06001445 def testFillZero(self):
1446 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001447 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassd178eab2018-09-14 04:57:08 -06001448 self.assertEqual(chr(0) * 16, data)
1449
Simon Glass0b489362018-09-14 04:57:09 -06001450 def testTextMissing(self):
1451 """Test for a text entry type where there is no text"""
1452 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001453 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001454 self.assertIn("Node '/binman/text': No value provided for text label "
1455 "'test-id'", str(e.exception))
1456
Simon Glass35b384c2018-09-14 04:57:10 -06001457 def testPackStart16Tpl(self):
1458 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001459 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001460 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1461
Simon Glass0bfa7b02018-09-14 04:57:12 -06001462 def testSelectImage(self):
1463 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001464 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001465
Simon Glasseb833d82019-04-25 21:58:34 -06001466 # We should only get the expected message in verbose mode
1467 for verbosity in (None, 2):
1468 with test_util.capture_sys_output() as (stdout, stderr):
1469 retcode = self._DoTestFile('006_dual_image.dts',
1470 verbosity=verbosity,
1471 images=['image2'])
1472 self.assertEqual(0, retcode)
1473 if verbosity:
1474 self.assertIn(expected, stdout.getvalue())
1475 else:
1476 self.assertNotIn(expected, stdout.getvalue())
1477
1478 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1479 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001480
Simon Glass6ed45ba2018-09-14 04:57:24 -06001481 def testUpdateFdtAll(self):
1482 """Test that all device trees are updated with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001483 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001484 use_real_dtb=True, update_dtb=True)
1485
1486 base_expected = {
1487 'section:image-pos': 0,
1488 'u-boot-tpl-dtb:size': 513,
1489 'u-boot-spl-dtb:size': 513,
1490 'u-boot-spl-dtb:offset': 493,
1491 'image-pos': 0,
1492 'section/u-boot-dtb:image-pos': 0,
1493 'u-boot-spl-dtb:image-pos': 493,
1494 'section/u-boot-dtb:size': 493,
1495 'u-boot-tpl-dtb:image-pos': 1006,
1496 'section/u-boot-dtb:offset': 0,
1497 'section:size': 493,
1498 'offset': 0,
1499 'section:offset': 0,
1500 'u-boot-tpl-dtb:offset': 1006,
1501 'size': 1519
1502 }
1503
1504 # We expect three device-tree files in the output, one after the other.
1505 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1506 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1507 # main U-Boot tree. All three should have the same postions and offset.
1508 start = 0
1509 for item in ['', 'spl', 'tpl']:
1510 dtb = fdt.Fdt.FromData(data[start:])
1511 dtb.Scan()
1512 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1513 'spl', 'tpl'])
1514 expected = dict(base_expected)
1515 if item:
1516 expected[item] = 0
1517 self.assertEqual(expected, props)
1518 start += dtb._fdt_obj.totalsize()
1519
1520 def testUpdateFdtOutput(self):
1521 """Test that output DTB files are updated"""
1522 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001523 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001524 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1525
1526 # Unfortunately, compiling a source file always results in a file
1527 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001528 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001529 # binman as a file called u-boot.dtb. To fix this, copy the file
1530 # over to the expected place.
1531 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1532 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1533 start = 0
1534 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1535 'tpl/u-boot-tpl.dtb.out']:
1536 dtb = fdt.Fdt.FromData(data[start:])
1537 size = dtb._fdt_obj.totalsize()
1538 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1539 outdata = tools.ReadFile(pathname)
1540 name = os.path.split(fname)[0]
1541
1542 if name:
1543 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1544 else:
1545 orig_indata = dtb_data
1546 self.assertNotEqual(outdata, orig_indata,
1547 "Expected output file '%s' be updated" % pathname)
1548 self.assertEqual(outdata, data[start:start + size],
1549 "Expected output file '%s' to match output image" %
1550 pathname)
1551 start += size
1552 finally:
1553 self._ResetDtbs()
1554
Simon Glass83d73c22018-09-14 04:57:26 -06001555 def _decompress(self, data):
1556 out = os.path.join(self._indir, 'lz4.tmp')
1557 with open(out, 'wb') as fd:
1558 fd.write(data)
Simon Glassb8f08762019-05-14 15:53:45 -06001559 return tools.Run('lz4', '-dc', out, binary=True)
Simon Glass83d73c22018-09-14 04:57:26 -06001560 '''
1561 try:
1562 orig = lz4.frame.decompress(data)
1563 except AttributeError:
1564 orig = lz4.decompress(data)
1565 '''
1566
1567 def testCompress(self):
1568 """Test compression of blobs"""
Simon Glass741f2d62018-10-01 12:22:30 -06001569 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001570 use_real_dtb=True, update_dtb=True)
1571 dtb = fdt.Fdt(out_dtb_fname)
1572 dtb.Scan()
1573 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1574 orig = self._decompress(data)
1575 self.assertEquals(COMPRESS_DATA, orig)
1576 expected = {
1577 'blob:uncomp-size': len(COMPRESS_DATA),
1578 'blob:size': len(data),
1579 'size': len(data),
1580 }
1581 self.assertEqual(expected, props)
1582
Simon Glass0a98b282018-09-14 04:57:28 -06001583 def testFiles(self):
1584 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001585 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001586 self.assertEqual(FILES_DATA, data)
1587
1588 def testFilesCompress(self):
1589 """Test bringing in multiple files and compressing them"""
Simon Glass741f2d62018-10-01 12:22:30 -06001590 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001591
1592 image = control.images['image']
1593 entries = image.GetEntries()
1594 files = entries['files']
1595 entries = files._section._entries
1596
1597 orig = ''
1598 for i in range(1, 3):
1599 key = '%d.dat' % i
1600 start = entries[key].image_pos
1601 len = entries[key].size
1602 chunk = data[start:start + len]
1603 orig += self._decompress(chunk)
1604
1605 self.assertEqual(FILES_DATA, orig)
1606
1607 def testFilesMissing(self):
1608 """Test missing files"""
1609 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001610 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001611 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1612 'no files', str(e.exception))
1613
1614 def testFilesNoPattern(self):
1615 """Test missing files"""
1616 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001617 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001618 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1619 str(e.exception))
1620
Simon Glassba64a0b2018-09-14 04:57:29 -06001621 def testExpandSize(self):
1622 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001623 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001624 map=True)
1625 expect = ('a' * 8 + U_BOOT_DATA +
1626 MRC_DATA + 'b' * 1 + U_BOOT_DATA +
1627 'c' * 8 + U_BOOT_DATA +
1628 'd' * 8)
1629 self.assertEqual(expect, data)
1630 self.assertEqual('''ImagePos Offset Size Name
163100000000 00000000 00000028 main-section
163200000000 00000000 00000008 fill
163300000008 00000008 00000004 u-boot
16340000000c 0000000c 00000004 section
16350000000c 00000000 00000003 intel-mrc
163600000010 00000010 00000004 u-boot2
163700000014 00000014 0000000c section2
163800000014 00000000 00000008 fill
16390000001c 00000008 00000004 u-boot
164000000020 00000020 00000008 fill2
1641''', map_data)
1642
1643 def testExpandSizeBad(self):
1644 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001645 with test_util.capture_sys_output() as (stdout, stderr):
1646 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001647 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001648 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1649 'expanding entry', str(e.exception))
1650
Simon Glasse0e5df92018-09-14 04:57:31 -06001651 def testHash(self):
1652 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001653 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001654 use_real_dtb=True, update_dtb=True)
1655 dtb = fdt.Fdt(out_dtb_fname)
1656 dtb.Scan()
1657 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1658 m = hashlib.sha256()
1659 m.update(U_BOOT_DATA)
1660 self.assertEqual(m.digest(), ''.join(hash_node.value))
1661
1662 def testHashNoAlgo(self):
1663 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001664 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001665 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1666 'hash node', str(e.exception))
1667
1668 def testHashBadAlgo(self):
1669 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001670 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001671 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1672 str(e.exception))
1673
1674 def testHashSection(self):
1675 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001676 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001677 use_real_dtb=True, update_dtb=True)
1678 dtb = fdt.Fdt(out_dtb_fname)
1679 dtb.Scan()
1680 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1681 m = hashlib.sha256()
1682 m.update(U_BOOT_DATA)
1683 m.update(16 * 'a')
1684 self.assertEqual(m.digest(), ''.join(hash_node.value))
1685
Simon Glassf0253632018-09-14 04:57:32 -06001686 def testPackUBootTplMicrocode(self):
1687 """Test that x86 microcode can be handled correctly in TPL
1688
1689 We expect to see the following in the image, in order:
1690 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1691 place
1692 u-boot-tpl.dtb with the microcode removed
1693 the microcode
1694 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001695 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001696 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001697 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001698 U_BOOT_TPL_NODTB_DATA)
1699 self.assertEqual('tplnodtb with microc' + pos_and_size +
1700 'ter somewhere in here', first)
1701
Simon Glassf8f8df62018-09-14 04:57:34 -06001702 def testFmapX86(self):
1703 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001704 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001705 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1706 expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7)
1707 self.assertEqual(expected, data[:32])
1708 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1709
1710 self.assertEqual(0x100, fhdr.image_size)
1711
1712 self.assertEqual(0, fentries[0].offset)
1713 self.assertEqual(4, fentries[0].size)
1714 self.assertEqual('U_BOOT', fentries[0].name)
1715
1716 self.assertEqual(4, fentries[1].offset)
1717 self.assertEqual(3, fentries[1].size)
1718 self.assertEqual('INTEL_MRC', fentries[1].name)
1719
1720 self.assertEqual(32, fentries[2].offset)
1721 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1722 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1723 self.assertEqual('FMAP', fentries[2].name)
1724
1725 def testFmapX86Section(self):
1726 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001727 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001728 expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7)
1729 self.assertEqual(expected, data[:32])
1730 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1731
1732 self.assertEqual(0x100, fhdr.image_size)
1733
1734 self.assertEqual(0, fentries[0].offset)
1735 self.assertEqual(4, fentries[0].size)
1736 self.assertEqual('U_BOOT', fentries[0].name)
1737
1738 self.assertEqual(4, fentries[1].offset)
1739 self.assertEqual(3, fentries[1].size)
1740 self.assertEqual('INTEL_MRC', fentries[1].name)
1741
1742 self.assertEqual(36, fentries[2].offset)
1743 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1744 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1745 self.assertEqual('FMAP', fentries[2].name)
1746
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001747 def testElf(self):
1748 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001749 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001750 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001751 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001752 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001753
1754 def testElfStripg(self):
1755 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001756 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001757 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001758 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001759 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001760
Simon Glass163ed6c2018-09-14 04:57:36 -06001761 def testPackOverlapMap(self):
1762 """Test that overlapping regions are detected"""
1763 with test_util.capture_sys_output() as (stdout, stderr):
1764 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001765 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001766 map_fname = tools.GetOutputFilename('image.map')
1767 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1768 stdout.getvalue())
1769
1770 # We should not get an inmage, but there should be a map file
1771 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1772 self.assertTrue(os.path.exists(map_fname))
1773 map_data = tools.ReadFile(map_fname)
1774 self.assertEqual('''ImagePos Offset Size Name
1775<none> 00000000 00000007 main-section
1776<none> 00000000 00000004 u-boot
1777<none> 00000003 00000004 u-boot-align
1778''', map_data)
1779
Simon Glass3ae192c2018-10-01 12:22:31 -06001780 def testPacRefCode(self):
1781 """Test that an image with an Intel Reference code binary works"""
1782 data = self._DoReadFile('100_intel_refcode.dts')
1783 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1784
Simon Glass9481c802019-04-25 21:58:39 -06001785 def testSectionOffset(self):
1786 """Tests use of a section with an offset"""
1787 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1788 map=True)
1789 self.assertEqual('''ImagePos Offset Size Name
179000000000 00000000 00000038 main-section
179100000004 00000004 00000010 section@0
179200000004 00000000 00000004 u-boot
179300000018 00000018 00000010 section@1
179400000018 00000000 00000004 u-boot
17950000002c 0000002c 00000004 section@2
17960000002c 00000000 00000004 u-boot
1797''', map_data)
1798 self.assertEqual(data,
1799 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x21) +
1800 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x61) +
1801 4 * chr(0x26) + U_BOOT_DATA + 8 * chr(0x26))
1802
Simon Glass53af22a2018-07-17 13:25:32 -06001803
Simon Glass9fc60b42017-11-12 21:52:22 -07001804if __name__ == "__main__":
1805 unittest.main()