blob: d0a8b751a2ce77f4f63d339c3c5fe5483b25e26c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glasse0e5df92018-09-14 04:57:31 -06009import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070010from optparse import OptionParser
11import os
12import shutil
13import struct
14import sys
15import tempfile
16import unittest
17
18import binman
19import cmdline
20import command
21import control
Simon Glass19790632017-11-13 18:55:01 -070022import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060023import fdt
Simon Glass4f443042016-11-25 20:15:52 -070024import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060025import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060026import test_util
Simon Glassc55a50f2018-09-14 04:57:19 -060027import state
Simon Glass4f443042016-11-25 20:15:52 -070028import tools
29import tout
30
31# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-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 Glassbb748372018-07-17 13:25:33 -060053TEXT_DATA = 'text'
54TEXT_DATA2 = 'text2'
55TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-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 Glassec127af2018-07-17 13:25:39 -060064
Simon Glass4f443042016-11-25 20:15:52 -070065
66class TestFunctional(unittest.TestCase):
67 """Functional tests for binman
68
69 Most of these use a sample .dts file to build an image and then check
70 that it looks correct. The sample files are in the test/ subdirectory
71 and are numbered.
72
73 For each entry type a very small test file is created using fixed
74 string contents. This makes it easy to test that things look right, and
75 debug problems.
76
77 In some cases a 'real' file must be used - these are also supplied in
78 the test/ diurectory.
79 """
80 @classmethod
81 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070082 global entry
83 import entry
84
Simon Glass4f443042016-11-25 20:15:52 -070085 # Handle the case where argv[0] is 'python'
86 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
87 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
88
89 # Create a temporary directory for input files
90 self._indir = tempfile.mkdtemp(prefix='binmant.')
91
92 # Create some test files
93 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
94 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
95 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060096 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070097 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -070098 TestFunctional._MakeInputFile('me.bin', ME_DATA)
99 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600100 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700101 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530102 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700103 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
104 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600105 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
106 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700107 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700108 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
109 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600110 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
111 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700112 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
113 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700114 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700115 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600116 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600117 TestFunctional._MakeInputDir('devkeys')
118 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600119 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700120
Simon Glasse0ff8552016-11-25 20:15:53 -0700121 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600122 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700123 TestFunctional._MakeInputFile('u-boot', fd.read())
124
125 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600126 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
128
Simon Glass0a98b282018-09-14 04:57:28 -0600129 shutil.copytree(self.TestFile('files'),
130 os.path.join(self._indir, 'files'))
131
Simon Glass83d73c22018-09-14 04:57:26 -0600132 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
133
Simon Glass4f443042016-11-25 20:15:52 -0700134 @classmethod
135 def tearDownClass(self):
136 """Remove the temporary input directory and its contents"""
137 if self._indir:
138 shutil.rmtree(self._indir)
139 self._indir = None
140
141 def setUp(self):
142 # Enable this to turn on debugging output
143 # tout.Init(tout.DEBUG)
144 command.test_result = None
145
146 def tearDown(self):
147 """Remove the temporary output directory"""
148 tools._FinaliseForTest()
149
Simon Glassb8ef5b62018-07-17 13:25:48 -0600150 @classmethod
151 def _ResetDtbs(self):
152 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
153 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
154 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
155
Simon Glass4f443042016-11-25 20:15:52 -0700156 def _RunBinman(self, *args, **kwargs):
157 """Run binman using the command line
158
159 Args:
160 Arguments to pass, as a list of strings
161 kwargs: Arguments to pass to Command.RunPipe()
162 """
163 result = command.RunPipe([[self._binman_pathname] + list(args)],
164 capture=True, capture_stderr=True, raise_on_error=False)
165 if result.return_code and kwargs.get('raise_on_error', True):
166 raise Exception("Error running '%s': %s" % (' '.join(args),
167 result.stdout + result.stderr))
168 return result
169
170 def _DoBinman(self, *args):
171 """Run binman using directly (in the same process)
172
173 Args:
174 Arguments to pass, as a list of strings
175 Returns:
176 Return value (0 for success)
177 """
Simon Glass7fe91732017-11-13 18:55:00 -0700178 args = list(args)
179 if '-D' in sys.argv:
180 args = args + ['-D']
181 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700182 options.pager = 'binman-invalid-pager'
183 options.build_dir = self._indir
184
185 # For testing, you can force an increase in verbosity here
186 # options.verbosity = tout.DEBUG
187 return control.Binman(options, args)
188
Simon Glass53af22a2018-07-17 13:25:32 -0600189 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600190 entry_args=None, images=None, use_real_dtb=False,
191 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700192 """Run binman with a given test file
193
194 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600195 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600196 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600197 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600198 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600199 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600200 entry_args: Dict of entry args to supply to binman
201 key: arg name
202 value: value of that arg
203 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700204 """
Simon Glass7fe91732017-11-13 18:55:00 -0700205 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
206 if debug:
207 args.append('-D')
Simon Glass3b0c3822018-06-01 09:38:20 -0600208 if map:
209 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600210 if update_dtb:
211 args.append('-up')
Simon Glass93d17412018-09-14 04:57:23 -0600212 if not use_real_dtb:
213 args.append('--fake-dtb')
Simon Glasseb833d82019-04-25 21:58:34 -0600214 if verbosity is not None:
215 args.append('-v%d' % verbosity)
Simon Glass53af22a2018-07-17 13:25:32 -0600216 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600217 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600218 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600219 if images:
220 for image in images:
221 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700222 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700223
224 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700225 """Set up a new test device-tree file
226
227 The given file is compiled and set up as the device tree to be used
228 for ths test.
229
230 Args:
231 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600232 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700233
234 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600235 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700236 """
Simon Glasse0e62752018-10-01 21:12:41 -0600237 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700238 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600239 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700240 data = fd.read()
241 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600242 tools.FinaliseOutputDir()
243 return data
Simon Glass4f443042016-11-25 20:15:52 -0700244
Simon Glass6ed45ba2018-09-14 04:57:24 -0600245 def _GetDtbContentsForSplTpl(self, dtb_data, name):
246 """Create a version of the main DTB for SPL or SPL
247
248 For testing we don't actually have different versions of the DTB. With
249 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
250 we don't normally have any unwanted nodes.
251
252 We still want the DTBs for SPL and TPL to be different though, since
253 otherwise it is confusing to know which one we are looking at. So add
254 an 'spl' or 'tpl' property to the top-level node.
255 """
256 dtb = fdt.Fdt.FromData(dtb_data)
257 dtb.Scan()
258 dtb.GetNode('/binman').AddZeroProp(name)
259 dtb.Sync(auto_resize=True)
260 dtb.Pack()
261 return dtb.GetContents()
262
Simon Glass16b8d6b2018-07-06 10:27:42 -0600263 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600264 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700265 """Run binman and return the resulting image
266
267 This runs binman with a given test file and then reads the resulting
268 output file. It is a shortcut function since most tests need to do
269 these steps.
270
271 Raises an assertion failure if binman returns a non-zero exit code.
272
273 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600274 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700275 use_real_dtb: True to use the test file as the contents of
276 the u-boot-dtb entry. Normally this is not needed and the
277 test contents (the U_BOOT_DTB_DATA string) can be used.
278 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600279 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600280 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600281 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700282
283 Returns:
284 Tuple:
285 Resulting image contents
286 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600287 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600288 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700289 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700290 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700291 # Use the compiled test file as the u-boot-dtb input
292 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700293 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600294
295 # For testing purposes, make a copy of the DT for SPL and TPL. Add
296 # a node indicating which it is, so aid verification.
297 for name in ['spl', 'tpl']:
298 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
299 outfile = os.path.join(self._indir, dtb_fname)
300 TestFunctional._MakeInputFile(dtb_fname,
301 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700302
303 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600304 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600305 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700306 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600307 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700308
309 # Find the (only) image, read it and return its contents
310 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600311 image_fname = tools.GetOutputFilename('image.bin')
312 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600313 if map:
314 map_fname = tools.GetOutputFilename('image.map')
315 with open(map_fname) as fd:
316 map_data = fd.read()
317 else:
318 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600319 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600320 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700321 finally:
322 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600323 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600324 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700325
Simon Glasse0ff8552016-11-25 20:15:53 -0700326 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600327 """Helper function which discards the device-tree binary
328
329 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600330 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600331 use_real_dtb: True to use the test file as the contents of
332 the u-boot-dtb entry. Normally this is not needed and the
333 test contents (the U_BOOT_DTB_DATA string) can be used.
334 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600335
336 Returns:
337 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600338 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700339 return self._DoReadFileDtb(fname, use_real_dtb)[0]
340
Simon Glass4f443042016-11-25 20:15:52 -0700341 @classmethod
342 def _MakeInputFile(self, fname, contents):
343 """Create a new test input file, creating directories as needed
344
345 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600346 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700347 contents: File contents to write in to the file
348 Returns:
349 Full pathname of file created
350 """
351 pathname = os.path.join(self._indir, fname)
352 dirname = os.path.dirname(pathname)
353 if dirname and not os.path.exists(dirname):
354 os.makedirs(dirname)
355 with open(pathname, 'wb') as fd:
356 fd.write(contents)
357 return pathname
358
359 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600360 def _MakeInputDir(self, dirname):
361 """Create a new test input directory, creating directories as needed
362
363 Args:
364 dirname: Directory name to create
365
366 Returns:
367 Full pathname of directory created
368 """
369 pathname = os.path.join(self._indir, dirname)
370 if not os.path.exists(pathname):
371 os.makedirs(pathname)
372 return pathname
373
374 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600375 def _SetupSplElf(self, src_fname='bss_data'):
376 """Set up an ELF file with a '_dt_ucode_base_size' symbol
377
378 Args:
379 Filename of ELF file to use as SPL
380 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600381 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600382 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
383
384 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700385 def TestFile(self, fname):
386 return os.path.join(self._binman_dir, 'test', fname)
387
388 def AssertInList(self, grep_list, target):
389 """Assert that at least one of a list of things is in a target
390
391 Args:
392 grep_list: List of strings to check
393 target: Target string
394 """
395 for grep in grep_list:
396 if grep in target:
397 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600398 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-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 Glass3ab95982018-08-01 15:22:37 -0600406 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700407 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600408 self.assertEqual(offset, entry.offset)
409 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700410
Simon Glasse0ff8552016-11-25 20:15:53 -0700411 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600412 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700413
414 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600415 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700416
417 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600418 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700419 """
420 return struct.unpack('>L', dtb[4:8])[0]
421
Simon Glasscee02e62018-07-17 13:25:52 -0600422 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600423 def AddNode(node, path):
424 if node.name != '/':
425 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600426 for subnode in node.subnodes:
427 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600428 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600429 prop_path = path + '/' + subnode.name + ':' + prop.name
430 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
431 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600432 AddNode(subnode, path)
433
434 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600435 AddNode(dtb.GetRoot(), '')
436 return tree
437
Simon Glass4f443042016-11-25 20:15:52 -0700438 def testRun(self):
439 """Test a basic run with valid args"""
440 result = self._RunBinman('-h')
441
442 def testFullHelp(self):
443 """Test that the full help is displayed with -H"""
444 result = self._RunBinman('-H')
445 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500446 # Remove possible extraneous strings
447 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
448 gothelp = result.stdout.replace(extra, '')
449 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700450 self.assertEqual(0, len(result.stderr))
451 self.assertEqual(0, result.return_code)
452
453 def testFullHelpInternal(self):
454 """Test that the full help is displayed with -H"""
455 try:
456 command.test_result = command.CommandResult()
457 result = self._DoBinman('-H')
458 help_file = os.path.join(self._binman_dir, 'README')
459 finally:
460 command.test_result = None
461
462 def testHelp(self):
463 """Test that the basic help is displayed with -h"""
464 result = self._RunBinman('-h')
465 self.assertTrue(len(result.stdout) > 200)
466 self.assertEqual(0, len(result.stderr))
467 self.assertEqual(0, result.return_code)
468
Simon Glass4f443042016-11-25 20:15:52 -0700469 def testBoard(self):
470 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600471 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700472 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
473 result = self._DoBinman('-b', 'sandbox')
474 self.assertEqual(0, result)
475
476 def testNeedBoard(self):
477 """Test that we get an error when no board ius supplied"""
478 with self.assertRaises(ValueError) as e:
479 result = self._DoBinman()
480 self.assertIn("Must provide a board to process (use -b <board>)",
481 str(e.exception))
482
483 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600484 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700485 with self.assertRaises(Exception) as e:
486 self._RunBinman('-d', 'missing_file')
487 # We get one error from libfdt, and a different one from fdtget.
488 self.AssertInList(["Couldn't open blob from 'missing_file'",
489 'No such file or directory'], str(e.exception))
490
491 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600492 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700493
494 Since this is a source file it should be compiled and the error
495 will come from the device-tree compiler (dtc).
496 """
497 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600498 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700499 self.assertIn("FATAL ERROR: Unable to parse input tree",
500 str(e.exception))
501
502 def testMissingNode(self):
503 """Test that a device tree without a 'binman' node generates an error"""
504 with self.assertRaises(Exception) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600505 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700506 self.assertIn("does not have a 'binman' node", str(e.exception))
507
508 def testEmpty(self):
509 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass741f2d62018-10-01 12:22:30 -0600510 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700511 self.assertEqual(0, len(result.stderr))
512 self.assertEqual(0, result.return_code)
513
514 def testInvalidEntry(self):
515 """Test that an invalid entry is flagged"""
516 with self.assertRaises(Exception) as e:
517 result = self._RunBinman('-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600518 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700519 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
520 "'/binman/not-a-valid-type'", str(e.exception))
521
522 def testSimple(self):
523 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600524 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700525 self.assertEqual(U_BOOT_DATA, data)
526
Simon Glass7fe91732017-11-13 18:55:00 -0700527 def testSimpleDebug(self):
528 """Test a simple binman run with debugging enabled"""
Simon Glass741f2d62018-10-01 12:22:30 -0600529 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700530
Simon Glass4f443042016-11-25 20:15:52 -0700531 def testDual(self):
532 """Test that we can handle creating two images
533
534 This also tests image padding.
535 """
Simon Glass741f2d62018-10-01 12:22:30 -0600536 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700537 self.assertEqual(0, retcode)
538
539 image = control.images['image1']
540 self.assertEqual(len(U_BOOT_DATA), image._size)
541 fname = tools.GetOutputFilename('image1.bin')
542 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600543 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700544 data = fd.read()
545 self.assertEqual(U_BOOT_DATA, data)
546
547 image = control.images['image2']
548 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
549 fname = tools.GetOutputFilename('image2.bin')
550 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600551 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700552 data = fd.read()
553 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600554 self.assertEqual(tools.GetBytes(0, 3), data[:3])
555 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700556
557 def testBadAlign(self):
558 """Test that an invalid alignment value is detected"""
559 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600560 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700561 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
562 "of two", str(e.exception))
563
564 def testPackSimple(self):
565 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600566 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700567 self.assertEqual(0, retcode)
568 self.assertIn('image', control.images)
569 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600570 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700571 self.assertEqual(5, len(entries))
572
573 # First u-boot
574 self.assertIn('u-boot', entries)
575 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600576 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700577 self.assertEqual(len(U_BOOT_DATA), entry.size)
578
579 # Second u-boot, aligned to 16-byte boundary
580 self.assertIn('u-boot-align', entries)
581 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600582 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700583 self.assertEqual(len(U_BOOT_DATA), entry.size)
584
585 # Third u-boot, size 23 bytes
586 self.assertIn('u-boot-size', entries)
587 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600588 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700589 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
590 self.assertEqual(23, entry.size)
591
592 # Fourth u-boot, placed immediate after the above
593 self.assertIn('u-boot-next', entries)
594 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600595 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700596 self.assertEqual(len(U_BOOT_DATA), entry.size)
597
Simon Glass3ab95982018-08-01 15:22:37 -0600598 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700599 self.assertIn('u-boot-fixed', entries)
600 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600601 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700602 self.assertEqual(len(U_BOOT_DATA), entry.size)
603
604 self.assertEqual(65, image._size)
605
606 def testPackExtra(self):
607 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600608 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700609
610 self.assertEqual(0, retcode)
611 self.assertIn('image', control.images)
612 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600613 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700614 self.assertEqual(5, len(entries))
615
616 # First u-boot with padding before and after
617 self.assertIn('u-boot', entries)
618 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600619 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700620 self.assertEqual(3, entry.pad_before)
621 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
622
623 # Second u-boot has an aligned size, but it has no effect
624 self.assertIn('u-boot-align-size-nop', entries)
625 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600626 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700627 self.assertEqual(4, entry.size)
628
629 # Third u-boot has an aligned size too
630 self.assertIn('u-boot-align-size', entries)
631 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600632 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700633 self.assertEqual(32, entry.size)
634
635 # Fourth u-boot has an aligned end
636 self.assertIn('u-boot-align-end', entries)
637 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600638 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700639 self.assertEqual(16, entry.size)
640
641 # Fifth u-boot immediately afterwards
642 self.assertIn('u-boot-align-both', entries)
643 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600644 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700645 self.assertEqual(64, entry.size)
646
647 self.CheckNoGaps(entries)
648 self.assertEqual(128, image._size)
649
650 def testPackAlignPowerOf2(self):
651 """Test that invalid entry alignment is detected"""
652 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600653 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
655 "of two", str(e.exception))
656
657 def testPackAlignSizePowerOf2(self):
658 """Test that invalid entry size alignment is detected"""
659 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600660 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700661 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
662 "power of two", str(e.exception))
663
664 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600665 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700666 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600667 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600668 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700669 "align 0x4 (4)", str(e.exception))
670
671 def testPackInvalidSizeAlign(self):
672 """Test that invalid entry size alignment is detected"""
673 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600674 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700675 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
676 "align-size 0x4 (4)", str(e.exception))
677
678 def testPackOverlap(self):
679 """Test that overlapping regions are detected"""
680 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600681 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600682 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700683 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
684 str(e.exception))
685
686 def testPackEntryOverflow(self):
687 """Test that entries that overflow their size are detected"""
688 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600689 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700690 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
691 "but entry size is 0x3 (3)", str(e.exception))
692
693 def testPackImageOverflow(self):
694 """Test that entries which overflow the image size are detected"""
695 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600696 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600697 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700698 "size 0x3 (3)", str(e.exception))
699
700 def testPackImageSize(self):
701 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600702 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700703 self.assertEqual(0, retcode)
704 self.assertIn('image', control.images)
705 image = control.images['image']
706 self.assertEqual(7, image._size)
707
708 def testPackImageSizeAlign(self):
709 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600710 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700711 self.assertEqual(0, retcode)
712 self.assertIn('image', control.images)
713 image = control.images['image']
714 self.assertEqual(16, image._size)
715
716 def testPackInvalidImageAlign(self):
717 """Test that invalid image alignment is detected"""
718 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600719 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600720 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700721 "align-size 0x8 (8)", str(e.exception))
722
723 def testPackAlignPowerOf2(self):
724 """Test that invalid image alignment is detected"""
725 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600726 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600727 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700728 "two", str(e.exception))
729
730 def testImagePadByte(self):
731 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600732 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600733 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600734 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
735 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700736
737 def testImageName(self):
738 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600739 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700740 self.assertEqual(0, retcode)
741 image = control.images['image1']
742 fname = tools.GetOutputFilename('test-name')
743 self.assertTrue(os.path.exists(fname))
744
745 image = control.images['image2']
746 fname = tools.GetOutputFilename('test-name.xx')
747 self.assertTrue(os.path.exists(fname))
748
749 def testBlobFilename(self):
750 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600751 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertEqual(BLOB_DATA, data)
753
754 def testPackSorted(self):
755 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600756 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600757 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600758 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
759 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700760
Simon Glass3ab95982018-08-01 15:22:37 -0600761 def testPackZeroOffset(self):
762 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700763 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600764 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600765 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700766 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
767 str(e.exception))
768
769 def testPackUbootDtb(self):
770 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600771 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700772 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700773
774 def testPackX86RomNoSize(self):
775 """Test that the end-at-4gb property requires a size property"""
776 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600777 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600778 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700779 "using end-at-4gb", str(e.exception))
780
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530781 def test4gbAndSkipAtStartTogether(self):
782 """Test that the end-at-4gb and skip-at-size property can't be used
783 together"""
784 with self.assertRaises(ValueError) as e:
785 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
786 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
787 "'skip-at-start'", str(e.exception))
788
Simon Glasse0ff8552016-11-25 20:15:53 -0700789 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600790 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700791 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600792 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600793 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600794 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700795 str(e.exception))
796
797 def testPackX86Rom(self):
798 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600799 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600800 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600801 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
802 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700803
804 def testPackX86RomMeNoDesc(self):
805 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600806 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600808 self._DoTestFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700809 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
810 "signature", str(e.exception))
811
812 def testPackX86RomBadDesc(self):
813 """Test that the Intel requires a descriptor entry"""
814 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600815 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600816 self.assertIn("Node '/binman/intel-me': No offset set with "
817 "offset-unset: should another entry provide this correct "
818 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700819
820 def testPackX86RomMe(self):
821 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600822 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700823 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
824
825 def testPackVga(self):
826 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600827 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700828 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
829
830 def testPackStart16(self):
831 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600832 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700833 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
834
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530835 def testPackPowerpcMpc85xxBootpgResetvec(self):
836 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
837 created"""
838 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
839 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
840
Simon Glass736bb0a2018-07-06 10:27:17 -0600841 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600842 """Handle running a test for insertion of microcode
843
844 Args:
845 dts_fname: Name of test .dts file
846 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600847 ucode_second: True if the microsecond entry is second instead of
848 third
Simon Glassadc57012018-07-06 10:27:16 -0600849
850 Returns:
851 Tuple:
852 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600853 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600854 in the above (two 4-byte words)
855 """
Simon Glass6b187df2017-11-12 21:52:27 -0700856 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700857
858 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600859 if ucode_second:
860 ucode_content = data[len(nodtb_data):]
861 ucode_pos = len(nodtb_data)
862 dtb_with_ucode = ucode_content[16:]
863 fdt_len = self.GetFdtLen(dtb_with_ucode)
864 else:
865 dtb_with_ucode = data[len(nodtb_data):]
866 fdt_len = self.GetFdtLen(dtb_with_ucode)
867 ucode_content = dtb_with_ucode[fdt_len:]
868 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700869 fname = tools.GetOutputFilename('test.dtb')
870 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600871 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600872 dtb = fdt.FdtScan(fname)
873 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700874 self.assertTrue(ucode)
875 for node in ucode.subnodes:
876 self.assertFalse(node.props.get('data'))
877
Simon Glasse0ff8552016-11-25 20:15:53 -0700878 # Check that the microcode appears immediately after the Fdt
879 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700880 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700881 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
882 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600883 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700884
885 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600886 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700887 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
888 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600889 u_boot = data[:len(nodtb_data)]
890 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700891
892 def testPackUbootMicrocode(self):
893 """Test that x86 microcode can be handled correctly
894
895 We expect to see the following in the image, in order:
896 u-boot-nodtb.bin with a microcode pointer inserted at the correct
897 place
898 u-boot.dtb with the microcode removed
899 the microcode
900 """
Simon Glass741f2d62018-10-01 12:22:30 -0600901 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700902 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600903 self.assertEqual(b'nodtb with microcode' + pos_and_size +
904 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700905
Simon Glass160a7662017-05-27 07:38:26 -0600906 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700907 """Test that x86 microcode can be handled correctly
908
909 We expect to see the following in the image, in order:
910 u-boot-nodtb.bin with a microcode pointer inserted at the correct
911 place
912 u-boot.dtb with the microcode
913 an empty microcode region
914 """
915 # We need the libfdt library to run this test since only that allows
916 # finding the offset of a property. This is required by
917 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600918 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700919
920 second = data[len(U_BOOT_NODTB_DATA):]
921
922 fdt_len = self.GetFdtLen(second)
923 third = second[fdt_len:]
924 second = second[:fdt_len]
925
Simon Glass160a7662017-05-27 07:38:26 -0600926 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
927 self.assertIn(ucode_data, second)
928 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700929
Simon Glass160a7662017-05-27 07:38:26 -0600930 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600931 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600932 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
933 len(ucode_data))
934 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -0600935 self.assertEqual(b'nodtb with microcode' + pos_and_size +
936 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700937
Simon Glass75db0862016-11-25 20:15:55 -0700938 def testPackUbootSingleMicrocode(self):
939 """Test that x86 microcode can be handled correctly with fdt_normal.
940 """
Simon Glass160a7662017-05-27 07:38:26 -0600941 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700942
Simon Glassc49deb82016-11-25 20:15:54 -0700943 def testUBootImg(self):
944 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600945 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -0700946 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700947
948 def testNoMicrocode(self):
949 """Test that a missing microcode region is detected"""
950 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600951 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700952 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
953 "node found in ", str(e.exception))
954
955 def testMicrocodeWithoutNode(self):
956 """Test that a missing u-boot-dtb-with-ucode node is detected"""
957 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600958 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700959 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
960 "microcode region u-boot-dtb-with-ucode", str(e.exception))
961
962 def testMicrocodeWithoutNode2(self):
963 """Test that a missing u-boot-ucode node is detected"""
964 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600965 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700966 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
967 "microcode region u-boot-ucode", str(e.exception))
968
969 def testMicrocodeWithoutPtrInElf(self):
970 """Test that a U-Boot binary without the microcode symbol is detected"""
971 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700972 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -0600973 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700974 TestFunctional._MakeInputFile('u-boot', fd.read())
975
976 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600977 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700978 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
979 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
980
981 finally:
982 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -0600983 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700984 TestFunctional._MakeInputFile('u-boot', fd.read())
985
986 def testMicrocodeNotInImage(self):
987 """Test that microcode must be placed within the image"""
988 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600989 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700990 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
991 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -0600992 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -0700993
994 def testWithoutMicrocode(self):
995 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -0600996 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -0700997 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -0600998 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700999
1000 # Now check the device tree has no microcode
1001 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1002 second = data[len(U_BOOT_NODTB_DATA):]
1003
1004 fdt_len = self.GetFdtLen(second)
1005 self.assertEqual(dtb, second[:fdt_len])
1006
1007 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1008 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001009 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001010
1011 def testUnknownPosSize(self):
1012 """Test that microcode must be placed within the image"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001014 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001015 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001016 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001017
1018 def testPackFsp(self):
1019 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001020 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001021 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1022
1023 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001024 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001025 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001026 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001027
1028 def testPackVbt(self):
1029 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001030 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001031 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001032
Simon Glass56509842017-11-12 21:52:25 -07001033 def testSplBssPad(self):
1034 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001035 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001036 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001037 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001038 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1039 data)
Simon Glass56509842017-11-12 21:52:25 -07001040
Simon Glass86af5112018-10-01 21:12:42 -06001041 def testSplBssPadMissing(self):
1042 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001043 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001044 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001045 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001046 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1047 str(e.exception))
1048
Simon Glass87722132017-11-12 21:52:26 -07001049 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001050 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001051 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001052 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1053
Simon Glass736bb0a2018-07-06 10:27:17 -06001054 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1055 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001056
1057 We expect to see the following in the image, in order:
1058 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1059 correct place
1060 u-boot.dtb with the microcode removed
1061 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001062
1063 Args:
1064 dts: Device tree file to use for test
1065 ucode_second: True if the microsecond entry is second instead of
1066 third
Simon Glass6b187df2017-11-12 21:52:27 -07001067 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001068 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001069 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1070 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001071 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1072 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001073
Simon Glass736bb0a2018-07-06 10:27:17 -06001074 def testPackUbootSplMicrocode(self):
1075 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001076 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001077
1078 def testPackUbootSplMicrocodeReorder(self):
1079 """Test that order doesn't matter for microcode entries
1080
1081 This is the same as testPackUbootSplMicrocode but when we process the
1082 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1083 entry, so we reply on binman to try later.
1084 """
Simon Glass741f2d62018-10-01 12:22:30 -06001085 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001086 ucode_second=True)
1087
Simon Glassca4f4ff2017-11-12 21:52:28 -07001088 def testPackMrc(self):
1089 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001090 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001091 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1092
Simon Glass47419ea2017-11-13 18:54:55 -07001093 def testSplDtb(self):
1094 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001095 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001096 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1097
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001098 def testSplNoDtb(self):
1099 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001100 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001101 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1102
Simon Glass19790632017-11-13 18:55:01 -07001103 def testSymbols(self):
1104 """Test binman can assign symbols embedded in U-Boot"""
1105 elf_fname = self.TestFile('u_boot_binman_syms')
1106 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1107 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001108 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001109
Simon Glass11ae93e2018-10-01 21:12:47 -06001110 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001111 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001112 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001113 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1114 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1115 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001116 self.assertEqual(expected, data)
1117
Simon Glassdd57c132018-06-01 09:38:11 -06001118 def testPackUnitAddress(self):
1119 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001120 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001121 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1122
Simon Glass18546952018-06-01 09:38:16 -06001123 def testSections(self):
1124 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001125 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-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 Glass18546952018-06-01 09:38:16 -06001129 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001130
Simon Glass3b0c3822018-06-01 09:38:20 -06001131 def testMap(self):
1132 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001133 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-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 Glass3b0c3822018-06-01 09:38:20 -06001142''', map_data)
1143
Simon Glassc8d48ef2018-06-01 09:38:21 -06001144 def testNamePrefix(self):
1145 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001146 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-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 Glassc8d48ef2018-06-01 09:38:21 -06001153''', map_data)
1154
Simon Glass736bb0a2018-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 Glass741f2d62018-10-01 12:22:30 -06001158 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass736bb0a2018-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 Glass5c890232018-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 Glass741f2d62018-10-01 12:22:30 -06001166 self._DoReadFile('059_change_size.dts', True)
Simon Glass5c890232018-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 Glass16b8d6b2018-07-06 10:27:42 -06001170 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001171 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001172 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001173 update_dtb=True)
Simon Glasscee02e62018-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 Glass16b8d6b2018-07-06 10:27:42 -06001177 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001178 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001179 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001180 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001181 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001182 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001183 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001184 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001185 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001186 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001187 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001188 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001189
Simon Glass3ab95982018-08-01 15:22:37 -06001190 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001191 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001192 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001193 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001194 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001195 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-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 Glass741f2d62018-10-01 12:22:30 -06001202 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001203 self.assertIn('Could not complete processing of Fdt: remaining '
1204 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001205
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001212 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001225 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001238 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001245 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001256 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-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 Glass741f2d62018-10-01 12:22:30 -06001272 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-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 Glassbb748372018-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 Glass741f2d62018-10-01 12:22:30 -06001284 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001285 entry_args=entry_args)
Simon Glassc6c10e72019-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 Glassbb748372018-07-17 13:25:33 -06001290 self.assertEqual(expected, data)
1291
Simon Glassfd8d1f72018-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 Glass11e36cc2018-07-17 13:25:38 -06001306 def testFmap(self):
1307 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001308 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001309 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001310 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1311 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001312 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001313 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-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 Glassc6c10e72019-05-17 22:00:46 -06001320 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-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 Glassc6c10e72019-05-17 22:00:46 -06001327 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001328
1329 self.assertEqual(16, fentries[1].offset)
1330 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001331 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-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 Glassc6c10e72019-05-17 22:00:46 -06001336 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001337
Simon Glassec127af2018-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 Glass741f2d62018-10-01 12:22:30 -06001343 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001344 entry_args=entry_args)
1345
Simon Glass3af8e492018-07-17 13:25:40 -06001346 def testFill(self):
1347 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001348 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001349 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-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 Glass741f2d62018-10-01 12:22:30 -06001355 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001356 self.assertIn("'fill' entry must have a size property",
1357 str(e.exception))
1358
Simon Glass0ef87aa2018-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 Glass1d0ebf72019-05-14 15:53:42 -06001365 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-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 Glass741f2d62018-10-01 12:22:30 -06001376 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001377
1378 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001379 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1380 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-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 Glass741f2d62018-10-01 12:22:30 -06001386 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-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 Glass741f2d62018-10-01 12:22:30 -06001393 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001394 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1395 str(e.exception))
1396
Simon Glass24d0d3c2018-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 Glassa326b492018-09-14 04:57:11 -06001401 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-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 Glass741f2d62018-10-01 12:22:30 -06001411 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-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 Glass741f2d62018-10-01 12:22:30 -06001419 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-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 Glass741f2d62018-10-01 12:22:30 -06001426 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-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 Glass741f2d62018-10-01 12:22:30 -06001433 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001434 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1435 "'other'", str(e.exception))
1436
Simon Glassb8ef5b62018-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 Glass1d0ebf72019-05-14 15:53:42 -06001440 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001441 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001442 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001443 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1444
Simon Glass15a587c2018-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 Glass741f2d62018-10-01 12:22:30 -06001448 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001449 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1450 "'pos'", str(e.exception))
1451
Simon Glassd178eab2018-09-14 04:57:08 -06001452 def testFillZero(self):
1453 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001454 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001455 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001456
Simon Glass0b489362018-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 Glass741f2d62018-10-01 12:22:30 -06001460 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-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 Glass35b384c2018-09-14 04:57:10 -06001464 def testPackStart16Tpl(self):
1465 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001466 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001467 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1468
Simon Glass0bfa7b02018-09-14 04:57:12 -06001469 def testSelectImage(self):
1470 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001471 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001472
Simon Glasseb833d82019-04-25 21:58:34 -06001473 # 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())
1484
1485 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1486 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001487
Simon Glass6ed45ba2018-09-14 04:57:24 -06001488 def testUpdateFdtAll(self):
1489 """Test that all device trees are updated with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001490 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-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 Glass741f2d62018-10-01 12:22:30 -06001530 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-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 Glass741f2d62018-10-01 12:22:30 -06001535 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-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 Glass83d73c22018-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 Glassb8f08762019-05-14 15:53:45 -06001566 return tools.Run('lz4', '-dc', out, binary=True)
Simon Glass83d73c22018-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 Glass741f2d62018-10-01 12:22:30 -06001576 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-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 Glass0a98b282018-09-14 04:57:28 -06001590 def testFiles(self):
1591 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001592 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-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 Glass741f2d62018-10-01 12:22:30 -06001597 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-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 Glassc6c10e72019-05-17 22:00:46 -06001604 orig = b''
Simon Glass0a98b282018-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 Glass741f2d62018-10-01 12:22:30 -06001617 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-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 Glass741f2d62018-10-01 12:22:30 -06001624 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001625 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1626 str(e.exception))
1627
Simon Glassba64a0b2018-09-14 04:57:29 -06001628 def testExpandSize(self):
1629 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001630 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001631 map=True)
Simon Glassc6c10e72019-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 Glassba64a0b2018-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 Glass163ed6c2018-09-14 04:57:36 -06001652 with test_util.capture_sys_output() as (stdout, stderr):
1653 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001654 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001655 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1656 'expanding entry', str(e.exception))
1657
Simon Glasse0e5df92018-09-14 04:57:31 -06001658 def testHash(self):
1659 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001660 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-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 Glassc6c10e72019-05-17 22:00:46 -06001667 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001668
1669 def testHashNoAlgo(self):
1670 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001671 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-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 Glass741f2d62018-10-01 12:22:30 -06001677 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-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 Glass741f2d62018-10-01 12:22:30 -06001683 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-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 Glassc6c10e72019-05-17 22:00:46 -06001690 m.update(tools.GetBytes(ord('a'), 16))
1691 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001692
Simon Glassf0253632018-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 Glass1d0ebf72019-05-14 15:53:42 -06001702 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001703 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001704 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001705 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001706 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1707 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001708
Simon Glassf8f8df62018-09-14 04:57:34 -06001709 def testFmapX86(self):
1710 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001711 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001712 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001713 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-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 Glassc6c10e72019-05-17 22:00:46 -06001721 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001722
1723 self.assertEqual(4, fentries[1].offset)
1724 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001725 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-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 Glassc6c10e72019-05-17 22:00:46 -06001730 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001731
1732 def testFmapX86Section(self):
1733 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001734 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001735 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-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 Glassc6c10e72019-05-17 22:00:46 -06001743 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001744
1745 self.assertEqual(4, fentries[1].offset)
1746 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001747 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-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 Glassc6c10e72019-05-17 22:00:46 -06001752 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001753
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001754 def testElf(self):
1755 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001756 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001757 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001758 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001759 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001760
1761 def testElfStripg(self):
1762 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001763 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001764 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001765 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001766 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001767
Simon Glass163ed6c2018-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 Glass741f2d62018-10-01 12:22:30 -06001772 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-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))
1780 map_data = tools.ReadFile(map_fname)
1781 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 Glass3ae192c2018-10-01 12:22:31 -06001787 def testPacRefCode(self):
1788 """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 Glass9481c802019-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 Glasse6d85ff2019-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 Glass9481c802019-04-25 21:58:39 -06001812
Simon Glass53af22a2018-07-17 13:25:32 -06001813
Simon Glass9fc60b42017-11-12 21:52:22 -07001814if __name__ == "__main__":
1815 unittest.main()