blob: b1569433234b00e9ee68fb9fe7b68082635e6c36 [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 Glass0a98b282018-09-14 04:57:28 -060057FILES_DATA = ("sorry I'm late\nOh, don't bother apologising, I'm " +
58 "sorry you're alive\n")
Simon Glass83d73c22018-09-14 04:57:26 -060059COMPRESS_DATA = 'data to compress'
Simon Glassec127af2018-07-17 13:25:39 -060060
Simon Glass4f443042016-11-25 20:15:52 -070061
62class TestFunctional(unittest.TestCase):
63 """Functional tests for binman
64
65 Most of these use a sample .dts file to build an image and then check
66 that it looks correct. The sample files are in the test/ subdirectory
67 and are numbered.
68
69 For each entry type a very small test file is created using fixed
70 string contents. This makes it easy to test that things look right, and
71 debug problems.
72
73 In some cases a 'real' file must be used - these are also supplied in
74 the test/ diurectory.
75 """
76 @classmethod
77 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070078 global entry
79 import entry
80
Simon Glass4f443042016-11-25 20:15:52 -070081 # Handle the case where argv[0] is 'python'
82 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
83 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
84
85 # Create a temporary directory for input files
86 self._indir = tempfile.mkdtemp(prefix='binmant.')
87
88 # Create some test files
89 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
90 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
91 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060092 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070093 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -070094 TestFunctional._MakeInputFile('me.bin', ME_DATA)
95 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060096 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -070097 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Simon Glass87722132017-11-12 21:52:26 -070098 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
99 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600100 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
101 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700102 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700103 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
104 U_BOOT_SPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700105 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
106 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700107 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700108 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600109 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600110 TestFunctional._MakeInputDir('devkeys')
111 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700112 self._output_setup = False
113
Simon Glasse0ff8552016-11-25 20:15:53 -0700114 # ELF file with a '_dt_ucode_base_size' symbol
115 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
116 TestFunctional._MakeInputFile('u-boot', fd.read())
117
118 # Intel flash descriptor file
119 with open(self.TestFile('descriptor.bin')) as fd:
120 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
121
Simon Glass0a98b282018-09-14 04:57:28 -0600122 shutil.copytree(self.TestFile('files'),
123 os.path.join(self._indir, 'files'))
124
Simon Glass83d73c22018-09-14 04:57:26 -0600125 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
126
Simon Glass4f443042016-11-25 20:15:52 -0700127 @classmethod
128 def tearDownClass(self):
129 """Remove the temporary input directory and its contents"""
130 if self._indir:
131 shutil.rmtree(self._indir)
132 self._indir = None
133
134 def setUp(self):
135 # Enable this to turn on debugging output
136 # tout.Init(tout.DEBUG)
137 command.test_result = None
138
139 def tearDown(self):
140 """Remove the temporary output directory"""
141 tools._FinaliseForTest()
142
Simon Glassb8ef5b62018-07-17 13:25:48 -0600143 @classmethod
144 def _ResetDtbs(self):
145 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
146 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
147 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
148
Simon Glass4f443042016-11-25 20:15:52 -0700149 def _RunBinman(self, *args, **kwargs):
150 """Run binman using the command line
151
152 Args:
153 Arguments to pass, as a list of strings
154 kwargs: Arguments to pass to Command.RunPipe()
155 """
156 result = command.RunPipe([[self._binman_pathname] + list(args)],
157 capture=True, capture_stderr=True, raise_on_error=False)
158 if result.return_code and kwargs.get('raise_on_error', True):
159 raise Exception("Error running '%s': %s" % (' '.join(args),
160 result.stdout + result.stderr))
161 return result
162
163 def _DoBinman(self, *args):
164 """Run binman using directly (in the same process)
165
166 Args:
167 Arguments to pass, as a list of strings
168 Returns:
169 Return value (0 for success)
170 """
Simon Glass7fe91732017-11-13 18:55:00 -0700171 args = list(args)
172 if '-D' in sys.argv:
173 args = args + ['-D']
174 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700175 options.pager = 'binman-invalid-pager'
176 options.build_dir = self._indir
177
178 # For testing, you can force an increase in verbosity here
179 # options.verbosity = tout.DEBUG
180 return control.Binman(options, args)
181
Simon Glass53af22a2018-07-17 13:25:32 -0600182 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glass93d17412018-09-14 04:57:23 -0600183 entry_args=None, images=None, use_real_dtb=False):
Simon Glass4f443042016-11-25 20:15:52 -0700184 """Run binman with a given test file
185
186 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600187 fname: Device-tree source filename to use (e.g. 05_simple.dts)
188 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600189 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600190 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600191 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600192 entry_args: Dict of entry args to supply to binman
193 key: arg name
194 value: value of that arg
195 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700196 """
Simon Glass7fe91732017-11-13 18:55:00 -0700197 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
198 if debug:
199 args.append('-D')
Simon Glass3b0c3822018-06-01 09:38:20 -0600200 if map:
201 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600202 if update_dtb:
203 args.append('-up')
Simon Glass93d17412018-09-14 04:57:23 -0600204 if not use_real_dtb:
205 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600206 if entry_args:
207 for arg, value in entry_args.iteritems():
208 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600209 if images:
210 for image in images:
211 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700212 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700213
214 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700215 """Set up a new test device-tree file
216
217 The given file is compiled and set up as the device tree to be used
218 for ths test.
219
220 Args:
221 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600222 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700223
224 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600225 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700226 """
Simon Glass4f443042016-11-25 20:15:52 -0700227 if not self._output_setup:
228 tools.PrepareOutputDir(self._indir, True)
229 self._output_setup = True
230 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
231 with open(dtb) as fd:
232 data = fd.read()
233 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700234 return data
Simon Glass4f443042016-11-25 20:15:52 -0700235
Simon Glass6ed45ba2018-09-14 04:57:24 -0600236 def _GetDtbContentsForSplTpl(self, dtb_data, name):
237 """Create a version of the main DTB for SPL or SPL
238
239 For testing we don't actually have different versions of the DTB. With
240 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
241 we don't normally have any unwanted nodes.
242
243 We still want the DTBs for SPL and TPL to be different though, since
244 otherwise it is confusing to know which one we are looking at. So add
245 an 'spl' or 'tpl' property to the top-level node.
246 """
247 dtb = fdt.Fdt.FromData(dtb_data)
248 dtb.Scan()
249 dtb.GetNode('/binman').AddZeroProp(name)
250 dtb.Sync(auto_resize=True)
251 dtb.Pack()
252 return dtb.GetContents()
253
Simon Glass16b8d6b2018-07-06 10:27:42 -0600254 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600255 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700256 """Run binman and return the resulting image
257
258 This runs binman with a given test file and then reads the resulting
259 output file. It is a shortcut function since most tests need to do
260 these steps.
261
262 Raises an assertion failure if binman returns a non-zero exit code.
263
264 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600265 fname: Device-tree source filename to use (e.g. 05_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700266 use_real_dtb: True to use the test file as the contents of
267 the u-boot-dtb entry. Normally this is not needed and the
268 test contents (the U_BOOT_DTB_DATA string) can be used.
269 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600270 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600271 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600272 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700273
274 Returns:
275 Tuple:
276 Resulting image contents
277 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600278 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600279 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700280 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700281 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700282 # Use the compiled test file as the u-boot-dtb input
283 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700284 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600285 infile = os.path.join(self._indir, 'u-boot.dtb')
286
287 # For testing purposes, make a copy of the DT for SPL and TPL. Add
288 # a node indicating which it is, so aid verification.
289 for name in ['spl', 'tpl']:
290 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
291 outfile = os.path.join(self._indir, dtb_fname)
292 TestFunctional._MakeInputFile(dtb_fname,
293 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700294
295 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600296 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600297 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700298 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600299 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700300
301 # Find the (only) image, read it and return its contents
302 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600303 image_fname = tools.GetOutputFilename('image.bin')
304 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600305 if map:
306 map_fname = tools.GetOutputFilename('image.map')
307 with open(map_fname) as fd:
308 map_data = fd.read()
309 else:
310 map_data = None
Simon Glass16b8d6b2018-07-06 10:27:42 -0600311 with open(image_fname) as fd:
312 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700313 finally:
314 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600315 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600316 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700317
Simon Glasse0ff8552016-11-25 20:15:53 -0700318 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600319 """Helper function which discards the device-tree binary
320
321 Args:
322 fname: Device-tree source filename to use (e.g. 05_simple.dts)
323 use_real_dtb: True to use the test file as the contents of
324 the u-boot-dtb entry. Normally this is not needed and the
325 test contents (the U_BOOT_DTB_DATA string) can be used.
326 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600327
328 Returns:
329 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600330 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700331 return self._DoReadFileDtb(fname, use_real_dtb)[0]
332
Simon Glass4f443042016-11-25 20:15:52 -0700333 @classmethod
334 def _MakeInputFile(self, fname, contents):
335 """Create a new test input file, creating directories as needed
336
337 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600338 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700339 contents: File contents to write in to the file
340 Returns:
341 Full pathname of file created
342 """
343 pathname = os.path.join(self._indir, fname)
344 dirname = os.path.dirname(pathname)
345 if dirname and not os.path.exists(dirname):
346 os.makedirs(dirname)
347 with open(pathname, 'wb') as fd:
348 fd.write(contents)
349 return pathname
350
351 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600352 def _MakeInputDir(self, dirname):
353 """Create a new test input directory, creating directories as needed
354
355 Args:
356 dirname: Directory name to create
357
358 Returns:
359 Full pathname of directory created
360 """
361 pathname = os.path.join(self._indir, dirname)
362 if not os.path.exists(pathname):
363 os.makedirs(pathname)
364 return pathname
365
366 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700367 def TestFile(self, fname):
368 return os.path.join(self._binman_dir, 'test', fname)
369
370 def AssertInList(self, grep_list, target):
371 """Assert that at least one of a list of things is in a target
372
373 Args:
374 grep_list: List of strings to check
375 target: Target string
376 """
377 for grep in grep_list:
378 if grep in target:
379 return
380 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
381
382 def CheckNoGaps(self, entries):
383 """Check that all entries fit together without gaps
384
385 Args:
386 entries: List of entries to check
387 """
Simon Glass3ab95982018-08-01 15:22:37 -0600388 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700389 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600390 self.assertEqual(offset, entry.offset)
391 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700392
Simon Glasse0ff8552016-11-25 20:15:53 -0700393 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600394 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700395
396 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600397 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700398
399 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600400 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700401 """
402 return struct.unpack('>L', dtb[4:8])[0]
403
Simon Glasscee02e62018-07-17 13:25:52 -0600404 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600405 def AddNode(node, path):
406 if node.name != '/':
407 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600408 for subnode in node.subnodes:
409 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600410 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600411 prop_path = path + '/' + subnode.name + ':' + prop.name
412 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
413 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600414 AddNode(subnode, path)
415
416 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600417 AddNode(dtb.GetRoot(), '')
418 return tree
419
Simon Glass4f443042016-11-25 20:15:52 -0700420 def testRun(self):
421 """Test a basic run with valid args"""
422 result = self._RunBinman('-h')
423
424 def testFullHelp(self):
425 """Test that the full help is displayed with -H"""
426 result = self._RunBinman('-H')
427 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500428 # Remove possible extraneous strings
429 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
430 gothelp = result.stdout.replace(extra, '')
431 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700432 self.assertEqual(0, len(result.stderr))
433 self.assertEqual(0, result.return_code)
434
435 def testFullHelpInternal(self):
436 """Test that the full help is displayed with -H"""
437 try:
438 command.test_result = command.CommandResult()
439 result = self._DoBinman('-H')
440 help_file = os.path.join(self._binman_dir, 'README')
441 finally:
442 command.test_result = None
443
444 def testHelp(self):
445 """Test that the basic help is displayed with -h"""
446 result = self._RunBinman('-h')
447 self.assertTrue(len(result.stdout) > 200)
448 self.assertEqual(0, len(result.stderr))
449 self.assertEqual(0, result.return_code)
450
Simon Glass4f443042016-11-25 20:15:52 -0700451 def testBoard(self):
452 """Test that we can run it with a specific board"""
453 self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
454 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
455 result = self._DoBinman('-b', 'sandbox')
456 self.assertEqual(0, result)
457
458 def testNeedBoard(self):
459 """Test that we get an error when no board ius supplied"""
460 with self.assertRaises(ValueError) as e:
461 result = self._DoBinman()
462 self.assertIn("Must provide a board to process (use -b <board>)",
463 str(e.exception))
464
465 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600466 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700467 with self.assertRaises(Exception) as e:
468 self._RunBinman('-d', 'missing_file')
469 # We get one error from libfdt, and a different one from fdtget.
470 self.AssertInList(["Couldn't open blob from 'missing_file'",
471 'No such file or directory'], str(e.exception))
472
473 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600474 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700475
476 Since this is a source file it should be compiled and the error
477 will come from the device-tree compiler (dtc).
478 """
479 with self.assertRaises(Exception) as e:
480 self._RunBinman('-d', self.TestFile('01_invalid.dts'))
481 self.assertIn("FATAL ERROR: Unable to parse input tree",
482 str(e.exception))
483
484 def testMissingNode(self):
485 """Test that a device tree without a 'binman' node generates an error"""
486 with self.assertRaises(Exception) as e:
487 self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
488 self.assertIn("does not have a 'binman' node", str(e.exception))
489
490 def testEmpty(self):
491 """Test that an empty binman node works OK (i.e. does nothing)"""
492 result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
493 self.assertEqual(0, len(result.stderr))
494 self.assertEqual(0, result.return_code)
495
496 def testInvalidEntry(self):
497 """Test that an invalid entry is flagged"""
498 with self.assertRaises(Exception) as e:
499 result = self._RunBinman('-d',
500 self.TestFile('04_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700501 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
502 "'/binman/not-a-valid-type'", str(e.exception))
503
504 def testSimple(self):
505 """Test a simple binman with a single file"""
506 data = self._DoReadFile('05_simple.dts')
507 self.assertEqual(U_BOOT_DATA, data)
508
Simon Glass7fe91732017-11-13 18:55:00 -0700509 def testSimpleDebug(self):
510 """Test a simple binman run with debugging enabled"""
511 data = self._DoTestFile('05_simple.dts', debug=True)
512
Simon Glass4f443042016-11-25 20:15:52 -0700513 def testDual(self):
514 """Test that we can handle creating two images
515
516 This also tests image padding.
517 """
518 retcode = self._DoTestFile('06_dual_image.dts')
519 self.assertEqual(0, retcode)
520
521 image = control.images['image1']
522 self.assertEqual(len(U_BOOT_DATA), image._size)
523 fname = tools.GetOutputFilename('image1.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)
528
529 image = control.images['image2']
530 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
531 fname = tools.GetOutputFilename('image2.bin')
532 self.assertTrue(os.path.exists(fname))
533 with open(fname) as fd:
534 data = fd.read()
535 self.assertEqual(U_BOOT_DATA, data[3:7])
536 self.assertEqual(chr(0) * 3, data[:3])
537 self.assertEqual(chr(0) * 5, data[7:])
538
539 def testBadAlign(self):
540 """Test that an invalid alignment value is detected"""
541 with self.assertRaises(ValueError) as e:
542 self._DoTestFile('07_bad_align.dts')
543 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
544 "of two", str(e.exception))
545
546 def testPackSimple(self):
547 """Test that packing works as expected"""
548 retcode = self._DoTestFile('08_pack.dts')
549 self.assertEqual(0, retcode)
550 self.assertIn('image', control.images)
551 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600552 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700553 self.assertEqual(5, len(entries))
554
555 # First u-boot
556 self.assertIn('u-boot', entries)
557 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600558 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700559 self.assertEqual(len(U_BOOT_DATA), entry.size)
560
561 # Second u-boot, aligned to 16-byte boundary
562 self.assertIn('u-boot-align', entries)
563 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600564 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700565 self.assertEqual(len(U_BOOT_DATA), entry.size)
566
567 # Third u-boot, size 23 bytes
568 self.assertIn('u-boot-size', entries)
569 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600570 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700571 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
572 self.assertEqual(23, entry.size)
573
574 # Fourth u-boot, placed immediate after the above
575 self.assertIn('u-boot-next', entries)
576 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600577 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700578 self.assertEqual(len(U_BOOT_DATA), entry.size)
579
Simon Glass3ab95982018-08-01 15:22:37 -0600580 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700581 self.assertIn('u-boot-fixed', entries)
582 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600583 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700584 self.assertEqual(len(U_BOOT_DATA), entry.size)
585
586 self.assertEqual(65, image._size)
587
588 def testPackExtra(self):
589 """Test that extra packing feature works as expected"""
590 retcode = self._DoTestFile('09_pack_extra.dts')
591
592 self.assertEqual(0, retcode)
593 self.assertIn('image', control.images)
594 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600595 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700596 self.assertEqual(5, len(entries))
597
598 # First u-boot with padding before and after
599 self.assertIn('u-boot', entries)
600 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600601 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700602 self.assertEqual(3, entry.pad_before)
603 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
604
605 # Second u-boot has an aligned size, but it has no effect
606 self.assertIn('u-boot-align-size-nop', entries)
607 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600608 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700609 self.assertEqual(4, entry.size)
610
611 # Third u-boot has an aligned size too
612 self.assertIn('u-boot-align-size', entries)
613 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600614 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700615 self.assertEqual(32, entry.size)
616
617 # Fourth u-boot has an aligned end
618 self.assertIn('u-boot-align-end', entries)
619 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600620 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700621 self.assertEqual(16, entry.size)
622
623 # Fifth u-boot immediately afterwards
624 self.assertIn('u-boot-align-both', entries)
625 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600626 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700627 self.assertEqual(64, entry.size)
628
629 self.CheckNoGaps(entries)
630 self.assertEqual(128, image._size)
631
632 def testPackAlignPowerOf2(self):
633 """Test that invalid entry alignment is detected"""
634 with self.assertRaises(ValueError) as e:
635 self._DoTestFile('10_pack_align_power2.dts')
636 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
637 "of two", str(e.exception))
638
639 def testPackAlignSizePowerOf2(self):
640 """Test that invalid entry size alignment is detected"""
641 with self.assertRaises(ValueError) as e:
642 self._DoTestFile('11_pack_align_size_power2.dts')
643 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
644 "power of two", str(e.exception))
645
646 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600647 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700648 with self.assertRaises(ValueError) as e:
649 self._DoTestFile('12_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600650 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700651 "align 0x4 (4)", str(e.exception))
652
653 def testPackInvalidSizeAlign(self):
654 """Test that invalid entry size alignment is detected"""
655 with self.assertRaises(ValueError) as e:
656 self._DoTestFile('13_pack_inv_size_align.dts')
657 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
658 "align-size 0x4 (4)", str(e.exception))
659
660 def testPackOverlap(self):
661 """Test that overlapping regions are detected"""
662 with self.assertRaises(ValueError) as e:
663 self._DoTestFile('14_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600664 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700665 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
666 str(e.exception))
667
668 def testPackEntryOverflow(self):
669 """Test that entries that overflow their size are detected"""
670 with self.assertRaises(ValueError) as e:
671 self._DoTestFile('15_pack_overflow.dts')
672 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
673 "but entry size is 0x3 (3)", str(e.exception))
674
675 def testPackImageOverflow(self):
676 """Test that entries which overflow the image size are detected"""
677 with self.assertRaises(ValueError) as e:
678 self._DoTestFile('16_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600679 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700680 "size 0x3 (3)", str(e.exception))
681
682 def testPackImageSize(self):
683 """Test that the image size can be set"""
684 retcode = self._DoTestFile('17_pack_image_size.dts')
685 self.assertEqual(0, retcode)
686 self.assertIn('image', control.images)
687 image = control.images['image']
688 self.assertEqual(7, image._size)
689
690 def testPackImageSizeAlign(self):
691 """Test that image size alignemnt works as expected"""
692 retcode = self._DoTestFile('18_pack_image_align.dts')
693 self.assertEqual(0, retcode)
694 self.assertIn('image', control.images)
695 image = control.images['image']
696 self.assertEqual(16, image._size)
697
698 def testPackInvalidImageAlign(self):
699 """Test that invalid image alignment is detected"""
700 with self.assertRaises(ValueError) as e:
701 self._DoTestFile('19_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600702 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700703 "align-size 0x8 (8)", str(e.exception))
704
705 def testPackAlignPowerOf2(self):
706 """Test that invalid image alignment is detected"""
707 with self.assertRaises(ValueError) as e:
708 self._DoTestFile('20_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600709 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700710 "two", str(e.exception))
711
712 def testImagePadByte(self):
713 """Test that the image pad byte can be specified"""
Simon Glass19790632017-11-13 18:55:01 -0700714 with open(self.TestFile('bss_data')) as fd:
715 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass4f443042016-11-25 20:15:52 -0700716 data = self._DoReadFile('21_image_pad.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700717 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700718
719 def testImageName(self):
720 """Test that image files can be named"""
721 retcode = self._DoTestFile('22_image_name.dts')
722 self.assertEqual(0, retcode)
723 image = control.images['image1']
724 fname = tools.GetOutputFilename('test-name')
725 self.assertTrue(os.path.exists(fname))
726
727 image = control.images['image2']
728 fname = tools.GetOutputFilename('test-name.xx')
729 self.assertTrue(os.path.exists(fname))
730
731 def testBlobFilename(self):
732 """Test that generic blobs can be provided by filename"""
733 data = self._DoReadFile('23_blob.dts')
734 self.assertEqual(BLOB_DATA, data)
735
736 def testPackSorted(self):
737 """Test that entries can be sorted"""
738 data = self._DoReadFile('24_sorted.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700739 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
Simon Glass4f443042016-11-25 20:15:52 -0700740 U_BOOT_DATA, data)
741
Simon Glass3ab95982018-08-01 15:22:37 -0600742 def testPackZeroOffset(self):
743 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700744 with self.assertRaises(ValueError) as e:
745 self._DoTestFile('25_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600746 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700747 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
748 str(e.exception))
749
750 def testPackUbootDtb(self):
751 """Test that a device tree can be added to U-Boot"""
752 data = self._DoReadFile('26_pack_u_boot_dtb.dts')
753 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700754
755 def testPackX86RomNoSize(self):
756 """Test that the end-at-4gb property requires a size property"""
757 with self.assertRaises(ValueError) as e:
758 self._DoTestFile('27_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600759 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700760 "using end-at-4gb", str(e.exception))
761
762 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600763 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700764 with self.assertRaises(ValueError) as e:
765 self._DoTestFile('28_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600766 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600767 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700768 str(e.exception))
769
770 def testPackX86Rom(self):
771 """Test that a basic x86 ROM can be created"""
772 data = self._DoReadFile('29_x86-rom.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700773 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
774 chr(0) * 2, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700775
776 def testPackX86RomMeNoDesc(self):
777 """Test that an invalid Intel descriptor entry is detected"""
778 TestFunctional._MakeInputFile('descriptor.bin', '')
779 with self.assertRaises(ValueError) as e:
780 self._DoTestFile('31_x86-rom-me.dts')
781 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
782 "signature", str(e.exception))
783
784 def testPackX86RomBadDesc(self):
785 """Test that the Intel requires a descriptor entry"""
786 with self.assertRaises(ValueError) as e:
787 self._DoTestFile('30_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600788 self.assertIn("Node '/binman/intel-me': No offset set with "
789 "offset-unset: should another entry provide this correct "
790 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700791
792 def testPackX86RomMe(self):
793 """Test that an x86 ROM with an ME region can be created"""
794 data = self._DoReadFile('31_x86-rom-me.dts')
795 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
796
797 def testPackVga(self):
798 """Test that an image with a VGA binary can be created"""
799 data = self._DoReadFile('32_intel-vga.dts')
800 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
801
802 def testPackStart16(self):
803 """Test that an image with an x86 start16 region can be created"""
804 data = self._DoReadFile('33_x86-start16.dts')
805 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
806
Simon Glass736bb0a2018-07-06 10:27:17 -0600807 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600808 """Handle running a test for insertion of microcode
809
810 Args:
811 dts_fname: Name of test .dts file
812 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600813 ucode_second: True if the microsecond entry is second instead of
814 third
Simon Glassadc57012018-07-06 10:27:16 -0600815
816 Returns:
817 Tuple:
818 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600819 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600820 in the above (two 4-byte words)
821 """
Simon Glass6b187df2017-11-12 21:52:27 -0700822 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700823
824 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600825 if ucode_second:
826 ucode_content = data[len(nodtb_data):]
827 ucode_pos = len(nodtb_data)
828 dtb_with_ucode = ucode_content[16:]
829 fdt_len = self.GetFdtLen(dtb_with_ucode)
830 else:
831 dtb_with_ucode = data[len(nodtb_data):]
832 fdt_len = self.GetFdtLen(dtb_with_ucode)
833 ucode_content = dtb_with_ucode[fdt_len:]
834 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700835 fname = tools.GetOutputFilename('test.dtb')
836 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600837 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600838 dtb = fdt.FdtScan(fname)
839 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700840 self.assertTrue(ucode)
841 for node in ucode.subnodes:
842 self.assertFalse(node.props.get('data'))
843
Simon Glasse0ff8552016-11-25 20:15:53 -0700844 # Check that the microcode appears immediately after the Fdt
845 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700846 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700847 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
848 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600849 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700850
851 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600852 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700853 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
854 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600855 u_boot = data[:len(nodtb_data)]
856 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700857
858 def testPackUbootMicrocode(self):
859 """Test that x86 microcode can be handled correctly
860
861 We expect to see the following in the image, in order:
862 u-boot-nodtb.bin with a microcode pointer inserted at the correct
863 place
864 u-boot.dtb with the microcode removed
865 the microcode
866 """
867 first, pos_and_size = self._RunMicrocodeTest('34_x86_ucode.dts',
868 U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700869 self.assertEqual('nodtb with microcode' + pos_and_size +
870 ' somewhere in here', first)
871
Simon Glass160a7662017-05-27 07:38:26 -0600872 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700873 """Test that x86 microcode can be handled correctly
874
875 We expect to see the following in the image, in order:
876 u-boot-nodtb.bin with a microcode pointer inserted at the correct
877 place
878 u-boot.dtb with the microcode
879 an empty microcode region
880 """
881 # We need the libfdt library to run this test since only that allows
882 # finding the offset of a property. This is required by
883 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glasse0ff8552016-11-25 20:15:53 -0700884 data = self._DoReadFile('35_x86_single_ucode.dts', True)
885
886 second = data[len(U_BOOT_NODTB_DATA):]
887
888 fdt_len = self.GetFdtLen(second)
889 third = second[fdt_len:]
890 second = second[:fdt_len]
891
Simon Glass160a7662017-05-27 07:38:26 -0600892 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
893 self.assertIn(ucode_data, second)
894 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700895
Simon Glass160a7662017-05-27 07:38:26 -0600896 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600897 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600898 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
899 len(ucode_data))
900 first = data[:len(U_BOOT_NODTB_DATA)]
901 self.assertEqual('nodtb with microcode' + pos_and_size +
902 ' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700903
Simon Glass75db0862016-11-25 20:15:55 -0700904 def testPackUbootSingleMicrocode(self):
905 """Test that x86 microcode can be handled correctly with fdt_normal.
906 """
Simon Glass160a7662017-05-27 07:38:26 -0600907 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700908
Simon Glassc49deb82016-11-25 20:15:54 -0700909 def testUBootImg(self):
910 """Test that u-boot.img can be put in a file"""
911 data = self._DoReadFile('36_u_boot_img.dts')
912 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700913
914 def testNoMicrocode(self):
915 """Test that a missing microcode region is detected"""
916 with self.assertRaises(ValueError) as e:
917 self._DoReadFile('37_x86_no_ucode.dts', True)
918 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
919 "node found in ", str(e.exception))
920
921 def testMicrocodeWithoutNode(self):
922 """Test that a missing u-boot-dtb-with-ucode node is detected"""
923 with self.assertRaises(ValueError) as e:
924 self._DoReadFile('38_x86_ucode_missing_node.dts', True)
925 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
926 "microcode region u-boot-dtb-with-ucode", str(e.exception))
927
928 def testMicrocodeWithoutNode2(self):
929 """Test that a missing u-boot-ucode node is detected"""
930 with self.assertRaises(ValueError) as e:
931 self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
932 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
933 "microcode region u-boot-ucode", str(e.exception))
934
935 def testMicrocodeWithoutPtrInElf(self):
936 """Test that a U-Boot binary without the microcode symbol is detected"""
937 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700938 try:
939 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
940 TestFunctional._MakeInputFile('u-boot', fd.read())
941
942 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600943 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700944 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
945 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
946
947 finally:
948 # Put the original file back
949 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
950 TestFunctional._MakeInputFile('u-boot', fd.read())
951
952 def testMicrocodeNotInImage(self):
953 """Test that microcode must be placed within the image"""
954 with self.assertRaises(ValueError) as e:
955 self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
956 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
957 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -0600958 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -0700959
960 def testWithoutMicrocode(self):
961 """Test that we can cope with an image without microcode (e.g. qemu)"""
962 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
963 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass16b8d6b2018-07-06 10:27:42 -0600964 data, dtb, _, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700965
966 # Now check the device tree has no microcode
967 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
968 second = data[len(U_BOOT_NODTB_DATA):]
969
970 fdt_len = self.GetFdtLen(second)
971 self.assertEqual(dtb, second[:fdt_len])
972
973 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
974 third = data[used_len:]
975 self.assertEqual(chr(0) * (0x200 - used_len), third)
976
977 def testUnknownPosSize(self):
978 """Test that microcode must be placed within the image"""
979 with self.assertRaises(ValueError) as e:
980 self._DoReadFile('41_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -0600981 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -0700982 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -0700983
984 def testPackFsp(self):
985 """Test that an image with a FSP binary can be created"""
986 data = self._DoReadFile('42_intel-fsp.dts')
987 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
988
989 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -0700990 """Test that an image with a CMC binary can be created"""
Simon Glassda229092016-11-25 20:15:56 -0700991 data = self._DoReadFile('43_intel-cmc.dts')
992 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -0700993
994 def testPackVbt(self):
995 """Test that an image with a VBT binary can be created"""
996 data = self._DoReadFile('46_intel-vbt.dts')
997 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -0700998
Simon Glass56509842017-11-12 21:52:25 -0700999 def testSplBssPad(self):
1000 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001001 # ELF file with a '__bss_size' symbol
1002 with open(self.TestFile('bss_data')) as fd:
1003 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass56509842017-11-12 21:52:25 -07001004 data = self._DoReadFile('47_spl_bss_pad.dts')
1005 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
1006
Simon Glassb50e5612017-11-13 18:54:54 -07001007 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1008 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1009 with self.assertRaises(ValueError) as e:
1010 data = self._DoReadFile('47_spl_bss_pad.dts')
1011 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1012 str(e.exception))
1013
Simon Glass87722132017-11-12 21:52:26 -07001014 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001015 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass87722132017-11-12 21:52:26 -07001016 data = self._DoReadFile('48_x86-start16-spl.dts')
1017 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1018
Simon Glass736bb0a2018-07-06 10:27:17 -06001019 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1020 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001021
1022 We expect to see the following in the image, in order:
1023 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1024 correct place
1025 u-boot.dtb with the microcode removed
1026 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001027
1028 Args:
1029 dts: Device tree file to use for test
1030 ucode_second: True if the microsecond entry is second instead of
1031 third
Simon Glass6b187df2017-11-12 21:52:27 -07001032 """
1033 # ELF file with a '_dt_ucode_base_size' symbol
1034 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1035 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass736bb0a2018-07-06 10:27:17 -06001036 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1037 ucode_second=ucode_second)
Simon Glass6b187df2017-11-12 21:52:27 -07001038 self.assertEqual('splnodtb with microc' + pos_and_size +
1039 'ter somewhere in here', first)
1040
Simon Glass736bb0a2018-07-06 10:27:17 -06001041 def testPackUbootSplMicrocode(self):
1042 """Test that x86 microcode can be handled correctly in SPL"""
1043 self._PackUbootSplMicrocode('49_x86_ucode_spl.dts')
1044
1045 def testPackUbootSplMicrocodeReorder(self):
1046 """Test that order doesn't matter for microcode entries
1047
1048 This is the same as testPackUbootSplMicrocode but when we process the
1049 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1050 entry, so we reply on binman to try later.
1051 """
1052 self._PackUbootSplMicrocode('58_x86_ucode_spl_needs_retry.dts',
1053 ucode_second=True)
1054
Simon Glassca4f4ff2017-11-12 21:52:28 -07001055 def testPackMrc(self):
1056 """Test that an image with an MRC binary can be created"""
1057 data = self._DoReadFile('50_intel_mrc.dts')
1058 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1059
Simon Glass47419ea2017-11-13 18:54:55 -07001060 def testSplDtb(self):
1061 """Test that an image with spl/u-boot-spl.dtb can be created"""
1062 data = self._DoReadFile('51_u_boot_spl_dtb.dts')
1063 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1064
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001065 def testSplNoDtb(self):
1066 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1067 data = self._DoReadFile('52_u_boot_spl_nodtb.dts')
1068 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1069
Simon Glass19790632017-11-13 18:55:01 -07001070 def testSymbols(self):
1071 """Test binman can assign symbols embedded in U-Boot"""
1072 elf_fname = self.TestFile('u_boot_binman_syms')
1073 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1074 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001075 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001076
1077 with open(self.TestFile('u_boot_binman_syms')) as fd:
1078 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1079 data = self._DoReadFile('53_symbols.dts')
1080 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1081 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1082 U_BOOT_DATA +
1083 sym_values + U_BOOT_SPL_DATA[16:])
1084 self.assertEqual(expected, data)
1085
Simon Glassdd57c132018-06-01 09:38:11 -06001086 def testPackUnitAddress(self):
1087 """Test that we support multiple binaries with the same name"""
1088 data = self._DoReadFile('54_unit_address.dts')
1089 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1090
Simon Glass18546952018-06-01 09:38:16 -06001091 def testSections(self):
1092 """Basic test of sections"""
1093 data = self._DoReadFile('55_sections.dts')
Simon Glass8122f392018-07-17 13:25:28 -06001094 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1095 U_BOOT_DATA + '&' * 4)
Simon Glass18546952018-06-01 09:38:16 -06001096 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001097
Simon Glass3b0c3822018-06-01 09:38:20 -06001098 def testMap(self):
1099 """Tests outputting a map of the images"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001100 _, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001101 self.assertEqual('''ImagePos Offset Size Name
110200000000 00000000 00000028 main-section
110300000000 00000000 00000010 section@0
110400000000 00000000 00000004 u-boot
110500000010 00000010 00000010 section@1
110600000010 00000000 00000004 u-boot
110700000020 00000020 00000004 section@2
110800000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001109''', map_data)
1110
Simon Glassc8d48ef2018-06-01 09:38:21 -06001111 def testNamePrefix(self):
1112 """Tests that name prefixes are used"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001113 _, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001114 self.assertEqual('''ImagePos Offset Size Name
111500000000 00000000 00000028 main-section
111600000000 00000000 00000010 section@0
111700000000 00000000 00000004 ro-u-boot
111800000010 00000010 00000010 section@1
111900000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001120''', map_data)
1121
Simon Glass736bb0a2018-07-06 10:27:17 -06001122 def testUnknownContents(self):
1123 """Test that obtaining the contents works as expected"""
1124 with self.assertRaises(ValueError) as e:
1125 self._DoReadFile('57_unknown_contents.dts', True)
1126 self.assertIn("Section '/binman': Internal error: Could not complete "
1127 "processing of contents: remaining [<_testing.Entry__testing ",
1128 str(e.exception))
1129
Simon Glass5c890232018-07-06 10:27:19 -06001130 def testBadChangeSize(self):
1131 """Test that trying to change the size of an entry fails"""
1132 with self.assertRaises(ValueError) as e:
1133 self._DoReadFile('59_change_size.dts', True)
1134 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1135 '2 to 1', str(e.exception))
1136
Simon Glass16b8d6b2018-07-06 10:27:42 -06001137 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001138 """Test that we can update the device tree with offset/size info"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001139 _, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
1140 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001141 dtb = fdt.Fdt(out_dtb_fname)
1142 dtb.Scan()
1143 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001144 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001145 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001146 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001147 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001148 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001149 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001150 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001151 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001152 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001153 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001154 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001155 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001156
Simon Glass3ab95982018-08-01 15:22:37 -06001157 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001158 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001159 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001160 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001161 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001162 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001163 'size': 40
1164 }, props)
1165
1166 def testUpdateFdtBad(self):
1167 """Test that we detect when ProcessFdt never completes"""
1168 with self.assertRaises(ValueError) as e:
1169 self._DoReadFileDtb('61_fdt_update_bad.dts', update_dtb=True)
1170 self.assertIn('Could not complete processing of Fdt: remaining '
1171 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001172
Simon Glass53af22a2018-07-17 13:25:32 -06001173 def testEntryArgs(self):
1174 """Test passing arguments to entries from the command line"""
1175 entry_args = {
1176 'test-str-arg': 'test1',
1177 'test-int-arg': '456',
1178 }
1179 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1180 self.assertIn('image', control.images)
1181 entry = control.images['image'].GetEntries()['_testing']
1182 self.assertEqual('test0', entry.test_str_fdt)
1183 self.assertEqual('test1', entry.test_str_arg)
1184 self.assertEqual(123, entry.test_int_fdt)
1185 self.assertEqual(456, entry.test_int_arg)
1186
1187 def testEntryArgsMissing(self):
1188 """Test missing arguments and properties"""
1189 entry_args = {
1190 'test-int-arg': '456',
1191 }
1192 self._DoReadFileDtb('63_entry_args_missing.dts', entry_args=entry_args)
1193 entry = control.images['image'].GetEntries()['_testing']
1194 self.assertEqual('test0', entry.test_str_fdt)
1195 self.assertEqual(None, entry.test_str_arg)
1196 self.assertEqual(None, entry.test_int_fdt)
1197 self.assertEqual(456, entry.test_int_arg)
1198
1199 def testEntryArgsRequired(self):
1200 """Test missing arguments and properties"""
1201 entry_args = {
1202 'test-int-arg': '456',
1203 }
1204 with self.assertRaises(ValueError) as e:
1205 self._DoReadFileDtb('64_entry_args_required.dts')
1206 self.assertIn("Node '/binman/_testing': Missing required "
1207 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1208 str(e.exception))
1209
1210 def testEntryArgsInvalidFormat(self):
1211 """Test that an invalid entry-argument format is detected"""
1212 args = ['-d', self.TestFile('64_entry_args_required.dts'), '-ano-value']
1213 with self.assertRaises(ValueError) as e:
1214 self._DoBinman(*args)
1215 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1216
1217 def testEntryArgsInvalidInteger(self):
1218 """Test that an invalid entry-argument integer is detected"""
1219 entry_args = {
1220 'test-int-arg': 'abc',
1221 }
1222 with self.assertRaises(ValueError) as e:
1223 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1224 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1225 "'test-int-arg' (value 'abc') to integer",
1226 str(e.exception))
1227
1228 def testEntryArgsInvalidDatatype(self):
1229 """Test that an invalid entry-argument datatype is detected
1230
1231 This test could be written in entry_test.py except that it needs
1232 access to control.entry_args, which seems more than that module should
1233 be able to see.
1234 """
1235 entry_args = {
1236 'test-bad-datatype-arg': '12',
1237 }
1238 with self.assertRaises(ValueError) as e:
1239 self._DoReadFileDtb('65_entry_args_unknown_datatype.dts',
1240 entry_args=entry_args)
1241 self.assertIn('GetArg() internal error: Unknown data type ',
1242 str(e.exception))
1243
Simon Glassbb748372018-07-17 13:25:33 -06001244 def testText(self):
1245 """Test for a text entry type"""
1246 entry_args = {
1247 'test-id': TEXT_DATA,
1248 'test-id2': TEXT_DATA2,
1249 'test-id3': TEXT_DATA3,
1250 }
1251 data, _, _, _ = self._DoReadFileDtb('66_text.dts',
1252 entry_args=entry_args)
1253 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1254 TEXT_DATA3 + 'some text')
1255 self.assertEqual(expected, data)
1256
Simon Glassfd8d1f72018-07-17 13:25:36 -06001257 def testEntryDocs(self):
1258 """Test for creation of entry documentation"""
1259 with test_util.capture_sys_output() as (stdout, stderr):
1260 control.WriteEntryDocs(binman.GetEntryModules())
1261 self.assertTrue(len(stdout.getvalue()) > 0)
1262
1263 def testEntryDocsMissing(self):
1264 """Test handling of missing entry documentation"""
1265 with self.assertRaises(ValueError) as e:
1266 with test_util.capture_sys_output() as (stdout, stderr):
1267 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1268 self.assertIn('Documentation is missing for modules: u_boot',
1269 str(e.exception))
1270
Simon Glass11e36cc2018-07-17 13:25:38 -06001271 def testFmap(self):
1272 """Basic test of generation of a flashrom fmap"""
1273 data = self._DoReadFile('67_fmap.dts')
1274 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1275 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1276 self.assertEqual(expected, data[:32])
1277 self.assertEqual('__FMAP__', fhdr.signature)
1278 self.assertEqual(1, fhdr.ver_major)
1279 self.assertEqual(0, fhdr.ver_minor)
1280 self.assertEqual(0, fhdr.base)
1281 self.assertEqual(16 + 16 +
1282 fmap_util.FMAP_HEADER_LEN +
1283 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1284 self.assertEqual('FMAP', fhdr.name)
1285 self.assertEqual(3, fhdr.nareas)
1286 for fentry in fentries:
1287 self.assertEqual(0, fentry.flags)
1288
1289 self.assertEqual(0, fentries[0].offset)
1290 self.assertEqual(4, fentries[0].size)
1291 self.assertEqual('RO_U_BOOT', fentries[0].name)
1292
1293 self.assertEqual(16, fentries[1].offset)
1294 self.assertEqual(4, fentries[1].size)
1295 self.assertEqual('RW_U_BOOT', fentries[1].name)
1296
1297 self.assertEqual(32, fentries[2].offset)
1298 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1299 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1300 self.assertEqual('FMAP', fentries[2].name)
1301
Simon Glassec127af2018-07-17 13:25:39 -06001302 def testBlobNamedByArg(self):
1303 """Test we can add a blob with the filename coming from an entry arg"""
1304 entry_args = {
1305 'cros-ec-rw-path': 'ecrw.bin',
1306 }
1307 data, _, _, _ = self._DoReadFileDtb('68_blob_named_by_arg.dts',
1308 entry_args=entry_args)
1309
Simon Glass3af8e492018-07-17 13:25:40 -06001310 def testFill(self):
1311 """Test for an fill entry type"""
1312 data = self._DoReadFile('69_fill.dts')
1313 expected = 8 * chr(0xff) + 8 * chr(0)
1314 self.assertEqual(expected, data)
1315
1316 def testFillNoSize(self):
1317 """Test for an fill entry type with no size"""
1318 with self.assertRaises(ValueError) as e:
1319 self._DoReadFile('70_fill_no_size.dts')
1320 self.assertIn("'fill' entry must have a size property",
1321 str(e.exception))
1322
Simon Glass0ef87aa2018-07-17 13:25:44 -06001323 def _HandleGbbCommand(self, pipe_list):
1324 """Fake calls to the futility utility"""
1325 if pipe_list[0][0] == 'futility':
1326 fname = pipe_list[0][-1]
1327 # Append our GBB data to the file, which will happen every time the
1328 # futility command is called.
1329 with open(fname, 'a') as fd:
1330 fd.write(GBB_DATA)
1331 return command.CommandResult()
1332
1333 def testGbb(self):
1334 """Test for the Chromium OS Google Binary Block"""
1335 command.test_result = self._HandleGbbCommand
1336 entry_args = {
1337 'keydir': 'devkeys',
1338 'bmpblk': 'bmpblk.bin',
1339 }
1340 data, _, _, _ = self._DoReadFileDtb('71_gbb.dts', entry_args=entry_args)
1341
1342 # Since futility
1343 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1344 self.assertEqual(expected, data)
1345
1346 def testGbbTooSmall(self):
1347 """Test for the Chromium OS Google Binary Block being large enough"""
1348 with self.assertRaises(ValueError) as e:
1349 self._DoReadFileDtb('72_gbb_too_small.dts')
1350 self.assertIn("Node '/binman/gbb': GBB is too small",
1351 str(e.exception))
1352
1353 def testGbbNoSize(self):
1354 """Test for the Chromium OS Google Binary Block having a size"""
1355 with self.assertRaises(ValueError) as e:
1356 self._DoReadFileDtb('73_gbb_no_size.dts')
1357 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1358 str(e.exception))
1359
Simon Glass24d0d3c2018-07-17 13:25:47 -06001360 def _HandleVblockCommand(self, pipe_list):
1361 """Fake calls to the futility utility"""
1362 if pipe_list[0][0] == 'futility':
1363 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001364 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001365 fd.write(VBLOCK_DATA)
1366 return command.CommandResult()
1367
1368 def testVblock(self):
1369 """Test for the Chromium OS Verified Boot Block"""
1370 command.test_result = self._HandleVblockCommand
1371 entry_args = {
1372 'keydir': 'devkeys',
1373 }
1374 data, _, _, _ = self._DoReadFileDtb('74_vblock.dts',
1375 entry_args=entry_args)
1376 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1377 self.assertEqual(expected, data)
1378
1379 def testVblockNoContent(self):
1380 """Test we detect a vblock which has no content to sign"""
1381 with self.assertRaises(ValueError) as e:
1382 self._DoReadFile('75_vblock_no_content.dts')
1383 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1384 'property', str(e.exception))
1385
1386 def testVblockBadPhandle(self):
1387 """Test that we detect a vblock with an invalid phandle in contents"""
1388 with self.assertRaises(ValueError) as e:
1389 self._DoReadFile('76_vblock_bad_phandle.dts')
1390 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1391 '1000', str(e.exception))
1392
1393 def testVblockBadEntry(self):
1394 """Test that we detect an entry that points to a non-entry"""
1395 with self.assertRaises(ValueError) as e:
1396 self._DoReadFile('77_vblock_bad_entry.dts')
1397 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1398 "'other'", str(e.exception))
1399
Simon Glassb8ef5b62018-07-17 13:25:48 -06001400 def testTpl(self):
1401 """Test that an image with TPL and ots device tree can be created"""
1402 # ELF file with a '__bss_size' symbol
1403 with open(self.TestFile('bss_data')) as fd:
1404 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1405 data = self._DoReadFile('78_u_boot_tpl.dts')
1406 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1407
Simon Glass15a587c2018-07-17 13:25:51 -06001408 def testUsesPos(self):
1409 """Test that the 'pos' property cannot be used anymore"""
1410 with self.assertRaises(ValueError) as e:
1411 data = self._DoReadFile('79_uses_pos.dts')
1412 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1413 "'pos'", str(e.exception))
1414
Simon Glassd178eab2018-09-14 04:57:08 -06001415 def testFillZero(self):
1416 """Test for an fill entry type with a size of 0"""
1417 data = self._DoReadFile('80_fill_empty.dts')
1418 self.assertEqual(chr(0) * 16, data)
1419
Simon Glass0b489362018-09-14 04:57:09 -06001420 def testTextMissing(self):
1421 """Test for a text entry type where there is no text"""
1422 with self.assertRaises(ValueError) as e:
1423 self._DoReadFileDtb('66_text.dts',)
1424 self.assertIn("Node '/binman/text': No value provided for text label "
1425 "'test-id'", str(e.exception))
1426
Simon Glass35b384c2018-09-14 04:57:10 -06001427 def testPackStart16Tpl(self):
1428 """Test that an image with an x86 start16 TPL region can be created"""
1429 data = self._DoReadFile('81_x86-start16-tpl.dts')
1430 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1431
Simon Glass0bfa7b02018-09-14 04:57:12 -06001432 def testSelectImage(self):
1433 """Test that we can select which images to build"""
1434 with test_util.capture_sys_output() as (stdout, stderr):
1435 retcode = self._DoTestFile('06_dual_image.dts', images=['image2'])
1436 self.assertEqual(0, retcode)
1437 self.assertIn('Skipping images: image1', stdout.getvalue())
1438
1439 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1440 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1441
Simon Glass6ed45ba2018-09-14 04:57:24 -06001442 def testUpdateFdtAll(self):
1443 """Test that all device trees are updated with offset/size info"""
1444 data, _, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1445 use_real_dtb=True, update_dtb=True)
1446
1447 base_expected = {
1448 'section:image-pos': 0,
1449 'u-boot-tpl-dtb:size': 513,
1450 'u-boot-spl-dtb:size': 513,
1451 'u-boot-spl-dtb:offset': 493,
1452 'image-pos': 0,
1453 'section/u-boot-dtb:image-pos': 0,
1454 'u-boot-spl-dtb:image-pos': 493,
1455 'section/u-boot-dtb:size': 493,
1456 'u-boot-tpl-dtb:image-pos': 1006,
1457 'section/u-boot-dtb:offset': 0,
1458 'section:size': 493,
1459 'offset': 0,
1460 'section:offset': 0,
1461 'u-boot-tpl-dtb:offset': 1006,
1462 'size': 1519
1463 }
1464
1465 # We expect three device-tree files in the output, one after the other.
1466 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1467 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1468 # main U-Boot tree. All three should have the same postions and offset.
1469 start = 0
1470 for item in ['', 'spl', 'tpl']:
1471 dtb = fdt.Fdt.FromData(data[start:])
1472 dtb.Scan()
1473 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1474 'spl', 'tpl'])
1475 expected = dict(base_expected)
1476 if item:
1477 expected[item] = 0
1478 self.assertEqual(expected, props)
1479 start += dtb._fdt_obj.totalsize()
1480
1481 def testUpdateFdtOutput(self):
1482 """Test that output DTB files are updated"""
1483 try:
1484 data, dtb_data, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1485 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1486
1487 # Unfortunately, compiling a source file always results in a file
1488 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1489 # source file (e.g. test/75_fdt_update_all.dts) thus does not enter
1490 # binman as a file called u-boot.dtb. To fix this, copy the file
1491 # over to the expected place.
1492 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1493 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1494 start = 0
1495 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1496 'tpl/u-boot-tpl.dtb.out']:
1497 dtb = fdt.Fdt.FromData(data[start:])
1498 size = dtb._fdt_obj.totalsize()
1499 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1500 outdata = tools.ReadFile(pathname)
1501 name = os.path.split(fname)[0]
1502
1503 if name:
1504 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1505 else:
1506 orig_indata = dtb_data
1507 self.assertNotEqual(outdata, orig_indata,
1508 "Expected output file '%s' be updated" % pathname)
1509 self.assertEqual(outdata, data[start:start + size],
1510 "Expected output file '%s' to match output image" %
1511 pathname)
1512 start += size
1513 finally:
1514 self._ResetDtbs()
1515
Simon Glass83d73c22018-09-14 04:57:26 -06001516 def _decompress(self, data):
1517 out = os.path.join(self._indir, 'lz4.tmp')
1518 with open(out, 'wb') as fd:
1519 fd.write(data)
1520 return tools.Run('lz4', '-dc', out)
1521 '''
1522 try:
1523 orig = lz4.frame.decompress(data)
1524 except AttributeError:
1525 orig = lz4.decompress(data)
1526 '''
1527
1528 def testCompress(self):
1529 """Test compression of blobs"""
1530 data, _, _, out_dtb_fname = self._DoReadFileDtb('83_compress.dts',
1531 use_real_dtb=True, update_dtb=True)
1532 dtb = fdt.Fdt(out_dtb_fname)
1533 dtb.Scan()
1534 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1535 orig = self._decompress(data)
1536 self.assertEquals(COMPRESS_DATA, orig)
1537 expected = {
1538 'blob:uncomp-size': len(COMPRESS_DATA),
1539 'blob:size': len(data),
1540 'size': len(data),
1541 }
1542 self.assertEqual(expected, props)
1543
Simon Glass0a98b282018-09-14 04:57:28 -06001544 def testFiles(self):
1545 """Test bringing in multiple files"""
1546 data = self._DoReadFile('84_files.dts')
1547 self.assertEqual(FILES_DATA, data)
1548
1549 def testFilesCompress(self):
1550 """Test bringing in multiple files and compressing them"""
1551 data = self._DoReadFile('85_files_compress.dts')
1552
1553 image = control.images['image']
1554 entries = image.GetEntries()
1555 files = entries['files']
1556 entries = files._section._entries
1557
1558 orig = ''
1559 for i in range(1, 3):
1560 key = '%d.dat' % i
1561 start = entries[key].image_pos
1562 len = entries[key].size
1563 chunk = data[start:start + len]
1564 orig += self._decompress(chunk)
1565
1566 self.assertEqual(FILES_DATA, orig)
1567
1568 def testFilesMissing(self):
1569 """Test missing files"""
1570 with self.assertRaises(ValueError) as e:
1571 data = self._DoReadFile('86_files_none.dts')
1572 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1573 'no files', str(e.exception))
1574
1575 def testFilesNoPattern(self):
1576 """Test missing files"""
1577 with self.assertRaises(ValueError) as e:
1578 data = self._DoReadFile('87_files_no_pattern.dts')
1579 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1580 str(e.exception))
1581
Simon Glassba64a0b2018-09-14 04:57:29 -06001582 def testExpandSize(self):
1583 """Test an expanding entry"""
1584 data, _, map_data, _ = self._DoReadFileDtb('88_expand_size.dts',
1585 map=True)
1586 expect = ('a' * 8 + U_BOOT_DATA +
1587 MRC_DATA + 'b' * 1 + U_BOOT_DATA +
1588 'c' * 8 + U_BOOT_DATA +
1589 'd' * 8)
1590 self.assertEqual(expect, data)
1591 self.assertEqual('''ImagePos Offset Size Name
159200000000 00000000 00000028 main-section
159300000000 00000000 00000008 fill
159400000008 00000008 00000004 u-boot
15950000000c 0000000c 00000004 section
15960000000c 00000000 00000003 intel-mrc
159700000010 00000010 00000004 u-boot2
159800000014 00000014 0000000c section2
159900000014 00000000 00000008 fill
16000000001c 00000008 00000004 u-boot
160100000020 00000020 00000008 fill2
1602''', map_data)
1603
1604 def testExpandSizeBad(self):
1605 """Test an expanding entry which fails to provide contents"""
1606 with self.assertRaises(ValueError) as e:
1607 self._DoReadFileDtb('89_expand_size_bad.dts', map=True)
1608 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1609 'expanding entry', str(e.exception))
1610
Simon Glass53af22a2018-07-17 13:25:32 -06001611
Simon Glass9fc60b42017-11-12 21:52:22 -07001612if __name__ == "__main__":
1613 unittest.main()