blob: 8577adb538028524080aa8f02cbc7683157cac88 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassae7cf032018-09-14 04:57:31 -06009import hashlib
Simon Glass57454f42016-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 Glass4ca8e042017-11-13 18:55:01 -070022import elf
Simon Glassa9440932017-05-27 07:38:30 -060023import fdt
Simon Glass57454f42016-11-25 20:15:52 -070024import fdt_util
Simon Glass704784b2018-07-17 13:25:38 -060025import fmap_util
Simon Glass969616c2018-07-17 13:25:36 -060026import test_util
Simon Glass29aa7362018-09-14 04:57:19 -060027import state
Simon Glass57454f42016-11-25 20:15:52 -070028import tools
29import tout
30
31# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060032U_BOOT_DATA = b'1234'
33U_BOOT_IMG_DATA = b'img'
34U_BOOT_SPL_DATA = b'56780123456789abcde'
35U_BOOT_TPL_DATA = b'tpl'
36BLOB_DATA = b'89'
37ME_DATA = b'0abcd'
38VGA_DATA = b'vga'
39U_BOOT_DTB_DATA = b'udtb'
40U_BOOT_SPL_DTB_DATA = b'spldtb'
41U_BOOT_TPL_DTB_DATA = b'tpldtb'
42X86_START16_DATA = b'start16'
43X86_START16_SPL_DATA = b'start16spl'
44X86_START16_TPL_DATA = b'start16tpl'
45PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
46U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
47U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
48U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
49FSP_DATA = b'fsp'
50CMC_DATA = b'cmc'
51VBT_DATA = b'vbt'
52MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060053TEXT_DATA = 'text'
54TEXT_DATA2 = 'text2'
55TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060056CROS_EC_RW_DATA = b'ecrw'
57GBB_DATA = b'gbbd'
58BMPBLK_DATA = b'bmp'
59VBLOCK_DATA = b'vblk'
60FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
61 b"sorry you're alive\n")
62COMPRESS_DATA = b'data to compress'
63REFCODE_DATA = b'refcode'
Simon Glassdb168d42018-07-17 13:25:39 -060064
Simon Glass57454f42016-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 Glassb3393262017-11-12 21:52:20 -070082 global entry
83 import entry
84
Simon Glass57454f42016-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 Glass8425a1f2018-07-17 13:25:48 -060096 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -070097 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -070098 TestFunctional._MakeInputFile('me.bin', ME_DATA)
99 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600100 self._ResetDtbs()
Simon Glass72232452016-11-25 20:15:53 -0700101 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya311d4842018-09-03 21:35:08 +0530102 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glasse83679d2017-11-12 21:52:26 -0700103 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
104 X86_START16_SPL_DATA)
Simon Glassed40e962018-09-14 04:57:10 -0600105 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
106 X86_START16_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700107 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700108 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
109 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600110 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
111 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700112 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
113 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700114 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700115 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600116 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600117 TestFunctional._MakeInputDir('devkeys')
118 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600119 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700120
Simon Glass72232452016-11-25 20:15:53 -0700121 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass33486662019-05-14 15:53:42 -0600122 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass72232452016-11-25 20:15:53 -0700123 TestFunctional._MakeInputFile('u-boot', fd.read())
124
125 # Intel flash descriptor file
Simon Glass33486662019-05-14 15:53:42 -0600126 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glass72232452016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
128
Simon Glassac6328c2018-09-14 04:57:28 -0600129 shutil.copytree(self.TestFile('files'),
130 os.path.join(self._indir, 'files'))
131
Simon Glass7ba33592018-09-14 04:57:26 -0600132 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
133
Simon Glass57454f42016-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 Glass8425a1f2018-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 Glass57454f42016-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 Glass075a45c2017-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 Glass57454f42016-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 Glass91710b32018-07-17 13:25:32 -0600189 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600190 entry_args=None, images=None, use_real_dtb=False,
191 verbosity=None):
Simon Glass57454f42016-11-25 20:15:52 -0700192 """Run binman with a given test file
193
194 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600195 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600196 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600197 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600198 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600199 tree before packing it into the image
Simon Glass3b376c32018-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 Glass57454f42016-11-25 20:15:52 -0700204 """
Simon Glass075a45c2017-11-13 18:55:00 -0700205 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
206 if debug:
207 args.append('-D')
Simon Glass30732662018-06-01 09:38:20 -0600208 if map:
209 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600210 if update_dtb:
211 args.append('-up')
Simon Glass31402012018-09-14 04:57:23 -0600212 if not use_real_dtb:
213 args.append('--fake-dtb')
Simon Glassb4595d82019-04-25 21:58:34 -0600214 if verbosity is not None:
215 args.append('-v%d' % verbosity)
Simon Glass91710b32018-07-17 13:25:32 -0600216 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600217 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600218 args.append('-a%s=%s' % (arg, value))
Simon Glass3b376c32018-09-14 04:57:12 -0600219 if images:
220 for image in images:
221 args += ['-i', image]
Simon Glass075a45c2017-11-13 18:55:00 -0700222 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700223
224 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-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 Glass1e324002018-06-01 09:38:19 -0600232 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700233
234 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600235 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700236 """
Simon Glass752e7552018-10-01 21:12:41 -0600237 tools.PrepareOutputDir(None)
Simon Glass57454f42016-11-25 20:15:52 -0700238 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass33486662019-05-14 15:53:42 -0600239 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700240 data = fd.read()
241 TestFunctional._MakeInputFile(outfile, data)
Simon Glass752e7552018-10-01 21:12:41 -0600242 tools.FinaliseOutputDir()
243 return data
Simon Glass57454f42016-11-25 20:15:52 -0700244
Simon Glasse219aa42018-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 Glassa87014e2018-07-06 10:27:42 -0600263 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glasse219aa42018-09-14 04:57:24 -0600264 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600274 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-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 Glass30732662018-06-01 09:38:20 -0600279 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600280 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600281 tree before packing it into the image
Simon Glass72232452016-11-25 20:15:53 -0700282
283 Returns:
284 Tuple:
285 Resulting image contents
286 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600287 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600288 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700289 """
Simon Glass72232452016-11-25 20:15:53 -0700290 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700291 # Use the compiled test file as the u-boot-dtb input
292 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700293 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-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 Glass57454f42016-11-25 20:15:52 -0700302
303 try:
Simon Glass91710b32018-07-17 13:25:32 -0600304 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glasse219aa42018-09-14 04:57:24 -0600305 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass57454f42016-11-25 20:15:52 -0700306 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600307 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700308
309 # Find the (only) image, read it and return its contents
310 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600311 image_fname = tools.GetOutputFilename('image.bin')
312 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-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 Glass33486662019-05-14 15:53:42 -0600319 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600320 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700321 finally:
322 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600323 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600324 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700325
Simon Glass72232452016-11-25 20:15:53 -0700326 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600327 """Helper function which discards the device-tree binary
328
329 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600330 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-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 Glassdef77b52018-07-17 13:25:27 -0600335
336 Returns:
337 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600338 """
Simon Glass72232452016-11-25 20:15:53 -0700339 return self._DoReadFileDtb(fname, use_real_dtb)[0]
340
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600346 fname: Filename to create
Simon Glass57454f42016-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 Glassc1ae83c2018-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 Glass7057d022018-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 Glass33486662019-05-14 15:53:42 -0600381 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass7057d022018-10-01 21:12:47 -0600382 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
383
384 @classmethod
Simon Glass57454f42016-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
Simon Glass848cdb52019-05-17 22:00:50 -0600398 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700399
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 Glasse8561af2018-08-01 15:22:37 -0600406 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700407 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600408 self.assertEqual(offset, entry.offset)
409 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700410
Simon Glass72232452016-11-25 20:15:53 -0700411 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600412 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700413
414 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600415 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700416
417 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600418 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700419 """
420 return struct.unpack('>L', dtb[4:8])[0]
421
Simon Glass5463a6a2018-07-17 13:25:52 -0600422 def _GetPropTree(self, dtb, prop_names):
Simon Glassa87014e2018-07-06 10:27:42 -0600423 def AddNode(node, path):
424 if node.name != '/':
425 path += '/' + node.name
Simon Glassa87014e2018-07-06 10:27:42 -0600426 for subnode in node.subnodes:
427 for prop in subnode.props.values():
Simon Glass5463a6a2018-07-17 13:25:52 -0600428 if prop.name in prop_names:
Simon Glassa87014e2018-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 Glassa87014e2018-07-06 10:27:42 -0600432 AddNode(subnode, path)
433
434 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600435 AddNode(dtb.GetRoot(), '')
436 return tree
437
Simon Glass57454f42016-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 Rinic3c0b6d2018-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 Glass57454f42016-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 Glass57454f42016-11-25 20:15:52 -0700469 def testBoard(self):
470 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600471 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-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 Glass1e324002018-06-01 09:38:19 -0600484 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-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 Glass1e324002018-06-01 09:38:19 -0600492 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600498 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600505 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600510 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600518 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600524 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700525 self.assertEqual(U_BOOT_DATA, data)
526
Simon Glass075a45c2017-11-13 18:55:00 -0700527 def testSimpleDebug(self):
528 """Test a simple binman run with debugging enabled"""
Simon Glass511f6582018-10-01 12:22:30 -0600529 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700530
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600536 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-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 Glass33486662019-05-14 15:53:42 -0600543 with open(fname, 'rb') as fd:
Simon Glass57454f42016-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 Glass33486662019-05-14 15:53:42 -0600551 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700552 data = fd.read()
553 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600554 self.assertEqual(tools.GetBytes(0, 3), data[:3])
555 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700556
557 def testBadAlign(self):
558 """Test that an invalid alignment value is detected"""
559 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600560 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600566 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700567 self.assertEqual(0, retcode)
568 self.assertIn('image', control.images)
569 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600570 entries = image.GetEntries()
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600576 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600582 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600588 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600595 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700596 self.assertEqual(len(U_BOOT_DATA), entry.size)
597
Simon Glasse8561af2018-08-01 15:22:37 -0600598 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700599 self.assertIn('u-boot-fixed', entries)
600 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600601 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600608 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700609
610 self.assertEqual(0, retcode)
611 self.assertIn('image', control.images)
612 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600613 entries = image.GetEntries()
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600619 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600626 self.assertEqual(12, entry.offset)
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600632 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600638 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600644 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600653 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600660 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-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 Glasse8561af2018-08-01 15:22:37 -0600665 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700666 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600667 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600668 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600674 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600681 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600682 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600689 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600696 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600697 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600702 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600710 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600719 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600720 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-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 Glass511f6582018-10-01 12:22:30 -0600726 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600727 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-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 Glass7057d022018-10-01 21:12:47 -0600732 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600733 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600734 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
735 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700736
737 def testImageName(self):
738 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600739 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700740 self.assertEqual(0, retcode)
741 image = control.images['image1']
742 fname = tools.GetOutputFilename('test-name')
743 self.assertTrue(os.path.exists(fname))
744
745 image = control.images['image2']
746 fname = tools.GetOutputFilename('test-name.xx')
747 self.assertTrue(os.path.exists(fname))
748
749 def testBlobFilename(self):
750 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600751 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700752 self.assertEqual(BLOB_DATA, data)
753
754 def testPackSorted(self):
755 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600756 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600757 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600758 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
759 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700760
Simon Glasse8561af2018-08-01 15:22:37 -0600761 def testPackZeroOffset(self):
762 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -0700763 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600764 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600765 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700766 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
767 str(e.exception))
768
769 def testPackUbootDtb(self):
770 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -0600771 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700772 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -0700773
774 def testPackX86RomNoSize(self):
775 """Test that the end-at-4gb property requires a size property"""
776 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600777 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600778 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -0700779 "using end-at-4gb", str(e.exception))
780
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530781 def test4gbAndSkipAtStartTogether(self):
782 """Test that the end-at-4gb and skip-at-size property can't be used
783 together"""
784 with self.assertRaises(ValueError) as e:
785 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
786 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
787 "'skip-at-start'", str(e.exception))
788
Simon Glass72232452016-11-25 20:15:53 -0700789 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600790 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -0700791 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600792 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600793 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glasseca32212018-06-01 09:38:12 -0600794 "the section starting at 0xffffffe0 (4294967264)",
Simon Glass72232452016-11-25 20:15:53 -0700795 str(e.exception))
796
797 def testPackX86Rom(self):
798 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -0600799 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600800 data = self._DoReadFile('029_x86-rom.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600801 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
802 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -0700803
804 def testPackX86RomMeNoDesc(self):
805 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass303f62f2019-05-17 22:00:46 -0600806 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glass72232452016-11-25 20:15:53 -0700807 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600808 self._DoTestFile('031_x86-rom-me.dts')
Simon Glassac4738b2019-07-08 13:18:32 -0600809 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
810 str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700811
812 def testPackX86RomBadDesc(self):
813 """Test that the Intel requires a descriptor entry"""
814 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600815 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600816 self.assertIn("Node '/binman/intel-me': No offset set with "
817 "offset-unset: should another entry provide this correct "
818 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700819
820 def testPackX86RomMe(self):
821 """Test that an x86 ROM with an ME region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600822 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glass72232452016-11-25 20:15:53 -0700823 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
824
825 def testPackVga(self):
826 """Test that an image with a VGA binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600827 data = self._DoReadFile('032_intel-vga.dts')
Simon Glass72232452016-11-25 20:15:53 -0700828 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
829
830 def testPackStart16(self):
831 """Test that an image with an x86 start16 region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600832 data = self._DoReadFile('033_x86-start16.dts')
Simon Glass72232452016-11-25 20:15:53 -0700833 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
834
Jagdish Gediya311d4842018-09-03 21:35:08 +0530835 def testPackPowerpcMpc85xxBootpgResetvec(self):
836 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
837 created"""
838 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
839 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
840
Simon Glass6ba679c2018-07-06 10:27:17 -0600841 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -0600842 """Handle running a test for insertion of microcode
843
844 Args:
845 dts_fname: Name of test .dts file
846 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -0600847 ucode_second: True if the microsecond entry is second instead of
848 third
Simon Glass820af1d2018-07-06 10:27:16 -0600849
850 Returns:
851 Tuple:
852 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -0600853 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -0600854 in the above (two 4-byte words)
855 """
Simon Glass3d274232017-11-12 21:52:27 -0700856 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -0700857
858 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -0600859 if ucode_second:
860 ucode_content = data[len(nodtb_data):]
861 ucode_pos = len(nodtb_data)
862 dtb_with_ucode = ucode_content[16:]
863 fdt_len = self.GetFdtLen(dtb_with_ucode)
864 else:
865 dtb_with_ucode = data[len(nodtb_data):]
866 fdt_len = self.GetFdtLen(dtb_with_ucode)
867 ucode_content = dtb_with_ucode[fdt_len:]
868 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -0700869 fname = tools.GetOutputFilename('test.dtb')
870 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -0600871 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -0600872 dtb = fdt.FdtScan(fname)
873 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -0700874 self.assertTrue(ucode)
875 for node in ucode.subnodes:
876 self.assertFalse(node.props.get('data'))
877
Simon Glass72232452016-11-25 20:15:53 -0700878 # Check that the microcode appears immediately after the Fdt
879 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -0700880 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -0700881 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
882 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -0600883 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -0700884
885 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -0600886 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -0700887 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
888 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -0600889 u_boot = data[:len(nodtb_data)]
890 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -0700891
892 def testPackUbootMicrocode(self):
893 """Test that x86 microcode can be handled correctly
894
895 We expect to see the following in the image, in order:
896 u-boot-nodtb.bin with a microcode pointer inserted at the correct
897 place
898 u-boot.dtb with the microcode removed
899 the microcode
900 """
Simon Glass511f6582018-10-01 12:22:30 -0600901 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -0700902 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -0600903 self.assertEqual(b'nodtb with microcode' + pos_and_size +
904 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -0700905
Simon Glassbac25c82017-05-27 07:38:26 -0600906 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -0700907 """Test that x86 microcode can be handled correctly
908
909 We expect to see the following in the image, in order:
910 u-boot-nodtb.bin with a microcode pointer inserted at the correct
911 place
912 u-boot.dtb with the microcode
913 an empty microcode region
914 """
915 # We need the libfdt library to run this test since only that allows
916 # finding the offset of a property. This is required by
917 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -0600918 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -0700919
920 second = data[len(U_BOOT_NODTB_DATA):]
921
922 fdt_len = self.GetFdtLen(second)
923 third = second[fdt_len:]
924 second = second[:fdt_len]
925
Simon Glassbac25c82017-05-27 07:38:26 -0600926 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
927 self.assertIn(ucode_data, second)
928 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700929
Simon Glassbac25c82017-05-27 07:38:26 -0600930 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -0600931 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -0600932 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
933 len(ucode_data))
934 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -0600935 self.assertEqual(b'nodtb with microcode' + pos_and_size +
936 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -0700937
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700938 def testPackUbootSingleMicrocode(self):
939 """Test that x86 microcode can be handled correctly with fdt_normal.
940 """
Simon Glassbac25c82017-05-27 07:38:26 -0600941 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700942
Simon Glass996021e2016-11-25 20:15:54 -0700943 def testUBootImg(self):
944 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -0600945 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -0700946 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700947
948 def testNoMicrocode(self):
949 """Test that a missing microcode region is detected"""
950 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600951 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700952 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
953 "node found in ", str(e.exception))
954
955 def testMicrocodeWithoutNode(self):
956 """Test that a missing u-boot-dtb-with-ucode node is detected"""
957 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600958 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700959 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
960 "microcode region u-boot-dtb-with-ucode", str(e.exception))
961
962 def testMicrocodeWithoutNode2(self):
963 """Test that a missing u-boot-ucode node is detected"""
964 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600965 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700966 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
967 "microcode region u-boot-ucode", str(e.exception))
968
969 def testMicrocodeWithoutPtrInElf(self):
970 """Test that a U-Boot binary without the microcode symbol is detected"""
971 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700972 try:
Simon Glass33486662019-05-14 15:53:42 -0600973 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700974 TestFunctional._MakeInputFile('u-boot', fd.read())
975
976 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -0600977 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700978 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
979 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
980
981 finally:
982 # Put the original file back
Simon Glass33486662019-05-14 15:53:42 -0600983 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700984 TestFunctional._MakeInputFile('u-boot', fd.read())
985
986 def testMicrocodeNotInImage(self):
987 """Test that microcode must be placed within the image"""
988 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600989 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700990 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
991 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -0600992 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700993
994 def testWithoutMicrocode(self):
995 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass33486662019-05-14 15:53:42 -0600996 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700997 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -0600998 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700999
1000 # Now check the device tree has no microcode
1001 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1002 second = data[len(U_BOOT_NODTB_DATA):]
1003
1004 fdt_len = self.GetFdtLen(second)
1005 self.assertEqual(dtb, second[:fdt_len])
1006
1007 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1008 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001009 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001010
1011 def testUnknownPosSize(self):
1012 """Test that microcode must be placed within the image"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001014 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001015 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001016 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001017
1018 def testPackFsp(self):
1019 """Test that an image with a FSP binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001020 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001021 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1022
1023 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001024 """Test that an image with a CMC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001025 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001026 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001027
1028 def testPackVbt(self):
1029 """Test that an image with a VBT binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001030 data = self._DoReadFile('046_intel-vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001031 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001032
Simon Glass7f94e832017-11-12 21:52:25 -07001033 def testSplBssPad(self):
1034 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001035 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001036 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001037 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001038 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1039 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001040
Simon Glass04cda032018-10-01 21:12:42 -06001041 def testSplBssPadMissing(self):
1042 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001043 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001044 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001045 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001046 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1047 str(e.exception))
1048
Simon Glasse83679d2017-11-12 21:52:26 -07001049 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001050 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001051 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001052 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1053
Simon Glass6ba679c2018-07-06 10:27:17 -06001054 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1055 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001056
1057 We expect to see the following in the image, in order:
1058 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1059 correct place
1060 u-boot.dtb with the microcode removed
1061 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001062
1063 Args:
1064 dts: Device tree file to use for test
1065 ucode_second: True if the microsecond entry is second instead of
1066 third
Simon Glass3d274232017-11-12 21:52:27 -07001067 """
Simon Glass7057d022018-10-01 21:12:47 -06001068 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001069 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1070 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001071 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1072 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001073
Simon Glass6ba679c2018-07-06 10:27:17 -06001074 def testPackUbootSplMicrocode(self):
1075 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001076 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001077
1078 def testPackUbootSplMicrocodeReorder(self):
1079 """Test that order doesn't matter for microcode entries
1080
1081 This is the same as testPackUbootSplMicrocode but when we process the
1082 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1083 entry, so we reply on binman to try later.
1084 """
Simon Glass511f6582018-10-01 12:22:30 -06001085 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001086 ucode_second=True)
1087
Simon Glassa409c932017-11-12 21:52:28 -07001088 def testPackMrc(self):
1089 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001090 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001091 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1092
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001093 def testSplDtb(self):
1094 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001095 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001096 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1097
Simon Glass0a6da312017-11-13 18:54:56 -07001098 def testSplNoDtb(self):
1099 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001100 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001101 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1102
Simon Glass4ca8e042017-11-13 18:55:01 -07001103 def testSymbols(self):
1104 """Test binman can assign symbols embedded in U-Boot"""
1105 elf_fname = self.TestFile('u_boot_binman_syms')
1106 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1107 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glasse8561af2018-08-01 15:22:37 -06001108 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001109
Simon Glass7057d022018-10-01 21:12:47 -06001110 self._SetupSplElf('u_boot_binman_syms')
Simon Glass511f6582018-10-01 12:22:30 -06001111 data = self._DoReadFile('053_symbols.dts')
Simon Glass4ca8e042017-11-13 18:55:01 -07001112 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glassac0d4952019-05-14 15:53:47 -06001113 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1114 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1115 U_BOOT_SPL_DATA[16:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001116 self.assertEqual(expected, data)
1117
Simon Glasse76a3e62018-06-01 09:38:11 -06001118 def testPackUnitAddress(self):
1119 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001120 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001121 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1122
Simon Glassa91e1152018-06-01 09:38:16 -06001123 def testSections(self):
1124 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001125 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001126 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1127 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1128 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001129 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001130
Simon Glass30732662018-06-01 09:38:20 -06001131 def testMap(self):
1132 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001133 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001134 self.assertEqual('''ImagePos Offset Size Name
113500000000 00000000 00000028 main-section
113600000000 00000000 00000010 section@0
113700000000 00000000 00000004 u-boot
113800000010 00000010 00000010 section@1
113900000010 00000000 00000004 u-boot
114000000020 00000020 00000004 section@2
114100000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001142''', map_data)
1143
Simon Glass3b78d532018-06-01 09:38:21 -06001144 def testNamePrefix(self):
1145 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001146 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001147 self.assertEqual('''ImagePos Offset Size Name
114800000000 00000000 00000028 main-section
114900000000 00000000 00000010 section@0
115000000000 00000000 00000004 ro-u-boot
115100000010 00000010 00000010 section@1
115200000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001153''', map_data)
1154
Simon Glass6ba679c2018-07-06 10:27:17 -06001155 def testUnknownContents(self):
1156 """Test that obtaining the contents works as expected"""
1157 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001158 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass6ba679c2018-07-06 10:27:17 -06001159 self.assertIn("Section '/binman': Internal error: Could not complete "
1160 "processing of contents: remaining [<_testing.Entry__testing ",
1161 str(e.exception))
1162
Simon Glass2e1169f2018-07-06 10:27:19 -06001163 def testBadChangeSize(self):
1164 """Test that trying to change the size of an entry fails"""
1165 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001166 self._DoReadFile('059_change_size.dts', True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001167 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1168 '2 to 1', str(e.exception))
1169
Simon Glassa87014e2018-07-06 10:27:42 -06001170 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001171 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001172 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001173 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001174 dtb = fdt.Fdt(out_dtb_fname)
1175 dtb.Scan()
1176 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glassa87014e2018-07-06 10:27:42 -06001177 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001178 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001179 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001180 '_testing:offset': 32,
Simon Glassa87014e2018-07-06 10:27:42 -06001181 '_testing:size': 1,
Simon Glass9dcc8612018-08-01 15:22:42 -06001182 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001183 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001184 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001185 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001186 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001187 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001188 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001189
Simon Glasse8561af2018-08-01 15:22:37 -06001190 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001191 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001192 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001193 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001194 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001195 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001196 'size': 40
1197 }, props)
1198
1199 def testUpdateFdtBad(self):
1200 """Test that we detect when ProcessFdt never completes"""
1201 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001202 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001203 self.assertIn('Could not complete processing of Fdt: remaining '
1204 '[<_testing.Entry__testing', str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001205
Simon Glass91710b32018-07-17 13:25:32 -06001206 def testEntryArgs(self):
1207 """Test passing arguments to entries from the command line"""
1208 entry_args = {
1209 'test-str-arg': 'test1',
1210 'test-int-arg': '456',
1211 }
Simon Glass511f6582018-10-01 12:22:30 -06001212 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001213 self.assertIn('image', control.images)
1214 entry = control.images['image'].GetEntries()['_testing']
1215 self.assertEqual('test0', entry.test_str_fdt)
1216 self.assertEqual('test1', entry.test_str_arg)
1217 self.assertEqual(123, entry.test_int_fdt)
1218 self.assertEqual(456, entry.test_int_arg)
1219
1220 def testEntryArgsMissing(self):
1221 """Test missing arguments and properties"""
1222 entry_args = {
1223 'test-int-arg': '456',
1224 }
Simon Glass511f6582018-10-01 12:22:30 -06001225 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001226 entry = control.images['image'].GetEntries()['_testing']
1227 self.assertEqual('test0', entry.test_str_fdt)
1228 self.assertEqual(None, entry.test_str_arg)
1229 self.assertEqual(None, entry.test_int_fdt)
1230 self.assertEqual(456, entry.test_int_arg)
1231
1232 def testEntryArgsRequired(self):
1233 """Test missing arguments and properties"""
1234 entry_args = {
1235 'test-int-arg': '456',
1236 }
1237 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001238 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass91710b32018-07-17 13:25:32 -06001239 self.assertIn("Node '/binman/_testing': Missing required "
1240 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1241 str(e.exception))
1242
1243 def testEntryArgsInvalidFormat(self):
1244 """Test that an invalid entry-argument format is detected"""
Simon Glass511f6582018-10-01 12:22:30 -06001245 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001246 with self.assertRaises(ValueError) as e:
1247 self._DoBinman(*args)
1248 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1249
1250 def testEntryArgsInvalidInteger(self):
1251 """Test that an invalid entry-argument integer is detected"""
1252 entry_args = {
1253 'test-int-arg': 'abc',
1254 }
1255 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001256 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001257 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1258 "'test-int-arg' (value 'abc') to integer",
1259 str(e.exception))
1260
1261 def testEntryArgsInvalidDatatype(self):
1262 """Test that an invalid entry-argument datatype is detected
1263
1264 This test could be written in entry_test.py except that it needs
1265 access to control.entry_args, which seems more than that module should
1266 be able to see.
1267 """
1268 entry_args = {
1269 'test-bad-datatype-arg': '12',
1270 }
1271 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001272 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001273 entry_args=entry_args)
1274 self.assertIn('GetArg() internal error: Unknown data type ',
1275 str(e.exception))
1276
Simon Glass2ca52032018-07-17 13:25:33 -06001277 def testText(self):
1278 """Test for a text entry type"""
1279 entry_args = {
1280 'test-id': TEXT_DATA,
1281 'test-id2': TEXT_DATA2,
1282 'test-id3': TEXT_DATA3,
1283 }
Simon Glass511f6582018-10-01 12:22:30 -06001284 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001285 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001286 expected = (tools.ToBytes(TEXT_DATA) +
1287 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1288 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
1289 b'some text')
Simon Glass2ca52032018-07-17 13:25:33 -06001290 self.assertEqual(expected, data)
1291
Simon Glass969616c2018-07-17 13:25:36 -06001292 def testEntryDocs(self):
1293 """Test for creation of entry documentation"""
1294 with test_util.capture_sys_output() as (stdout, stderr):
1295 control.WriteEntryDocs(binman.GetEntryModules())
1296 self.assertTrue(len(stdout.getvalue()) > 0)
1297
1298 def testEntryDocsMissing(self):
1299 """Test handling of missing entry documentation"""
1300 with self.assertRaises(ValueError) as e:
1301 with test_util.capture_sys_output() as (stdout, stderr):
1302 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1303 self.assertIn('Documentation is missing for modules: u_boot',
1304 str(e.exception))
1305
Simon Glass704784b2018-07-17 13:25:38 -06001306 def testFmap(self):
1307 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001308 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001309 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001310 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1311 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001312 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001313 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001314 self.assertEqual(1, fhdr.ver_major)
1315 self.assertEqual(0, fhdr.ver_minor)
1316 self.assertEqual(0, fhdr.base)
1317 self.assertEqual(16 + 16 +
1318 fmap_util.FMAP_HEADER_LEN +
1319 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001320 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass704784b2018-07-17 13:25:38 -06001321 self.assertEqual(3, fhdr.nareas)
1322 for fentry in fentries:
1323 self.assertEqual(0, fentry.flags)
1324
1325 self.assertEqual(0, fentries[0].offset)
1326 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001327 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass704784b2018-07-17 13:25:38 -06001328
1329 self.assertEqual(16, fentries[1].offset)
1330 self.assertEqual(4, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001331 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass704784b2018-07-17 13:25:38 -06001332
1333 self.assertEqual(32, fentries[2].offset)
1334 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1335 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001336 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass704784b2018-07-17 13:25:38 -06001337
Simon Glassdb168d42018-07-17 13:25:39 -06001338 def testBlobNamedByArg(self):
1339 """Test we can add a blob with the filename coming from an entry arg"""
1340 entry_args = {
1341 'cros-ec-rw-path': 'ecrw.bin',
1342 }
Simon Glass511f6582018-10-01 12:22:30 -06001343 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassdb168d42018-07-17 13:25:39 -06001344 entry_args=entry_args)
1345
Simon Glass53f53992018-07-17 13:25:40 -06001346 def testFill(self):
1347 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001348 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001349 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001350 self.assertEqual(expected, data)
1351
1352 def testFillNoSize(self):
1353 """Test for an fill entry type with no size"""
1354 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001355 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001356 self.assertIn("'fill' entry must have a size property",
1357 str(e.exception))
1358
Simon Glassc1ae83c2018-07-17 13:25:44 -06001359 def _HandleGbbCommand(self, pipe_list):
1360 """Fake calls to the futility utility"""
1361 if pipe_list[0][0] == 'futility':
1362 fname = pipe_list[0][-1]
1363 # Append our GBB data to the file, which will happen every time the
1364 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001365 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001366 fd.write(GBB_DATA)
1367 return command.CommandResult()
1368
1369 def testGbb(self):
1370 """Test for the Chromium OS Google Binary Block"""
1371 command.test_result = self._HandleGbbCommand
1372 entry_args = {
1373 'keydir': 'devkeys',
1374 'bmpblk': 'bmpblk.bin',
1375 }
Simon Glass511f6582018-10-01 12:22:30 -06001376 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001377
1378 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001379 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1380 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001381 self.assertEqual(expected, data)
1382
1383 def testGbbTooSmall(self):
1384 """Test for the Chromium OS Google Binary Block being large enough"""
1385 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001386 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001387 self.assertIn("Node '/binman/gbb': GBB is too small",
1388 str(e.exception))
1389
1390 def testGbbNoSize(self):
1391 """Test for the Chromium OS Google Binary Block having a size"""
1392 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001393 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001394 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1395 str(e.exception))
1396
Simon Glass5c350162018-07-17 13:25:47 -06001397 def _HandleVblockCommand(self, pipe_list):
1398 """Fake calls to the futility utility"""
1399 if pipe_list[0][0] == 'futility':
1400 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001401 with open(fname, 'wb') as fd:
Simon Glass5c350162018-07-17 13:25:47 -06001402 fd.write(VBLOCK_DATA)
1403 return command.CommandResult()
1404
1405 def testVblock(self):
1406 """Test for the Chromium OS Verified Boot Block"""
1407 command.test_result = self._HandleVblockCommand
1408 entry_args = {
1409 'keydir': 'devkeys',
1410 }
Simon Glass511f6582018-10-01 12:22:30 -06001411 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001412 entry_args=entry_args)
1413 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1414 self.assertEqual(expected, data)
1415
1416 def testVblockNoContent(self):
1417 """Test we detect a vblock which has no content to sign"""
1418 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001419 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001420 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1421 'property', str(e.exception))
1422
1423 def testVblockBadPhandle(self):
1424 """Test that we detect a vblock with an invalid phandle in contents"""
1425 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001426 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001427 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1428 '1000', str(e.exception))
1429
1430 def testVblockBadEntry(self):
1431 """Test that we detect an entry that points to a non-entry"""
1432 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001433 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001434 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1435 "'other'", str(e.exception))
1436
Simon Glass8425a1f2018-07-17 13:25:48 -06001437 def testTpl(self):
1438 """Test that an image with TPL and ots device tree can be created"""
1439 # ELF file with a '__bss_size' symbol
Simon Glass33486662019-05-14 15:53:42 -06001440 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass8425a1f2018-07-17 13:25:48 -06001441 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001442 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001443 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1444
Simon Glass24b97442018-07-17 13:25:51 -06001445 def testUsesPos(self):
1446 """Test that the 'pos' property cannot be used anymore"""
1447 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001448 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001449 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1450 "'pos'", str(e.exception))
1451
Simon Glass274bf092018-09-14 04:57:08 -06001452 def testFillZero(self):
1453 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001454 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001455 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001456
Simon Glass267de432018-09-14 04:57:09 -06001457 def testTextMissing(self):
1458 """Test for a text entry type where there is no text"""
1459 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001460 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001461 self.assertIn("Node '/binman/text': No value provided for text label "
1462 "'test-id'", str(e.exception))
1463
Simon Glassed40e962018-09-14 04:57:10 -06001464 def testPackStart16Tpl(self):
1465 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001466 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001467 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1468
Simon Glass3b376c32018-09-14 04:57:12 -06001469 def testSelectImage(self):
1470 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001471 expected = 'Skipping images: image1'
1472
1473 # We should only get the expected message in verbose mode
1474 for verbosity in (None, 2):
1475 with test_util.capture_sys_output() as (stdout, stderr):
1476 retcode = self._DoTestFile('006_dual_image.dts',
1477 verbosity=verbosity,
1478 images=['image2'])
1479 self.assertEqual(0, retcode)
1480 if verbosity:
1481 self.assertIn(expected, stdout.getvalue())
1482 else:
1483 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001484
Simon Glassb4595d82019-04-25 21:58:34 -06001485 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1486 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass3b376c32018-09-14 04:57:12 -06001487
Simon Glasse219aa42018-09-14 04:57:24 -06001488 def testUpdateFdtAll(self):
1489 """Test that all device trees are updated with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001490 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001491 use_real_dtb=True, update_dtb=True)
1492
1493 base_expected = {
1494 'section:image-pos': 0,
1495 'u-boot-tpl-dtb:size': 513,
1496 'u-boot-spl-dtb:size': 513,
1497 'u-boot-spl-dtb:offset': 493,
1498 'image-pos': 0,
1499 'section/u-boot-dtb:image-pos': 0,
1500 'u-boot-spl-dtb:image-pos': 493,
1501 'section/u-boot-dtb:size': 493,
1502 'u-boot-tpl-dtb:image-pos': 1006,
1503 'section/u-boot-dtb:offset': 0,
1504 'section:size': 493,
1505 'offset': 0,
1506 'section:offset': 0,
1507 'u-boot-tpl-dtb:offset': 1006,
1508 'size': 1519
1509 }
1510
1511 # We expect three device-tree files in the output, one after the other.
1512 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1513 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1514 # main U-Boot tree. All three should have the same postions and offset.
1515 start = 0
1516 for item in ['', 'spl', 'tpl']:
1517 dtb = fdt.Fdt.FromData(data[start:])
1518 dtb.Scan()
1519 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1520 'spl', 'tpl'])
1521 expected = dict(base_expected)
1522 if item:
1523 expected[item] = 0
1524 self.assertEqual(expected, props)
1525 start += dtb._fdt_obj.totalsize()
1526
1527 def testUpdateFdtOutput(self):
1528 """Test that output DTB files are updated"""
1529 try:
Simon Glass511f6582018-10-01 12:22:30 -06001530 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001531 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1532
1533 # Unfortunately, compiling a source file always results in a file
1534 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001535 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001536 # binman as a file called u-boot.dtb. To fix this, copy the file
1537 # over to the expected place.
1538 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1539 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1540 start = 0
1541 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1542 'tpl/u-boot-tpl.dtb.out']:
1543 dtb = fdt.Fdt.FromData(data[start:])
1544 size = dtb._fdt_obj.totalsize()
1545 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1546 outdata = tools.ReadFile(pathname)
1547 name = os.path.split(fname)[0]
1548
1549 if name:
1550 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1551 else:
1552 orig_indata = dtb_data
1553 self.assertNotEqual(outdata, orig_indata,
1554 "Expected output file '%s' be updated" % pathname)
1555 self.assertEqual(outdata, data[start:start + size],
1556 "Expected output file '%s' to match output image" %
1557 pathname)
1558 start += size
1559 finally:
1560 self._ResetDtbs()
1561
Simon Glass7ba33592018-09-14 04:57:26 -06001562 def _decompress(self, data):
1563 out = os.path.join(self._indir, 'lz4.tmp')
1564 with open(out, 'wb') as fd:
1565 fd.write(data)
Simon Glass3861cc42019-05-14 15:53:45 -06001566 return tools.Run('lz4', '-dc', out, binary=True)
Simon Glass7ba33592018-09-14 04:57:26 -06001567 '''
1568 try:
1569 orig = lz4.frame.decompress(data)
1570 except AttributeError:
1571 orig = lz4.decompress(data)
1572 '''
1573
1574 def testCompress(self):
1575 """Test compression of blobs"""
Simon Glass511f6582018-10-01 12:22:30 -06001576 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001577 use_real_dtb=True, update_dtb=True)
1578 dtb = fdt.Fdt(out_dtb_fname)
1579 dtb.Scan()
1580 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1581 orig = self._decompress(data)
1582 self.assertEquals(COMPRESS_DATA, orig)
1583 expected = {
1584 'blob:uncomp-size': len(COMPRESS_DATA),
1585 'blob:size': len(data),
1586 'size': len(data),
1587 }
1588 self.assertEqual(expected, props)
1589
Simon Glassac6328c2018-09-14 04:57:28 -06001590 def testFiles(self):
1591 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001592 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001593 self.assertEqual(FILES_DATA, data)
1594
1595 def testFilesCompress(self):
1596 """Test bringing in multiple files and compressing them"""
Simon Glass511f6582018-10-01 12:22:30 -06001597 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001598
1599 image = control.images['image']
1600 entries = image.GetEntries()
1601 files = entries['files']
1602 entries = files._section._entries
1603
Simon Glass303f62f2019-05-17 22:00:46 -06001604 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001605 for i in range(1, 3):
1606 key = '%d.dat' % i
1607 start = entries[key].image_pos
1608 len = entries[key].size
1609 chunk = data[start:start + len]
1610 orig += self._decompress(chunk)
1611
1612 self.assertEqual(FILES_DATA, orig)
1613
1614 def testFilesMissing(self):
1615 """Test missing files"""
1616 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001617 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001618 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1619 'no files', str(e.exception))
1620
1621 def testFilesNoPattern(self):
1622 """Test missing files"""
1623 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001624 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001625 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1626 str(e.exception))
1627
Simon Glassfa79a812018-09-14 04:57:29 -06001628 def testExpandSize(self):
1629 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001630 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001631 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001632 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1633 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1634 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1635 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001636 self.assertEqual(expect, data)
1637 self.assertEqual('''ImagePos Offset Size Name
163800000000 00000000 00000028 main-section
163900000000 00000000 00000008 fill
164000000008 00000008 00000004 u-boot
16410000000c 0000000c 00000004 section
16420000000c 00000000 00000003 intel-mrc
164300000010 00000010 00000004 u-boot2
164400000014 00000014 0000000c section2
164500000014 00000000 00000008 fill
16460000001c 00000008 00000004 u-boot
164700000020 00000020 00000008 fill2
1648''', map_data)
1649
1650 def testExpandSizeBad(self):
1651 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001652 with test_util.capture_sys_output() as (stdout, stderr):
1653 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001654 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001655 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1656 'expanding entry', str(e.exception))
1657
Simon Glassae7cf032018-09-14 04:57:31 -06001658 def testHash(self):
1659 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001660 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001661 use_real_dtb=True, update_dtb=True)
1662 dtb = fdt.Fdt(out_dtb_fname)
1663 dtb.Scan()
1664 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1665 m = hashlib.sha256()
1666 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001667 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001668
1669 def testHashNoAlgo(self):
1670 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001671 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001672 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1673 'hash node', str(e.exception))
1674
1675 def testHashBadAlgo(self):
1676 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001677 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001678 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1679 str(e.exception))
1680
1681 def testHashSection(self):
1682 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001683 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001684 use_real_dtb=True, update_dtb=True)
1685 dtb = fdt.Fdt(out_dtb_fname)
1686 dtb.Scan()
1687 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1688 m = hashlib.sha256()
1689 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001690 m.update(tools.GetBytes(ord('a'), 16))
1691 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001692
Simon Glass3fb4f422018-09-14 04:57:32 -06001693 def testPackUBootTplMicrocode(self):
1694 """Test that x86 microcode can be handled correctly in TPL
1695
1696 We expect to see the following in the image, in order:
1697 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1698 place
1699 u-boot-tpl.dtb with the microcode removed
1700 the microcode
1701 """
Simon Glass33486662019-05-14 15:53:42 -06001702 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass3fb4f422018-09-14 04:57:32 -06001703 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001704 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06001705 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001706 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1707 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06001708
Simon Glassc64aea52018-09-14 04:57:34 -06001709 def testFmapX86(self):
1710 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001711 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001712 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001713 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001714 self.assertEqual(expected, data[:32])
1715 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1716
1717 self.assertEqual(0x100, fhdr.image_size)
1718
1719 self.assertEqual(0, fentries[0].offset)
1720 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001721 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001722
1723 self.assertEqual(4, fentries[1].offset)
1724 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001725 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001726
1727 self.assertEqual(32, fentries[2].offset)
1728 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1729 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001730 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001731
1732 def testFmapX86Section(self):
1733 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001734 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001735 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001736 self.assertEqual(expected, data[:32])
1737 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1738
1739 self.assertEqual(0x100, fhdr.image_size)
1740
1741 self.assertEqual(0, fentries[0].offset)
1742 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001743 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001744
1745 self.assertEqual(4, fentries[1].offset)
1746 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001747 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001748
1749 self.assertEqual(36, fentries[2].offset)
1750 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1751 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001752 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001753
Simon Glassb1714232018-09-14 04:57:35 -06001754 def testElf(self):
1755 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001756 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001757 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001758 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001759 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001760
Simon Glass0d673792019-07-08 13:18:25 -06001761 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06001762 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001763 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001764 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001765 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001766 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001767
Simon Glasscd817d52018-09-14 04:57:36 -06001768 def testPackOverlapMap(self):
1769 """Test that overlapping regions are detected"""
1770 with test_util.capture_sys_output() as (stdout, stderr):
1771 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001772 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06001773 map_fname = tools.GetOutputFilename('image.map')
1774 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1775 stdout.getvalue())
1776
1777 # We should not get an inmage, but there should be a map file
1778 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1779 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06001780 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06001781 self.assertEqual('''ImagePos Offset Size Name
1782<none> 00000000 00000007 main-section
1783<none> 00000000 00000004 u-boot
1784<none> 00000003 00000004 u-boot-align
1785''', map_data)
1786
Simon Glass0d673792019-07-08 13:18:25 -06001787 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06001788 """Test that an image with an Intel Reference code binary works"""
1789 data = self._DoReadFile('100_intel_refcode.dts')
1790 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1791
Simon Glasseb023b32019-04-25 21:58:39 -06001792 def testSectionOffset(self):
1793 """Tests use of a section with an offset"""
1794 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1795 map=True)
1796 self.assertEqual('''ImagePos Offset Size Name
179700000000 00000000 00000038 main-section
179800000004 00000004 00000010 section@0
179900000004 00000000 00000004 u-boot
180000000018 00000018 00000010 section@1
180100000018 00000000 00000004 u-boot
18020000002c 0000002c 00000004 section@2
18030000002c 00000000 00000004 u-boot
1804''', map_data)
1805 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06001806 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1807 tools.GetBytes(0x21, 12) +
1808 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1809 tools.GetBytes(0x61, 12) +
1810 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1811 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06001812
Simon Glass91710b32018-07-17 13:25:32 -06001813
Simon Glassac599912017-11-12 21:52:22 -07001814if __name__ == "__main__":
1815 unittest.main()