blob: 1c3c46fc23afe4d554277d0203f29f19202ecef5 [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 Glass83d73c22018-09-14 04:57:26 -060057COMPRESS_DATA = 'data to compress'
Simon Glassec127af2018-07-17 13:25:39 -060058
Simon Glass4f443042016-11-25 20:15:52 -070059
60class TestFunctional(unittest.TestCase):
61 """Functional tests for binman
62
63 Most of these use a sample .dts file to build an image and then check
64 that it looks correct. The sample files are in the test/ subdirectory
65 and are numbered.
66
67 For each entry type a very small test file is created using fixed
68 string contents. This makes it easy to test that things look right, and
69 debug problems.
70
71 In some cases a 'real' file must be used - these are also supplied in
72 the test/ diurectory.
73 """
74 @classmethod
75 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070076 global entry
77 import entry
78
Simon Glass4f443042016-11-25 20:15:52 -070079 # Handle the case where argv[0] is 'python'
80 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
81 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
82
83 # Create a temporary directory for input files
84 self._indir = tempfile.mkdtemp(prefix='binmant.')
85
86 # Create some test files
87 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
88 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
89 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060090 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -070091 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -070092 TestFunctional._MakeInputFile('me.bin', ME_DATA)
93 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -060094 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -070095 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Simon Glass87722132017-11-12 21:52:26 -070096 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
97 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -060098 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
99 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700100 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700101 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
102 U_BOOT_SPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700103 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
104 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700105 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700106 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600107 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600108 TestFunctional._MakeInputDir('devkeys')
109 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700110 self._output_setup = False
111
Simon Glasse0ff8552016-11-25 20:15:53 -0700112 # ELF file with a '_dt_ucode_base_size' symbol
113 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
114 TestFunctional._MakeInputFile('u-boot', fd.read())
115
116 # Intel flash descriptor file
117 with open(self.TestFile('descriptor.bin')) as fd:
118 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
119
Simon Glass83d73c22018-09-14 04:57:26 -0600120 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
121
Simon Glass4f443042016-11-25 20:15:52 -0700122 @classmethod
123 def tearDownClass(self):
124 """Remove the temporary input directory and its contents"""
125 if self._indir:
126 shutil.rmtree(self._indir)
127 self._indir = None
128
129 def setUp(self):
130 # Enable this to turn on debugging output
131 # tout.Init(tout.DEBUG)
132 command.test_result = None
133
134 def tearDown(self):
135 """Remove the temporary output directory"""
136 tools._FinaliseForTest()
137
Simon Glassb8ef5b62018-07-17 13:25:48 -0600138 @classmethod
139 def _ResetDtbs(self):
140 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
141 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
142 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
143
Simon Glass4f443042016-11-25 20:15:52 -0700144 def _RunBinman(self, *args, **kwargs):
145 """Run binman using the command line
146
147 Args:
148 Arguments to pass, as a list of strings
149 kwargs: Arguments to pass to Command.RunPipe()
150 """
151 result = command.RunPipe([[self._binman_pathname] + list(args)],
152 capture=True, capture_stderr=True, raise_on_error=False)
153 if result.return_code and kwargs.get('raise_on_error', True):
154 raise Exception("Error running '%s': %s" % (' '.join(args),
155 result.stdout + result.stderr))
156 return result
157
158 def _DoBinman(self, *args):
159 """Run binman using directly (in the same process)
160
161 Args:
162 Arguments to pass, as a list of strings
163 Returns:
164 Return value (0 for success)
165 """
Simon Glass7fe91732017-11-13 18:55:00 -0700166 args = list(args)
167 if '-D' in sys.argv:
168 args = args + ['-D']
169 (options, args) = cmdline.ParseArgs(args)
Simon Glass4f443042016-11-25 20:15:52 -0700170 options.pager = 'binman-invalid-pager'
171 options.build_dir = self._indir
172
173 # For testing, you can force an increase in verbosity here
174 # options.verbosity = tout.DEBUG
175 return control.Binman(options, args)
176
Simon Glass53af22a2018-07-17 13:25:32 -0600177 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glass93d17412018-09-14 04:57:23 -0600178 entry_args=None, images=None, use_real_dtb=False):
Simon Glass4f443042016-11-25 20:15:52 -0700179 """Run binman with a given test file
180
181 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600182 fname: Device-tree source filename to use (e.g. 05_simple.dts)
183 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600184 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600185 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600186 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600187 entry_args: Dict of entry args to supply to binman
188 key: arg name
189 value: value of that arg
190 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700191 """
Simon Glass7fe91732017-11-13 18:55:00 -0700192 args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
193 if debug:
194 args.append('-D')
Simon Glass3b0c3822018-06-01 09:38:20 -0600195 if map:
196 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600197 if update_dtb:
198 args.append('-up')
Simon Glass93d17412018-09-14 04:57:23 -0600199 if not use_real_dtb:
200 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600201 if entry_args:
202 for arg, value in entry_args.iteritems():
203 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600204 if images:
205 for image in images:
206 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700207 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700208
209 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700210 """Set up a new test device-tree file
211
212 The given file is compiled and set up as the device tree to be used
213 for ths test.
214
215 Args:
216 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600217 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700218
219 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600220 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700221 """
Simon Glass4f443042016-11-25 20:15:52 -0700222 if not self._output_setup:
223 tools.PrepareOutputDir(self._indir, True)
224 self._output_setup = True
225 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
226 with open(dtb) as fd:
227 data = fd.read()
228 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700229 return data
Simon Glass4f443042016-11-25 20:15:52 -0700230
Simon Glass6ed45ba2018-09-14 04:57:24 -0600231 def _GetDtbContentsForSplTpl(self, dtb_data, name):
232 """Create a version of the main DTB for SPL or SPL
233
234 For testing we don't actually have different versions of the DTB. With
235 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
236 we don't normally have any unwanted nodes.
237
238 We still want the DTBs for SPL and TPL to be different though, since
239 otherwise it is confusing to know which one we are looking at. So add
240 an 'spl' or 'tpl' property to the top-level node.
241 """
242 dtb = fdt.Fdt.FromData(dtb_data)
243 dtb.Scan()
244 dtb.GetNode('/binman').AddZeroProp(name)
245 dtb.Sync(auto_resize=True)
246 dtb.Pack()
247 return dtb.GetContents()
248
Simon Glass16b8d6b2018-07-06 10:27:42 -0600249 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600250 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700251 """Run binman and return the resulting image
252
253 This runs binman with a given test file and then reads the resulting
254 output file. It is a shortcut function since most tests need to do
255 these steps.
256
257 Raises an assertion failure if binman returns a non-zero exit code.
258
259 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600260 fname: Device-tree source filename to use (e.g. 05_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700261 use_real_dtb: True to use the test file as the contents of
262 the u-boot-dtb entry. Normally this is not needed and the
263 test contents (the U_BOOT_DTB_DATA string) can be used.
264 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600265 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600266 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600267 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700268
269 Returns:
270 Tuple:
271 Resulting image contents
272 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600273 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600274 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700275 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700276 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700277 # Use the compiled test file as the u-boot-dtb input
278 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700279 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600280 infile = os.path.join(self._indir, 'u-boot.dtb')
281
282 # For testing purposes, make a copy of the DT for SPL and TPL. Add
283 # a node indicating which it is, so aid verification.
284 for name in ['spl', 'tpl']:
285 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
286 outfile = os.path.join(self._indir, dtb_fname)
287 TestFunctional._MakeInputFile(dtb_fname,
288 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700289
290 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600291 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600292 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700293 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600294 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700295
296 # Find the (only) image, read it and return its contents
297 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600298 image_fname = tools.GetOutputFilename('image.bin')
299 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600300 if map:
301 map_fname = tools.GetOutputFilename('image.map')
302 with open(map_fname) as fd:
303 map_data = fd.read()
304 else:
305 map_data = None
Simon Glass16b8d6b2018-07-06 10:27:42 -0600306 with open(image_fname) as fd:
307 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700308 finally:
309 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600310 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600311 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700312
Simon Glasse0ff8552016-11-25 20:15:53 -0700313 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600314 """Helper function which discards the device-tree binary
315
316 Args:
317 fname: Device-tree source filename to use (e.g. 05_simple.dts)
318 use_real_dtb: True to use the test file as the contents of
319 the u-boot-dtb entry. Normally this is not needed and the
320 test contents (the U_BOOT_DTB_DATA string) can be used.
321 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600322
323 Returns:
324 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600325 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700326 return self._DoReadFileDtb(fname, use_real_dtb)[0]
327
Simon Glass4f443042016-11-25 20:15:52 -0700328 @classmethod
329 def _MakeInputFile(self, fname, contents):
330 """Create a new test input file, creating directories as needed
331
332 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600333 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700334 contents: File contents to write in to the file
335 Returns:
336 Full pathname of file created
337 """
338 pathname = os.path.join(self._indir, fname)
339 dirname = os.path.dirname(pathname)
340 if dirname and not os.path.exists(dirname):
341 os.makedirs(dirname)
342 with open(pathname, 'wb') as fd:
343 fd.write(contents)
344 return pathname
345
346 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600347 def _MakeInputDir(self, dirname):
348 """Create a new test input directory, creating directories as needed
349
350 Args:
351 dirname: Directory name to create
352
353 Returns:
354 Full pathname of directory created
355 """
356 pathname = os.path.join(self._indir, dirname)
357 if not os.path.exists(pathname):
358 os.makedirs(pathname)
359 return pathname
360
361 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700362 def TestFile(self, fname):
363 return os.path.join(self._binman_dir, 'test', fname)
364
365 def AssertInList(self, grep_list, target):
366 """Assert that at least one of a list of things is in a target
367
368 Args:
369 grep_list: List of strings to check
370 target: Target string
371 """
372 for grep in grep_list:
373 if grep in target:
374 return
375 self.fail("Error: '%' not found in '%s'" % (grep_list, target))
376
377 def CheckNoGaps(self, entries):
378 """Check that all entries fit together without gaps
379
380 Args:
381 entries: List of entries to check
382 """
Simon Glass3ab95982018-08-01 15:22:37 -0600383 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700384 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600385 self.assertEqual(offset, entry.offset)
386 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700387
Simon Glasse0ff8552016-11-25 20:15:53 -0700388 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600389 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700390
391 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600392 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700393
394 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600395 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700396 """
397 return struct.unpack('>L', dtb[4:8])[0]
398
Simon Glasscee02e62018-07-17 13:25:52 -0600399 def _GetPropTree(self, dtb, prop_names):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600400 def AddNode(node, path):
401 if node.name != '/':
402 path += '/' + node.name
Simon Glass16b8d6b2018-07-06 10:27:42 -0600403 for subnode in node.subnodes:
404 for prop in subnode.props.values():
Simon Glasscee02e62018-07-17 13:25:52 -0600405 if prop.name in prop_names:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600406 prop_path = path + '/' + subnode.name + ':' + prop.name
407 tree[prop_path[len('/binman/'):]] = fdt_util.fdt32_to_cpu(
408 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600409 AddNode(subnode, path)
410
411 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600412 AddNode(dtb.GetRoot(), '')
413 return tree
414
Simon Glass4f443042016-11-25 20:15:52 -0700415 def testRun(self):
416 """Test a basic run with valid args"""
417 result = self._RunBinman('-h')
418
419 def testFullHelp(self):
420 """Test that the full help is displayed with -H"""
421 result = self._RunBinman('-H')
422 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500423 # Remove possible extraneous strings
424 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
425 gothelp = result.stdout.replace(extra, '')
426 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700427 self.assertEqual(0, len(result.stderr))
428 self.assertEqual(0, result.return_code)
429
430 def testFullHelpInternal(self):
431 """Test that the full help is displayed with -H"""
432 try:
433 command.test_result = command.CommandResult()
434 result = self._DoBinman('-H')
435 help_file = os.path.join(self._binman_dir, 'README')
436 finally:
437 command.test_result = None
438
439 def testHelp(self):
440 """Test that the basic help is displayed with -h"""
441 result = self._RunBinman('-h')
442 self.assertTrue(len(result.stdout) > 200)
443 self.assertEqual(0, len(result.stderr))
444 self.assertEqual(0, result.return_code)
445
Simon Glass4f443042016-11-25 20:15:52 -0700446 def testBoard(self):
447 """Test that we can run it with a specific board"""
448 self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb')
449 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
450 result = self._DoBinman('-b', 'sandbox')
451 self.assertEqual(0, result)
452
453 def testNeedBoard(self):
454 """Test that we get an error when no board ius supplied"""
455 with self.assertRaises(ValueError) as e:
456 result = self._DoBinman()
457 self.assertIn("Must provide a board to process (use -b <board>)",
458 str(e.exception))
459
460 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600461 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700462 with self.assertRaises(Exception) as e:
463 self._RunBinman('-d', 'missing_file')
464 # We get one error from libfdt, and a different one from fdtget.
465 self.AssertInList(["Couldn't open blob from 'missing_file'",
466 'No such file or directory'], str(e.exception))
467
468 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600469 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700470
471 Since this is a source file it should be compiled and the error
472 will come from the device-tree compiler (dtc).
473 """
474 with self.assertRaises(Exception) as e:
475 self._RunBinman('-d', self.TestFile('01_invalid.dts'))
476 self.assertIn("FATAL ERROR: Unable to parse input tree",
477 str(e.exception))
478
479 def testMissingNode(self):
480 """Test that a device tree without a 'binman' node generates an error"""
481 with self.assertRaises(Exception) as e:
482 self._DoBinman('-d', self.TestFile('02_missing_node.dts'))
483 self.assertIn("does not have a 'binman' node", str(e.exception))
484
485 def testEmpty(self):
486 """Test that an empty binman node works OK (i.e. does nothing)"""
487 result = self._RunBinman('-d', self.TestFile('03_empty.dts'))
488 self.assertEqual(0, len(result.stderr))
489 self.assertEqual(0, result.return_code)
490
491 def testInvalidEntry(self):
492 """Test that an invalid entry is flagged"""
493 with self.assertRaises(Exception) as e:
494 result = self._RunBinman('-d',
495 self.TestFile('04_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700496 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
497 "'/binman/not-a-valid-type'", str(e.exception))
498
499 def testSimple(self):
500 """Test a simple binman with a single file"""
501 data = self._DoReadFile('05_simple.dts')
502 self.assertEqual(U_BOOT_DATA, data)
503
Simon Glass7fe91732017-11-13 18:55:00 -0700504 def testSimpleDebug(self):
505 """Test a simple binman run with debugging enabled"""
506 data = self._DoTestFile('05_simple.dts', debug=True)
507
Simon Glass4f443042016-11-25 20:15:52 -0700508 def testDual(self):
509 """Test that we can handle creating two images
510
511 This also tests image padding.
512 """
513 retcode = self._DoTestFile('06_dual_image.dts')
514 self.assertEqual(0, retcode)
515
516 image = control.images['image1']
517 self.assertEqual(len(U_BOOT_DATA), image._size)
518 fname = tools.GetOutputFilename('image1.bin')
519 self.assertTrue(os.path.exists(fname))
520 with open(fname) as fd:
521 data = fd.read()
522 self.assertEqual(U_BOOT_DATA, data)
523
524 image = control.images['image2']
525 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size)
526 fname = tools.GetOutputFilename('image2.bin')
527 self.assertTrue(os.path.exists(fname))
528 with open(fname) as fd:
529 data = fd.read()
530 self.assertEqual(U_BOOT_DATA, data[3:7])
531 self.assertEqual(chr(0) * 3, data[:3])
532 self.assertEqual(chr(0) * 5, data[7:])
533
534 def testBadAlign(self):
535 """Test that an invalid alignment value is detected"""
536 with self.assertRaises(ValueError) as e:
537 self._DoTestFile('07_bad_align.dts')
538 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
539 "of two", str(e.exception))
540
541 def testPackSimple(self):
542 """Test that packing works as expected"""
543 retcode = self._DoTestFile('08_pack.dts')
544 self.assertEqual(0, retcode)
545 self.assertIn('image', control.images)
546 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600547 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700548 self.assertEqual(5, len(entries))
549
550 # First u-boot
551 self.assertIn('u-boot', entries)
552 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600553 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700554 self.assertEqual(len(U_BOOT_DATA), entry.size)
555
556 # Second u-boot, aligned to 16-byte boundary
557 self.assertIn('u-boot-align', entries)
558 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600559 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700560 self.assertEqual(len(U_BOOT_DATA), entry.size)
561
562 # Third u-boot, size 23 bytes
563 self.assertIn('u-boot-size', entries)
564 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600565 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700566 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
567 self.assertEqual(23, entry.size)
568
569 # Fourth u-boot, placed immediate after the above
570 self.assertIn('u-boot-next', entries)
571 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600572 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700573 self.assertEqual(len(U_BOOT_DATA), entry.size)
574
Simon Glass3ab95982018-08-01 15:22:37 -0600575 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700576 self.assertIn('u-boot-fixed', entries)
577 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600578 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700579 self.assertEqual(len(U_BOOT_DATA), entry.size)
580
581 self.assertEqual(65, image._size)
582
583 def testPackExtra(self):
584 """Test that extra packing feature works as expected"""
585 retcode = self._DoTestFile('09_pack_extra.dts')
586
587 self.assertEqual(0, retcode)
588 self.assertIn('image', control.images)
589 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600590 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700591 self.assertEqual(5, len(entries))
592
593 # First u-boot with padding before and after
594 self.assertIn('u-boot', entries)
595 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600596 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700597 self.assertEqual(3, entry.pad_before)
598 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
599
600 # Second u-boot has an aligned size, but it has no effect
601 self.assertIn('u-boot-align-size-nop', entries)
602 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600603 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700604 self.assertEqual(4, entry.size)
605
606 # Third u-boot has an aligned size too
607 self.assertIn('u-boot-align-size', entries)
608 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600609 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700610 self.assertEqual(32, entry.size)
611
612 # Fourth u-boot has an aligned end
613 self.assertIn('u-boot-align-end', entries)
614 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600615 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700616 self.assertEqual(16, entry.size)
617
618 # Fifth u-boot immediately afterwards
619 self.assertIn('u-boot-align-both', entries)
620 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600621 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700622 self.assertEqual(64, entry.size)
623
624 self.CheckNoGaps(entries)
625 self.assertEqual(128, image._size)
626
627 def testPackAlignPowerOf2(self):
628 """Test that invalid entry alignment is detected"""
629 with self.assertRaises(ValueError) as e:
630 self._DoTestFile('10_pack_align_power2.dts')
631 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
632 "of two", str(e.exception))
633
634 def testPackAlignSizePowerOf2(self):
635 """Test that invalid entry size alignment is detected"""
636 with self.assertRaises(ValueError) as e:
637 self._DoTestFile('11_pack_align_size_power2.dts')
638 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
639 "power of two", str(e.exception))
640
641 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600642 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700643 with self.assertRaises(ValueError) as e:
644 self._DoTestFile('12_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600645 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700646 "align 0x4 (4)", str(e.exception))
647
648 def testPackInvalidSizeAlign(self):
649 """Test that invalid entry size alignment is detected"""
650 with self.assertRaises(ValueError) as e:
651 self._DoTestFile('13_pack_inv_size_align.dts')
652 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
653 "align-size 0x4 (4)", str(e.exception))
654
655 def testPackOverlap(self):
656 """Test that overlapping regions are detected"""
657 with self.assertRaises(ValueError) as e:
658 self._DoTestFile('14_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600659 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700660 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
661 str(e.exception))
662
663 def testPackEntryOverflow(self):
664 """Test that entries that overflow their size are detected"""
665 with self.assertRaises(ValueError) as e:
666 self._DoTestFile('15_pack_overflow.dts')
667 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
668 "but entry size is 0x3 (3)", str(e.exception))
669
670 def testPackImageOverflow(self):
671 """Test that entries which overflow the image size are detected"""
672 with self.assertRaises(ValueError) as e:
673 self._DoTestFile('16_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600674 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700675 "size 0x3 (3)", str(e.exception))
676
677 def testPackImageSize(self):
678 """Test that the image size can be set"""
679 retcode = self._DoTestFile('17_pack_image_size.dts')
680 self.assertEqual(0, retcode)
681 self.assertIn('image', control.images)
682 image = control.images['image']
683 self.assertEqual(7, image._size)
684
685 def testPackImageSizeAlign(self):
686 """Test that image size alignemnt works as expected"""
687 retcode = self._DoTestFile('18_pack_image_align.dts')
688 self.assertEqual(0, retcode)
689 self.assertIn('image', control.images)
690 image = control.images['image']
691 self.assertEqual(16, image._size)
692
693 def testPackInvalidImageAlign(self):
694 """Test that invalid image alignment is detected"""
695 with self.assertRaises(ValueError) as e:
696 self._DoTestFile('19_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600697 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700698 "align-size 0x8 (8)", str(e.exception))
699
700 def testPackAlignPowerOf2(self):
701 """Test that invalid image alignment is detected"""
702 with self.assertRaises(ValueError) as e:
703 self._DoTestFile('20_pack_inv_image_align_power2.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600704 self.assertIn("Section '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700705 "two", str(e.exception))
706
707 def testImagePadByte(self):
708 """Test that the image pad byte can be specified"""
Simon Glass19790632017-11-13 18:55:01 -0700709 with open(self.TestFile('bss_data')) as fd:
710 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass4f443042016-11-25 20:15:52 -0700711 data = self._DoReadFile('21_image_pad.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700712 self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 1) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700713
714 def testImageName(self):
715 """Test that image files can be named"""
716 retcode = self._DoTestFile('22_image_name.dts')
717 self.assertEqual(0, retcode)
718 image = control.images['image1']
719 fname = tools.GetOutputFilename('test-name')
720 self.assertTrue(os.path.exists(fname))
721
722 image = control.images['image2']
723 fname = tools.GetOutputFilename('test-name.xx')
724 self.assertTrue(os.path.exists(fname))
725
726 def testBlobFilename(self):
727 """Test that generic blobs can be provided by filename"""
728 data = self._DoReadFile('23_blob.dts')
729 self.assertEqual(BLOB_DATA, data)
730
731 def testPackSorted(self):
732 """Test that entries can be sorted"""
733 data = self._DoReadFile('24_sorted.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700734 self.assertEqual(chr(0) * 1 + U_BOOT_SPL_DATA + chr(0) * 2 +
Simon Glass4f443042016-11-25 20:15:52 -0700735 U_BOOT_DATA, data)
736
Simon Glass3ab95982018-08-01 15:22:37 -0600737 def testPackZeroOffset(self):
738 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700739 with self.assertRaises(ValueError) as e:
740 self._DoTestFile('25_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600741 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700742 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
743 str(e.exception))
744
745 def testPackUbootDtb(self):
746 """Test that a device tree can be added to U-Boot"""
747 data = self._DoReadFile('26_pack_u_boot_dtb.dts')
748 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700749
750 def testPackX86RomNoSize(self):
751 """Test that the end-at-4gb property requires a size property"""
752 with self.assertRaises(ValueError) as e:
753 self._DoTestFile('27_pack_4gb_no_size.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600754 self.assertIn("Section '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700755 "using end-at-4gb", str(e.exception))
756
757 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600758 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700759 with self.assertRaises(ValueError) as e:
760 self._DoTestFile('28_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600761 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600762 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700763 str(e.exception))
764
765 def testPackX86Rom(self):
766 """Test that a basic x86 ROM can be created"""
767 data = self._DoReadFile('29_x86-rom.dts')
Simon Glassf6898902017-11-13 18:54:59 -0700768 self.assertEqual(U_BOOT_DATA + chr(0) * 7 + U_BOOT_SPL_DATA +
769 chr(0) * 2, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700770
771 def testPackX86RomMeNoDesc(self):
772 """Test that an invalid Intel descriptor entry is detected"""
773 TestFunctional._MakeInputFile('descriptor.bin', '')
774 with self.assertRaises(ValueError) as e:
775 self._DoTestFile('31_x86-rom-me.dts')
776 self.assertIn("Node '/binman/intel-descriptor': Cannot find FD "
777 "signature", str(e.exception))
778
779 def testPackX86RomBadDesc(self):
780 """Test that the Intel requires a descriptor entry"""
781 with self.assertRaises(ValueError) as e:
782 self._DoTestFile('30_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600783 self.assertIn("Node '/binman/intel-me': No offset set with "
784 "offset-unset: should another entry provide this correct "
785 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700786
787 def testPackX86RomMe(self):
788 """Test that an x86 ROM with an ME region can be created"""
789 data = self._DoReadFile('31_x86-rom-me.dts')
790 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
791
792 def testPackVga(self):
793 """Test that an image with a VGA binary can be created"""
794 data = self._DoReadFile('32_intel-vga.dts')
795 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
796
797 def testPackStart16(self):
798 """Test that an image with an x86 start16 region can be created"""
799 data = self._DoReadFile('33_x86-start16.dts')
800 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
801
Simon Glass736bb0a2018-07-06 10:27:17 -0600802 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600803 """Handle running a test for insertion of microcode
804
805 Args:
806 dts_fname: Name of test .dts file
807 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600808 ucode_second: True if the microsecond entry is second instead of
809 third
Simon Glassadc57012018-07-06 10:27:16 -0600810
811 Returns:
812 Tuple:
813 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600814 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600815 in the above (two 4-byte words)
816 """
Simon Glass6b187df2017-11-12 21:52:27 -0700817 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700818
819 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600820 if ucode_second:
821 ucode_content = data[len(nodtb_data):]
822 ucode_pos = len(nodtb_data)
823 dtb_with_ucode = ucode_content[16:]
824 fdt_len = self.GetFdtLen(dtb_with_ucode)
825 else:
826 dtb_with_ucode = data[len(nodtb_data):]
827 fdt_len = self.GetFdtLen(dtb_with_ucode)
828 ucode_content = dtb_with_ucode[fdt_len:]
829 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700830 fname = tools.GetOutputFilename('test.dtb')
831 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600832 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600833 dtb = fdt.FdtScan(fname)
834 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700835 self.assertTrue(ucode)
836 for node in ucode.subnodes:
837 self.assertFalse(node.props.get('data'))
838
Simon Glasse0ff8552016-11-25 20:15:53 -0700839 # Check that the microcode appears immediately after the Fdt
840 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700841 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700842 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
843 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600844 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700845
846 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600847 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700848 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
849 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600850 u_boot = data[:len(nodtb_data)]
851 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700852
853 def testPackUbootMicrocode(self):
854 """Test that x86 microcode can be handled correctly
855
856 We expect to see the following in the image, in order:
857 u-boot-nodtb.bin with a microcode pointer inserted at the correct
858 place
859 u-boot.dtb with the microcode removed
860 the microcode
861 """
862 first, pos_and_size = self._RunMicrocodeTest('34_x86_ucode.dts',
863 U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700864 self.assertEqual('nodtb with microcode' + pos_and_size +
865 ' somewhere in here', first)
866
Simon Glass160a7662017-05-27 07:38:26 -0600867 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700868 """Test that x86 microcode can be handled correctly
869
870 We expect to see the following in the image, in order:
871 u-boot-nodtb.bin with a microcode pointer inserted at the correct
872 place
873 u-boot.dtb with the microcode
874 an empty microcode region
875 """
876 # We need the libfdt library to run this test since only that allows
877 # finding the offset of a property. This is required by
878 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glasse0ff8552016-11-25 20:15:53 -0700879 data = self._DoReadFile('35_x86_single_ucode.dts', True)
880
881 second = data[len(U_BOOT_NODTB_DATA):]
882
883 fdt_len = self.GetFdtLen(second)
884 third = second[fdt_len:]
885 second = second[:fdt_len]
886
Simon Glass160a7662017-05-27 07:38:26 -0600887 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
888 self.assertIn(ucode_data, second)
889 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700890
Simon Glass160a7662017-05-27 07:38:26 -0600891 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600892 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600893 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
894 len(ucode_data))
895 first = data[:len(U_BOOT_NODTB_DATA)]
896 self.assertEqual('nodtb with microcode' + pos_and_size +
897 ' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -0700898
Simon Glass75db0862016-11-25 20:15:55 -0700899 def testPackUbootSingleMicrocode(self):
900 """Test that x86 microcode can be handled correctly with fdt_normal.
901 """
Simon Glass160a7662017-05-27 07:38:26 -0600902 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700903
Simon Glassc49deb82016-11-25 20:15:54 -0700904 def testUBootImg(self):
905 """Test that u-boot.img can be put in a file"""
906 data = self._DoReadFile('36_u_boot_img.dts')
907 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -0700908
909 def testNoMicrocode(self):
910 """Test that a missing microcode region is detected"""
911 with self.assertRaises(ValueError) as e:
912 self._DoReadFile('37_x86_no_ucode.dts', True)
913 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
914 "node found in ", str(e.exception))
915
916 def testMicrocodeWithoutNode(self):
917 """Test that a missing u-boot-dtb-with-ucode node is detected"""
918 with self.assertRaises(ValueError) as e:
919 self._DoReadFile('38_x86_ucode_missing_node.dts', True)
920 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
921 "microcode region u-boot-dtb-with-ucode", str(e.exception))
922
923 def testMicrocodeWithoutNode2(self):
924 """Test that a missing u-boot-ucode node is detected"""
925 with self.assertRaises(ValueError) as e:
926 self._DoReadFile('39_x86_ucode_missing_node2.dts', True)
927 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
928 "microcode region u-boot-ucode", str(e.exception))
929
930 def testMicrocodeWithoutPtrInElf(self):
931 """Test that a U-Boot binary without the microcode symbol is detected"""
932 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -0700933 try:
934 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
935 TestFunctional._MakeInputFile('u-boot', fd.read())
936
937 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -0600938 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -0700939 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
940 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
941
942 finally:
943 # Put the original file back
944 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
945 TestFunctional._MakeInputFile('u-boot', fd.read())
946
947 def testMicrocodeNotInImage(self):
948 """Test that microcode must be placed within the image"""
949 with self.assertRaises(ValueError) as e:
950 self._DoReadFile('40_x86_ucode_not_in_image.dts', True)
951 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
952 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -0600953 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -0700954
955 def testWithoutMicrocode(self):
956 """Test that we can cope with an image without microcode (e.g. qemu)"""
957 with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
958 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass16b8d6b2018-07-06 10:27:42 -0600959 data, dtb, _, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -0700960
961 # Now check the device tree has no microcode
962 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
963 second = data[len(U_BOOT_NODTB_DATA):]
964
965 fdt_len = self.GetFdtLen(second)
966 self.assertEqual(dtb, second[:fdt_len])
967
968 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
969 third = data[used_len:]
970 self.assertEqual(chr(0) * (0x200 - used_len), third)
971
972 def testUnknownPosSize(self):
973 """Test that microcode must be placed within the image"""
974 with self.assertRaises(ValueError) as e:
975 self._DoReadFile('41_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -0600976 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -0700977 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -0700978
979 def testPackFsp(self):
980 """Test that an image with a FSP binary can be created"""
981 data = self._DoReadFile('42_intel-fsp.dts')
982 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
983
984 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -0700985 """Test that an image with a CMC binary can be created"""
Simon Glassda229092016-11-25 20:15:56 -0700986 data = self._DoReadFile('43_intel-cmc.dts')
987 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -0700988
989 def testPackVbt(self):
990 """Test that an image with a VBT binary can be created"""
991 data = self._DoReadFile('46_intel-vbt.dts')
992 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -0700993
Simon Glass56509842017-11-12 21:52:25 -0700994 def testSplBssPad(self):
995 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -0700996 # ELF file with a '__bss_size' symbol
997 with open(self.TestFile('bss_data')) as fd:
998 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass56509842017-11-12 21:52:25 -0700999 data = self._DoReadFile('47_spl_bss_pad.dts')
1000 self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data)
1001
Simon Glassb50e5612017-11-13 18:54:54 -07001002 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1003 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1004 with self.assertRaises(ValueError) as e:
1005 data = self._DoReadFile('47_spl_bss_pad.dts')
1006 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1007 str(e.exception))
1008
Simon Glass87722132017-11-12 21:52:26 -07001009 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001010 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass87722132017-11-12 21:52:26 -07001011 data = self._DoReadFile('48_x86-start16-spl.dts')
1012 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1013
Simon Glass736bb0a2018-07-06 10:27:17 -06001014 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1015 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001016
1017 We expect to see the following in the image, in order:
1018 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1019 correct place
1020 u-boot.dtb with the microcode removed
1021 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001022
1023 Args:
1024 dts: Device tree file to use for test
1025 ucode_second: True if the microsecond entry is second instead of
1026 third
Simon Glass6b187df2017-11-12 21:52:27 -07001027 """
1028 # ELF file with a '_dt_ucode_base_size' symbol
1029 with open(self.TestFile('u_boot_ucode_ptr')) as fd:
1030 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
Simon Glass736bb0a2018-07-06 10:27:17 -06001031 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1032 ucode_second=ucode_second)
Simon Glass6b187df2017-11-12 21:52:27 -07001033 self.assertEqual('splnodtb with microc' + pos_and_size +
1034 'ter somewhere in here', first)
1035
Simon Glass736bb0a2018-07-06 10:27:17 -06001036 def testPackUbootSplMicrocode(self):
1037 """Test that x86 microcode can be handled correctly in SPL"""
1038 self._PackUbootSplMicrocode('49_x86_ucode_spl.dts')
1039
1040 def testPackUbootSplMicrocodeReorder(self):
1041 """Test that order doesn't matter for microcode entries
1042
1043 This is the same as testPackUbootSplMicrocode but when we process the
1044 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1045 entry, so we reply on binman to try later.
1046 """
1047 self._PackUbootSplMicrocode('58_x86_ucode_spl_needs_retry.dts',
1048 ucode_second=True)
1049
Simon Glassca4f4ff2017-11-12 21:52:28 -07001050 def testPackMrc(self):
1051 """Test that an image with an MRC binary can be created"""
1052 data = self._DoReadFile('50_intel_mrc.dts')
1053 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1054
Simon Glass47419ea2017-11-13 18:54:55 -07001055 def testSplDtb(self):
1056 """Test that an image with spl/u-boot-spl.dtb can be created"""
1057 data = self._DoReadFile('51_u_boot_spl_dtb.dts')
1058 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1059
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001060 def testSplNoDtb(self):
1061 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
1062 data = self._DoReadFile('52_u_boot_spl_nodtb.dts')
1063 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1064
Simon Glass19790632017-11-13 18:55:01 -07001065 def testSymbols(self):
1066 """Test binman can assign symbols embedded in U-Boot"""
1067 elf_fname = self.TestFile('u_boot_binman_syms')
1068 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1069 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001070 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001071
1072 with open(self.TestFile('u_boot_binman_syms')) as fd:
1073 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
1074 data = self._DoReadFile('53_symbols.dts')
1075 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
1076 expected = (sym_values + U_BOOT_SPL_DATA[16:] + chr(0xff) +
1077 U_BOOT_DATA +
1078 sym_values + U_BOOT_SPL_DATA[16:])
1079 self.assertEqual(expected, data)
1080
Simon Glassdd57c132018-06-01 09:38:11 -06001081 def testPackUnitAddress(self):
1082 """Test that we support multiple binaries with the same name"""
1083 data = self._DoReadFile('54_unit_address.dts')
1084 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1085
Simon Glass18546952018-06-01 09:38:16 -06001086 def testSections(self):
1087 """Basic test of sections"""
1088 data = self._DoReadFile('55_sections.dts')
Simon Glass8122f392018-07-17 13:25:28 -06001089 expected = (U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 +
1090 U_BOOT_DATA + '&' * 4)
Simon Glass18546952018-06-01 09:38:16 -06001091 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001092
Simon Glass3b0c3822018-06-01 09:38:20 -06001093 def testMap(self):
1094 """Tests outputting a map of the images"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001095 _, _, map_data, _ = self._DoReadFileDtb('55_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001096 self.assertEqual('''ImagePos Offset Size Name
109700000000 00000000 00000028 main-section
109800000000 00000000 00000010 section@0
109900000000 00000000 00000004 u-boot
110000000010 00000010 00000010 section@1
110100000010 00000000 00000004 u-boot
110200000020 00000020 00000004 section@2
110300000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001104''', map_data)
1105
Simon Glassc8d48ef2018-06-01 09:38:21 -06001106 def testNamePrefix(self):
1107 """Tests that name prefixes are used"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001108 _, _, map_data, _ = self._DoReadFileDtb('56_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001109 self.assertEqual('''ImagePos Offset Size Name
111000000000 00000000 00000028 main-section
111100000000 00000000 00000010 section@0
111200000000 00000000 00000004 ro-u-boot
111300000010 00000010 00000010 section@1
111400000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001115''', map_data)
1116
Simon Glass736bb0a2018-07-06 10:27:17 -06001117 def testUnknownContents(self):
1118 """Test that obtaining the contents works as expected"""
1119 with self.assertRaises(ValueError) as e:
1120 self._DoReadFile('57_unknown_contents.dts', True)
1121 self.assertIn("Section '/binman': Internal error: Could not complete "
1122 "processing of contents: remaining [<_testing.Entry__testing ",
1123 str(e.exception))
1124
Simon Glass5c890232018-07-06 10:27:19 -06001125 def testBadChangeSize(self):
1126 """Test that trying to change the size of an entry fails"""
1127 with self.assertRaises(ValueError) as e:
1128 self._DoReadFile('59_change_size.dts', True)
1129 self.assertIn("Node '/binman/_testing': Cannot update entry size from "
1130 '2 to 1', str(e.exception))
1131
Simon Glass16b8d6b2018-07-06 10:27:42 -06001132 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001133 """Test that we can update the device tree with offset/size info"""
Simon Glass16b8d6b2018-07-06 10:27:42 -06001134 _, _, _, out_dtb_fname = self._DoReadFileDtb('60_fdt_update.dts',
1135 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001136 dtb = fdt.Fdt(out_dtb_fname)
1137 dtb.Scan()
1138 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos'])
Simon Glass16b8d6b2018-07-06 10:27:42 -06001139 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001140 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001141 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001142 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001143 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001144 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001145 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001146 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001147 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001148 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001149 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001150 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001151
Simon Glass3ab95982018-08-01 15:22:37 -06001152 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001153 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001154 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001155 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001156 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001157 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001158 'size': 40
1159 }, props)
1160
1161 def testUpdateFdtBad(self):
1162 """Test that we detect when ProcessFdt never completes"""
1163 with self.assertRaises(ValueError) as e:
1164 self._DoReadFileDtb('61_fdt_update_bad.dts', update_dtb=True)
1165 self.assertIn('Could not complete processing of Fdt: remaining '
1166 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001167
Simon Glass53af22a2018-07-17 13:25:32 -06001168 def testEntryArgs(self):
1169 """Test passing arguments to entries from the command line"""
1170 entry_args = {
1171 'test-str-arg': 'test1',
1172 'test-int-arg': '456',
1173 }
1174 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1175 self.assertIn('image', control.images)
1176 entry = control.images['image'].GetEntries()['_testing']
1177 self.assertEqual('test0', entry.test_str_fdt)
1178 self.assertEqual('test1', entry.test_str_arg)
1179 self.assertEqual(123, entry.test_int_fdt)
1180 self.assertEqual(456, entry.test_int_arg)
1181
1182 def testEntryArgsMissing(self):
1183 """Test missing arguments and properties"""
1184 entry_args = {
1185 'test-int-arg': '456',
1186 }
1187 self._DoReadFileDtb('63_entry_args_missing.dts', entry_args=entry_args)
1188 entry = control.images['image'].GetEntries()['_testing']
1189 self.assertEqual('test0', entry.test_str_fdt)
1190 self.assertEqual(None, entry.test_str_arg)
1191 self.assertEqual(None, entry.test_int_fdt)
1192 self.assertEqual(456, entry.test_int_arg)
1193
1194 def testEntryArgsRequired(self):
1195 """Test missing arguments and properties"""
1196 entry_args = {
1197 'test-int-arg': '456',
1198 }
1199 with self.assertRaises(ValueError) as e:
1200 self._DoReadFileDtb('64_entry_args_required.dts')
1201 self.assertIn("Node '/binman/_testing': Missing required "
1202 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1203 str(e.exception))
1204
1205 def testEntryArgsInvalidFormat(self):
1206 """Test that an invalid entry-argument format is detected"""
1207 args = ['-d', self.TestFile('64_entry_args_required.dts'), '-ano-value']
1208 with self.assertRaises(ValueError) as e:
1209 self._DoBinman(*args)
1210 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1211
1212 def testEntryArgsInvalidInteger(self):
1213 """Test that an invalid entry-argument integer is detected"""
1214 entry_args = {
1215 'test-int-arg': 'abc',
1216 }
1217 with self.assertRaises(ValueError) as e:
1218 self._DoReadFileDtb('62_entry_args.dts', entry_args=entry_args)
1219 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1220 "'test-int-arg' (value 'abc') to integer",
1221 str(e.exception))
1222
1223 def testEntryArgsInvalidDatatype(self):
1224 """Test that an invalid entry-argument datatype is detected
1225
1226 This test could be written in entry_test.py except that it needs
1227 access to control.entry_args, which seems more than that module should
1228 be able to see.
1229 """
1230 entry_args = {
1231 'test-bad-datatype-arg': '12',
1232 }
1233 with self.assertRaises(ValueError) as e:
1234 self._DoReadFileDtb('65_entry_args_unknown_datatype.dts',
1235 entry_args=entry_args)
1236 self.assertIn('GetArg() internal error: Unknown data type ',
1237 str(e.exception))
1238
Simon Glassbb748372018-07-17 13:25:33 -06001239 def testText(self):
1240 """Test for a text entry type"""
1241 entry_args = {
1242 'test-id': TEXT_DATA,
1243 'test-id2': TEXT_DATA2,
1244 'test-id3': TEXT_DATA3,
1245 }
1246 data, _, _, _ = self._DoReadFileDtb('66_text.dts',
1247 entry_args=entry_args)
1248 expected = (TEXT_DATA + chr(0) * (8 - len(TEXT_DATA)) + TEXT_DATA2 +
1249 TEXT_DATA3 + 'some text')
1250 self.assertEqual(expected, data)
1251
Simon Glassfd8d1f72018-07-17 13:25:36 -06001252 def testEntryDocs(self):
1253 """Test for creation of entry documentation"""
1254 with test_util.capture_sys_output() as (stdout, stderr):
1255 control.WriteEntryDocs(binman.GetEntryModules())
1256 self.assertTrue(len(stdout.getvalue()) > 0)
1257
1258 def testEntryDocsMissing(self):
1259 """Test handling of missing entry documentation"""
1260 with self.assertRaises(ValueError) as e:
1261 with test_util.capture_sys_output() as (stdout, stderr):
1262 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1263 self.assertIn('Documentation is missing for modules: u_boot',
1264 str(e.exception))
1265
Simon Glass11e36cc2018-07-17 13:25:38 -06001266 def testFmap(self):
1267 """Basic test of generation of a flashrom fmap"""
1268 data = self._DoReadFile('67_fmap.dts')
1269 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1270 expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12
1271 self.assertEqual(expected, data[:32])
1272 self.assertEqual('__FMAP__', fhdr.signature)
1273 self.assertEqual(1, fhdr.ver_major)
1274 self.assertEqual(0, fhdr.ver_minor)
1275 self.assertEqual(0, fhdr.base)
1276 self.assertEqual(16 + 16 +
1277 fmap_util.FMAP_HEADER_LEN +
1278 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
1279 self.assertEqual('FMAP', fhdr.name)
1280 self.assertEqual(3, fhdr.nareas)
1281 for fentry in fentries:
1282 self.assertEqual(0, fentry.flags)
1283
1284 self.assertEqual(0, fentries[0].offset)
1285 self.assertEqual(4, fentries[0].size)
1286 self.assertEqual('RO_U_BOOT', fentries[0].name)
1287
1288 self.assertEqual(16, fentries[1].offset)
1289 self.assertEqual(4, fentries[1].size)
1290 self.assertEqual('RW_U_BOOT', fentries[1].name)
1291
1292 self.assertEqual(32, fentries[2].offset)
1293 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1294 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
1295 self.assertEqual('FMAP', fentries[2].name)
1296
Simon Glassec127af2018-07-17 13:25:39 -06001297 def testBlobNamedByArg(self):
1298 """Test we can add a blob with the filename coming from an entry arg"""
1299 entry_args = {
1300 'cros-ec-rw-path': 'ecrw.bin',
1301 }
1302 data, _, _, _ = self._DoReadFileDtb('68_blob_named_by_arg.dts',
1303 entry_args=entry_args)
1304
Simon Glass3af8e492018-07-17 13:25:40 -06001305 def testFill(self):
1306 """Test for an fill entry type"""
1307 data = self._DoReadFile('69_fill.dts')
1308 expected = 8 * chr(0xff) + 8 * chr(0)
1309 self.assertEqual(expected, data)
1310
1311 def testFillNoSize(self):
1312 """Test for an fill entry type with no size"""
1313 with self.assertRaises(ValueError) as e:
1314 self._DoReadFile('70_fill_no_size.dts')
1315 self.assertIn("'fill' entry must have a size property",
1316 str(e.exception))
1317
Simon Glass0ef87aa2018-07-17 13:25:44 -06001318 def _HandleGbbCommand(self, pipe_list):
1319 """Fake calls to the futility utility"""
1320 if pipe_list[0][0] == 'futility':
1321 fname = pipe_list[0][-1]
1322 # Append our GBB data to the file, which will happen every time the
1323 # futility command is called.
1324 with open(fname, 'a') as fd:
1325 fd.write(GBB_DATA)
1326 return command.CommandResult()
1327
1328 def testGbb(self):
1329 """Test for the Chromium OS Google Binary Block"""
1330 command.test_result = self._HandleGbbCommand
1331 entry_args = {
1332 'keydir': 'devkeys',
1333 'bmpblk': 'bmpblk.bin',
1334 }
1335 data, _, _, _ = self._DoReadFileDtb('71_gbb.dts', entry_args=entry_args)
1336
1337 # Since futility
1338 expected = GBB_DATA + GBB_DATA + 8 * chr(0) + (0x2180 - 16) * chr(0)
1339 self.assertEqual(expected, data)
1340
1341 def testGbbTooSmall(self):
1342 """Test for the Chromium OS Google Binary Block being large enough"""
1343 with self.assertRaises(ValueError) as e:
1344 self._DoReadFileDtb('72_gbb_too_small.dts')
1345 self.assertIn("Node '/binman/gbb': GBB is too small",
1346 str(e.exception))
1347
1348 def testGbbNoSize(self):
1349 """Test for the Chromium OS Google Binary Block having a size"""
1350 with self.assertRaises(ValueError) as e:
1351 self._DoReadFileDtb('73_gbb_no_size.dts')
1352 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1353 str(e.exception))
1354
Simon Glass24d0d3c2018-07-17 13:25:47 -06001355 def _HandleVblockCommand(self, pipe_list):
1356 """Fake calls to the futility utility"""
1357 if pipe_list[0][0] == 'futility':
1358 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001359 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001360 fd.write(VBLOCK_DATA)
1361 return command.CommandResult()
1362
1363 def testVblock(self):
1364 """Test for the Chromium OS Verified Boot Block"""
1365 command.test_result = self._HandleVblockCommand
1366 entry_args = {
1367 'keydir': 'devkeys',
1368 }
1369 data, _, _, _ = self._DoReadFileDtb('74_vblock.dts',
1370 entry_args=entry_args)
1371 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1372 self.assertEqual(expected, data)
1373
1374 def testVblockNoContent(self):
1375 """Test we detect a vblock which has no content to sign"""
1376 with self.assertRaises(ValueError) as e:
1377 self._DoReadFile('75_vblock_no_content.dts')
1378 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1379 'property', str(e.exception))
1380
1381 def testVblockBadPhandle(self):
1382 """Test that we detect a vblock with an invalid phandle in contents"""
1383 with self.assertRaises(ValueError) as e:
1384 self._DoReadFile('76_vblock_bad_phandle.dts')
1385 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1386 '1000', str(e.exception))
1387
1388 def testVblockBadEntry(self):
1389 """Test that we detect an entry that points to a non-entry"""
1390 with self.assertRaises(ValueError) as e:
1391 self._DoReadFile('77_vblock_bad_entry.dts')
1392 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1393 "'other'", str(e.exception))
1394
Simon Glassb8ef5b62018-07-17 13:25:48 -06001395 def testTpl(self):
1396 """Test that an image with TPL and ots device tree can be created"""
1397 # ELF file with a '__bss_size' symbol
1398 with open(self.TestFile('bss_data')) as fd:
1399 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1400 data = self._DoReadFile('78_u_boot_tpl.dts')
1401 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1402
Simon Glass15a587c2018-07-17 13:25:51 -06001403 def testUsesPos(self):
1404 """Test that the 'pos' property cannot be used anymore"""
1405 with self.assertRaises(ValueError) as e:
1406 data = self._DoReadFile('79_uses_pos.dts')
1407 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1408 "'pos'", str(e.exception))
1409
Simon Glassd178eab2018-09-14 04:57:08 -06001410 def testFillZero(self):
1411 """Test for an fill entry type with a size of 0"""
1412 data = self._DoReadFile('80_fill_empty.dts')
1413 self.assertEqual(chr(0) * 16, data)
1414
Simon Glass0b489362018-09-14 04:57:09 -06001415 def testTextMissing(self):
1416 """Test for a text entry type where there is no text"""
1417 with self.assertRaises(ValueError) as e:
1418 self._DoReadFileDtb('66_text.dts',)
1419 self.assertIn("Node '/binman/text': No value provided for text label "
1420 "'test-id'", str(e.exception))
1421
Simon Glass35b384c2018-09-14 04:57:10 -06001422 def testPackStart16Tpl(self):
1423 """Test that an image with an x86 start16 TPL region can be created"""
1424 data = self._DoReadFile('81_x86-start16-tpl.dts')
1425 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1426
Simon Glass0bfa7b02018-09-14 04:57:12 -06001427 def testSelectImage(self):
1428 """Test that we can select which images to build"""
1429 with test_util.capture_sys_output() as (stdout, stderr):
1430 retcode = self._DoTestFile('06_dual_image.dts', images=['image2'])
1431 self.assertEqual(0, retcode)
1432 self.assertIn('Skipping images: image1', stdout.getvalue())
1433
1434 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1435 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
1436
Simon Glass6ed45ba2018-09-14 04:57:24 -06001437 def testUpdateFdtAll(self):
1438 """Test that all device trees are updated with offset/size info"""
1439 data, _, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1440 use_real_dtb=True, update_dtb=True)
1441
1442 base_expected = {
1443 'section:image-pos': 0,
1444 'u-boot-tpl-dtb:size': 513,
1445 'u-boot-spl-dtb:size': 513,
1446 'u-boot-spl-dtb:offset': 493,
1447 'image-pos': 0,
1448 'section/u-boot-dtb:image-pos': 0,
1449 'u-boot-spl-dtb:image-pos': 493,
1450 'section/u-boot-dtb:size': 493,
1451 'u-boot-tpl-dtb:image-pos': 1006,
1452 'section/u-boot-dtb:offset': 0,
1453 'section:size': 493,
1454 'offset': 0,
1455 'section:offset': 0,
1456 'u-boot-tpl-dtb:offset': 1006,
1457 'size': 1519
1458 }
1459
1460 # We expect three device-tree files in the output, one after the other.
1461 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1462 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1463 # main U-Boot tree. All three should have the same postions and offset.
1464 start = 0
1465 for item in ['', 'spl', 'tpl']:
1466 dtb = fdt.Fdt.FromData(data[start:])
1467 dtb.Scan()
1468 props = self._GetPropTree(dtb, ['offset', 'size', 'image-pos',
1469 'spl', 'tpl'])
1470 expected = dict(base_expected)
1471 if item:
1472 expected[item] = 0
1473 self.assertEqual(expected, props)
1474 start += dtb._fdt_obj.totalsize()
1475
1476 def testUpdateFdtOutput(self):
1477 """Test that output DTB files are updated"""
1478 try:
1479 data, dtb_data, _, _ = self._DoReadFileDtb('82_fdt_update_all.dts',
1480 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1481
1482 # Unfortunately, compiling a source file always results in a file
1483 # called source.dtb (see fdt_util.EnsureCompiled()). The test
1484 # source file (e.g. test/75_fdt_update_all.dts) thus does not enter
1485 # binman as a file called u-boot.dtb. To fix this, copy the file
1486 # over to the expected place.
1487 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1488 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1489 start = 0
1490 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1491 'tpl/u-boot-tpl.dtb.out']:
1492 dtb = fdt.Fdt.FromData(data[start:])
1493 size = dtb._fdt_obj.totalsize()
1494 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1495 outdata = tools.ReadFile(pathname)
1496 name = os.path.split(fname)[0]
1497
1498 if name:
1499 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1500 else:
1501 orig_indata = dtb_data
1502 self.assertNotEqual(outdata, orig_indata,
1503 "Expected output file '%s' be updated" % pathname)
1504 self.assertEqual(outdata, data[start:start + size],
1505 "Expected output file '%s' to match output image" %
1506 pathname)
1507 start += size
1508 finally:
1509 self._ResetDtbs()
1510
Simon Glass83d73c22018-09-14 04:57:26 -06001511 def _decompress(self, data):
1512 out = os.path.join(self._indir, 'lz4.tmp')
1513 with open(out, 'wb') as fd:
1514 fd.write(data)
1515 return tools.Run('lz4', '-dc', out)
1516 '''
1517 try:
1518 orig = lz4.frame.decompress(data)
1519 except AttributeError:
1520 orig = lz4.decompress(data)
1521 '''
1522
1523 def testCompress(self):
1524 """Test compression of blobs"""
1525 data, _, _, out_dtb_fname = self._DoReadFileDtb('83_compress.dts',
1526 use_real_dtb=True, update_dtb=True)
1527 dtb = fdt.Fdt(out_dtb_fname)
1528 dtb.Scan()
1529 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1530 orig = self._decompress(data)
1531 self.assertEquals(COMPRESS_DATA, orig)
1532 expected = {
1533 'blob:uncomp-size': len(COMPRESS_DATA),
1534 'blob:size': len(data),
1535 'size': len(data),
1536 }
1537 self.assertEqual(expected, props)
1538
Simon Glass53af22a2018-07-17 13:25:32 -06001539
Simon Glass9fc60b42017-11-12 21:52:22 -07001540if __name__ == "__main__":
1541 unittest.main()