blob: 6bfef7b63a6ce9079b5b5b21a1be7cb3a6320047 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
9from optparse import OptionParser
10import os
11import shutil
12import struct
13import sys
14import tempfile
15import unittest
16
17import binman
18import cmdline
19import command
20import control
Simon Glass19790632017-11-13 18:55:01 -070021import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060022import fdt
Simon Glass4f443042016-11-25 20:15:52 -070023import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060024import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060025import test_util
Simon Glassc55a50f2018-09-14 04:57:19 -060026import state
Simon Glass4f443042016-11-25 20:15:52 -070027import tools
28import tout
29
30# Contents of test files, corresponding to different entry types
Simon Glass6b187df2017-11-12 21:52:27 -070031U_BOOT_DATA = '1234'
32U_BOOT_IMG_DATA = 'img'
Simon Glassf6898902017-11-13 18:54:59 -070033U_BOOT_SPL_DATA = '56780123456789abcde'
Simon Glassb8ef5b62018-07-17 13:25:48 -060034U_BOOT_TPL_DATA = 'tpl'
Simon Glass6b187df2017-11-12 21:52:27 -070035BLOB_DATA = '89'
36ME_DATA = '0abcd'
37VGA_DATA = 'vga'
38U_BOOT_DTB_DATA = 'udtb'
Simon Glass47419ea2017-11-13 18:54:55 -070039U_BOOT_SPL_DTB_DATA = 'spldtb'
Simon Glassb8ef5b62018-07-17 13:25:48 -060040U_BOOT_TPL_DTB_DATA = 'tpldtb'
Simon Glass6b187df2017-11-12 21:52:27 -070041X86_START16_DATA = 'start16'
42X86_START16_SPL_DATA = 'start16spl'
Simon Glass35b384c2018-09-14 04:57:10 -060043X86_START16_TPL_DATA = 'start16tpl'
Simon Glass6b187df2017-11-12 21:52:27 -070044U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here'
45U_BOOT_SPL_NODTB_DATA = 'splnodtb with microcode pointer somewhere in here'
46FSP_DATA = 'fsp'
47CMC_DATA = 'cmc'
48VBT_DATA = 'vbt'
Simon Glassca4f4ff2017-11-12 21:52:28 -070049MRC_DATA = 'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060050TEXT_DATA = 'text'
51TEXT_DATA2 = 'text2'
52TEXT_DATA3 = 'text3'
Simon Glassec127af2018-07-17 13:25:39 -060053CROS_EC_RW_DATA = 'ecrw'
Simon Glass0ef87aa2018-07-17 13:25:44 -060054GBB_DATA = 'gbbd'
55BMPBLK_DATA = 'bmp'
Simon Glass24d0d3c2018-07-17 13:25:47 -060056VBLOCK_DATA = 'vblk'
Simon Glassec127af2018-07-17 13:25:39 -060057
Simon Glass4f443042016-11-25 20:15:52 -070058
59class TestFunctional(unittest.TestCase):
60 """Functional tests for binman
61
62 Most of these use a sample .dts file to build an image and then check
63 that it looks correct. The sample files are in the test/ subdirectory
64 and are numbered.
65
66 For each entry type a very small test file is created using fixed
67 string contents. This makes it easy to test that things look right, and
68 debug problems.
69
70 In some cases a 'real' file must be used - these are also supplied in
71 the test/ diurectory.
72 """
73 @classmethod
74 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070075 global entry
76 import entry
77
Simon Glass4f443042016-11-25 20:15:52 -070078 # Handle the case where argv[0] is 'python'
79 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
80 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
81
82 # Create a temporary directory for input files
83 self._indir = tempfile.mkdtemp(prefix='binmant.')
84
85 # Create some test files
86 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
87 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
88 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060089 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070090 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -070091 TestFunctional._MakeInputFile('me.bin', ME_DATA)
92 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060093 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -070094 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Simon Glass87722132017-11-12 21:52:26 -070095 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
96 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -060097 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
98 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070099 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700100 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
101 U_BOOT_SPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700102 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
103 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700104 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700105 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600106 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600107 TestFunctional._MakeInputDir('devkeys')
108 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700109 self._output_setup = False
110
Simon Glasse0ff8552016-11-25 20:15:53 -0700111 # ELF file with a '_dt_ucode_base_size' symbol
112 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
113 TestFunctional._MakeInputFile('u-boot', fd.read())
114
115 # Intel flash descriptor file
116 with open(self.TestFile('descriptor.bin')) as fd:
117 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
118
Simon Glass4f443042016-11-25 20:15:52 -0700119 @classmethod
120 def tearDownClass(self):
121 """Remove the temporary input directory and its contents"""
122 if self._indir:
123 shutil.rmtree(self._indir)
124 self._indir = None
125
126 def setUp(self):
127 # Enable this to turn on debugging output
128 # tout.Init(tout.DEBUG)
129 command.test_result = None
130
131 def tearDown(self):
132 """Remove the temporary output directory"""
133 tools._FinaliseForTest()
134
Simon Glassb8ef5b62018-07-17 13:25:48 -0600135 @classmethod
136 def _ResetDtbs(self):
137 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
138 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
139 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
140
Simon Glass4f443042016-11-25 20:15:52 -0700141 def _RunBinman(self, *args, **kwargs):
142 """Run binman using the command line
143
144 Args:
145 Arguments to pass, as a list of strings
146 kwargs: Arguments to pass to Command.RunPipe()
147 """
148 result = command.RunPipe([[self._binman_pathname] + list(args)],
149 capture=True, capture_stderr=True, raise_on_error=False)
150 if result.return_code and kwargs.get('raise_on_error', True):
151 raise Exception("Error running '%s': %s" % (' '.join(args),
152 result.stdout + result.stderr))
153 return result
154
155 def _DoBinman(self, *args):
156 """Run binman using directly (in the same process)
157
158 Args:
159 Arguments to pass, as a list of strings
160 Returns:
161 Return value (0 for success)
162 """
Simon Glass7fe91732017-11-13 18:55:00 -0700163 args = list(args)
164 if '-D' in sys.argv:
165 args = args + ['-D']
166 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700167 options.pager = 'binman-invalid-pager'
168 options.build_dir = self._indir
169
170 # For testing, you can force an increase in verbosity here
171 # options.verbosity = tout.DEBUG
172 return control.Binman(options, args)
173
Simon Glass53af22a2018-07-17 13:25:32 -0600174 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glass93d17412018-09-14 04:57:23 -0600175 entry_args=None, images=None, use_real_dtb=False):
Simon Glass4f443042016-11-25 20:15:52 -0700176 """Run binman with a given test file
177
178 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600179 fname: Device-tree source filename to use (e.g. 05_simple.dts)
180 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600181 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600182 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600183 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600184 entry_args: Dict of entry args to supply to binman
185 key: arg name
186 value: value of that arg
187 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700188 """
Simon Glass7fe91732017-11-13 18:55:00 -0700189 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
190 if debug:
191 args.append('-D')
Simon Glass3b0c3822018-06-01 09:38:20 -0600192 if map:
193 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600194 if update_dtb:
195 args.append('-up')
Simon Glass93d17412018-09-14 04:57:23 -0600196 if not use_real_dtb:
197 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600198 if entry_args:
199 for arg, value in entry_args.iteritems():
200 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600201 if images:
202 for image in images:
203 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700204 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700205
206 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700207 """Set up a new test device-tree file
208
209 The given file is compiled and set up as the device tree to be used
210 for ths test.
211
212 Args:
213 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600214 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700215
216 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600217 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700218 """
Simon Glass4f443042016-11-25 20:15:52 -0700219 if not self._output_setup:
220 tools.PrepareOutputDir(self._indir, True)
221 self._output_setup = True
222 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
223 with open(dtb) as fd:
224 data = fd.read()
225 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700226 return data
Simon Glass4f443042016-11-25 20:15:52 -0700227
Simon Glass6ed45ba2018-09-14 04:57:24 -0600228 def _GetDtbContentsForSplTpl(self, dtb_data, name):
229 """Create a version of the main DTB for SPL or SPL
230
231 For testing we don't actually have different versions of the DTB. With
232 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
233 we don't normally have any unwanted nodes.
234
235 We still want the DTBs for SPL and TPL to be different though, since
236 otherwise it is confusing to know which one we are looking at. So add
237 an 'spl' or 'tpl' property to the top-level node.
238 """
239 dtb = fdt.Fdt.FromData(dtb_data)
240 dtb.Scan()
241 dtb.GetNode('/binman').AddZeroProp(name)
242 dtb.Sync(auto_resize=True)
243 dtb.Pack()
244 return dtb.GetContents()
245
Simon Glass16b8d6b2018-07-06 10:27:42 -0600246 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600247 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700248 """Run binman and return the resulting image
249
250 This runs binman with a given test file and then reads the resulting
251 output file. It is a shortcut function since most tests need to do
252 these steps.
253
254 Raises an assertion failure if binman returns a non-zero exit code.
255
256 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600257 fname: Device-tree source filename to use (e.g. 05_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700258 use_real_dtb: True to use the test file as the contents of
259 the u-boot-dtb entry. Normally this is not needed and the
260 test contents (the U_BOOT_DTB_DATA string) can be used.
261 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600262 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600263 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600264 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700265
266 Returns:
267 Tuple:
268 Resulting image contents
269 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600270 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600271 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700272 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700273 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700274 # Use the compiled test file as the u-boot-dtb input
275 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700276 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600277 infile = os.path.join(self._indir, 'u-boot.dtb')
278
279 # For testing purposes, make a copy of the DT for SPL and TPL. Add
280 # a node indicating which it is, so aid verification.
281 for name in ['spl', 'tpl']:
282 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
283 outfile = os.path.join(self._indir, dtb_fname)
284 TestFunctional._MakeInputFile(dtb_fname,
285 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700286
287 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600288 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600289 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700290 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600291 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700292
293 # Find the (only) image, read it and return its contents
294 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600295 image_fname = tools.GetOutputFilename('image.bin')
296 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600297 if map:
298 map_fname = tools.GetOutputFilename('image.map')
299 with open(map_fname) as fd:
300 map_data = fd.read()
301 else:
302 map_data = None
Simon Glass16b8d6b2018-07-06 10:27:42 -0600303 with open(image_fname) as fd:
304 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700305 finally:
306 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600307 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600308 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700309
Simon Glasse0ff8552016-11-25 20:15:53 -0700310 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600311 """Helper function which discards the device-tree binary
312
313 Args:
314 fname: Device-tree source filename to use (e.g. 05_simple.dts)
315 use_real_dtb: True to use the test file as the contents of
316 the u-boot-dtb entry. Normally this is not needed and the
317 test contents (the U_BOOT_DTB_DATA string) can be used.
318 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600319
320 Returns:
321 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600322 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700323 return self._DoReadFileDtb(fname, use_real_dtb)[0]
324
Simon Glass4f443042016-11-25 20:15:52 -0700325 @classmethod
326 def _MakeInputFile(self, fname, contents):
327 """Create a new test input file, creating directories as needed
328
329 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600330 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700331 contents: File contents to write in to the file
332 Returns:
333 Full pathname of file created
334 """
335 pathname = os.path.join(self._indir, fname)
336 dirname = os.path.dirname(pathname)
337 if dirname and not os.path.exists(dirname):
338 os.makedirs(dirname)
339 with open(pathname, 'wb') as fd:
340 fd.write(contents)
341 return pathname
342
343 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600344 def _MakeInputDir(self, dirname):
345 """Create a new test input directory, creating directories as needed
346
347 Args:
348 dirname: Directory name to create
349
350 Returns:
351 Full pathname of directory created
352 """
353 pathname = os.path.join(self._indir, dirname)
354 if not os.path.exists(pathname):
355 os.makedirs(pathname)
356 return pathname
357
358 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700359 def TestFile(self, fname):
360 return os.path.join(self._binman_dir, 'test', fname)
361
362 def AssertInList(self, grep_list, target):
363 """Assert that at least one of a list of things is in a target
364
365 Args:
366 grep_list: List of strings to check
367 target: Target string
368 """
369 for grep in grep_list:
370 if grep in target:
371 return
372 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
373
374 def CheckNoGaps(self, entries):
375 """Check that all entries fit together without gaps
376
377 Args:
378 entries: List of entries to check
379 """
Simon Glass3ab95982018-08-01 15:22:37 -0600380 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700381 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600382 self.assertEqual(offset, entry.offset)
383 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700384
Simon Glasse0ff8552016-11-25 20:15:53 -0700385 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600386 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700387
388 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600389 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700390
391 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600392 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700393 """
394 return struct.unpack('>L', dtb[4:8])[0]
395
Simon Glasscee02e62018-07-17 13:25:52 -0600396 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600397 def AddNode(node, path):
398 if node.name != '/':
399 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600400 for subnode in node.subnodes:
401 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600402 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600403 prop_path = path + '/' + subnode.name + ':' + prop.name
404 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
405 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600406 AddNode(subnode, path)
407
408 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600409 AddNode(dtb.GetRoot(), '')
410 return tree
411
Simon Glass4f443042016-11-25 20:15:52 -0700412 def testRun(self):
413 """Test a basic run with valid args"""
414 result = self._RunBinman('-h')
415
416 def testFullHelp(self):
417 """Test that the full help is displayed with -H"""
418 result = self._RunBinman('-H')
419 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500420 # Remove possible extraneous strings
421 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
422 gothelp = result.stdout.replace(extra, '')
423 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700424 self.assertEqual(0, len(result.stderr))
425 self.assertEqual(0, result.return_code)
426
427 def testFullHelpInternal(self):
428 """Test that the full help is displayed with -H"""
429 try:
430 command.test_result = command.CommandResult()
431 result = self._DoBinman('-H')
432 help_file = os.path.join(self._binman_dir, 'README')
433 finally:
434 command.test_result = None
435
436 def testHelp(self):
437 """Test that the basic help is displayed with -h"""
438 result = self._RunBinman('-h')
439 self.assertTrue(len(result.stdout) > 200)
440 self.assertEqual(0, len(result.stderr))
441 self.assertEqual(0, result.return_code)
442
Simon Glass4f443042016-11-25 20:15:52 -0700443 def testBoard(self):
444 """Test that we can run it with a specific board"""
445 self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
446 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
447 result = self._DoBinman('-b', 'sandbox')
448 self.assertEqual(0, result)
449
450 def testNeedBoard(self):
451 """Test that we get an error when no board ius supplied"""
452 with self.assertRaises(ValueError) as e:
453 result = self._DoBinman()
454 self.assertIn("Must provide a board to process (use -b <board>)",
455 str(e.exception))
456
457 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600458 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700459 with self.assertRaises(Exception) as e:
460 self._RunBinman('-d', 'missing_file')
461 # We get one error from libfdt, and a different one from fdtget.
462 self.AssertInList(["Couldn't open blob from 'missing_file'",
463 'No such file or directory'], str(e.exception))
464
465 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600466 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700467
468 Since this is a source file it should be compiled and the error
469 will come from the device-tree compiler (dtc).
470 """
471 with self.assertRaises(Exception) as e:
472 self._RunBinman('-d', self.TestFile('01_invalid.dts'))
473 self.assertIn("FATAL ERROR: Unable to parse input tree",
474 str(e.exception))
475
476 def testMissingNode(self):
477 """Test that a device tree without a 'binman' node generates an error"""
478 with self.assertRaises(Exception) as e:
479 self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
480 self.assertIn("does not have a 'binman' node", str(e.exception))
481
482 def testEmpty(self):
483 """Test that an empty binman node works OK (i.e. does nothing)"""
484 result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
485 self.assertEqual(0, len(result.stderr))
486 self.assertEqual(0, result.return_code)
487
488 def testInvalidEntry(self):
489 """Test that an invalid entry is flagged"""
490 with self.assertRaises(Exception) as e:
491 result = self._RunBinman('-d',
492 self.TestFile('04_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700493 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
494 "'/binman/not-a-valid-type'", str(e.exception))
495
496 def testSimple(self):
497 """Test a simple binman with a single file"""
498 data = self._DoReadFile('05_simple.dts')
499 self.assertEqual(U_BOOT_DATA, data)
500
Simon Glass7fe91732017-11-13 18:55:00 -0700501 def testSimpleDebug(self):
502 """Test a simple binman run with debugging enabled"""
503 data = self._DoTestFile('05_simple.dts', debug=True)
504
Simon Glass4f443042016-11-25 20:15:52 -0700505 def testDual(self):
506 """Test that we can handle creating two images
507
508 This also tests image padding.
509 """
510 retcode = self._DoTestFile('06_dual_image.dts')
511 self.assertEqual(0, retcode)
512
513 image = control.images['image1']
514 self.assertEqual(len(U_BOOT_DATA), image._size)
515 fname = tools.GetOutputFilename('image1.bin')
516 self.assertTrue(os.path.exists(fname))
517 with open(fname) as fd:
518 data = fd.read()
519 self.assertEqual(U_BOOT_DATA, data)
520
521 image = control.images['image2']
522 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
523 fname = tools.GetOutputFilename('image2.bin')
524 self.assertTrue(os.path.exists(fname))
525 with open(fname) as fd:
526 data = fd.read()
527 self.assertEqual(U_BOOT_DATA, data[3:7])
528 self.assertEqual(chr(0) * 3, data[:3])
529 self.assertEqual(chr(0) * 5, data[7:])
530
531 def testBadAlign(self):
532 """Test that an invalid alignment value is detected"""
533 with self.assertRaises(ValueError) as e:
534 self._DoTestFile('07_bad_align.dts')
535 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
536 "of two", str(e.exception))
537
538 def testPackSimple(self):
539 """Test that packing works as expected"""
540 retcode = self._DoTestFile('08_pack.dts')
541 self.assertEqual(0, retcode)
542 self.assertIn('image', control.images)
543 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600544 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700545 self.assertEqual(5, len(entries))
546
547 # First u-boot
548 self.assertIn('u-boot', entries)
549 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600550 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700551 self.assertEqual(len(U_BOOT_DATA), entry.size)
552
553 # Second u-boot, aligned to 16-byte boundary
554 self.assertIn('u-boot-align', entries)
555 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600556 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700557 self.assertEqual(len(U_BOOT_DATA), entry.size)
558
559 # Third u-boot, size 23 bytes
560 self.assertIn('u-boot-size', entries)
561 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600562 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700563 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
564 self.assertEqual(23, entry.size)
565
566 # Fourth u-boot, placed immediate after the above
567 self.assertIn('u-boot-next', entries)
568 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600569 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700570 self.assertEqual(len(U_BOOT_DATA), entry.size)
571
Simon Glass3ab95982018-08-01 15:22:37 -0600572 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700573 self.assertIn('u-boot-fixed', entries)
574 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600575 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700576 self.assertEqual(len(U_BOOT_DATA), entry.size)
577
578 self.assertEqual(65, image._size)
579
580 def testPackExtra(self):
581 """Test that extra packing feature works as expected"""
582 retcode = self._DoTestFile('09_pack_extra.dts')
583
584 self.assertEqual(0, retcode)
585 self.assertIn('image', control.images)
586 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600587 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700588 self.assertEqual(5, len(entries))
589
590 # First u-boot with padding before and after
591 self.assertIn('u-boot', entries)
592 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600593 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700594 self.assertEqual(3, entry.pad_before)
595 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
596
597 # Second u-boot has an aligned size, but it has no effect
598 self.assertIn('u-boot-align-size-nop', entries)
599 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600600 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700601 self.assertEqual(4, entry.size)
602
603 # Third u-boot has an aligned size too
604 self.assertIn('u-boot-align-size', entries)
605 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600606 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700607 self.assertEqual(32, entry.size)
608
609 # Fourth u-boot has an aligned end
610 self.assertIn('u-boot-align-end', entries)
611 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600612 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700613 self.assertEqual(16, entry.size)
614
615 # Fifth u-boot immediately afterwards
616 self.assertIn('u-boot-align-both', entries)
617 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600618 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700619 self.assertEqual(64, entry.size)
620
621 self.CheckNoGaps(entries)
622 self.assertEqual(128, image._size)
623
624 def testPackAlignPowerOf2(self):
625 """Test that invalid entry alignment is detected"""
626 with self.assertRaises(ValueError) as e:
627 self._DoTestFile('10_pack_align_power2.dts')
628 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
629 "of two", str(e.exception))
630
631 def testPackAlignSizePowerOf2(self):
632 """Test that invalid entry size alignment is detected"""
633 with self.assertRaises(ValueError) as e:
634 self._DoTestFile('11_pack_align_size_power2.dts')
635 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
636 "power of two", str(e.exception))
637
638 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600639 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700640 with self.assertRaises(ValueError) as e:
641 self._DoTestFile('12_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600642 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700643 "align 0x4 (4)", str(e.exception))
644
645 def testPackInvalidSizeAlign(self):
646 """Test that invalid entry size alignment is detected"""
647 with self.assertRaises(ValueError) as e:
648 self._DoTestFile('13_pack_inv_size_align.dts')
649 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
650 "align-size 0x4 (4)", str(e.exception))
651
652 def testPackOverlap(self):
653 """Test that overlapping regions are detected"""
654 with self.assertRaises(ValueError) as e:
655 self._DoTestFile('14_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600656 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700657 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
658 str(e.exception))
659
660 def testPackEntryOverflow(self):
661 """Test that entries that overflow their size are detected"""
662 with self.assertRaises(ValueError) as e:
663 self._DoTestFile('15_pack_overflow.dts')
664 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
665 "but entry size is 0x3 (3)", str(e.exception))
666
667 def testPackImageOverflow(self):
668 """Test that entries which overflow the image size are detected"""
669 with self.assertRaises(ValueError) as e:
670 self._DoTestFile('16_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600671 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700672 "size 0x3 (3)", str(e.exception))
673
674 def testPackImageSize(self):
675 """Test that the image size can be set"""
676 retcode = self._DoTestFile('17_pack_image_size.dts')
677 self.assertEqual(0, retcode)
678 self.assertIn('image', control.images)
679 image = control.images['image']
680 self.assertEqual(7, image._size)
681
682 def testPackImageSizeAlign(self):
683 """Test that image size alignemnt works as expected"""
684 retcode = self._DoTestFile('18_pack_image_align.dts')
685 self.assertEqual(0, retcode)
686 self.assertIn('image', control.images)
687 image = control.images['image']
688 self.assertEqual(16, image._size)
689
690 def testPackInvalidImageAlign(self):
691 """Test that invalid image alignment is detected"""
692 with self.assertRaises(ValueError) as e:
693 self._DoTestFile('19_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600694 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700695 "align-size 0x8 (8)", str(e.exception))
696
697 def testPackAlignPowerOf2(self):
698 """Test that invalid image alignment is detected"""
699 with self.assertRaises(ValueError) as e:
700 self._DoTestFile('20_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600701 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700702 "two", str(e.exception))
703
704 def testImagePadByte(self):
705 """Test that the image pad byte can be specified"""
Simon Glass19790632017-11-13 18:55:01 -0700706 with open(self.TestFile('bss_data')) as fd:
707 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass4f443042016-11-25 20:15:52 -0700708 data = self._DoReadFile('21_image_pad.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700709 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700710
711 def testImageName(self):
712 """Test that image files can be named"""
713 retcode = self._DoTestFile('22_image_name.dts')
714 self.assertEqual(0, retcode)
715 image = control.images['image1']
716 fname = tools.GetOutputFilename('test-name')
717 self.assertTrue(os.path.exists(fname))
718
719 image = control.images['image2']
720 fname = tools.GetOutputFilename('test-name.xx')
721 self.assertTrue(os.path.exists(fname))
722
723 def testBlobFilename(self):
724 """Test that generic blobs can be provided by filename"""
725 data = self._DoReadFile('23_blob.dts')
726 self.assertEqual(BLOB_DATA, data)
727
728 def testPackSorted(self):
729 """Test that entries can be sorted"""
730 data = self._DoReadFile('24_sorted.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700731 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
Simon Glass4f443042016-11-25 20:15:52 -0700732 U_BOOT_DATA, data)
733
Simon Glass3ab95982018-08-01 15:22:37 -0600734 def testPackZeroOffset(self):
735 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700736 with self.assertRaises(ValueError) as e:
737 self._DoTestFile('25_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600738 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700739 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
740 str(e.exception))
741
742 def testPackUbootDtb(self):
743 """Test that a device tree can be added to U-Boot"""
744 data = self._DoReadFile('26_pack_u_boot_dtb.dts')
745 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700746
747 def testPackX86RomNoSize(self):
748 """Test that the end-at-4gb property requires a size property"""
749 with self.assertRaises(ValueError) as e:
750 self._DoTestFile('27_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600751 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700752 "using end-at-4gb", str(e.exception))
753
754 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600755 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700756 with self.assertRaises(ValueError) as e:
757 self._DoTestFile('28_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600758 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600759 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700760 str(e.exception))
761
762 def testPackX86Rom(self):
763 """Test that a basic x86 ROM can be created"""
764 data = self._DoReadFile('29_x86-rom.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700765 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
766 chr(0) * 2, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700767
768 def testPackX86RomMeNoDesc(self):
769 """Test that an invalid Intel descriptor entry is detected"""
770 TestFunctional._MakeInputFile('descriptor.bin', '')
771 with self.assertRaises(ValueError) as e:
772 self._DoTestFile('31_x86-rom-me.dts')
773 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
774 "signature", str(e.exception))
775
776 def testPackX86RomBadDesc(self):
777 """Test that the Intel requires a descriptor entry"""
778 with self.assertRaises(ValueError) as e:
779 self._DoTestFile('30_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600780 self.assertIn("Node '/binman/intel-me': No offset set with "
781 "offset-unset: should another entry provide this correct "
782 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700783
784 def testPackX86RomMe(self):
785 """Test that an x86 ROM with an ME region can be created"""
786 data = self._DoReadFile('31_x86-rom-me.dts')
787 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
788
789 def testPackVga(self):
790 """Test that an image with a VGA binary can be created"""
791 data = self._DoReadFile('32_intel-vga.dts')
792 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
793
794 def testPackStart16(self):
795 """Test that an image with an x86 start16 region can be created"""
796 data = self._DoReadFile('33_x86-start16.dts')
797 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
798
Simon Glass736bb0a2018-07-06 10:27:17 -0600799 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600800 """Handle running a test for insertion of microcode
801
802 Args:
803 dts_fname: Name of test .dts file
804 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600805 ucode_second: True if the microsecond entry is second instead of
806 third
Simon Glassadc57012018-07-06 10:27:16 -0600807
808 Returns:
809 Tuple:
810 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600811 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600812 in the above (two 4-byte words)
813 """
Simon Glass6b187df2017-11-12 21:52:27 -0700814 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700815
816 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600817 if ucode_second:
818 ucode_content = data[len(nodtb_data):]
819 ucode_pos = len(nodtb_data)
820 dtb_with_ucode = ucode_content[16:]
821 fdt_len = self.GetFdtLen(dtb_with_ucode)
822 else:
823 dtb_with_ucode = data[len(nodtb_data):]
824 fdt_len = self.GetFdtLen(dtb_with_ucode)
825 ucode_content = dtb_with_ucode[fdt_len:]
826 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700827 fname = tools.GetOutputFilename('test.dtb')
828 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600829 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600830 dtb = fdt.FdtScan(fname)
831 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700832 self.assertTrue(ucode)
833 for node in ucode.subnodes:
834 self.assertFalse(node.props.get('data'))
835
Simon Glasse0ff8552016-11-25 20:15:53 -0700836 # Check that the microcode appears immediately after the Fdt
837 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700838 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700839 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
840 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600841 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700842
843 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600844 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700845 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
846 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600847 u_boot = data[:len(nodtb_data)]
848 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700849
850 def testPackUbootMicrocode(self):
851 """Test that x86 microcode can be handled correctly
852
853 We expect to see the following in the image, in order:
854 u-boot-nodtb.bin with a microcode pointer inserted at the correct
855 place
856 u-boot.dtb with the microcode removed
857 the microcode
858 """
859 first, pos_and_size = self._RunMicrocodeTest('34_x86_ucode.dts',
860 U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700861 self.assertEqual('nodtb with microcode' + pos_and_size +
862 ' somewhere in here', first)
863
Simon Glass160a7662017-05-27 07:38:26 -0600864 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700865 """Test that x86 microcode can be handled correctly
866
867 We expect to see the following in the image, in order:
868 u-boot-nodtb.bin with a microcode pointer inserted at the correct
869 place
870 u-boot.dtb with the microcode
871 an empty microcode region
872 """
873 # We need the libfdt library to run this test since only that allows
874 # finding the offset of a property. This is required by
875 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glasse0ff8552016-11-25 20:15:53 -0700876 data = self._DoReadFile('35_x86_single_ucode.dts', True)
877
878 second = data[len(U_BOOT_NODTB_DATA):]
879
880 fdt_len = self.GetFdtLen(second)
881 third = second[fdt_len:]
882 second = second[:fdt_len]
883
Simon Glass160a7662017-05-27 07:38:26 -0600884 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
885 self.assertIn(ucode_data, second)
886 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700887
Simon Glass160a7662017-05-27 07:38:26 -0600888 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600889 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600890 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
891 len(ucode_data))
892 first = data[:len(U_BOOT_NODTB_DATA)]
893 self.assertEqual('nodtb with microcode' + pos_and_size +
894 ' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700895
Simon Glass75db0862016-11-25 20:15:55 -0700896 def testPackUbootSingleMicrocode(self):
897 """Test that x86 microcode can be handled correctly with fdt_normal.
898 """
Simon Glass160a7662017-05-27 07:38:26 -0600899 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700900
Simon Glassc49deb82016-11-25 20:15:54 -0700901 def testUBootImg(self):
902 """Test that u-boot.img can be put in a file"""
903 data = self._DoReadFile('36_u_boot_img.dts')
904 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700905
906 def testNoMicrocode(self):
907 """Test that a missing microcode region is detected"""
908 with self.assertRaises(ValueError) as e:
909 self._DoReadFile('37_x86_no_ucode.dts', True)
910 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
911 "node found in ", str(e.exception))
912
913 def testMicrocodeWithoutNode(self):
914 """Test that a missing u-boot-dtb-with-ucode node is detected"""
915 with self.assertRaises(ValueError) as e:
916 self._DoReadFile('38_x86_ucode_missing_node.dts', True)
917 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
918 "microcode region u-boot-dtb-with-ucode", str(e.exception))
919
920 def testMicrocodeWithoutNode2(self):
921 """Test that a missing u-boot-ucode node is detected"""
922 with self.assertRaises(ValueError) as e:
923 self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
924 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
925 "microcode region u-boot-ucode", str(e.exception))
926
927 def testMicrocodeWithoutPtrInElf(self):
928 """Test that a U-Boot binary without the microcode symbol is detected"""
929 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700930 try:
931 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
932 TestFunctional._MakeInputFile('u-boot', fd.read())
933
934 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600935 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700936 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
937 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
938
939 finally:
940 # Put the original file back
941 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
942 TestFunctional._MakeInputFile('u-boot', fd.read())
943
944 def testMicrocodeNotInImage(self):
945 """Test that microcode must be placed within the image"""
946 with self.assertRaises(ValueError) as e:
947 self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
948 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
949 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -0600950 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -0700951
952 def testWithoutMicrocode(self):
953 """Test that we can cope with an image without microcode (e.g. qemu)"""
954 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
955 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass16b8d6b2018-07-06 10:27:42 -0600956 data, dtb, _, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700957
958 # Now check the device tree has no microcode
959 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
960 second = data[len(U_BOOT_NODTB_DATA):]
961
962 fdt_len = self.GetFdtLen(second)
963 self.assertEqual(dtb, second[:fdt_len])
964
965 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
966 third = data[used_len:]
967 self.assertEqual(chr(0) * (0x200 - used_len), third)
968
969 def testUnknownPosSize(self):
970 """Test that microcode must be placed within the image"""
971 with self.assertRaises(ValueError) as e:
972 self._DoReadFile('41_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -0600973 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -0700974 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -0700975
976 def testPackFsp(self):
977 """Test that an image with a FSP binary can be created"""
978 data = self._DoReadFile('42_intel-fsp.dts')
979 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
980
981 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -0700982 """Test that an image with a CMC binary can be created"""
Simon Glassda229092016-11-25 20:15:56 -0700983 data = self._DoReadFile('43_intel-cmc.dts')
984 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -0700985
986 def testPackVbt(self):
987 """Test that an image with a VBT binary can be created"""
988 data = self._DoReadFile('46_intel-vbt.dts')
989 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -0700990
Simon Glass56509842017-11-12 21:52:25 -0700991 def testSplBssPad(self):
992 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -0700993 # ELF file with a '__bss_size' symbol
994 with open(self.TestFile('bss_data')) as fd:
995 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass56509842017-11-12 21:52:25 -0700996 data = self._DoReadFile('47_spl_bss_pad.dts')
997 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
998
Simon Glassb50e5612017-11-13 18:54:54 -0700999 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1000 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1001 with self.assertRaises(ValueError) as e:
1002 data = self._DoReadFile('47_spl_bss_pad.dts')
1003 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1004 str(e.exception))
1005
Simon Glass87722132017-11-12 21:52:26 -07001006 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001007 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass87722132017-11-12 21:52:26 -07001008 data = self._DoReadFile('48_x86-start16-spl.dts')
1009 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1010
Simon Glass736bb0a2018-07-06 10:27:17 -06001011 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1012 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001013
1014 We expect to see the following in the image, in order:
1015 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1016 correct place
1017 u-boot.dtb with the microcode removed
1018 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001019
1020 Args:
1021 dts: Device tree file to use for test
1022 ucode_second: True if the microsecond entry is second instead of
1023 third
Simon Glass6b187df2017-11-12 21:52:27 -07001024 """
1025 # ELF file with a '_dt_ucode_base_size' symbol
1026 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1027 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass736bb0a2018-07-06 10:27:17 -06001028 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1029 ucode_second=ucode_second)
Simon Glass6b187df2017-11-12 21:52:27 -07001030 self.assertEqual('splnodtb with microc' + pos_and_size +
1031 'ter somewhere in here', first)
1032
Simon Glass736bb0a2018-07-06 10:27:17 -06001033 def testPackUbootSplMicrocode(self):
1034 """Test that x86 microcode can be handled correctly in SPL"""
1035 self._PackUbootSplMicrocode('49_x86_ucode_spl.dts')
1036
1037 def testPackUbootSplMicrocodeReorder(self):
1038 """Test that order doesn't matter for microcode entries
1039
1040 This is the same as testPackUbootSplMicrocode but when we process the
1041 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1042 entry, so we reply on binman to try later.
1043 """
1044 self._PackUbootSplMicrocode('58_x86_ucode_spl_needs_retry.dts',
1045 ucode_second=True)
1046
Simon Glassca4f4ff2017-11-12 21:52:28 -07001047 def testPackMrc(self):
1048 """Test that an image with an MRC binary can be created"""
1049 data = self._DoReadFile('50_intel_mrc.dts')
1050 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1051
Simon Glass47419ea2017-11-13 18:54:55 -07001052 def testSplDtb(self):
1053 """Test that an image with spl/u-boot-spl.dtb can be created"""
1054 data = self._DoReadFile('51_u_boot_spl_dtb.dts')
1055 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1056
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001057 def testSplNoDtb(self):
1058 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1059 data = self._DoReadFile('52_u_boot_spl_nodtb.dts')
1060 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1061
Simon Glass19790632017-11-13 18:55:01 -07001062 def testSymbols(self):
1063 """Test binman can assign symbols embedded in U-Boot"""
1064 elf_fname = self.TestFile('u_boot_binman_syms')
1065 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1066 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001067 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001068
1069 with open(self.TestFile('u_boot_binman_syms')) as fd:
1070 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1071 data = self._DoReadFile('53_symbols.dts')
1072 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1073 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1074 U_BOOT_DATA +
1075 sym_values + U_BOOT_SPL_DATA[16:])
1076 self.assertEqual(expected, data)
1077
Simon Glassdd57c132018-06-01 09:38:11 -06001078 def testPackUnitAddress(self):
1079 """Test that we support multiple binaries with the same name"""
1080 data = self._DoReadFile('54_unit_address.dts')
1081 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1082
Simon Glass18546952018-06-01 09:38:16 -06001083 def testSections(self):
1084 """Basic test of sections"""
1085 data = self._DoReadFile('55_sections.dts')
Simon Glass8122f392018-07-17 13:25:28 -06001086 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1087 U_BOOT_DATA + '&' * 4)
Simon Glass18546952018-06-01 09:38:16 -06001088 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001089
Simon Glass3b0c3822018-06-01 09:38:20 -06001090 def testMap(self):
1091 """Tests outputting a map of the images"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001092 _, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001093 self.assertEqual('''ImagePos Offset Size Name
109400000000 00000000 00000028 main-section
109500000000 00000000 00000010 section@0
109600000000 00000000 00000004 u-boot
109700000010 00000010 00000010 section@1
109800000010 00000000 00000004 u-boot
109900000020 00000020 00000004 section@2
110000000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001101''', map_data)
1102
Simon Glassc8d48ef2018-06-01 09:38:21 -06001103 def testNamePrefix(self):
1104 """Tests that name prefixes are used"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001105 _, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001106 self.assertEqual('''ImagePos Offset Size Name
110700000000 00000000 00000028 main-section
110800000000 00000000 00000010 section@0
110900000000 00000000 00000004 ro-u-boot
111000000010 00000010 00000010 section@1
111100000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001112''', map_data)
1113
Simon Glass736bb0a2018-07-06 10:27:17 -06001114 def testUnknownContents(self):
1115 """Test that obtaining the contents works as expected"""
1116 with self.assertRaises(ValueError) as e:
1117 self._DoReadFile('57_unknown_contents.dts', True)
1118 self.assertIn("Section '/binman': Internal error: Could not complete "
1119 "processing of contents: remaining [<_testing.Entry__testing ",
1120 str(e.exception))
1121
Simon Glass5c890232018-07-06 10:27:19 -06001122 def testBadChangeSize(self):
1123 """Test that trying to change the size of an entry fails"""
1124 with self.assertRaises(ValueError) as e:
1125 self._DoReadFile('59_change_size.dts', True)
1126 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1127 '2 to 1', str(e.exception))
1128
Simon Glass16b8d6b2018-07-06 10:27:42 -06001129 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001130 """Test that we can update the device tree with offset/size info"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001131 _, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
1132 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001133 dtb = fdt.Fdt(out_dtb_fname)
1134 dtb.Scan()
1135 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001136 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001137 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001138 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001139 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001140 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001141 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001142 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001143 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001144 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001145 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001146 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001147 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001148
Simon Glass3ab95982018-08-01 15:22:37 -06001149 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001150 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001151 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001152 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001153 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001154 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001155 'size': 40
1156 }, props)
1157
1158 def testUpdateFdtBad(self):
1159 """Test that we detect when ProcessFdt never completes"""
1160 with self.assertRaises(ValueError) as e:
1161 self._DoReadFileDtb('61_fdt_update_bad.dts', update_dtb=True)
1162 self.assertIn('Could not complete processing of Fdt: remaining '
1163 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001164
Simon Glass53af22a2018-07-17 13:25:32 -06001165 def testEntryArgs(self):
1166 """Test passing arguments to entries from the command line"""
1167 entry_args = {
1168 'test-str-arg': 'test1',
1169 'test-int-arg': '456',
1170 }
1171 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1172 self.assertIn('image', control.images)
1173 entry = control.images['image'].GetEntries()['_testing']
1174 self.assertEqual('test0', entry.test_str_fdt)
1175 self.assertEqual('test1', entry.test_str_arg)
1176 self.assertEqual(123, entry.test_int_fdt)
1177 self.assertEqual(456, entry.test_int_arg)
1178
1179 def testEntryArgsMissing(self):
1180 """Test missing arguments and properties"""
1181 entry_args = {
1182 'test-int-arg': '456',
1183 }
1184 self._DoReadFileDtb('63_entry_args_missing.dts', entry_args=entry_args)
1185 entry = control.images['image'].GetEntries()['_testing']
1186 self.assertEqual('test0', entry.test_str_fdt)
1187 self.assertEqual(None, entry.test_str_arg)
1188 self.assertEqual(None, entry.test_int_fdt)
1189 self.assertEqual(456, entry.test_int_arg)
1190
1191 def testEntryArgsRequired(self):
1192 """Test missing arguments and properties"""
1193 entry_args = {
1194 'test-int-arg': '456',
1195 }
1196 with self.assertRaises(ValueError) as e:
1197 self._DoReadFileDtb('64_entry_args_required.dts')
1198 self.assertIn("Node '/binman/_testing': Missing required "
1199 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1200 str(e.exception))
1201
1202 def testEntryArgsInvalidFormat(self):
1203 """Test that an invalid entry-argument format is detected"""
1204 args = ['-d', self.TestFile('64_entry_args_required.dts'), '-ano-value']
1205 with self.assertRaises(ValueError) as e:
1206 self._DoBinman(*args)
1207 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1208
1209 def testEntryArgsInvalidInteger(self):
1210 """Test that an invalid entry-argument integer is detected"""
1211 entry_args = {
1212 'test-int-arg': 'abc',
1213 }
1214 with self.assertRaises(ValueError) as e:
1215 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1216 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1217 "'test-int-arg' (value 'abc') to integer",
1218 str(e.exception))
1219
1220 def testEntryArgsInvalidDatatype(self):
1221 """Test that an invalid entry-argument datatype is detected
1222
1223 This test could be written in entry_test.py except that it needs
1224 access to control.entry_args, which seems more than that module should
1225 be able to see.
1226 """
1227 entry_args = {
1228 'test-bad-datatype-arg': '12',
1229 }
1230 with self.assertRaises(ValueError) as e:
1231 self._DoReadFileDtb('65_entry_args_unknown_datatype.dts',
1232 entry_args=entry_args)
1233 self.assertIn('GetArg() internal error: Unknown data type ',
1234 str(e.exception))
1235
Simon Glassbb748372018-07-17 13:25:33 -06001236 def testText(self):
1237 """Test for a text entry type"""
1238 entry_args = {
1239 'test-id': TEXT_DATA,
1240 'test-id2': TEXT_DATA2,
1241 'test-id3': TEXT_DATA3,
1242 }
1243 data, _, _, _ = self._DoReadFileDtb('66_text.dts',
1244 entry_args=entry_args)
1245 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1246 TEXT_DATA3 + 'some text')
1247 self.assertEqual(expected, data)
1248
Simon Glassfd8d1f72018-07-17 13:25:36 -06001249 def testEntryDocs(self):
1250 """Test for creation of entry documentation"""
1251 with test_util.capture_sys_output() as (stdout, stderr):
1252 control.WriteEntryDocs(binman.GetEntryModules())
1253 self.assertTrue(len(stdout.getvalue()) > 0)
1254
1255 def testEntryDocsMissing(self):
1256 """Test handling of missing entry documentation"""
1257 with self.assertRaises(ValueError) as e:
1258 with test_util.capture_sys_output() as (stdout, stderr):
1259 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1260 self.assertIn('Documentation is missing for modules: u_boot',
1261 str(e.exception))
1262
Simon Glass11e36cc2018-07-17 13:25:38 -06001263 def testFmap(self):
1264 """Basic test of generation of a flashrom fmap"""
1265 data = self._DoReadFile('67_fmap.dts')
1266 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1267 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1268 self.assertEqual(expected, data[:32])
1269 self.assertEqual('__FMAP__', fhdr.signature)
1270 self.assertEqual(1, fhdr.ver_major)
1271 self.assertEqual(0, fhdr.ver_minor)
1272 self.assertEqual(0, fhdr.base)
1273 self.assertEqual(16 + 16 +
1274 fmap_util.FMAP_HEADER_LEN +
1275 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1276 self.assertEqual('FMAP', fhdr.name)
1277 self.assertEqual(3, fhdr.nareas)
1278 for fentry in fentries:
1279 self.assertEqual(0, fentry.flags)
1280
1281 self.assertEqual(0, fentries[0].offset)
1282 self.assertEqual(4, fentries[0].size)
1283 self.assertEqual('RO_U_BOOT', fentries[0].name)
1284
1285 self.assertEqual(16, fentries[1].offset)
1286 self.assertEqual(4, fentries[1].size)
1287 self.assertEqual('RW_U_BOOT', fentries[1].name)
1288
1289 self.assertEqual(32, fentries[2].offset)
1290 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1291 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1292 self.assertEqual('FMAP', fentries[2].name)
1293
Simon Glassec127af2018-07-17 13:25:39 -06001294 def testBlobNamedByArg(self):
1295 """Test we can add a blob with the filename coming from an entry arg"""
1296 entry_args = {
1297 'cros-ec-rw-path': 'ecrw.bin',
1298 }
1299 data, _, _, _ = self._DoReadFileDtb('68_blob_named_by_arg.dts',
1300 entry_args=entry_args)
1301
Simon Glass3af8e492018-07-17 13:25:40 -06001302 def testFill(self):
1303 """Test for an fill entry type"""
1304 data = self._DoReadFile('69_fill.dts')
1305 expected = 8 * chr(0xff) + 8 * chr(0)
1306 self.assertEqual(expected, data)
1307
1308 def testFillNoSize(self):
1309 """Test for an fill entry type with no size"""
1310 with self.assertRaises(ValueError) as e:
1311 self._DoReadFile('70_fill_no_size.dts')
1312 self.assertIn("'fill' entry must have a size property",
1313 str(e.exception))
1314
Simon Glass0ef87aa2018-07-17 13:25:44 -06001315 def _HandleGbbCommand(self, pipe_list):
1316 """Fake calls to the futility utility"""
1317 if pipe_list[0][0] == 'futility':
1318 fname = pipe_list[0][-1]
1319 # Append our GBB data to the file, which will happen every time the
1320 # futility command is called.
1321 with open(fname, 'a') as fd:
1322 fd.write(GBB_DATA)
1323 return command.CommandResult()
1324
1325 def testGbb(self):
1326 """Test for the Chromium OS Google Binary Block"""
1327 command.test_result = self._HandleGbbCommand
1328 entry_args = {
1329 'keydir': 'devkeys',
1330 'bmpblk': 'bmpblk.bin',
1331 }
1332 data, _, _, _ = self._DoReadFileDtb('71_gbb.dts', entry_args=entry_args)
1333
1334 # Since futility
1335 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1336 self.assertEqual(expected, data)
1337
1338 def testGbbTooSmall(self):
1339 """Test for the Chromium OS Google Binary Block being large enough"""
1340 with self.assertRaises(ValueError) as e:
1341 self._DoReadFileDtb('72_gbb_too_small.dts')
1342 self.assertIn("Node '/binman/gbb': GBB is too small",
1343 str(e.exception))
1344
1345 def testGbbNoSize(self):
1346 """Test for the Chromium OS Google Binary Block having a size"""
1347 with self.assertRaises(ValueError) as e:
1348 self._DoReadFileDtb('73_gbb_no_size.dts')
1349 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1350 str(e.exception))
1351
Simon Glass24d0d3c2018-07-17 13:25:47 -06001352 def _HandleVblockCommand(self, pipe_list):
1353 """Fake calls to the futility utility"""
1354 if pipe_list[0][0] == 'futility':
1355 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001356 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001357 fd.write(VBLOCK_DATA)
1358 return command.CommandResult()
1359
1360 def testVblock(self):
1361 """Test for the Chromium OS Verified Boot Block"""
1362 command.test_result = self._HandleVblockCommand
1363 entry_args = {
1364 'keydir': 'devkeys',
1365 }
1366 data, _, _, _ = self._DoReadFileDtb('74_vblock.dts',
1367 entry_args=entry_args)
1368 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1369 self.assertEqual(expected, data)
1370
1371 def testVblockNoContent(self):
1372 """Test we detect a vblock which has no content to sign"""
1373 with self.assertRaises(ValueError) as e:
1374 self._DoReadFile('75_vblock_no_content.dts')
1375 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1376 'property', str(e.exception))
1377
1378 def testVblockBadPhandle(self):
1379 """Test that we detect a vblock with an invalid phandle in contents"""
1380 with self.assertRaises(ValueError) as e:
1381 self._DoReadFile('76_vblock_bad_phandle.dts')
1382 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1383 '1000', str(e.exception))
1384
1385 def testVblockBadEntry(self):
1386 """Test that we detect an entry that points to a non-entry"""
1387 with self.assertRaises(ValueError) as e:
1388 self._DoReadFile('77_vblock_bad_entry.dts')
1389 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1390 "'other'", str(e.exception))
1391
Simon Glassb8ef5b62018-07-17 13:25:48 -06001392 def testTpl(self):
1393 """Test that an image with TPL and ots device tree can be created"""
1394 # ELF file with a '__bss_size' symbol
1395 with open(self.TestFile('bss_data')) as fd:
1396 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1397 data = self._DoReadFile('78_u_boot_tpl.dts')
1398 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1399
Simon Glass15a587c2018-07-17 13:25:51 -06001400 def testUsesPos(self):
1401 """Test that the 'pos' property cannot be used anymore"""
1402 with self.assertRaises(ValueError) as e:
1403 data = self._DoReadFile('79_uses_pos.dts')
1404 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1405 "'pos'", str(e.exception))
1406
Simon Glassd178eab2018-09-14 04:57:08 -06001407 def testFillZero(self):
1408 """Test for an fill entry type with a size of 0"""
1409 data = self._DoReadFile('80_fill_empty.dts')
1410 self.assertEqual(chr(0) * 16, data)
1411
Simon Glass0b489362018-09-14 04:57:09 -06001412 def testTextMissing(self):
1413 """Test for a text entry type where there is no text"""
1414 with self.assertRaises(ValueError) as e:
1415 self._DoReadFileDtb('66_text.dts',)
1416 self.assertIn("Node '/binman/text': No value provided for text label "
1417 "'test-id'", str(e.exception))
1418
Simon Glass35b384c2018-09-14 04:57:10 -06001419 def testPackStart16Tpl(self):
1420 """Test that an image with an x86 start16 TPL region can be created"""
1421 data = self._DoReadFile('81_x86-start16-tpl.dts')
1422 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1423
Simon Glass0bfa7b02018-09-14 04:57:12 -06001424 def testSelectImage(self):
1425 """Test that we can select which images to build"""
1426 with test_util.capture_sys_output() as (stdout, stderr):
1427 retcode = self._DoTestFile('06_dual_image.dts', images=['image2'])
1428 self.assertEqual(0, retcode)
1429 self.assertIn('Skipping images: image1', stdout.getvalue())
1430
1431 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1432 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1433
Simon Glass6ed45ba2018-09-14 04:57:24 -06001434 def testUpdateFdtAll(self):
1435 """Test that all device trees are updated with offset/size info"""
1436 data, _, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1437 use_real_dtb=True, update_dtb=True)
1438
1439 base_expected = {
1440 'section:image-pos': 0,
1441 'u-boot-tpl-dtb:size': 513,
1442 'u-boot-spl-dtb:size': 513,
1443 'u-boot-spl-dtb:offset': 493,
1444 'image-pos': 0,
1445 'section/u-boot-dtb:image-pos': 0,
1446 'u-boot-spl-dtb:image-pos': 493,
1447 'section/u-boot-dtb:size': 493,
1448 'u-boot-tpl-dtb:image-pos': 1006,
1449 'section/u-boot-dtb:offset': 0,
1450 'section:size': 493,
1451 'offset': 0,
1452 'section:offset': 0,
1453 'u-boot-tpl-dtb:offset': 1006,
1454 'size': 1519
1455 }
1456
1457 # We expect three device-tree files in the output, one after the other.
1458 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1459 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1460 # main U-Boot tree. All three should have the same postions and offset.
1461 start = 0
1462 for item in ['', 'spl', 'tpl']:
1463 dtb = fdt.Fdt.FromData(data[start:])
1464 dtb.Scan()
1465 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1466 'spl', 'tpl'])
1467 expected = dict(base_expected)
1468 if item:
1469 expected[item] = 0
1470 self.assertEqual(expected, props)
1471 start += dtb._fdt_obj.totalsize()
1472
1473 def testUpdateFdtOutput(self):
1474 """Test that output DTB files are updated"""
1475 try:
1476 data, dtb_data, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1477 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1478
1479 # Unfortunately, compiling a source file always results in a file
1480 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1481 # source file (e.g. test/75_fdt_update_all.dts) thus does not enter
1482 # binman as a file called u-boot.dtb. To fix this, copy the file
1483 # over to the expected place.
1484 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1485 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1486 start = 0
1487 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1488 'tpl/u-boot-tpl.dtb.out']:
1489 dtb = fdt.Fdt.FromData(data[start:])
1490 size = dtb._fdt_obj.totalsize()
1491 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1492 outdata = tools.ReadFile(pathname)
1493 name = os.path.split(fname)[0]
1494
1495 if name:
1496 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1497 else:
1498 orig_indata = dtb_data
1499 self.assertNotEqual(outdata, orig_indata,
1500 "Expected output file '%s' be updated" % pathname)
1501 self.assertEqual(outdata, data[start:start + size],
1502 "Expected output file '%s' to match output image" %
1503 pathname)
1504 start += size
1505 finally:
1506 self._ResetDtbs()
1507
Simon Glass53af22a2018-07-17 13:25:32 -06001508
Simon Glass9fc60b42017-11-12 21:52:22 -07001509if __name__ == "__main__":
1510 unittest.main()