blob: 4d96933cb4d4b08fe15a45a884d541d403fbb7f9 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassae7cf032018-09-14 04:57:31 -06009import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070010from optparse import OptionParser
11import os
12import shutil
13import struct
14import sys
15import tempfile
16import unittest
17
18import binman
19import cmdline
20import command
21import control
Simon Glass4ca8e042017-11-13 18:55:01 -070022import elf
Simon Glassa9440932017-05-27 07:38:30 -060023import fdt
Simon Glass57454f42016-11-25 20:15:52 -070024import fdt_util
Simon Glass704784b2018-07-17 13:25:38 -060025import fmap_util
Simon Glass969616c2018-07-17 13:25:36 -060026import test_util
Simon Glass29aa7362018-09-14 04:57:19 -060027import state
Simon Glass57454f42016-11-25 20:15:52 -070028import tools
29import tout
30
31# Contents of test files, corresponding to different entry types
Simon Glass3d274232017-11-12 21:52:27 -070032U_BOOT_DATA = '1234'
33U_BOOT_IMG_DATA = 'img'
Simon Glassd6051522017-11-13 18:54:59 -070034U_BOOT_SPL_DATA = '56780123456789abcde'
Simon Glass8425a1f2018-07-17 13:25:48 -060035U_BOOT_TPL_DATA = 'tpl'
Simon Glass3d274232017-11-12 21:52:27 -070036BLOB_DATA = '89'
37ME_DATA = '0abcd'
38VGA_DATA = 'vga'
39U_BOOT_DTB_DATA = 'udtb'
Simon Glass9aa6a6f2017-11-13 18:54:55 -070040U_BOOT_SPL_DTB_DATA = 'spldtb'
Simon Glass8425a1f2018-07-17 13:25:48 -060041U_BOOT_TPL_DTB_DATA = 'tpldtb'
Simon Glass3d274232017-11-12 21:52:27 -070042X86_START16_DATA = 'start16'
43X86_START16_SPL_DATA = 'start16spl'
Simon Glassed40e962018-09-14 04:57:10 -060044X86_START16_TPL_DATA = 'start16tpl'
Jagdish Gediya311d4842018-09-03 21:35:08 +053045PPC_MPC85XX_BR_DATA = 'ppcmpc85xxbr'
Simon Glass3d274232017-11-12 21:52:27 -070046U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
47U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
Simon Glass3fb4f422018-09-14 04:57:32 -060048U_BOOT_TPL_NODTB_DATA = 'tplnodtb with microcode pointer somewhere in here'
Simon Glass3d274232017-11-12 21:52:27 -070049FSP_DATA = 'fsp'
50CMC_DATA = 'cmc'
51VBT_DATA = 'vbt'
Simon Glassa409c932017-11-12 21:52:28 -070052MRC_DATA = 'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060053TEXT_DATA = 'text'
54TEXT_DATA2 = 'text2'
55TEXT_DATA3 = 'text3'
Simon Glassdb168d42018-07-17 13:25:39 -060056CROS_EC_RW_DATA = 'ecrw'
Simon Glassc1ae83c2018-07-17 13:25:44 -060057GBB_DATA = 'gbbd'
58BMPBLK_DATA = 'bmp'
Simon Glass5c350162018-07-17 13:25:47 -060059VBLOCK_DATA = 'vblk'
Simon Glassac6328c2018-09-14 04:57:28 -060060FILES_DATA = ("sorry I'm late\nOh, don't bother apologising, I'm " +
61 "sorry you're alive\n")
Simon Glass7ba33592018-09-14 04:57:26 -060062COMPRESS_DATA = 'data to compress'
Simon Glass41902e42018-10-01 12:22:31 -060063REFCODE_DATA = 'refcode'
Simon Glassdb168d42018-07-17 13:25:39 -060064
Simon Glass57454f42016-11-25 20:15:52 -070065
66class TestFunctional(unittest.TestCase):
67 """Functional tests for binman
68
69 Most of these use a sample .dts file to build an image and then check
70 that it looks correct. The sample files are in the test/ subdirectory
71 and are numbered.
72
73 For each entry type a very small test file is created using fixed
74 string contents. This makes it easy to test that things look right, and
75 debug problems.
76
77 In some cases a 'real' file must be used - these are also supplied in
78 the test/ diurectory.
79 """
80 @classmethod
81 def setUpClass(self):
Simon Glassb3393262017-11-12 21:52:20 -070082 global entry
83 import entry
84
Simon Glass57454f42016-11-25 20:15:52 -070085 # Handle the case where argv[0] is 'python'
86 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
87 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
88
89 # Create a temporary directory for input files
90 self._indir = tempfile.mkdtemp(prefix='binmant.')
91
92 # Create some test files
93 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
94 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
95 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -060096 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -070097 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -070098 TestFunctional._MakeInputFile('me.bin', ME_DATA)
99 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600100 self._ResetDtbs()
Simon Glass72232452016-11-25 20:15:53 -0700101 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya311d4842018-09-03 21:35:08 +0530102 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glasse83679d2017-11-12 21:52:26 -0700103 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
104 X86_START16_SPL_DATA)
Simon Glassed40e962018-09-14 04:57:10 -0600105 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
106 X86_START16_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700107 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700108 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
109 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600110 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
111 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700112 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
113 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700114 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700115 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600116 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600117 TestFunctional._MakeInputDir('devkeys')
118 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600119 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700120
Simon Glass72232452016-11-25 20:15:53 -0700121 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass33486662019-05-14 15:53:42 -0600122 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass72232452016-11-25 20:15:53 -0700123 TestFunctional._MakeInputFile('u-boot', fd.read())
124
125 # Intel flash descriptor file
Simon Glass33486662019-05-14 15:53:42 -0600126 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glass72232452016-11-25 20:15:53 -0700127 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
128
Simon Glassac6328c2018-09-14 04:57:28 -0600129 shutil.copytree(self.TestFile('files'),
130 os.path.join(self._indir, 'files'))
131
Simon Glass7ba33592018-09-14 04:57:26 -0600132 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
133
Simon Glass57454f42016-11-25 20:15:52 -0700134 @classmethod
135 def tearDownClass(self):
136 """Remove the temporary input directory and its contents"""
137 if self._indir:
138 shutil.rmtree(self._indir)
139 self._indir = None
140
141 def setUp(self):
142 # Enable this to turn on debugging output
143 # tout.Init(tout.DEBUG)
144 command.test_result = None
145
146 def tearDown(self):
147 """Remove the temporary output directory"""
148 tools._FinaliseForTest()
149
Simon Glass8425a1f2018-07-17 13:25:48 -0600150 @classmethod
151 def _ResetDtbs(self):
152 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
153 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
154 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
155
Simon Glass57454f42016-11-25 20:15:52 -0700156 def _RunBinman(self, *args, **kwargs):
157 """Run binman using the command line
158
159 Args:
160 Arguments to pass, as a list of strings
161 kwargs: Arguments to pass to Command.RunPipe()
162 """
163 result = command.RunPipe([[self._binman_pathname] + list(args)],
164 capture=True, capture_stderr=True, raise_on_error=False)
165 if result.return_code and kwargs.get('raise_on_error', True):
166 raise Exception("Error running '%s': %s" % (' '.join(args),
167 result.stdout + result.stderr))
168 return result
169
170 def _DoBinman(self, *args):
171 """Run binman using directly (in the same process)
172
173 Args:
174 Arguments to pass, as a list of strings
175 Returns:
176 Return value (0 for success)
177 """
Simon Glass075a45c2017-11-13 18:55:00 -0700178 args = list(args)
179 if '-D' in sys.argv:
180 args = args + ['-D']
181 (options, args) = cmdline.ParseArgs(args)
Simon Glass57454f42016-11-25 20:15:52 -0700182 options.pager = 'binman-invalid-pager'
183 options.build_dir = self._indir
184
185 # For testing, you can force an increase in verbosity here
186 # options.verbosity = tout.DEBUG
187 return control.Binman(options, args)
188
Simon Glass91710b32018-07-17 13:25:32 -0600189 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600190 entry_args=None, images=None, use_real_dtb=False,
191 verbosity=None):
Simon Glass57454f42016-11-25 20:15:52 -0700192 """Run binman with a given test file
193
194 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600195 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600196 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600197 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600198 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600199 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600200 entry_args: Dict of entry args to supply to binman
201 key: arg name
202 value: value of that arg
203 images: List of image names to build
Simon Glass57454f42016-11-25 20:15:52 -0700204 """
Simon Glass075a45c2017-11-13 18:55:00 -0700205 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
206 if debug:
207 args.append('-D')
Simon Glass30732662018-06-01 09:38:20 -0600208 if map:
209 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600210 if update_dtb:
211 args.append('-up')
Simon Glass31402012018-09-14 04:57:23 -0600212 if not use_real_dtb:
213 args.append('--fake-dtb')
Simon Glassb4595d82019-04-25 21:58:34 -0600214 if verbosity is not None:
215 args.append('-v%d' % verbosity)
Simon Glass91710b32018-07-17 13:25:32 -0600216 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600217 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600218 args.append('-a%s=%s' % (arg, value))
Simon Glass3b376c32018-09-14 04:57:12 -0600219 if images:
220 for image in images:
221 args += ['-i', image]
Simon Glass075a45c2017-11-13 18:55:00 -0700222 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700223
224 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700225 """Set up a new test device-tree file
226
227 The given file is compiled and set up as the device tree to be used
228 for ths test.
229
230 Args:
231 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600232 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700233
234 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600235 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700236 """
Simon Glass752e7552018-10-01 21:12:41 -0600237 tools.PrepareOutputDir(None)
Simon Glass57454f42016-11-25 20:15:52 -0700238 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass33486662019-05-14 15:53:42 -0600239 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700240 data = fd.read()
241 TestFunctional._MakeInputFile(outfile, data)
Simon Glass752e7552018-10-01 21:12:41 -0600242 tools.FinaliseOutputDir()
243 return data
Simon Glass57454f42016-11-25 20:15:52 -0700244
Simon Glasse219aa42018-09-14 04:57:24 -0600245 def _GetDtbContentsForSplTpl(self, dtb_data, name):
246 """Create a version of the main DTB for SPL or SPL
247
248 For testing we don't actually have different versions of the DTB. With
249 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
250 we don't normally have any unwanted nodes.
251
252 We still want the DTBs for SPL and TPL to be different though, since
253 otherwise it is confusing to know which one we are looking at. So add
254 an 'spl' or 'tpl' property to the top-level node.
255 """
256 dtb = fdt.Fdt.FromData(dtb_data)
257 dtb.Scan()
258 dtb.GetNode('/binman').AddZeroProp(name)
259 dtb.Sync(auto_resize=True)
260 dtb.Pack()
261 return dtb.GetContents()
262
Simon Glassa87014e2018-07-06 10:27:42 -0600263 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glasse219aa42018-09-14 04:57:24 -0600264 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass57454f42016-11-25 20:15:52 -0700265 """Run binman and return the resulting image
266
267 This runs binman with a given test file and then reads the resulting
268 output file. It is a shortcut function since most tests need to do
269 these steps.
270
271 Raises an assertion failure if binman returns a non-zero exit code.
272
273 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600274 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700275 use_real_dtb: True to use the test file as the contents of
276 the u-boot-dtb entry. Normally this is not needed and the
277 test contents (the U_BOOT_DTB_DATA string) can be used.
278 But in some test we need the real contents.
Simon Glass30732662018-06-01 09:38:20 -0600279 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600280 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600281 tree before packing it into the image
Simon Glass72232452016-11-25 20:15:53 -0700282
283 Returns:
284 Tuple:
285 Resulting image contents
286 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600287 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600288 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700289 """
Simon Glass72232452016-11-25 20:15:53 -0700290 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700291 # Use the compiled test file as the u-boot-dtb input
292 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700293 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600294 infile = os.path.join(self._indir, 'u-boot.dtb')
295
296 # For testing purposes, make a copy of the DT for SPL and TPL. Add
297 # a node indicating which it is, so aid verification.
298 for name in ['spl', 'tpl']:
299 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
300 outfile = os.path.join(self._indir, dtb_fname)
301 TestFunctional._MakeInputFile(dtb_fname,
302 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700303
304 try:
Simon Glass91710b32018-07-17 13:25:32 -0600305 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glasse219aa42018-09-14 04:57:24 -0600306 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass57454f42016-11-25 20:15:52 -0700307 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600308 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700309
310 # Find the (only) image, read it and return its contents
311 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600312 image_fname = tools.GetOutputFilename('image.bin')
313 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600314 if map:
315 map_fname = tools.GetOutputFilename('image.map')
316 with open(map_fname) as fd:
317 map_data = fd.read()
318 else:
319 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600320 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600321 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700322 finally:
323 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600324 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600325 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700326
Simon Glass72232452016-11-25 20:15:53 -0700327 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600328 """Helper function which discards the device-tree binary
329
330 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600331 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600332 use_real_dtb: True to use the test file as the contents of
333 the u-boot-dtb entry. Normally this is not needed and the
334 test contents (the U_BOOT_DTB_DATA string) can be used.
335 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600336
337 Returns:
338 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600339 """
Simon Glass72232452016-11-25 20:15:53 -0700340 return self._DoReadFileDtb(fname, use_real_dtb)[0]
341
Simon Glass57454f42016-11-25 20:15:52 -0700342 @classmethod
343 def _MakeInputFile(self, fname, contents):
344 """Create a new test input file, creating directories as needed
345
346 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600347 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700348 contents: File contents to write in to the file
349 Returns:
350 Full pathname of file created
351 """
352 pathname = os.path.join(self._indir, fname)
353 dirname = os.path.dirname(pathname)
354 if dirname and not os.path.exists(dirname):
355 os.makedirs(dirname)
356 with open(pathname, 'wb') as fd:
357 fd.write(contents)
358 return pathname
359
360 @classmethod
Simon Glassc1ae83c2018-07-17 13:25:44 -0600361 def _MakeInputDir(self, dirname):
362 """Create a new test input directory, creating directories as needed
363
364 Args:
365 dirname: Directory name to create
366
367 Returns:
368 Full pathname of directory created
369 """
370 pathname = os.path.join(self._indir, dirname)
371 if not os.path.exists(pathname):
372 os.makedirs(pathname)
373 return pathname
374
375 @classmethod
Simon Glass7057d022018-10-01 21:12:47 -0600376 def _SetupSplElf(self, src_fname='bss_data'):
377 """Set up an ELF file with a '_dt_ucode_base_size' symbol
378
379 Args:
380 Filename of ELF file to use as SPL
381 """
Simon Glass33486662019-05-14 15:53:42 -0600382 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass7057d022018-10-01 21:12:47 -0600383 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
384
385 @classmethod
Simon Glass57454f42016-11-25 20:15:52 -0700386 def TestFile(self, fname):
387 return os.path.join(self._binman_dir, 'test', fname)
388
389 def AssertInList(self, grep_list, target):
390 """Assert that at least one of a list of things is in a target
391
392 Args:
393 grep_list: List of strings to check
394 target: Target string
395 """
396 for grep in grep_list:
397 if grep in target:
398 return
399 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
400
401 def CheckNoGaps(self, entries):
402 """Check that all entries fit together without gaps
403
404 Args:
405 entries: List of entries to check
406 """
Simon Glasse8561af2018-08-01 15:22:37 -0600407 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700408 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600409 self.assertEqual(offset, entry.offset)
410 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700411
Simon Glass72232452016-11-25 20:15:53 -0700412 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600413 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700414
415 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600416 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700417
418 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600419 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700420 """
421 return struct.unpack('>L', dtb[4:8])[0]
422
Simon Glass5463a6a2018-07-17 13:25:52 -0600423 def _GetPropTree(self, dtb, prop_names):
Simon Glassa87014e2018-07-06 10:27:42 -0600424 def AddNode(node, path):
425 if node.name != '/':
426 path += '/' + node.name
Simon Glassa87014e2018-07-06 10:27:42 -0600427 for subnode in node.subnodes:
428 for prop in subnode.props.values():
Simon Glass5463a6a2018-07-17 13:25:52 -0600429 if prop.name in prop_names:
Simon Glassa87014e2018-07-06 10:27:42 -0600430 prop_path = path + '/' + subnode.name + ':' + prop.name
431 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
432 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600433 AddNode(subnode, path)
434
435 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600436 AddNode(dtb.GetRoot(), '')
437 return tree
438
Simon Glass57454f42016-11-25 20:15:52 -0700439 def testRun(self):
440 """Test a basic run with valid args"""
441 result = self._RunBinman('-h')
442
443 def testFullHelp(self):
444 """Test that the full help is displayed with -H"""
445 result = self._RunBinman('-H')
446 help_file = os.path.join(self._binman_dir, 'README')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500447 # Remove possible extraneous strings
448 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
449 gothelp = result.stdout.replace(extra, '')
450 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700451 self.assertEqual(0, len(result.stderr))
452 self.assertEqual(0, result.return_code)
453
454 def testFullHelpInternal(self):
455 """Test that the full help is displayed with -H"""
456 try:
457 command.test_result = command.CommandResult()
458 result = self._DoBinman('-H')
459 help_file = os.path.join(self._binman_dir, 'README')
460 finally:
461 command.test_result = None
462
463 def testHelp(self):
464 """Test that the basic help is displayed with -h"""
465 result = self._RunBinman('-h')
466 self.assertTrue(len(result.stdout) > 200)
467 self.assertEqual(0, len(result.stderr))
468 self.assertEqual(0, result.return_code)
469
Simon Glass57454f42016-11-25 20:15:52 -0700470 def testBoard(self):
471 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600472 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700473 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
474 result = self._DoBinman('-b', 'sandbox')
475 self.assertEqual(0, result)
476
477 def testNeedBoard(self):
478 """Test that we get an error when no board ius supplied"""
479 with self.assertRaises(ValueError) as e:
480 result = self._DoBinman()
481 self.assertIn("Must provide a board to process (use -b <board>)",
482 str(e.exception))
483
484 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600485 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700486 with self.assertRaises(Exception) as e:
487 self._RunBinman('-d', 'missing_file')
488 # We get one error from libfdt, and a different one from fdtget.
489 self.AssertInList(["Couldn't open blob from 'missing_file'",
490 'No such file or directory'], str(e.exception))
491
492 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600493 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700494
495 Since this is a source file it should be compiled and the error
496 will come from the device-tree compiler (dtc).
497 """
498 with self.assertRaises(Exception) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600499 self._RunBinman('-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700500 self.assertIn("FATAL ERROR: Unable to parse input tree",
501 str(e.exception))
502
503 def testMissingNode(self):
504 """Test that a device tree without a 'binman' node generates an error"""
505 with self.assertRaises(Exception) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600506 self._DoBinman('-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700507 self.assertIn("does not have a 'binman' node", str(e.exception))
508
509 def testEmpty(self):
510 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass511f6582018-10-01 12:22:30 -0600511 result = self._RunBinman('-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700512 self.assertEqual(0, len(result.stderr))
513 self.assertEqual(0, result.return_code)
514
515 def testInvalidEntry(self):
516 """Test that an invalid entry is flagged"""
517 with self.assertRaises(Exception) as e:
518 result = self._RunBinman('-d',
Simon Glass511f6582018-10-01 12:22:30 -0600519 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700520 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
521 "'/binman/not-a-valid-type'", str(e.exception))
522
523 def testSimple(self):
524 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600525 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700526 self.assertEqual(U_BOOT_DATA, data)
527
Simon Glass075a45c2017-11-13 18:55:00 -0700528 def testSimpleDebug(self):
529 """Test a simple binman run with debugging enabled"""
Simon Glass511f6582018-10-01 12:22:30 -0600530 data = self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700531
Simon Glass57454f42016-11-25 20:15:52 -0700532 def testDual(self):
533 """Test that we can handle creating two images
534
535 This also tests image padding.
536 """
Simon Glass511f6582018-10-01 12:22:30 -0600537 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700538 self.assertEqual(0, retcode)
539
540 image = control.images['image1']
541 self.assertEqual(len(U_BOOT_DATA), image._size)
542 fname = tools.GetOutputFilename('image1.bin')
543 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600544 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700545 data = fd.read()
546 self.assertEqual(U_BOOT_DATA, data)
547
548 image = control.images['image2']
549 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
550 fname = tools.GetOutputFilename('image2.bin')
551 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600552 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700553 data = fd.read()
554 self.assertEqual(U_BOOT_DATA, data[3:7])
555 self.assertEqual(chr(0) * 3, data[:3])
556 self.assertEqual(chr(0) * 5, data[7:])
557
558 def testBadAlign(self):
559 """Test that an invalid alignment value is detected"""
560 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600561 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700562 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
563 "of two", str(e.exception))
564
565 def testPackSimple(self):
566 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600567 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700568 self.assertEqual(0, retcode)
569 self.assertIn('image', control.images)
570 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600571 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700572 self.assertEqual(5, len(entries))
573
574 # First u-boot
575 self.assertIn('u-boot', entries)
576 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600577 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700578 self.assertEqual(len(U_BOOT_DATA), entry.size)
579
580 # Second u-boot, aligned to 16-byte boundary
581 self.assertIn('u-boot-align', entries)
582 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600583 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700584 self.assertEqual(len(U_BOOT_DATA), entry.size)
585
586 # Third u-boot, size 23 bytes
587 self.assertIn('u-boot-size', entries)
588 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600589 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700590 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
591 self.assertEqual(23, entry.size)
592
593 # Fourth u-boot, placed immediate after the above
594 self.assertIn('u-boot-next', entries)
595 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600596 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700597 self.assertEqual(len(U_BOOT_DATA), entry.size)
598
Simon Glasse8561af2018-08-01 15:22:37 -0600599 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700600 self.assertIn('u-boot-fixed', entries)
601 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600602 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700603 self.assertEqual(len(U_BOOT_DATA), entry.size)
604
605 self.assertEqual(65, image._size)
606
607 def testPackExtra(self):
608 """Test that extra packing feature works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600609 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700610
611 self.assertEqual(0, retcode)
612 self.assertIn('image', control.images)
613 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600614 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700615 self.assertEqual(5, len(entries))
616
617 # First u-boot with padding before and after
618 self.assertIn('u-boot', entries)
619 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600620 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700621 self.assertEqual(3, entry.pad_before)
622 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
623
624 # Second u-boot has an aligned size, but it has no effect
625 self.assertIn('u-boot-align-size-nop', entries)
626 entry = entries['u-boot-align-size-nop']
Simon Glasse8561af2018-08-01 15:22:37 -0600627 self.assertEqual(12, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700628 self.assertEqual(4, entry.size)
629
630 # Third u-boot has an aligned size too
631 self.assertIn('u-boot-align-size', entries)
632 entry = entries['u-boot-align-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600633 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700634 self.assertEqual(32, entry.size)
635
636 # Fourth u-boot has an aligned end
637 self.assertIn('u-boot-align-end', entries)
638 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600639 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700640 self.assertEqual(16, entry.size)
641
642 # Fifth u-boot immediately afterwards
643 self.assertIn('u-boot-align-both', entries)
644 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600645 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700646 self.assertEqual(64, entry.size)
647
648 self.CheckNoGaps(entries)
649 self.assertEqual(128, image._size)
650
651 def testPackAlignPowerOf2(self):
652 """Test that invalid entry alignment is detected"""
653 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600654 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700655 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
656 "of two", str(e.exception))
657
658 def testPackAlignSizePowerOf2(self):
659 """Test that invalid entry size alignment is detected"""
660 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600661 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700662 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
663 "power of two", str(e.exception))
664
665 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600666 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700667 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600668 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600669 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700670 "align 0x4 (4)", str(e.exception))
671
672 def testPackInvalidSizeAlign(self):
673 """Test that invalid entry size alignment is detected"""
674 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600675 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700676 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
677 "align-size 0x4 (4)", str(e.exception))
678
679 def testPackOverlap(self):
680 """Test that overlapping regions are detected"""
681 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600682 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600683 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700684 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
685 str(e.exception))
686
687 def testPackEntryOverflow(self):
688 """Test that entries that overflow their size are detected"""
689 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600690 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700691 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
692 "but entry size is 0x3 (3)", str(e.exception))
693
694 def testPackImageOverflow(self):
695 """Test that entries which overflow the image size are detected"""
696 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600697 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600698 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700699 "size 0x3 (3)", str(e.exception))
700
701 def testPackImageSize(self):
702 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600703 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700704 self.assertEqual(0, retcode)
705 self.assertIn('image', control.images)
706 image = control.images['image']
707 self.assertEqual(7, image._size)
708
709 def testPackImageSizeAlign(self):
710 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600711 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700712 self.assertEqual(0, retcode)
713 self.assertIn('image', control.images)
714 image = control.images['image']
715 self.assertEqual(16, image._size)
716
717 def testPackInvalidImageAlign(self):
718 """Test that invalid image alignment is detected"""
719 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600720 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600721 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700722 "align-size 0x8 (8)", str(e.exception))
723
724 def testPackAlignPowerOf2(self):
725 """Test that invalid image alignment is detected"""
726 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600727 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600728 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700729 "two", str(e.exception))
730
731 def testImagePadByte(self):
732 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600733 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600734 data = self._DoReadFile('021_image_pad.dts')
Simon Glassd6051522017-11-13 18:54:59 -0700735 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700736
737 def testImageName(self):
738 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600739 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700740 self.assertEqual(0, retcode)
741 image = control.images['image1']
742 fname = tools.GetOutputFilename('test-name')
743 self.assertTrue(os.path.exists(fname))
744
745 image = control.images['image2']
746 fname = tools.GetOutputFilename('test-name.xx')
747 self.assertTrue(os.path.exists(fname))
748
749 def testBlobFilename(self):
750 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600751 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700752 self.assertEqual(BLOB_DATA, data)
753
754 def testPackSorted(self):
755 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600756 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600757 data = self._DoReadFile('024_sorted.dts')
Simon Glassd6051522017-11-13 18:54:59 -0700758 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
Simon Glass57454f42016-11-25 20:15:52 -0700759 U_BOOT_DATA, data)
760
Simon Glasse8561af2018-08-01 15:22:37 -0600761 def testPackZeroOffset(self):
762 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -0700763 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600764 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600765 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700766 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
767 str(e.exception))
768
769 def testPackUbootDtb(self):
770 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -0600771 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700772 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -0700773
774 def testPackX86RomNoSize(self):
775 """Test that the end-at-4gb property requires a size property"""
776 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600777 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600778 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -0700779 "using end-at-4gb", str(e.exception))
780
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530781 def test4gbAndSkipAtStartTogether(self):
782 """Test that the end-at-4gb and skip-at-size property can't be used
783 together"""
784 with self.assertRaises(ValueError) as e:
785 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
786 self.assertIn("Section '/binman': Provide either 'end-at-4gb' or "
787 "'skip-at-start'", str(e.exception))
788
Simon Glass72232452016-11-25 20:15:53 -0700789 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600790 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -0700791 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600792 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600793 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glasseca32212018-06-01 09:38:12 -0600794 "the section starting at 0xffffffe0 (4294967264)",
Simon Glass72232452016-11-25 20:15:53 -0700795 str(e.exception))
796
797 def testPackX86Rom(self):
798 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -0600799 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600800 data = self._DoReadFile('029_x86-rom.dts')
Simon Glassd6051522017-11-13 18:54:59 -0700801 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
802 chr(0) * 2, data)
Simon Glass72232452016-11-25 20:15:53 -0700803
804 def testPackX86RomMeNoDesc(self):
805 """Test that an invalid Intel descriptor entry is detected"""
806 TestFunctional._MakeInputFile('descriptor.bin', '')
807 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600808 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass72232452016-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 Glass511f6582018-10-01 12:22:30 -0600815 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600816 self.assertIn("Node '/binman/intel-me': No offset set with "
817 "offset-unset: should another entry provide this correct "
818 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700819
820 def testPackX86RomMe(self):
821 """Test that an x86 ROM with an ME region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600822 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glass72232452016-11-25 20:15:53 -0700823 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
824
825 def testPackVga(self):
826 """Test that an image with a VGA binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600827 data = self._DoReadFile('032_intel-vga.dts')
Simon Glass72232452016-11-25 20:15:53 -0700828 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
829
830 def testPackStart16(self):
831 """Test that an image with an x86 start16 region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -0600832 data = self._DoReadFile('033_x86-start16.dts')
Simon Glass72232452016-11-25 20:15:53 -0700833 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
834
Jagdish Gediya311d4842018-09-03 21:35:08 +0530835 def testPackPowerpcMpc85xxBootpgResetvec(self):
836 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
837 created"""
838 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
839 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
840
Simon Glass6ba679c2018-07-06 10:27:17 -0600841 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -0600842 """Handle running a test for insertion of microcode
843
844 Args:
845 dts_fname: Name of test .dts file
846 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -0600847 ucode_second: True if the microsecond entry is second instead of
848 third
Simon Glass820af1d2018-07-06 10:27:16 -0600849
850 Returns:
851 Tuple:
852 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -0600853 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -0600854 in the above (two 4-byte words)
855 """
Simon Glass3d274232017-11-12 21:52:27 -0700856 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -0700857
858 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -0600859 if ucode_second:
860 ucode_content = data[len(nodtb_data):]
861 ucode_pos = len(nodtb_data)
862 dtb_with_ucode = ucode_content[16:]
863 fdt_len = self.GetFdtLen(dtb_with_ucode)
864 else:
865 dtb_with_ucode = data[len(nodtb_data):]
866 fdt_len = self.GetFdtLen(dtb_with_ucode)
867 ucode_content = dtb_with_ucode[fdt_len:]
868 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -0700869 fname = tools.GetOutputFilename('test.dtb')
870 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -0600871 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -0600872 dtb = fdt.FdtScan(fname)
873 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -0700874 self.assertTrue(ucode)
875 for node in ucode.subnodes:
876 self.assertFalse(node.props.get('data'))
877
Simon Glass72232452016-11-25 20:15:53 -0700878 # Check that the microcode appears immediately after the Fdt
879 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -0700880 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -0700881 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
882 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -0600883 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -0700884
885 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -0600886 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -0700887 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
888 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -0600889 u_boot = data[:len(nodtb_data)]
890 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -0700891
892 def testPackUbootMicrocode(self):
893 """Test that x86 microcode can be handled correctly
894
895 We expect to see the following in the image, in order:
896 u-boot-nodtb.bin with a microcode pointer inserted at the correct
897 place
898 u-boot.dtb with the microcode removed
899 the microcode
900 """
Simon Glass511f6582018-10-01 12:22:30 -0600901 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -0700902 U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700903 self.assertEqual('nodtb with microcode' + pos_and_size +
904 ' somewhere in here', first)
905
Simon Glassbac25c82017-05-27 07:38:26 -0600906 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -0700907 """Test that x86 microcode can be handled correctly
908
909 We expect to see the following in the image, in order:
910 u-boot-nodtb.bin with a microcode pointer inserted at the correct
911 place
912 u-boot.dtb with the microcode
913 an empty microcode region
914 """
915 # We need the libfdt library to run this test since only that allows
916 # finding the offset of a property. This is required by
917 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -0600918 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -0700919
920 second = data[len(U_BOOT_NODTB_DATA):]
921
922 fdt_len = self.GetFdtLen(second)
923 third = second[fdt_len:]
924 second = second[:fdt_len]
925
Simon Glassbac25c82017-05-27 07:38:26 -0600926 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
927 self.assertIn(ucode_data, second)
928 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700929
Simon Glassbac25c82017-05-27 07:38:26 -0600930 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -0600931 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -0600932 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
933 len(ucode_data))
934 first = data[:len(U_BOOT_NODTB_DATA)]
935 self.assertEqual('nodtb with microcode' + pos_and_size +
936 ' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -0700937
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700938 def testPackUbootSingleMicrocode(self):
939 """Test that x86 microcode can be handled correctly with fdt_normal.
940 """
Simon Glassbac25c82017-05-27 07:38:26 -0600941 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700942
Simon Glass996021e2016-11-25 20:15:54 -0700943 def testUBootImg(self):
944 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -0600945 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -0700946 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700947
948 def testNoMicrocode(self):
949 """Test that a missing microcode region is detected"""
950 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600951 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700952 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
953 "node found in ", str(e.exception))
954
955 def testMicrocodeWithoutNode(self):
956 """Test that a missing u-boot-dtb-with-ucode node is detected"""
957 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600958 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700959 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
960 "microcode region u-boot-dtb-with-ucode", str(e.exception))
961
962 def testMicrocodeWithoutNode2(self):
963 """Test that a missing u-boot-ucode node is detected"""
964 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600965 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700966 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
967 "microcode region u-boot-ucode", str(e.exception))
968
969 def testMicrocodeWithoutPtrInElf(self):
970 """Test that a U-Boot binary without the microcode symbol is detected"""
971 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700972 try:
Simon Glass33486662019-05-14 15:53:42 -0600973 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700974 TestFunctional._MakeInputFile('u-boot', fd.read())
975
976 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -0600977 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700978 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
979 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
980
981 finally:
982 # Put the original file back
Simon Glass33486662019-05-14 15:53:42 -0600983 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700984 TestFunctional._MakeInputFile('u-boot', fd.read())
985
986 def testMicrocodeNotInImage(self):
987 """Test that microcode must be placed within the image"""
988 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600989 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700990 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
991 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -0600992 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700993
994 def testWithoutMicrocode(self):
995 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass33486662019-05-14 15:53:42 -0600996 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700997 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -0600998 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -0700999
1000 # Now check the device tree has no microcode
1001 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1002 second = data[len(U_BOOT_NODTB_DATA):]
1003
1004 fdt_len = self.GetFdtLen(second)
1005 self.assertEqual(dtb, second[:fdt_len])
1006
1007 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1008 third = data[used_len:]
1009 self.assertEqual(chr(0) * (0x200 - used_len), third)
1010
1011 def testUnknownPosSize(self):
1012 """Test that microcode must be placed within the image"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001014 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001015 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001016 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001017
1018 def testPackFsp(self):
1019 """Test that an image with a FSP binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001020 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001021 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1022
1023 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001024 """Test that an image with a CMC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001025 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001026 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001027
1028 def testPackVbt(self):
1029 """Test that an image with a VBT binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001030 data = self._DoReadFile('046_intel-vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001031 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001032
Simon Glass7f94e832017-11-12 21:52:25 -07001033 def testSplBssPad(self):
1034 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001035 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001036 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001037 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass7f94e832017-11-12 21:52:25 -07001038 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
1039
Simon Glass04cda032018-10-01 21:12:42 -06001040 def testSplBssPadMissing(self):
1041 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001042 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001043 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001044 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001045 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1046 str(e.exception))
1047
Simon Glasse83679d2017-11-12 21:52:26 -07001048 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001049 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001050 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001051 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1052
Simon Glass6ba679c2018-07-06 10:27:17 -06001053 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1054 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001055
1056 We expect to see the following in the image, in order:
1057 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1058 correct place
1059 u-boot.dtb with the microcode removed
1060 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001061
1062 Args:
1063 dts: Device tree file to use for test
1064 ucode_second: True if the microsecond entry is second instead of
1065 third
Simon Glass3d274232017-11-12 21:52:27 -07001066 """
Simon Glass7057d022018-10-01 21:12:47 -06001067 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001068 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1069 ucode_second=ucode_second)
Simon Glass3d274232017-11-12 21:52:27 -07001070 self.assertEqual('splnodtb with microc' + pos_and_size +
1071 'ter somewhere in here', first)
1072
Simon Glass6ba679c2018-07-06 10:27:17 -06001073 def testPackUbootSplMicrocode(self):
1074 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001075 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001076
1077 def testPackUbootSplMicrocodeReorder(self):
1078 """Test that order doesn't matter for microcode entries
1079
1080 This is the same as testPackUbootSplMicrocode but when we process the
1081 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1082 entry, so we reply on binman to try later.
1083 """
Simon Glass511f6582018-10-01 12:22:30 -06001084 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001085 ucode_second=True)
1086
Simon Glassa409c932017-11-12 21:52:28 -07001087 def testPackMrc(self):
1088 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001089 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001090 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1091
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001092 def testSplDtb(self):
1093 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001094 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001095 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1096
Simon Glass0a6da312017-11-13 18:54:56 -07001097 def testSplNoDtb(self):
1098 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001099 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001100 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1101
Simon Glass4ca8e042017-11-13 18:55:01 -07001102 def testSymbols(self):
1103 """Test binman can assign symbols embedded in U-Boot"""
1104 elf_fname = self.TestFile('u_boot_binman_syms')
1105 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1106 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glasse8561af2018-08-01 15:22:37 -06001107 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001108
Simon Glass7057d022018-10-01 21:12:47 -06001109 self._SetupSplElf('u_boot_binman_syms')
Simon Glass511f6582018-10-01 12:22:30 -06001110 data = self._DoReadFile('053_symbols.dts')
Simon Glass4ca8e042017-11-13 18:55:01 -07001111 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1112 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1113 U_BOOT_DATA +
1114 sym_values + U_BOOT_SPL_DATA[16:])
1115 self.assertEqual(expected, data)
1116
Simon Glasse76a3e62018-06-01 09:38:11 -06001117 def testPackUnitAddress(self):
1118 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001119 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001120 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1121
Simon Glassa91e1152018-06-01 09:38:16 -06001122 def testSections(self):
1123 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001124 data = self._DoReadFile('055_sections.dts')
Simon Glass3a9a2b82018-07-17 13:25:28 -06001125 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1126 U_BOOT_DATA + '&' * 4)
Simon Glassa91e1152018-06-01 09:38:16 -06001127 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001128
Simon Glass30732662018-06-01 09:38:20 -06001129 def testMap(self):
1130 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001131 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001132 self.assertEqual('''ImagePos Offset Size Name
113300000000 00000000 00000028 main-section
113400000000 00000000 00000010 section@0
113500000000 00000000 00000004 u-boot
113600000010 00000010 00000010 section@1
113700000010 00000000 00000004 u-boot
113800000020 00000020 00000004 section@2
113900000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001140''', map_data)
1141
Simon Glass3b78d532018-06-01 09:38:21 -06001142 def testNamePrefix(self):
1143 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001144 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001145 self.assertEqual('''ImagePos Offset Size Name
114600000000 00000000 00000028 main-section
114700000000 00000000 00000010 section@0
114800000000 00000000 00000004 ro-u-boot
114900000010 00000010 00000010 section@1
115000000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001151''', map_data)
1152
Simon Glass6ba679c2018-07-06 10:27:17 -06001153 def testUnknownContents(self):
1154 """Test that obtaining the contents works as expected"""
1155 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001156 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass6ba679c2018-07-06 10:27:17 -06001157 self.assertIn("Section '/binman': Internal error: Could not complete "
1158 "processing of contents: remaining [<_testing.Entry__testing ",
1159 str(e.exception))
1160
Simon Glass2e1169f2018-07-06 10:27:19 -06001161 def testBadChangeSize(self):
1162 """Test that trying to change the size of an entry fails"""
1163 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001164 self._DoReadFile('059_change_size.dts', True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001165 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1166 '2 to 1', str(e.exception))
1167
Simon Glassa87014e2018-07-06 10:27:42 -06001168 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001169 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001170 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001171 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001172 dtb = fdt.Fdt(out_dtb_fname)
1173 dtb.Scan()
1174 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glassa87014e2018-07-06 10:27:42 -06001175 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001176 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001177 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001178 '_testing:offset': 32,
Simon Glassa87014e2018-07-06 10:27:42 -06001179 '_testing:size': 1,
Simon Glass9dcc8612018-08-01 15:22:42 -06001180 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001181 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001182 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001183 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001184 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001185 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001186 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001187
Simon Glasse8561af2018-08-01 15:22:37 -06001188 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001189 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001190 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001191 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001192 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001193 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001194 'size': 40
1195 }, props)
1196
1197 def testUpdateFdtBad(self):
1198 """Test that we detect when ProcessFdt never completes"""
1199 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001200 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001201 self.assertIn('Could not complete processing of Fdt: remaining '
1202 '[<_testing.Entry__testing', str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001203
Simon Glass91710b32018-07-17 13:25:32 -06001204 def testEntryArgs(self):
1205 """Test passing arguments to entries from the command line"""
1206 entry_args = {
1207 'test-str-arg': 'test1',
1208 'test-int-arg': '456',
1209 }
Simon Glass511f6582018-10-01 12:22:30 -06001210 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001211 self.assertIn('image', control.images)
1212 entry = control.images['image'].GetEntries()['_testing']
1213 self.assertEqual('test0', entry.test_str_fdt)
1214 self.assertEqual('test1', entry.test_str_arg)
1215 self.assertEqual(123, entry.test_int_fdt)
1216 self.assertEqual(456, entry.test_int_arg)
1217
1218 def testEntryArgsMissing(self):
1219 """Test missing arguments and properties"""
1220 entry_args = {
1221 'test-int-arg': '456',
1222 }
Simon Glass511f6582018-10-01 12:22:30 -06001223 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001224 entry = control.images['image'].GetEntries()['_testing']
1225 self.assertEqual('test0', entry.test_str_fdt)
1226 self.assertEqual(None, entry.test_str_arg)
1227 self.assertEqual(None, entry.test_int_fdt)
1228 self.assertEqual(456, entry.test_int_arg)
1229
1230 def testEntryArgsRequired(self):
1231 """Test missing arguments and properties"""
1232 entry_args = {
1233 'test-int-arg': '456',
1234 }
1235 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001236 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass91710b32018-07-17 13:25:32 -06001237 self.assertIn("Node '/binman/_testing': Missing required "
1238 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1239 str(e.exception))
1240
1241 def testEntryArgsInvalidFormat(self):
1242 """Test that an invalid entry-argument format is detected"""
Simon Glass511f6582018-10-01 12:22:30 -06001243 args = ['-d', self.TestFile('064_entry_args_required.dts'), '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001244 with self.assertRaises(ValueError) as e:
1245 self._DoBinman(*args)
1246 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1247
1248 def testEntryArgsInvalidInteger(self):
1249 """Test that an invalid entry-argument integer is detected"""
1250 entry_args = {
1251 'test-int-arg': 'abc',
1252 }
1253 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001254 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001255 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1256 "'test-int-arg' (value 'abc') to integer",
1257 str(e.exception))
1258
1259 def testEntryArgsInvalidDatatype(self):
1260 """Test that an invalid entry-argument datatype is detected
1261
1262 This test could be written in entry_test.py except that it needs
1263 access to control.entry_args, which seems more than that module should
1264 be able to see.
1265 """
1266 entry_args = {
1267 'test-bad-datatype-arg': '12',
1268 }
1269 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001270 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001271 entry_args=entry_args)
1272 self.assertIn('GetArg() internal error: Unknown data type ',
1273 str(e.exception))
1274
Simon Glass2ca52032018-07-17 13:25:33 -06001275 def testText(self):
1276 """Test for a text entry type"""
1277 entry_args = {
1278 'test-id': TEXT_DATA,
1279 'test-id2': TEXT_DATA2,
1280 'test-id3': TEXT_DATA3,
1281 }
Simon Glass511f6582018-10-01 12:22:30 -06001282 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001283 entry_args=entry_args)
1284 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1285 TEXT_DATA3 + 'some text')
1286 self.assertEqual(expected, data)
1287
Simon Glass969616c2018-07-17 13:25:36 -06001288 def testEntryDocs(self):
1289 """Test for creation of entry documentation"""
1290 with test_util.capture_sys_output() as (stdout, stderr):
1291 control.WriteEntryDocs(binman.GetEntryModules())
1292 self.assertTrue(len(stdout.getvalue()) > 0)
1293
1294 def testEntryDocsMissing(self):
1295 """Test handling of missing entry documentation"""
1296 with self.assertRaises(ValueError) as e:
1297 with test_util.capture_sys_output() as (stdout, stderr):
1298 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1299 self.assertIn('Documentation is missing for modules: u_boot',
1300 str(e.exception))
1301
Simon Glass704784b2018-07-17 13:25:38 -06001302 def testFmap(self):
1303 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001304 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001305 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1306 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1307 self.assertEqual(expected, data[:32])
1308 self.assertEqual('__FMAP__', fhdr.signature)
1309 self.assertEqual(1, fhdr.ver_major)
1310 self.assertEqual(0, fhdr.ver_minor)
1311 self.assertEqual(0, fhdr.base)
1312 self.assertEqual(16 + 16 +
1313 fmap_util.FMAP_HEADER_LEN +
1314 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1315 self.assertEqual('FMAP', fhdr.name)
1316 self.assertEqual(3, fhdr.nareas)
1317 for fentry in fentries:
1318 self.assertEqual(0, fentry.flags)
1319
1320 self.assertEqual(0, fentries[0].offset)
1321 self.assertEqual(4, fentries[0].size)
1322 self.assertEqual('RO_U_BOOT', fentries[0].name)
1323
1324 self.assertEqual(16, fentries[1].offset)
1325 self.assertEqual(4, fentries[1].size)
1326 self.assertEqual('RW_U_BOOT', fentries[1].name)
1327
1328 self.assertEqual(32, fentries[2].offset)
1329 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1330 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1331 self.assertEqual('FMAP', fentries[2].name)
1332
Simon Glassdb168d42018-07-17 13:25:39 -06001333 def testBlobNamedByArg(self):
1334 """Test we can add a blob with the filename coming from an entry arg"""
1335 entry_args = {
1336 'cros-ec-rw-path': 'ecrw.bin',
1337 }
Simon Glass511f6582018-10-01 12:22:30 -06001338 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassdb168d42018-07-17 13:25:39 -06001339 entry_args=entry_args)
1340
Simon Glass53f53992018-07-17 13:25:40 -06001341 def testFill(self):
1342 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001343 data = self._DoReadFile('069_fill.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001344 expected = 8 * chr(0xff) + 8 * chr(0)
1345 self.assertEqual(expected, data)
1346
1347 def testFillNoSize(self):
1348 """Test for an fill entry type with no size"""
1349 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001350 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001351 self.assertIn("'fill' entry must have a size property",
1352 str(e.exception))
1353
Simon Glassc1ae83c2018-07-17 13:25:44 -06001354 def _HandleGbbCommand(self, pipe_list):
1355 """Fake calls to the futility utility"""
1356 if pipe_list[0][0] == 'futility':
1357 fname = pipe_list[0][-1]
1358 # Append our GBB data to the file, which will happen every time the
1359 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001360 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001361 fd.write(GBB_DATA)
1362 return command.CommandResult()
1363
1364 def testGbb(self):
1365 """Test for the Chromium OS Google Binary Block"""
1366 command.test_result = self._HandleGbbCommand
1367 entry_args = {
1368 'keydir': 'devkeys',
1369 'bmpblk': 'bmpblk.bin',
1370 }
Simon Glass511f6582018-10-01 12:22:30 -06001371 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001372
1373 # Since futility
1374 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1375 self.assertEqual(expected, data)
1376
1377 def testGbbTooSmall(self):
1378 """Test for the Chromium OS Google Binary Block being large enough"""
1379 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001380 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001381 self.assertIn("Node '/binman/gbb': GBB is too small",
1382 str(e.exception))
1383
1384 def testGbbNoSize(self):
1385 """Test for the Chromium OS Google Binary Block having a size"""
1386 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001387 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001388 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1389 str(e.exception))
1390
Simon Glass5c350162018-07-17 13:25:47 -06001391 def _HandleVblockCommand(self, pipe_list):
1392 """Fake calls to the futility utility"""
1393 if pipe_list[0][0] == 'futility':
1394 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001395 with open(fname, 'wb') as fd:
Simon Glass5c350162018-07-17 13:25:47 -06001396 fd.write(VBLOCK_DATA)
1397 return command.CommandResult()
1398
1399 def testVblock(self):
1400 """Test for the Chromium OS Verified Boot Block"""
1401 command.test_result = self._HandleVblockCommand
1402 entry_args = {
1403 'keydir': 'devkeys',
1404 }
Simon Glass511f6582018-10-01 12:22:30 -06001405 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001406 entry_args=entry_args)
1407 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1408 self.assertEqual(expected, data)
1409
1410 def testVblockNoContent(self):
1411 """Test we detect a vblock which has no content to sign"""
1412 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001413 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001414 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1415 'property', str(e.exception))
1416
1417 def testVblockBadPhandle(self):
1418 """Test that we detect a vblock with an invalid phandle in contents"""
1419 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001420 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001421 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1422 '1000', str(e.exception))
1423
1424 def testVblockBadEntry(self):
1425 """Test that we detect an entry that points to a non-entry"""
1426 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001427 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001428 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1429 "'other'", str(e.exception))
1430
Simon Glass8425a1f2018-07-17 13:25:48 -06001431 def testTpl(self):
1432 """Test that an image with TPL and ots device tree can be created"""
1433 # ELF file with a '__bss_size' symbol
Simon Glass33486662019-05-14 15:53:42 -06001434 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass8425a1f2018-07-17 13:25:48 -06001435 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001436 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001437 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1438
Simon Glass24b97442018-07-17 13:25:51 -06001439 def testUsesPos(self):
1440 """Test that the 'pos' property cannot be used anymore"""
1441 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001442 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001443 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1444 "'pos'", str(e.exception))
1445
Simon Glass274bf092018-09-14 04:57:08 -06001446 def testFillZero(self):
1447 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001448 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass274bf092018-09-14 04:57:08 -06001449 self.assertEqual(chr(0) * 16, data)
1450
Simon Glass267de432018-09-14 04:57:09 -06001451 def testTextMissing(self):
1452 """Test for a text entry type where there is no text"""
1453 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001454 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001455 self.assertIn("Node '/binman/text': No value provided for text label "
1456 "'test-id'", str(e.exception))
1457
Simon Glassed40e962018-09-14 04:57:10 -06001458 def testPackStart16Tpl(self):
1459 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001460 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001461 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1462
Simon Glass3b376c32018-09-14 04:57:12 -06001463 def testSelectImage(self):
1464 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001465 expected = 'Skipping images: image1'
1466
1467 # We should only get the expected message in verbose mode
1468 for verbosity in (None, 2):
1469 with test_util.capture_sys_output() as (stdout, stderr):
1470 retcode = self._DoTestFile('006_dual_image.dts',
1471 verbosity=verbosity,
1472 images=['image2'])
1473 self.assertEqual(0, retcode)
1474 if verbosity:
1475 self.assertIn(expected, stdout.getvalue())
1476 else:
1477 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001478
Simon Glassb4595d82019-04-25 21:58:34 -06001479 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1480 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass3b376c32018-09-14 04:57:12 -06001481
Simon Glasse219aa42018-09-14 04:57:24 -06001482 def testUpdateFdtAll(self):
1483 """Test that all device trees are updated with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001484 data, _, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001485 use_real_dtb=True, update_dtb=True)
1486
1487 base_expected = {
1488 'section:image-pos': 0,
1489 'u-boot-tpl-dtb:size': 513,
1490 'u-boot-spl-dtb:size': 513,
1491 'u-boot-spl-dtb:offset': 493,
1492 'image-pos': 0,
1493 'section/u-boot-dtb:image-pos': 0,
1494 'u-boot-spl-dtb:image-pos': 493,
1495 'section/u-boot-dtb:size': 493,
1496 'u-boot-tpl-dtb:image-pos': 1006,
1497 'section/u-boot-dtb:offset': 0,
1498 'section:size': 493,
1499 'offset': 0,
1500 'section:offset': 0,
1501 'u-boot-tpl-dtb:offset': 1006,
1502 'size': 1519
1503 }
1504
1505 # We expect three device-tree files in the output, one after the other.
1506 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1507 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1508 # main U-Boot tree. All three should have the same postions and offset.
1509 start = 0
1510 for item in ['', 'spl', 'tpl']:
1511 dtb = fdt.Fdt.FromData(data[start:])
1512 dtb.Scan()
1513 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1514 'spl', 'tpl'])
1515 expected = dict(base_expected)
1516 if item:
1517 expected[item] = 0
1518 self.assertEqual(expected, props)
1519 start += dtb._fdt_obj.totalsize()
1520
1521 def testUpdateFdtOutput(self):
1522 """Test that output DTB files are updated"""
1523 try:
Simon Glass511f6582018-10-01 12:22:30 -06001524 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001525 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1526
1527 # Unfortunately, compiling a source file always results in a file
1528 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001529 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001530 # binman as a file called u-boot.dtb. To fix this, copy the file
1531 # over to the expected place.
1532 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1533 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1534 start = 0
1535 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1536 'tpl/u-boot-tpl.dtb.out']:
1537 dtb = fdt.Fdt.FromData(data[start:])
1538 size = dtb._fdt_obj.totalsize()
1539 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1540 outdata = tools.ReadFile(pathname)
1541 name = os.path.split(fname)[0]
1542
1543 if name:
1544 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1545 else:
1546 orig_indata = dtb_data
1547 self.assertNotEqual(outdata, orig_indata,
1548 "Expected output file '%s' be updated" % pathname)
1549 self.assertEqual(outdata, data[start:start + size],
1550 "Expected output file '%s' to match output image" %
1551 pathname)
1552 start += size
1553 finally:
1554 self._ResetDtbs()
1555
Simon Glass7ba33592018-09-14 04:57:26 -06001556 def _decompress(self, data):
1557 out = os.path.join(self._indir, 'lz4.tmp')
1558 with open(out, 'wb') as fd:
1559 fd.write(data)
Simon Glass3861cc42019-05-14 15:53:45 -06001560 return tools.Run('lz4', '-dc', out, binary=True)
Simon Glass7ba33592018-09-14 04:57:26 -06001561 '''
1562 try:
1563 orig = lz4.frame.decompress(data)
1564 except AttributeError:
1565 orig = lz4.decompress(data)
1566 '''
1567
1568 def testCompress(self):
1569 """Test compression of blobs"""
Simon Glass511f6582018-10-01 12:22:30 -06001570 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001571 use_real_dtb=True, update_dtb=True)
1572 dtb = fdt.Fdt(out_dtb_fname)
1573 dtb.Scan()
1574 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1575 orig = self._decompress(data)
1576 self.assertEquals(COMPRESS_DATA, orig)
1577 expected = {
1578 'blob:uncomp-size': len(COMPRESS_DATA),
1579 'blob:size': len(data),
1580 'size': len(data),
1581 }
1582 self.assertEqual(expected, props)
1583
Simon Glassac6328c2018-09-14 04:57:28 -06001584 def testFiles(self):
1585 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001586 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001587 self.assertEqual(FILES_DATA, data)
1588
1589 def testFilesCompress(self):
1590 """Test bringing in multiple files and compressing them"""
Simon Glass511f6582018-10-01 12:22:30 -06001591 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001592
1593 image = control.images['image']
1594 entries = image.GetEntries()
1595 files = entries['files']
1596 entries = files._section._entries
1597
1598 orig = ''
1599 for i in range(1, 3):
1600 key = '%d.dat' % i
1601 start = entries[key].image_pos
1602 len = entries[key].size
1603 chunk = data[start:start + len]
1604 orig += self._decompress(chunk)
1605
1606 self.assertEqual(FILES_DATA, orig)
1607
1608 def testFilesMissing(self):
1609 """Test missing files"""
1610 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001611 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001612 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1613 'no files', str(e.exception))
1614
1615 def testFilesNoPattern(self):
1616 """Test missing files"""
1617 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001618 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001619 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1620 str(e.exception))
1621
Simon Glassfa79a812018-09-14 04:57:29 -06001622 def testExpandSize(self):
1623 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001624 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001625 map=True)
1626 expect = ('a' * 8 + U_BOOT_DATA +
1627 MRC_DATA + 'b' * 1 + U_BOOT_DATA +
1628 'c' * 8 + U_BOOT_DATA +
1629 'd' * 8)
1630 self.assertEqual(expect, data)
1631 self.assertEqual('''ImagePos Offset Size Name
163200000000 00000000 00000028 main-section
163300000000 00000000 00000008 fill
163400000008 00000008 00000004 u-boot
16350000000c 0000000c 00000004 section
16360000000c 00000000 00000003 intel-mrc
163700000010 00000010 00000004 u-boot2
163800000014 00000014 0000000c section2
163900000014 00000000 00000008 fill
16400000001c 00000008 00000004 u-boot
164100000020 00000020 00000008 fill2
1642''', map_data)
1643
1644 def testExpandSizeBad(self):
1645 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001646 with test_util.capture_sys_output() as (stdout, stderr):
1647 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001648 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001649 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1650 'expanding entry', str(e.exception))
1651
Simon Glassae7cf032018-09-14 04:57:31 -06001652 def testHash(self):
1653 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001654 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001655 use_real_dtb=True, update_dtb=True)
1656 dtb = fdt.Fdt(out_dtb_fname)
1657 dtb.Scan()
1658 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1659 m = hashlib.sha256()
1660 m.update(U_BOOT_DATA)
1661 self.assertEqual(m.digest(), ''.join(hash_node.value))
1662
1663 def testHashNoAlgo(self):
1664 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001665 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001666 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1667 'hash node', str(e.exception))
1668
1669 def testHashBadAlgo(self):
1670 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001671 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001672 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1673 str(e.exception))
1674
1675 def testHashSection(self):
1676 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001677 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001678 use_real_dtb=True, update_dtb=True)
1679 dtb = fdt.Fdt(out_dtb_fname)
1680 dtb.Scan()
1681 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1682 m = hashlib.sha256()
1683 m.update(U_BOOT_DATA)
1684 m.update(16 * 'a')
1685 self.assertEqual(m.digest(), ''.join(hash_node.value))
1686
Simon Glass3fb4f422018-09-14 04:57:32 -06001687 def testPackUBootTplMicrocode(self):
1688 """Test that x86 microcode can be handled correctly in TPL
1689
1690 We expect to see the following in the image, in order:
1691 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1692 place
1693 u-boot-tpl.dtb with the microcode removed
1694 the microcode
1695 """
Simon Glass33486662019-05-14 15:53:42 -06001696 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass3fb4f422018-09-14 04:57:32 -06001697 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001698 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06001699 U_BOOT_TPL_NODTB_DATA)
1700 self.assertEqual('tplnodtb with microc' + pos_and_size +
1701 'ter somewhere in here', first)
1702
Simon Glassc64aea52018-09-14 04:57:34 -06001703 def testFmapX86(self):
1704 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001705 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001706 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1707 expected = U_BOOT_DATA + MRC_DATA + 'a' * (32 - 7)
1708 self.assertEqual(expected, data[:32])
1709 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1710
1711 self.assertEqual(0x100, fhdr.image_size)
1712
1713 self.assertEqual(0, fentries[0].offset)
1714 self.assertEqual(4, fentries[0].size)
1715 self.assertEqual('U_BOOT', fentries[0].name)
1716
1717 self.assertEqual(4, fentries[1].offset)
1718 self.assertEqual(3, fentries[1].size)
1719 self.assertEqual('INTEL_MRC', fentries[1].name)
1720
1721 self.assertEqual(32, fentries[2].offset)
1722 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1723 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1724 self.assertEqual('FMAP', fentries[2].name)
1725
1726 def testFmapX86Section(self):
1727 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001728 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001729 expected = U_BOOT_DATA + MRC_DATA + 'b' * (32 - 7)
1730 self.assertEqual(expected, data[:32])
1731 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1732
1733 self.assertEqual(0x100, fhdr.image_size)
1734
1735 self.assertEqual(0, fentries[0].offset)
1736 self.assertEqual(4, fentries[0].size)
1737 self.assertEqual('U_BOOT', fentries[0].name)
1738
1739 self.assertEqual(4, fentries[1].offset)
1740 self.assertEqual(3, fentries[1].size)
1741 self.assertEqual('INTEL_MRC', fentries[1].name)
1742
1743 self.assertEqual(36, fentries[2].offset)
1744 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1745 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1746 self.assertEqual('FMAP', fentries[2].name)
1747
Simon Glassb1714232018-09-14 04:57:35 -06001748 def testElf(self):
1749 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001750 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001751 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001752 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001753 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001754
1755 def testElfStripg(self):
1756 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001757 self._SetupSplElf()
Simon Glass33486662019-05-14 15:53:42 -06001758 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001759 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001760 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001761
Simon Glasscd817d52018-09-14 04:57:36 -06001762 def testPackOverlapMap(self):
1763 """Test that overlapping regions are detected"""
1764 with test_util.capture_sys_output() as (stdout, stderr):
1765 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001766 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06001767 map_fname = tools.GetOutputFilename('image.map')
1768 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1769 stdout.getvalue())
1770
1771 # We should not get an inmage, but there should be a map file
1772 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1773 self.assertTrue(os.path.exists(map_fname))
1774 map_data = tools.ReadFile(map_fname)
1775 self.assertEqual('''ImagePos Offset Size Name
1776<none> 00000000 00000007 main-section
1777<none> 00000000 00000004 u-boot
1778<none> 00000003 00000004 u-boot-align
1779''', map_data)
1780
Simon Glass41902e42018-10-01 12:22:31 -06001781 def testPacRefCode(self):
1782 """Test that an image with an Intel Reference code binary works"""
1783 data = self._DoReadFile('100_intel_refcode.dts')
1784 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1785
Simon Glasseb023b32019-04-25 21:58:39 -06001786 def testSectionOffset(self):
1787 """Tests use of a section with an offset"""
1788 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1789 map=True)
1790 self.assertEqual('''ImagePos Offset Size Name
179100000000 00000000 00000038 main-section
179200000004 00000004 00000010 section@0
179300000004 00000000 00000004 u-boot
179400000018 00000018 00000010 section@1
179500000018 00000000 00000004 u-boot
17960000002c 0000002c 00000004 section@2
17970000002c 00000000 00000004 u-boot
1798''', map_data)
1799 self.assertEqual(data,
1800 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x21) +
1801 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x61) +
1802 4 * chr(0x26) + U_BOOT_DATA + 8 * chr(0x26))
1803
Simon Glass91710b32018-07-17 13:25:32 -06001804
Simon Glassac599912017-11-12 21:52:22 -07001805if __name__ == "__main__":
1806 unittest.main()