blob: bb8862662775c3ff01151250a8b984c29c8f422f [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glassd5164a72019-07-08 13:18:49 -06009from __future__ import print_function
10
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
14import shutil
15import struct
16import sys
17import tempfile
18import unittest
19
20import binman
Simon Glassac62fba2019-07-08 13:18:53 -060021import cbfs_util
Simon Glass4f443042016-11-25 20:15:52 -070022import cmdline
23import command
24import control
Simon Glass19790632017-11-13 18:55:01 -070025import elf
Simon Glass99ed4a22017-05-27 07:38:30 -060026import fdt
Simon Glasse1925fa2019-07-08 14:25:44 -060027from etype import fdtmap
Simon Glass2d260032019-07-08 14:25:45 -060028from etype import image_header
Simon Glass4f443042016-11-25 20:15:52 -070029import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060030import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060031import test_util
Simon Glassc5ac1382019-07-08 13:18:54 -060032import gzip
Simon Glassffded752019-07-08 14:25:46 -060033from image import Image
Simon Glassc55a50f2018-09-14 04:57:19 -060034import state
Simon Glass4f443042016-11-25 20:15:52 -070035import tools
36import tout
37
38# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
41U_BOOT_SPL_DATA = b'56780123456789abcde'
42U_BOOT_TPL_DATA = b'tpl'
43BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
52PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
53U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
54U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
55U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
56FSP_DATA = b'fsp'
57CMC_DATA = b'cmc'
58VBT_DATA = b'vbt'
59MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060060TEXT_DATA = 'text'
61TEXT_DATA2 = 'text2'
62TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060063CROS_EC_RW_DATA = b'ecrw'
64GBB_DATA = b'gbbd'
65BMPBLK_DATA = b'bmp'
66VBLOCK_DATA = b'vblk'
67FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
68 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060069COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060070REFCODE_DATA = b'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060071
Simon Glass6ccbfcd2019-07-20 12:23:47 -060072# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060073EXTRACT_DTB_SIZE = 0x3c9
74
Simon Glass6ccbfcd2019-07-20 12:23:47 -060075# Properties expected to be in the device tree when update_dtb is used
76BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
77
Simon Glass4f443042016-11-25 20:15:52 -070078
79class TestFunctional(unittest.TestCase):
80 """Functional tests for binman
81
82 Most of these use a sample .dts file to build an image and then check
83 that it looks correct. The sample files are in the test/ subdirectory
84 and are numbered.
85
86 For each entry type a very small test file is created using fixed
87 string contents. This makes it easy to test that things look right, and
88 debug problems.
89
90 In some cases a 'real' file must be used - these are also supplied in
91 the test/ diurectory.
92 """
93 @classmethod
94 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070095 global entry
96 import entry
97
Simon Glass4f443042016-11-25 20:15:52 -070098 # Handle the case where argv[0] is 'python'
99 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
100 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
101
102 # Create a temporary directory for input files
103 self._indir = tempfile.mkdtemp(prefix='binmant.')
104
105 # Create some test files
106 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
107 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
108 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600109 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700110 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700111 TestFunctional._MakeInputFile('me.bin', ME_DATA)
112 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600113 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700114 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530115 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700116 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
117 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600118 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
119 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700120 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700121 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
122 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600123 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
124 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700125 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
126 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700127 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700128 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600129 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600130 TestFunctional._MakeInputDir('devkeys')
131 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600132 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700133
Simon Glasse0ff8552016-11-25 20:15:53 -0700134 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600135 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700136 TestFunctional._MakeInputFile('u-boot', fd.read())
137
138 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600139 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700140 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
141
Simon Glass0a98b282018-09-14 04:57:28 -0600142 shutil.copytree(self.TestFile('files'),
143 os.path.join(self._indir, 'files'))
144
Simon Glass83d73c22018-09-14 04:57:26 -0600145 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
146
Simon Glassac62fba2019-07-08 13:18:53 -0600147 # Travis-CI may have an old lz4
148 self.have_lz4 = True
149 try:
150 tools.Run('lz4', '--no-frame-crc', '-c',
151 os.path.join(self._indir, 'u-boot.bin'))
152 except:
153 self.have_lz4 = False
154
Simon Glass4f443042016-11-25 20:15:52 -0700155 @classmethod
156 def tearDownClass(self):
157 """Remove the temporary input directory and its contents"""
Simon Glassd5164a72019-07-08 13:18:49 -0600158 if self.preserve_indir:
159 print('Preserving input dir: %s' % self._indir)
160 else:
161 if self._indir:
162 shutil.rmtree(self._indir)
Simon Glass4f443042016-11-25 20:15:52 -0700163 self._indir = None
164
Simon Glassd5164a72019-07-08 13:18:49 -0600165 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600166 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600167 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600168 """Accept arguments controlling test execution
169
170 Args:
171 preserve_indir: Preserve the shared input directory used by all
172 tests in this class.
173 preserve_outdir: Preserve the output directories used by tests. Each
174 test has its own, so this is normally only useful when running a
175 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600176 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600177 """
178 cls.preserve_indir = preserve_indir
179 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600180 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600181 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600182
Simon Glassac62fba2019-07-08 13:18:53 -0600183 def _CheckLz4(self):
184 if not self.have_lz4:
185 self.skipTest('lz4 --no-frame-crc not available')
186
Simon Glass4f443042016-11-25 20:15:52 -0700187 def setUp(self):
188 # Enable this to turn on debugging output
189 # tout.Init(tout.DEBUG)
190 command.test_result = None
191
192 def tearDown(self):
193 """Remove the temporary output directory"""
Simon Glassd5164a72019-07-08 13:18:49 -0600194 if self.preserve_outdirs:
195 print('Preserving output dir: %s' % tools.outdir)
196 else:
197 tools._FinaliseForTest()
Simon Glass4f443042016-11-25 20:15:52 -0700198
Simon Glassb8ef5b62018-07-17 13:25:48 -0600199 @classmethod
200 def _ResetDtbs(self):
201 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
202 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
203 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
204
Simon Glass4f443042016-11-25 20:15:52 -0700205 def _RunBinman(self, *args, **kwargs):
206 """Run binman using the command line
207
208 Args:
209 Arguments to pass, as a list of strings
210 kwargs: Arguments to pass to Command.RunPipe()
211 """
212 result = command.RunPipe([[self._binman_pathname] + list(args)],
213 capture=True, capture_stderr=True, raise_on_error=False)
214 if result.return_code and kwargs.get('raise_on_error', True):
215 raise Exception("Error running '%s': %s" % (' '.join(args),
216 result.stdout + result.stderr))
217 return result
218
Simon Glass53cd5d92019-07-08 14:25:29 -0600219 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700220 """Run binman using directly (in the same process)
221
222 Args:
223 Arguments to pass, as a list of strings
224 Returns:
225 Return value (0 for success)
226 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600227 argv = list(argv)
228 args = cmdline.ParseArgs(argv)
229 args.pager = 'binman-invalid-pager'
230 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700231
232 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600233 # args.verbosity = tout.DEBUG
234 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700235
Simon Glass53af22a2018-07-17 13:25:32 -0600236 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600237 entry_args=None, images=None, use_real_dtb=False,
238 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700239 """Run binman with a given test file
240
241 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600242 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600243 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600244 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600245 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600246 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600247 entry_args: Dict of entry args to supply to binman
248 key: arg name
249 value: value of that arg
250 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700251 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600252 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700253 if debug:
254 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600255 if verbosity is not None:
256 args.append('-v%d' % verbosity)
257 elif self.verbosity:
258 args.append('-v%d' % self.verbosity)
259 if self.toolpath:
260 for path in self.toolpath:
261 args += ['--toolpath', path]
262 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600263 if map:
264 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600265 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600266 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600267 if not use_real_dtb:
268 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600269 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600270 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600271 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600272 if images:
273 for image in images:
274 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700275 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700276
277 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700278 """Set up a new test device-tree file
279
280 The given file is compiled and set up as the device tree to be used
281 for ths test.
282
283 Args:
284 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600285 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700286
287 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600288 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700289 """
Simon Glasse0e62752018-10-01 21:12:41 -0600290 tools.PrepareOutputDir(None)
Simon Glass4f443042016-11-25 20:15:52 -0700291 dtb = fdt_util.EnsureCompiled(self.TestFile(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600292 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700293 data = fd.read()
294 TestFunctional._MakeInputFile(outfile, data)
Simon Glasse0e62752018-10-01 21:12:41 -0600295 tools.FinaliseOutputDir()
296 return data
Simon Glass4f443042016-11-25 20:15:52 -0700297
Simon Glass6ed45ba2018-09-14 04:57:24 -0600298 def _GetDtbContentsForSplTpl(self, dtb_data, name):
299 """Create a version of the main DTB for SPL or SPL
300
301 For testing we don't actually have different versions of the DTB. With
302 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
303 we don't normally have any unwanted nodes.
304
305 We still want the DTBs for SPL and TPL to be different though, since
306 otherwise it is confusing to know which one we are looking at. So add
307 an 'spl' or 'tpl' property to the top-level node.
308 """
309 dtb = fdt.Fdt.FromData(dtb_data)
310 dtb.Scan()
311 dtb.GetNode('/binman').AddZeroProp(name)
312 dtb.Sync(auto_resize=True)
313 dtb.Pack()
314 return dtb.GetContents()
315
Simon Glass16b8d6b2018-07-06 10:27:42 -0600316 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600317 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700318 """Run binman and return the resulting image
319
320 This runs binman with a given test file and then reads the resulting
321 output file. It is a shortcut function since most tests need to do
322 these steps.
323
324 Raises an assertion failure if binman returns a non-zero exit code.
325
326 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600327 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700328 use_real_dtb: True to use the test file as the contents of
329 the u-boot-dtb entry. Normally this is not needed and the
330 test contents (the U_BOOT_DTB_DATA string) can be used.
331 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600332 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600333 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600334 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700335
336 Returns:
337 Tuple:
338 Resulting image contents
339 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600340 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600341 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700342 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700343 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700344 # Use the compiled test file as the u-boot-dtb input
345 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700346 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600347
348 # For testing purposes, make a copy of the DT for SPL and TPL. Add
349 # a node indicating which it is, so aid verification.
350 for name in ['spl', 'tpl']:
351 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
352 outfile = os.path.join(self._indir, dtb_fname)
353 TestFunctional._MakeInputFile(dtb_fname,
354 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700355
356 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600357 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600358 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700359 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600360 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700361
362 # Find the (only) image, read it and return its contents
363 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600364 image_fname = tools.GetOutputFilename('image.bin')
365 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600366 if map:
367 map_fname = tools.GetOutputFilename('image.map')
368 with open(map_fname) as fd:
369 map_data = fd.read()
370 else:
371 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600372 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600373 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700374 finally:
375 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600376 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600377 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700378
Simon Glass3c081312019-07-08 14:25:26 -0600379 def _DoReadFileRealDtb(self, fname):
380 """Run binman with a real .dtb file and return the resulting data
381
382 Args:
383 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
384
385 Returns:
386 Resulting image contents
387 """
388 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
389
Simon Glasse0ff8552016-11-25 20:15:53 -0700390 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600391 """Helper function which discards the device-tree binary
392
393 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600394 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600395 use_real_dtb: True to use the test file as the contents of
396 the u-boot-dtb entry. Normally this is not needed and the
397 test contents (the U_BOOT_DTB_DATA string) can be used.
398 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600399
400 Returns:
401 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600402 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700403 return self._DoReadFileDtb(fname, use_real_dtb)[0]
404
Simon Glass4f443042016-11-25 20:15:52 -0700405 @classmethod
406 def _MakeInputFile(self, fname, contents):
407 """Create a new test input file, creating directories as needed
408
409 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600410 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700411 contents: File contents to write in to the file
412 Returns:
413 Full pathname of file created
414 """
415 pathname = os.path.join(self._indir, fname)
416 dirname = os.path.dirname(pathname)
417 if dirname and not os.path.exists(dirname):
418 os.makedirs(dirname)
419 with open(pathname, 'wb') as fd:
420 fd.write(contents)
421 return pathname
422
423 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600424 def _MakeInputDir(self, dirname):
425 """Create a new test input directory, creating directories as needed
426
427 Args:
428 dirname: Directory name to create
429
430 Returns:
431 Full pathname of directory created
432 """
433 pathname = os.path.join(self._indir, dirname)
434 if not os.path.exists(pathname):
435 os.makedirs(pathname)
436 return pathname
437
438 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600439 def _SetupSplElf(self, src_fname='bss_data'):
440 """Set up an ELF file with a '_dt_ucode_base_size' symbol
441
442 Args:
443 Filename of ELF file to use as SPL
444 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600445 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600446 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
447
448 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700449 def TestFile(self, fname):
450 return os.path.join(self._binman_dir, 'test', fname)
451
452 def AssertInList(self, grep_list, target):
453 """Assert that at least one of a list of things is in a target
454
455 Args:
456 grep_list: List of strings to check
457 target: Target string
458 """
459 for grep in grep_list:
460 if grep in target:
461 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600462 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700463
464 def CheckNoGaps(self, entries):
465 """Check that all entries fit together without gaps
466
467 Args:
468 entries: List of entries to check
469 """
Simon Glass3ab95982018-08-01 15:22:37 -0600470 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700471 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600472 self.assertEqual(offset, entry.offset)
473 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700474
Simon Glasse0ff8552016-11-25 20:15:53 -0700475 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600476 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700477
478 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600479 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700480
481 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600482 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700483 """
484 return struct.unpack('>L', dtb[4:8])[0]
485
Simon Glass086cec92019-07-08 14:25:27 -0600486 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600487 def AddNode(node, path):
488 if node.name != '/':
489 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600490 for prop in node.props.values():
491 if prop.name in prop_names:
492 prop_path = path + ':' + prop.name
493 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
494 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600495 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600496 AddNode(subnode, path)
497
498 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600499 AddNode(dtb.GetRoot(), '')
500 return tree
501
Simon Glass4f443042016-11-25 20:15:52 -0700502 def testRun(self):
503 """Test a basic run with valid args"""
504 result = self._RunBinman('-h')
505
506 def testFullHelp(self):
507 """Test that the full help is displayed with -H"""
508 result = self._RunBinman('-H')
509 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500510 # Remove possible extraneous strings
511 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
512 gothelp = result.stdout.replace(extra, '')
513 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700514 self.assertEqual(0, len(result.stderr))
515 self.assertEqual(0, result.return_code)
516
517 def testFullHelpInternal(self):
518 """Test that the full help is displayed with -H"""
519 try:
520 command.test_result = command.CommandResult()
521 result = self._DoBinman('-H')
522 help_file = os.path.join(self._binman_dir, 'README')
523 finally:
524 command.test_result = None
525
526 def testHelp(self):
527 """Test that the basic help is displayed with -h"""
528 result = self._RunBinman('-h')
529 self.assertTrue(len(result.stdout) > 200)
530 self.assertEqual(0, len(result.stderr))
531 self.assertEqual(0, result.return_code)
532
Simon Glass4f443042016-11-25 20:15:52 -0700533 def testBoard(self):
534 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600535 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700536 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600537 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700538 self.assertEqual(0, result)
539
540 def testNeedBoard(self):
541 """Test that we get an error when no board ius supplied"""
542 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600543 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700544 self.assertIn("Must provide a board to process (use -b <board>)",
545 str(e.exception))
546
547 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600548 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700549 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600550 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700551 # We get one error from libfdt, and a different one from fdtget.
552 self.AssertInList(["Couldn't open blob from 'missing_file'",
553 'No such file or directory'], str(e.exception))
554
555 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600556 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700557
558 Since this is a source file it should be compiled and the error
559 will come from the device-tree compiler (dtc).
560 """
561 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600562 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700563 self.assertIn("FATAL ERROR: Unable to parse input tree",
564 str(e.exception))
565
566 def testMissingNode(self):
567 """Test that a device tree without a 'binman' node generates an error"""
568 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600569 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700570 self.assertIn("does not have a 'binman' node", str(e.exception))
571
572 def testEmpty(self):
573 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600574 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700575 self.assertEqual(0, len(result.stderr))
576 self.assertEqual(0, result.return_code)
577
578 def testInvalidEntry(self):
579 """Test that an invalid entry is flagged"""
580 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600581 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600582 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700583 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
584 "'/binman/not-a-valid-type'", str(e.exception))
585
586 def testSimple(self):
587 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600588 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700589 self.assertEqual(U_BOOT_DATA, data)
590
Simon Glass7fe91732017-11-13 18:55:00 -0700591 def testSimpleDebug(self):
592 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600593 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700594
Simon Glass4f443042016-11-25 20:15:52 -0700595 def testDual(self):
596 """Test that we can handle creating two images
597
598 This also tests image padding.
599 """
Simon Glass741f2d62018-10-01 12:22:30 -0600600 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700601 self.assertEqual(0, retcode)
602
603 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600604 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700605 fname = tools.GetOutputFilename('image1.bin')
606 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600607 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700608 data = fd.read()
609 self.assertEqual(U_BOOT_DATA, data)
610
611 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600612 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700613 fname = tools.GetOutputFilename('image2.bin')
614 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600615 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700616 data = fd.read()
617 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600618 self.assertEqual(tools.GetBytes(0, 3), data[:3])
619 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700620
621 def testBadAlign(self):
622 """Test that an invalid alignment value is detected"""
623 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600624 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700625 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
626 "of two", str(e.exception))
627
628 def testPackSimple(self):
629 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600630 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700631 self.assertEqual(0, retcode)
632 self.assertIn('image', control.images)
633 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600634 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700635 self.assertEqual(5, len(entries))
636
637 # First u-boot
638 self.assertIn('u-boot', entries)
639 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600640 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700641 self.assertEqual(len(U_BOOT_DATA), entry.size)
642
643 # Second u-boot, aligned to 16-byte boundary
644 self.assertIn('u-boot-align', entries)
645 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600646 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700647 self.assertEqual(len(U_BOOT_DATA), entry.size)
648
649 # Third u-boot, size 23 bytes
650 self.assertIn('u-boot-size', entries)
651 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600652 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700653 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
654 self.assertEqual(23, entry.size)
655
656 # Fourth u-boot, placed immediate after the above
657 self.assertIn('u-boot-next', entries)
658 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600659 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700660 self.assertEqual(len(U_BOOT_DATA), entry.size)
661
Simon Glass3ab95982018-08-01 15:22:37 -0600662 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700663 self.assertIn('u-boot-fixed', entries)
664 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600665 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700666 self.assertEqual(len(U_BOOT_DATA), entry.size)
667
Simon Glass8beb11e2019-07-08 14:25:47 -0600668 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700669
670 def testPackExtra(self):
671 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600672 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700673
674 self.assertEqual(0, retcode)
675 self.assertIn('image', control.images)
676 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600677 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700678 self.assertEqual(5, len(entries))
679
680 # First u-boot with padding before and after
681 self.assertIn('u-boot', entries)
682 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600683 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700684 self.assertEqual(3, entry.pad_before)
685 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
686
687 # Second u-boot has an aligned size, but it has no effect
688 self.assertIn('u-boot-align-size-nop', entries)
689 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600690 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700691 self.assertEqual(4, entry.size)
692
693 # Third u-boot has an aligned size too
694 self.assertIn('u-boot-align-size', entries)
695 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600696 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700697 self.assertEqual(32, entry.size)
698
699 # Fourth u-boot has an aligned end
700 self.assertIn('u-boot-align-end', entries)
701 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600702 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700703 self.assertEqual(16, entry.size)
704
705 # Fifth u-boot immediately afterwards
706 self.assertIn('u-boot-align-both', entries)
707 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600708 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700709 self.assertEqual(64, entry.size)
710
711 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600712 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700713
714 def testPackAlignPowerOf2(self):
715 """Test that invalid entry alignment is detected"""
716 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600717 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700718 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
719 "of two", str(e.exception))
720
721 def testPackAlignSizePowerOf2(self):
722 """Test that invalid entry size alignment is detected"""
723 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600724 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700725 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
726 "power of two", str(e.exception))
727
728 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600729 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700730 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600731 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600732 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700733 "align 0x4 (4)", str(e.exception))
734
735 def testPackInvalidSizeAlign(self):
736 """Test that invalid entry size alignment is detected"""
737 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600738 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700739 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
740 "align-size 0x4 (4)", str(e.exception))
741
742 def testPackOverlap(self):
743 """Test that overlapping regions are detected"""
744 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600745 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600746 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) 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 testPackEntryOverflow(self):
751 """Test that entries that overflow their size are detected"""
752 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600753 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700754 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
755 "but entry size is 0x3 (3)", str(e.exception))
756
757 def testPackImageOverflow(self):
758 """Test that entries which overflow the image size are detected"""
759 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600760 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600761 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700762 "size 0x3 (3)", str(e.exception))
763
764 def testPackImageSize(self):
765 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600766 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700767 self.assertEqual(0, retcode)
768 self.assertIn('image', control.images)
769 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600770 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700771
772 def testPackImageSizeAlign(self):
773 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600774 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700775 self.assertEqual(0, retcode)
776 self.assertIn('image', control.images)
777 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600778 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700779
780 def testPackInvalidImageAlign(self):
781 """Test that invalid image alignment is detected"""
782 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600783 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600784 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700785 "align-size 0x8 (8)", str(e.exception))
786
787 def testPackAlignPowerOf2(self):
788 """Test that invalid image alignment is detected"""
789 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600790 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600791 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700792 "two", str(e.exception))
793
794 def testImagePadByte(self):
795 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600796 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600797 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600798 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
799 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700800
801 def testImageName(self):
802 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600803 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700804 self.assertEqual(0, retcode)
805 image = control.images['image1']
806 fname = tools.GetOutputFilename('test-name')
807 self.assertTrue(os.path.exists(fname))
808
809 image = control.images['image2']
810 fname = tools.GetOutputFilename('test-name.xx')
811 self.assertTrue(os.path.exists(fname))
812
813 def testBlobFilename(self):
814 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600815 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700816 self.assertEqual(BLOB_DATA, data)
817
818 def testPackSorted(self):
819 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600820 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600821 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600822 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
823 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700824
Simon Glass3ab95982018-08-01 15:22:37 -0600825 def testPackZeroOffset(self):
826 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700827 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600828 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600829 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700830 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
831 str(e.exception))
832
833 def testPackUbootDtb(self):
834 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600835 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700836 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700837
838 def testPackX86RomNoSize(self):
839 """Test that the end-at-4gb property requires a size property"""
840 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600841 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600842 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700843 "using end-at-4gb", str(e.exception))
844
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530845 def test4gbAndSkipAtStartTogether(self):
846 """Test that the end-at-4gb and skip-at-size property can't be used
847 together"""
848 with self.assertRaises(ValueError) as e:
849 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600850 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530851 "'skip-at-start'", str(e.exception))
852
Simon Glasse0ff8552016-11-25 20:15:53 -0700853 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600854 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700855 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600856 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600857 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600858 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700859 str(e.exception))
860
861 def testPackX86Rom(self):
862 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600863 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600864 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600865 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
866 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700867
868 def testPackX86RomMeNoDesc(self):
869 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600870 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700871 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600872 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600873 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
874 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700875
876 def testPackX86RomBadDesc(self):
877 """Test that the Intel requires a descriptor entry"""
878 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600879 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600880 self.assertIn("Node '/binman/intel-me': No offset set with "
881 "offset-unset: should another entry provide this correct "
882 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700883
884 def testPackX86RomMe(self):
885 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600886 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600887 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
888 if data[:0x1000] != expected_desc:
889 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700890 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
891
892 def testPackVga(self):
893 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600894 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700895 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
896
897 def testPackStart16(self):
898 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600899 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700900 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
901
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530902 def testPackPowerpcMpc85xxBootpgResetvec(self):
903 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
904 created"""
905 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
906 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
907
Simon Glass736bb0a2018-07-06 10:27:17 -0600908 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600909 """Handle running a test for insertion of microcode
910
911 Args:
912 dts_fname: Name of test .dts file
913 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600914 ucode_second: True if the microsecond entry is second instead of
915 third
Simon Glassadc57012018-07-06 10:27:16 -0600916
917 Returns:
918 Tuple:
919 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600920 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600921 in the above (two 4-byte words)
922 """
Simon Glass6b187df2017-11-12 21:52:27 -0700923 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700924
925 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600926 if ucode_second:
927 ucode_content = data[len(nodtb_data):]
928 ucode_pos = len(nodtb_data)
929 dtb_with_ucode = ucode_content[16:]
930 fdt_len = self.GetFdtLen(dtb_with_ucode)
931 else:
932 dtb_with_ucode = data[len(nodtb_data):]
933 fdt_len = self.GetFdtLen(dtb_with_ucode)
934 ucode_content = dtb_with_ucode[fdt_len:]
935 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700936 fname = tools.GetOutputFilename('test.dtb')
937 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600938 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600939 dtb = fdt.FdtScan(fname)
940 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700941 self.assertTrue(ucode)
942 for node in ucode.subnodes:
943 self.assertFalse(node.props.get('data'))
944
Simon Glasse0ff8552016-11-25 20:15:53 -0700945 # Check that the microcode appears immediately after the Fdt
946 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700947 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700948 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
949 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600950 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700951
952 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600953 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700954 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
955 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600956 u_boot = data[:len(nodtb_data)]
957 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700958
959 def testPackUbootMicrocode(self):
960 """Test that x86 microcode can be handled correctly
961
962 We expect to see the following in the image, in order:
963 u-boot-nodtb.bin with a microcode pointer inserted at the correct
964 place
965 u-boot.dtb with the microcode removed
966 the microcode
967 """
Simon Glass741f2d62018-10-01 12:22:30 -0600968 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700969 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600970 self.assertEqual(b'nodtb with microcode' + pos_and_size +
971 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700972
Simon Glass160a7662017-05-27 07:38:26 -0600973 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700974 """Test that x86 microcode can be handled correctly
975
976 We expect to see the following in the image, in order:
977 u-boot-nodtb.bin with a microcode pointer inserted at the correct
978 place
979 u-boot.dtb with the microcode
980 an empty microcode region
981 """
982 # We need the libfdt library to run this test since only that allows
983 # finding the offset of a property. This is required by
984 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600985 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700986
987 second = data[len(U_BOOT_NODTB_DATA):]
988
989 fdt_len = self.GetFdtLen(second)
990 third = second[fdt_len:]
991 second = second[:fdt_len]
992
Simon Glass160a7662017-05-27 07:38:26 -0600993 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
994 self.assertIn(ucode_data, second)
995 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700996
Simon Glass160a7662017-05-27 07:38:26 -0600997 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600998 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -0600999 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1000 len(ucode_data))
1001 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001002 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1003 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001004
Simon Glass75db0862016-11-25 20:15:55 -07001005 def testPackUbootSingleMicrocode(self):
1006 """Test that x86 microcode can be handled correctly with fdt_normal.
1007 """
Simon Glass160a7662017-05-27 07:38:26 -06001008 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001009
Simon Glassc49deb82016-11-25 20:15:54 -07001010 def testUBootImg(self):
1011 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001012 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001013 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001014
1015 def testNoMicrocode(self):
1016 """Test that a missing microcode region is detected"""
1017 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001018 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001019 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1020 "node found in ", str(e.exception))
1021
1022 def testMicrocodeWithoutNode(self):
1023 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1024 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001025 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001026 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1027 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1028
1029 def testMicrocodeWithoutNode2(self):
1030 """Test that a missing u-boot-ucode node is detected"""
1031 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001032 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001033 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1034 "microcode region u-boot-ucode", str(e.exception))
1035
1036 def testMicrocodeWithoutPtrInElf(self):
1037 """Test that a U-Boot binary without the microcode symbol is detected"""
1038 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001039 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001040 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001041 TestFunctional._MakeInputFile('u-boot', fd.read())
1042
1043 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001044 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001045 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1046 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1047
1048 finally:
1049 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -06001050 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001051 TestFunctional._MakeInputFile('u-boot', fd.read())
1052
1053 def testMicrocodeNotInImage(self):
1054 """Test that microcode must be placed within the image"""
1055 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001056 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001057 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1058 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001059 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001060
1061 def testWithoutMicrocode(self):
1062 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001063 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001064 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001065 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001066
1067 # Now check the device tree has no microcode
1068 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1069 second = data[len(U_BOOT_NODTB_DATA):]
1070
1071 fdt_len = self.GetFdtLen(second)
1072 self.assertEqual(dtb, second[:fdt_len])
1073
1074 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1075 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001076 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001077
1078 def testUnknownPosSize(self):
1079 """Test that microcode must be placed within the image"""
1080 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001081 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001082 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001083 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001084
1085 def testPackFsp(self):
1086 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001087 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001088 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1089
1090 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001091 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001092 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001093 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001094
1095 def testPackVbt(self):
1096 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001097 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001098 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001099
Simon Glass56509842017-11-12 21:52:25 -07001100 def testSplBssPad(self):
1101 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001102 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001103 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001104 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001105 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1106 data)
Simon Glass56509842017-11-12 21:52:25 -07001107
Simon Glass86af5112018-10-01 21:12:42 -06001108 def testSplBssPadMissing(self):
1109 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001110 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001111 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001112 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001113 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1114 str(e.exception))
1115
Simon Glass87722132017-11-12 21:52:26 -07001116 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001117 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001118 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001119 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1120
Simon Glass736bb0a2018-07-06 10:27:17 -06001121 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1122 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001123
1124 We expect to see the following in the image, in order:
1125 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1126 correct place
1127 u-boot.dtb with the microcode removed
1128 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001129
1130 Args:
1131 dts: Device tree file to use for test
1132 ucode_second: True if the microsecond entry is second instead of
1133 third
Simon Glass6b187df2017-11-12 21:52:27 -07001134 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001135 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001136 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1137 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001138 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1139 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001140
Simon Glass736bb0a2018-07-06 10:27:17 -06001141 def testPackUbootSplMicrocode(self):
1142 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001143 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001144
1145 def testPackUbootSplMicrocodeReorder(self):
1146 """Test that order doesn't matter for microcode entries
1147
1148 This is the same as testPackUbootSplMicrocode but when we process the
1149 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1150 entry, so we reply on binman to try later.
1151 """
Simon Glass741f2d62018-10-01 12:22:30 -06001152 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001153 ucode_second=True)
1154
Simon Glassca4f4ff2017-11-12 21:52:28 -07001155 def testPackMrc(self):
1156 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001157 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001158 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1159
Simon Glass47419ea2017-11-13 18:54:55 -07001160 def testSplDtb(self):
1161 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001162 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001163 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1164
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001165 def testSplNoDtb(self):
1166 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001167 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001168 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1169
Simon Glass19790632017-11-13 18:55:01 -07001170 def testSymbols(self):
1171 """Test binman can assign symbols embedded in U-Boot"""
1172 elf_fname = self.TestFile('u_boot_binman_syms')
1173 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1174 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001175 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001176
Simon Glass11ae93e2018-10-01 21:12:47 -06001177 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001178 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001179 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001180 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1181 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1182 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001183 self.assertEqual(expected, data)
1184
Simon Glassdd57c132018-06-01 09:38:11 -06001185 def testPackUnitAddress(self):
1186 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001187 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001188 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1189
Simon Glass18546952018-06-01 09:38:16 -06001190 def testSections(self):
1191 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001192 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001193 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1194 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1195 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001196 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001197
Simon Glass3b0c3822018-06-01 09:38:20 -06001198 def testMap(self):
1199 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001200 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001201 self.assertEqual('''ImagePos Offset Size Name
120200000000 00000000 00000028 main-section
120300000000 00000000 00000010 section@0
120400000000 00000000 00000004 u-boot
120500000010 00000010 00000010 section@1
120600000010 00000000 00000004 u-boot
120700000020 00000020 00000004 section@2
120800000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001209''', map_data)
1210
Simon Glassc8d48ef2018-06-01 09:38:21 -06001211 def testNamePrefix(self):
1212 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001213 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001214 self.assertEqual('''ImagePos Offset Size Name
121500000000 00000000 00000028 main-section
121600000000 00000000 00000010 section@0
121700000000 00000000 00000004 ro-u-boot
121800000010 00000010 00000010 section@1
121900000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001220''', map_data)
1221
Simon Glass736bb0a2018-07-06 10:27:17 -06001222 def testUnknownContents(self):
1223 """Test that obtaining the contents works as expected"""
1224 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001225 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001226 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass736bb0a2018-07-06 10:27:17 -06001227 "processing of contents: remaining [<_testing.Entry__testing ",
1228 str(e.exception))
1229
Simon Glass5c890232018-07-06 10:27:19 -06001230 def testBadChangeSize(self):
1231 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001232 try:
1233 state.SetAllowEntryExpansion(False)
1234 with self.assertRaises(ValueError) as e:
1235 self._DoReadFile('059_change_size.dts', True)
1236 self.assertIn("Node '/binman/_testing': Cannot update entry size from 1 to 2",
1237 str(e.exception))
1238 finally:
1239 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001240
Simon Glass16b8d6b2018-07-06 10:27:42 -06001241 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001242 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001243 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001244 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001245 dtb = fdt.Fdt(out_dtb_fname)
1246 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06001247 props = self._GetPropTree(dtb, BASE_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001248 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001249 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001250 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001251 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001252 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001253 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001254 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001255 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001256 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001257 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001258 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001259 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001260
Simon Glass3ab95982018-08-01 15:22:37 -06001261 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001262 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001263 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001264 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001265 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001266 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001267 'size': 40
1268 }, props)
1269
1270 def testUpdateFdtBad(self):
1271 """Test that we detect when ProcessFdt never completes"""
1272 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001273 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001274 self.assertIn('Could not complete processing of Fdt: remaining '
1275 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001276
Simon Glass53af22a2018-07-17 13:25:32 -06001277 def testEntryArgs(self):
1278 """Test passing arguments to entries from the command line"""
1279 entry_args = {
1280 'test-str-arg': 'test1',
1281 'test-int-arg': '456',
1282 }
Simon Glass741f2d62018-10-01 12:22:30 -06001283 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001284 self.assertIn('image', control.images)
1285 entry = control.images['image'].GetEntries()['_testing']
1286 self.assertEqual('test0', entry.test_str_fdt)
1287 self.assertEqual('test1', entry.test_str_arg)
1288 self.assertEqual(123, entry.test_int_fdt)
1289 self.assertEqual(456, entry.test_int_arg)
1290
1291 def testEntryArgsMissing(self):
1292 """Test missing arguments and properties"""
1293 entry_args = {
1294 'test-int-arg': '456',
1295 }
Simon Glass741f2d62018-10-01 12:22:30 -06001296 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001297 entry = control.images['image'].GetEntries()['_testing']
1298 self.assertEqual('test0', entry.test_str_fdt)
1299 self.assertEqual(None, entry.test_str_arg)
1300 self.assertEqual(None, entry.test_int_fdt)
1301 self.assertEqual(456, entry.test_int_arg)
1302
1303 def testEntryArgsRequired(self):
1304 """Test missing arguments and properties"""
1305 entry_args = {
1306 'test-int-arg': '456',
1307 }
1308 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001309 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001310 self.assertIn("Node '/binman/_testing': Missing required "
1311 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1312 str(e.exception))
1313
1314 def testEntryArgsInvalidFormat(self):
1315 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001316 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1317 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001318 with self.assertRaises(ValueError) as e:
1319 self._DoBinman(*args)
1320 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1321
1322 def testEntryArgsInvalidInteger(self):
1323 """Test that an invalid entry-argument integer is detected"""
1324 entry_args = {
1325 'test-int-arg': 'abc',
1326 }
1327 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001328 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001329 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1330 "'test-int-arg' (value 'abc') to integer",
1331 str(e.exception))
1332
1333 def testEntryArgsInvalidDatatype(self):
1334 """Test that an invalid entry-argument datatype is detected
1335
1336 This test could be written in entry_test.py except that it needs
1337 access to control.entry_args, which seems more than that module should
1338 be able to see.
1339 """
1340 entry_args = {
1341 'test-bad-datatype-arg': '12',
1342 }
1343 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001344 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001345 entry_args=entry_args)
1346 self.assertIn('GetArg() internal error: Unknown data type ',
1347 str(e.exception))
1348
Simon Glassbb748372018-07-17 13:25:33 -06001349 def testText(self):
1350 """Test for a text entry type"""
1351 entry_args = {
1352 'test-id': TEXT_DATA,
1353 'test-id2': TEXT_DATA2,
1354 'test-id3': TEXT_DATA3,
1355 }
Simon Glass741f2d62018-10-01 12:22:30 -06001356 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001357 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001358 expected = (tools.ToBytes(TEXT_DATA) +
1359 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1360 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001361 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001362 self.assertEqual(expected, data)
1363
Simon Glassfd8d1f72018-07-17 13:25:36 -06001364 def testEntryDocs(self):
1365 """Test for creation of entry documentation"""
1366 with test_util.capture_sys_output() as (stdout, stderr):
1367 control.WriteEntryDocs(binman.GetEntryModules())
1368 self.assertTrue(len(stdout.getvalue()) > 0)
1369
1370 def testEntryDocsMissing(self):
1371 """Test handling of missing entry documentation"""
1372 with self.assertRaises(ValueError) as e:
1373 with test_util.capture_sys_output() as (stdout, stderr):
1374 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1375 self.assertIn('Documentation is missing for modules: u_boot',
1376 str(e.exception))
1377
Simon Glass11e36cc2018-07-17 13:25:38 -06001378 def testFmap(self):
1379 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001380 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001381 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001382 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1383 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001384 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001385 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001386 self.assertEqual(1, fhdr.ver_major)
1387 self.assertEqual(0, fhdr.ver_minor)
1388 self.assertEqual(0, fhdr.base)
1389 self.assertEqual(16 + 16 +
1390 fmap_util.FMAP_HEADER_LEN +
1391 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001392 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001393 self.assertEqual(3, fhdr.nareas)
1394 for fentry in fentries:
1395 self.assertEqual(0, fentry.flags)
1396
1397 self.assertEqual(0, fentries[0].offset)
1398 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001399 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001400
1401 self.assertEqual(16, fentries[1].offset)
1402 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001403 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001404
1405 self.assertEqual(32, fentries[2].offset)
1406 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1407 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001408 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001409
Simon Glassec127af2018-07-17 13:25:39 -06001410 def testBlobNamedByArg(self):
1411 """Test we can add a blob with the filename coming from an entry arg"""
1412 entry_args = {
1413 'cros-ec-rw-path': 'ecrw.bin',
1414 }
Simon Glass741f2d62018-10-01 12:22:30 -06001415 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001416 entry_args=entry_args)
1417
Simon Glass3af8e492018-07-17 13:25:40 -06001418 def testFill(self):
1419 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001420 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001421 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001422 self.assertEqual(expected, data)
1423
1424 def testFillNoSize(self):
1425 """Test for an fill entry type with no size"""
1426 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001427 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001428 self.assertIn("'fill' entry must have a size property",
1429 str(e.exception))
1430
Simon Glass0ef87aa2018-07-17 13:25:44 -06001431 def _HandleGbbCommand(self, pipe_list):
1432 """Fake calls to the futility utility"""
1433 if pipe_list[0][0] == 'futility':
1434 fname = pipe_list[0][-1]
1435 # Append our GBB data to the file, which will happen every time the
1436 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001437 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001438 fd.write(GBB_DATA)
1439 return command.CommandResult()
1440
1441 def testGbb(self):
1442 """Test for the Chromium OS Google Binary Block"""
1443 command.test_result = self._HandleGbbCommand
1444 entry_args = {
1445 'keydir': 'devkeys',
1446 'bmpblk': 'bmpblk.bin',
1447 }
Simon Glass741f2d62018-10-01 12:22:30 -06001448 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001449
1450 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001451 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1452 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001453 self.assertEqual(expected, data)
1454
1455 def testGbbTooSmall(self):
1456 """Test for the Chromium OS Google Binary Block being large enough"""
1457 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001458 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001459 self.assertIn("Node '/binman/gbb': GBB is too small",
1460 str(e.exception))
1461
1462 def testGbbNoSize(self):
1463 """Test for the Chromium OS Google Binary Block having a size"""
1464 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001465 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001466 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1467 str(e.exception))
1468
Simon Glass24d0d3c2018-07-17 13:25:47 -06001469 def _HandleVblockCommand(self, pipe_list):
1470 """Fake calls to the futility utility"""
1471 if pipe_list[0][0] == 'futility':
1472 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001473 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001474 fd.write(VBLOCK_DATA)
1475 return command.CommandResult()
1476
1477 def testVblock(self):
1478 """Test for the Chromium OS Verified Boot Block"""
1479 command.test_result = self._HandleVblockCommand
1480 entry_args = {
1481 'keydir': 'devkeys',
1482 }
Simon Glass741f2d62018-10-01 12:22:30 -06001483 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001484 entry_args=entry_args)
1485 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1486 self.assertEqual(expected, data)
1487
1488 def testVblockNoContent(self):
1489 """Test we detect a vblock which has no content to sign"""
1490 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001491 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001492 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1493 'property', str(e.exception))
1494
1495 def testVblockBadPhandle(self):
1496 """Test that we detect a vblock with an invalid phandle in contents"""
1497 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001498 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001499 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1500 '1000', str(e.exception))
1501
1502 def testVblockBadEntry(self):
1503 """Test that we detect an entry that points to a non-entry"""
1504 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001505 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001506 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1507 "'other'", str(e.exception))
1508
Simon Glassb8ef5b62018-07-17 13:25:48 -06001509 def testTpl(self):
1510 """Test that an image with TPL and ots device tree can be created"""
1511 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001512 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001513 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001514 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001515 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1516
Simon Glass15a587c2018-07-17 13:25:51 -06001517 def testUsesPos(self):
1518 """Test that the 'pos' property cannot be used anymore"""
1519 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001520 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001521 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1522 "'pos'", str(e.exception))
1523
Simon Glassd178eab2018-09-14 04:57:08 -06001524 def testFillZero(self):
1525 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001526 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001527 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001528
Simon Glass0b489362018-09-14 04:57:09 -06001529 def testTextMissing(self):
1530 """Test for a text entry type where there is no text"""
1531 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001532 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001533 self.assertIn("Node '/binman/text': No value provided for text label "
1534 "'test-id'", str(e.exception))
1535
Simon Glass35b384c2018-09-14 04:57:10 -06001536 def testPackStart16Tpl(self):
1537 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001538 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001539 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1540
Simon Glass0bfa7b02018-09-14 04:57:12 -06001541 def testSelectImage(self):
1542 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001543 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001544
Simon Glasseb833d82019-04-25 21:58:34 -06001545 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001546 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001547 with test_util.capture_sys_output() as (stdout, stderr):
1548 retcode = self._DoTestFile('006_dual_image.dts',
1549 verbosity=verbosity,
1550 images=['image2'])
1551 self.assertEqual(0, retcode)
1552 if verbosity:
1553 self.assertIn(expected, stdout.getvalue())
1554 else:
1555 self.assertNotIn(expected, stdout.getvalue())
1556
1557 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1558 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001559
Simon Glass6ed45ba2018-09-14 04:57:24 -06001560 def testUpdateFdtAll(self):
1561 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001562 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001563
1564 base_expected = {
1565 'section:image-pos': 0,
1566 'u-boot-tpl-dtb:size': 513,
1567 'u-boot-spl-dtb:size': 513,
1568 'u-boot-spl-dtb:offset': 493,
1569 'image-pos': 0,
1570 'section/u-boot-dtb:image-pos': 0,
1571 'u-boot-spl-dtb:image-pos': 493,
1572 'section/u-boot-dtb:size': 493,
1573 'u-boot-tpl-dtb:image-pos': 1006,
1574 'section/u-boot-dtb:offset': 0,
1575 'section:size': 493,
1576 'offset': 0,
1577 'section:offset': 0,
1578 'u-boot-tpl-dtb:offset': 1006,
1579 'size': 1519
1580 }
1581
1582 # We expect three device-tree files in the output, one after the other.
1583 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1584 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1585 # main U-Boot tree. All three should have the same postions and offset.
1586 start = 0
1587 for item in ['', 'spl', 'tpl']:
1588 dtb = fdt.Fdt.FromData(data[start:])
1589 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06001590 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001591 expected = dict(base_expected)
1592 if item:
1593 expected[item] = 0
1594 self.assertEqual(expected, props)
1595 start += dtb._fdt_obj.totalsize()
1596
1597 def testUpdateFdtOutput(self):
1598 """Test that output DTB files are updated"""
1599 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001600 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001601 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1602
1603 # Unfortunately, compiling a source file always results in a file
1604 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001605 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001606 # binman as a file called u-boot.dtb. To fix this, copy the file
1607 # over to the expected place.
1608 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1609 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1610 start = 0
1611 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1612 'tpl/u-boot-tpl.dtb.out']:
1613 dtb = fdt.Fdt.FromData(data[start:])
1614 size = dtb._fdt_obj.totalsize()
1615 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1616 outdata = tools.ReadFile(pathname)
1617 name = os.path.split(fname)[0]
1618
1619 if name:
1620 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1621 else:
1622 orig_indata = dtb_data
1623 self.assertNotEqual(outdata, orig_indata,
1624 "Expected output file '%s' be updated" % pathname)
1625 self.assertEqual(outdata, data[start:start + size],
1626 "Expected output file '%s' to match output image" %
1627 pathname)
1628 start += size
1629 finally:
1630 self._ResetDtbs()
1631
Simon Glass83d73c22018-09-14 04:57:26 -06001632 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001633 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001634
1635 def testCompress(self):
1636 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001637 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001638 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001639 use_real_dtb=True, update_dtb=True)
1640 dtb = fdt.Fdt(out_dtb_fname)
1641 dtb.Scan()
1642 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1643 orig = self._decompress(data)
1644 self.assertEquals(COMPRESS_DATA, orig)
1645 expected = {
1646 'blob:uncomp-size': len(COMPRESS_DATA),
1647 'blob:size': len(data),
1648 'size': len(data),
1649 }
1650 self.assertEqual(expected, props)
1651
Simon Glass0a98b282018-09-14 04:57:28 -06001652 def testFiles(self):
1653 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001654 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001655 self.assertEqual(FILES_DATA, data)
1656
1657 def testFilesCompress(self):
1658 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001659 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001660 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001661
1662 image = control.images['image']
1663 entries = image.GetEntries()
1664 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001665 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001666
Simon Glassc6c10e72019-05-17 22:00:46 -06001667 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001668 for i in range(1, 3):
1669 key = '%d.dat' % i
1670 start = entries[key].image_pos
1671 len = entries[key].size
1672 chunk = data[start:start + len]
1673 orig += self._decompress(chunk)
1674
1675 self.assertEqual(FILES_DATA, orig)
1676
1677 def testFilesMissing(self):
1678 """Test missing files"""
1679 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001680 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001681 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1682 'no files', str(e.exception))
1683
1684 def testFilesNoPattern(self):
1685 """Test missing files"""
1686 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001687 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001688 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1689 str(e.exception))
1690
Simon Glassba64a0b2018-09-14 04:57:29 -06001691 def testExpandSize(self):
1692 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001693 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001694 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001695 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1696 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1697 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1698 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001699 self.assertEqual(expect, data)
1700 self.assertEqual('''ImagePos Offset Size Name
170100000000 00000000 00000028 main-section
170200000000 00000000 00000008 fill
170300000008 00000008 00000004 u-boot
17040000000c 0000000c 00000004 section
17050000000c 00000000 00000003 intel-mrc
170600000010 00000010 00000004 u-boot2
170700000014 00000014 0000000c section2
170800000014 00000000 00000008 fill
17090000001c 00000008 00000004 u-boot
171000000020 00000020 00000008 fill2
1711''', map_data)
1712
1713 def testExpandSizeBad(self):
1714 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001715 with test_util.capture_sys_output() as (stdout, stderr):
1716 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001717 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001718 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1719 'expanding entry', str(e.exception))
1720
Simon Glasse0e5df92018-09-14 04:57:31 -06001721 def testHash(self):
1722 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001723 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001724 use_real_dtb=True, update_dtb=True)
1725 dtb = fdt.Fdt(out_dtb_fname)
1726 dtb.Scan()
1727 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1728 m = hashlib.sha256()
1729 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001730 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001731
1732 def testHashNoAlgo(self):
1733 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001734 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001735 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1736 'hash node', str(e.exception))
1737
1738 def testHashBadAlgo(self):
1739 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001740 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001741 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1742 str(e.exception))
1743
1744 def testHashSection(self):
1745 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001746 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001747 use_real_dtb=True, update_dtb=True)
1748 dtb = fdt.Fdt(out_dtb_fname)
1749 dtb.Scan()
1750 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1751 m = hashlib.sha256()
1752 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001753 m.update(tools.GetBytes(ord('a'), 16))
1754 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001755
Simon Glassf0253632018-09-14 04:57:32 -06001756 def testPackUBootTplMicrocode(self):
1757 """Test that x86 microcode can be handled correctly in TPL
1758
1759 We expect to see the following in the image, in order:
1760 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1761 place
1762 u-boot-tpl.dtb with the microcode removed
1763 the microcode
1764 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001765 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001766 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001767 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001768 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001769 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1770 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001771
Simon Glassf8f8df62018-09-14 04:57:34 -06001772 def testFmapX86(self):
1773 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001774 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001775 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001776 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001777 self.assertEqual(expected, data[:32])
1778 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1779
1780 self.assertEqual(0x100, fhdr.image_size)
1781
1782 self.assertEqual(0, fentries[0].offset)
1783 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001784 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001785
1786 self.assertEqual(4, fentries[1].offset)
1787 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001788 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001789
1790 self.assertEqual(32, fentries[2].offset)
1791 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1792 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001793 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001794
1795 def testFmapX86Section(self):
1796 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001797 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001798 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001799 self.assertEqual(expected, data[:32])
1800 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1801
1802 self.assertEqual(0x100, fhdr.image_size)
1803
1804 self.assertEqual(0, fentries[0].offset)
1805 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001806 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001807
1808 self.assertEqual(4, fentries[1].offset)
1809 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001810 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001811
1812 self.assertEqual(36, fentries[2].offset)
1813 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1814 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001815 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001816
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001817 def testElf(self):
1818 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001819 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001820 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001821 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1822 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001823 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001824 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001825
Simon Glass093d1682019-07-08 13:18:25 -06001826 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001827 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001828 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001829 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001830 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001831 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001832
Simon Glass163ed6c2018-09-14 04:57:36 -06001833 def testPackOverlapMap(self):
1834 """Test that overlapping regions are detected"""
1835 with test_util.capture_sys_output() as (stdout, stderr):
1836 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001837 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001838 map_fname = tools.GetOutputFilename('image.map')
1839 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1840 stdout.getvalue())
1841
1842 # We should not get an inmage, but there should be a map file
1843 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1844 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001845 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001846 self.assertEqual('''ImagePos Offset Size Name
1847<none> 00000000 00000007 main-section
1848<none> 00000000 00000004 u-boot
1849<none> 00000003 00000004 u-boot-align
1850''', map_data)
1851
Simon Glass093d1682019-07-08 13:18:25 -06001852 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001853 """Test that an image with an Intel Reference code binary works"""
1854 data = self._DoReadFile('100_intel_refcode.dts')
1855 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1856
Simon Glass9481c802019-04-25 21:58:39 -06001857 def testSectionOffset(self):
1858 """Tests use of a section with an offset"""
1859 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1860 map=True)
1861 self.assertEqual('''ImagePos Offset Size Name
186200000000 00000000 00000038 main-section
186300000004 00000004 00000010 section@0
186400000004 00000000 00000004 u-boot
186500000018 00000018 00000010 section@1
186600000018 00000000 00000004 u-boot
18670000002c 0000002c 00000004 section@2
18680000002c 00000000 00000004 u-boot
1869''', map_data)
1870 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001871 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1872 tools.GetBytes(0x21, 12) +
1873 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1874 tools.GetBytes(0x61, 12) +
1875 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1876 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001877
Simon Glassac62fba2019-07-08 13:18:53 -06001878 def testCbfsRaw(self):
1879 """Test base handling of a Coreboot Filesystem (CBFS)
1880
1881 The exact contents of the CBFS is verified by similar tests in
1882 cbfs_util_test.py. The tests here merely check that the files added to
1883 the CBFS can be found in the final image.
1884 """
1885 data = self._DoReadFile('102_cbfs_raw.dts')
1886 size = 0xb0
1887
1888 cbfs = cbfs_util.CbfsReader(data)
1889 self.assertEqual(size, cbfs.rom_size)
1890
1891 self.assertIn('u-boot-dtb', cbfs.files)
1892 cfile = cbfs.files['u-boot-dtb']
1893 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1894
1895 def testCbfsArch(self):
1896 """Test on non-x86 architecture"""
1897 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1898 size = 0x100
1899
1900 cbfs = cbfs_util.CbfsReader(data)
1901 self.assertEqual(size, cbfs.rom_size)
1902
1903 self.assertIn('u-boot-dtb', cbfs.files)
1904 cfile = cbfs.files['u-boot-dtb']
1905 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1906
1907 def testCbfsStage(self):
1908 """Tests handling of a Coreboot Filesystem (CBFS)"""
1909 if not elf.ELF_TOOLS:
1910 self.skipTest('Python elftools not available')
1911 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1912 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1913 size = 0xb0
1914
1915 data = self._DoReadFile('104_cbfs_stage.dts')
1916 cbfs = cbfs_util.CbfsReader(data)
1917 self.assertEqual(size, cbfs.rom_size)
1918
1919 self.assertIn('u-boot', cbfs.files)
1920 cfile = cbfs.files['u-boot']
1921 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1922
1923 def testCbfsRawCompress(self):
1924 """Test handling of compressing raw files"""
1925 self._CheckLz4()
1926 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1927 size = 0x140
1928
1929 cbfs = cbfs_util.CbfsReader(data)
1930 self.assertIn('u-boot', cbfs.files)
1931 cfile = cbfs.files['u-boot']
1932 self.assertEqual(COMPRESS_DATA, cfile.data)
1933
1934 def testCbfsBadArch(self):
1935 """Test handling of a bad architecture"""
1936 with self.assertRaises(ValueError) as e:
1937 self._DoReadFile('106_cbfs_bad_arch.dts')
1938 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1939
1940 def testCbfsNoSize(self):
1941 """Test handling of a missing size property"""
1942 with self.assertRaises(ValueError) as e:
1943 self._DoReadFile('107_cbfs_no_size.dts')
1944 self.assertIn('entry must have a size property', str(e.exception))
1945
1946 def testCbfsNoCOntents(self):
1947 """Test handling of a CBFS entry which does not provide contentsy"""
1948 with self.assertRaises(ValueError) as e:
1949 self._DoReadFile('108_cbfs_no_contents.dts')
1950 self.assertIn('Could not complete processing of contents',
1951 str(e.exception))
1952
1953 def testCbfsBadCompress(self):
1954 """Test handling of a bad architecture"""
1955 with self.assertRaises(ValueError) as e:
1956 self._DoReadFile('109_cbfs_bad_compress.dts')
1957 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1958 str(e.exception))
1959
1960 def testCbfsNamedEntries(self):
1961 """Test handling of named entries"""
1962 data = self._DoReadFile('110_cbfs_name.dts')
1963
1964 cbfs = cbfs_util.CbfsReader(data)
1965 self.assertIn('FRED', cbfs.files)
1966 cfile1 = cbfs.files['FRED']
1967 self.assertEqual(U_BOOT_DATA, cfile1.data)
1968
1969 self.assertIn('hello', cbfs.files)
1970 cfile2 = cbfs.files['hello']
1971 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1972
Simon Glassc5ac1382019-07-08 13:18:54 -06001973 def _SetupIfwi(self, fname):
1974 """Set up to run an IFWI test
1975
1976 Args:
1977 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1978 """
1979 self._SetupSplElf()
1980
1981 # Intel Integrated Firmware Image (IFWI) file
1982 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1983 data = fd.read()
1984 TestFunctional._MakeInputFile(fname,data)
1985
1986 def _CheckIfwi(self, data):
1987 """Check that an image with an IFWI contains the correct output
1988
1989 Args:
1990 data: Conents of output file
1991 """
1992 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1993 if data[:0x1000] != expected_desc:
1994 self.fail('Expected descriptor binary at start of image')
1995
1996 # We expect to find the TPL wil in subpart IBBP entry IBBL
1997 image_fname = tools.GetOutputFilename('image.bin')
1998 tpl_fname = tools.GetOutputFilename('tpl.out')
1999 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2000 subpart='IBBP', entry_name='IBBL')
2001
2002 tpl_data = tools.ReadFile(tpl_fname)
2003 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2004
2005 def testPackX86RomIfwi(self):
2006 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2007 self._SetupIfwi('fitimage.bin')
2008 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2009 self._CheckIfwi(data)
2010
2011 def testPackX86RomIfwiNoDesc(self):
2012 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2013 self._SetupIfwi('ifwi.bin')
2014 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2015 self._CheckIfwi(data)
2016
2017 def testPackX86RomIfwiNoData(self):
2018 """Test that an x86 ROM with IFWI handles missing data"""
2019 self._SetupIfwi('ifwi.bin')
2020 with self.assertRaises(ValueError) as e:
2021 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2022 self.assertIn('Could not complete processing of contents',
2023 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002024
Simon Glasse073d4e2019-07-08 13:18:56 -06002025 def testCbfsOffset(self):
2026 """Test a CBFS with files at particular offsets
2027
2028 Like all CFBS tests, this is just checking the logic that calls
2029 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2030 """
2031 data = self._DoReadFile('114_cbfs_offset.dts')
2032 size = 0x200
2033
2034 cbfs = cbfs_util.CbfsReader(data)
2035 self.assertEqual(size, cbfs.rom_size)
2036
2037 self.assertIn('u-boot', cbfs.files)
2038 cfile = cbfs.files['u-boot']
2039 self.assertEqual(U_BOOT_DATA, cfile.data)
2040 self.assertEqual(0x40, cfile.cbfs_offset)
2041
2042 self.assertIn('u-boot-dtb', cbfs.files)
2043 cfile2 = cbfs.files['u-boot-dtb']
2044 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2045 self.assertEqual(0x140, cfile2.cbfs_offset)
2046
Simon Glass086cec92019-07-08 14:25:27 -06002047 def testFdtmap(self):
2048 """Test an FDT map can be inserted in the image"""
2049 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2050 fdtmap_data = data[len(U_BOOT_DATA):]
2051 magic = fdtmap_data[:8]
2052 self.assertEqual('_FDTMAP_', magic)
2053 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2054
2055 fdt_data = fdtmap_data[16:]
2056 dtb = fdt.Fdt.FromData(fdt_data)
2057 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002058 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002059 self.assertEqual({
2060 'image-pos': 0,
2061 'offset': 0,
2062 'u-boot:offset': 0,
2063 'u-boot:size': len(U_BOOT_DATA),
2064 'u-boot:image-pos': 0,
2065 'fdtmap:image-pos': 4,
2066 'fdtmap:offset': 4,
2067 'fdtmap:size': len(fdtmap_data),
2068 'size': len(data),
2069 }, props)
2070
2071 def testFdtmapNoMatch(self):
2072 """Check handling of an FDT map when the section cannot be found"""
2073 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2074
2075 # Mangle the section name, which should cause a mismatch between the
2076 # correct FDT path and the one expected by the section
2077 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002078 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002079 entries = image.GetEntries()
2080 fdtmap = entries['fdtmap']
2081 with self.assertRaises(ValueError) as e:
2082 fdtmap._GetFdtmap()
2083 self.assertIn("Cannot locate node for path '/binman-suffix'",
2084 str(e.exception))
2085
Simon Glasscf228942019-07-08 14:25:28 -06002086 def testFdtmapHeader(self):
2087 """Test an FDT map and image header can be inserted in the image"""
2088 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2089 fdtmap_pos = len(U_BOOT_DATA)
2090 fdtmap_data = data[fdtmap_pos:]
2091 fdt_data = fdtmap_data[16:]
2092 dtb = fdt.Fdt.FromData(fdt_data)
2093 fdt_size = dtb.GetFdtObj().totalsize()
2094 hdr_data = data[-8:]
2095 self.assertEqual('BinM', hdr_data[:4])
2096 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2097 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2098
2099 def testFdtmapHeaderStart(self):
2100 """Test an image header can be inserted at the image start"""
2101 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2102 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2103 hdr_data = data[:8]
2104 self.assertEqual('BinM', hdr_data[:4])
2105 offset = struct.unpack('<I', hdr_data[4:])[0]
2106 self.assertEqual(fdtmap_pos, offset)
2107
2108 def testFdtmapHeaderPos(self):
2109 """Test an image header can be inserted at a chosen position"""
2110 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2111 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2112 hdr_data = data[0x80:0x88]
2113 self.assertEqual('BinM', hdr_data[:4])
2114 offset = struct.unpack('<I', hdr_data[4:])[0]
2115 self.assertEqual(fdtmap_pos, offset)
2116
2117 def testHeaderMissingFdtmap(self):
2118 """Test an image header requires an fdtmap"""
2119 with self.assertRaises(ValueError) as e:
2120 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2121 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2122 str(e.exception))
2123
2124 def testHeaderNoLocation(self):
2125 """Test an image header with a no specified location is detected"""
2126 with self.assertRaises(ValueError) as e:
2127 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2128 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2129 str(e.exception))
2130
Simon Glassc52c9e72019-07-08 14:25:37 -06002131 def testEntryExpand(self):
2132 """Test expanding an entry after it is packed"""
2133 data = self._DoReadFile('121_entry_expand.dts')
2134 self.assertEqual(b'aa', data[:2])
2135 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2136 self.assertEqual(b'aa', data[-2:])
2137
2138 def testEntryExpandBad(self):
2139 """Test expanding an entry after it is packed, twice"""
2140 with self.assertRaises(ValueError) as e:
2141 self._DoReadFile('122_entry_expand_twice.dts')
2142 self.assertIn("Image '/binman': Entries expanded after packing",
2143 str(e.exception))
2144
2145 def testEntryExpandSection(self):
2146 """Test expanding an entry within a section after it is packed"""
2147 data = self._DoReadFile('123_entry_expand_section.dts')
2148 self.assertEqual(b'aa', data[:2])
2149 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2150 self.assertEqual(b'aa', data[-2:])
2151
Simon Glass6c223fd2019-07-08 14:25:38 -06002152 def testCompressDtb(self):
2153 """Test that compress of device-tree files is supported"""
2154 self._CheckLz4()
2155 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2156 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2157 comp_data = data[len(U_BOOT_DATA):]
2158 orig = self._decompress(comp_data)
2159 dtb = fdt.Fdt.FromData(orig)
2160 dtb.Scan()
2161 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2162 expected = {
2163 'u-boot:size': len(U_BOOT_DATA),
2164 'u-boot-dtb:uncomp-size': len(orig),
2165 'u-boot-dtb:size': len(comp_data),
2166 'size': len(data),
2167 }
2168 self.assertEqual(expected, props)
2169
Simon Glass69f7cb32019-07-08 14:25:41 -06002170 def testCbfsUpdateFdt(self):
2171 """Test that we can update the device tree with CBFS offset/size info"""
2172 self._CheckLz4()
2173 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2174 update_dtb=True)
2175 dtb = fdt.Fdt(out_dtb_fname)
2176 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002177 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002178 del props['cbfs/u-boot:size']
2179 self.assertEqual({
2180 'offset': 0,
2181 'size': len(data),
2182 'image-pos': 0,
2183 'cbfs:offset': 0,
2184 'cbfs:size': len(data),
2185 'cbfs:image-pos': 0,
2186 'cbfs/u-boot:offset': 0x38,
2187 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2188 'cbfs/u-boot:image-pos': 0x38,
2189 'cbfs/u-boot-dtb:offset': 0xb8,
2190 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2191 'cbfs/u-boot-dtb:image-pos': 0xb8,
2192 }, props)
2193
Simon Glass8a1ad062019-07-08 14:25:42 -06002194 def testCbfsBadType(self):
2195 """Test an image header with a no specified location is detected"""
2196 with self.assertRaises(ValueError) as e:
2197 self._DoReadFile('126_cbfs_bad_type.dts')
2198 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2199
Simon Glass41b8ba02019-07-08 14:25:43 -06002200 def testList(self):
2201 """Test listing the files in an image"""
2202 self._CheckLz4()
2203 data = self._DoReadFile('127_list.dts')
2204 image = control.images['image']
2205 entries = image.BuildEntryList()
2206 self.assertEqual(7, len(entries))
2207
2208 ent = entries[0]
2209 self.assertEqual(0, ent.indent)
2210 self.assertEqual('main-section', ent.name)
2211 self.assertEqual('section', ent.etype)
2212 self.assertEqual(len(data), ent.size)
2213 self.assertEqual(0, ent.image_pos)
2214 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002215 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002216
2217 ent = entries[1]
2218 self.assertEqual(1, ent.indent)
2219 self.assertEqual('u-boot', ent.name)
2220 self.assertEqual('u-boot', ent.etype)
2221 self.assertEqual(len(U_BOOT_DATA), ent.size)
2222 self.assertEqual(0, ent.image_pos)
2223 self.assertEqual(None, ent.uncomp_size)
2224 self.assertEqual(0, ent.offset)
2225
2226 ent = entries[2]
2227 self.assertEqual(1, ent.indent)
2228 self.assertEqual('section', ent.name)
2229 self.assertEqual('section', ent.etype)
2230 section_size = ent.size
2231 self.assertEqual(0x100, ent.image_pos)
2232 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002233 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002234
2235 ent = entries[3]
2236 self.assertEqual(2, ent.indent)
2237 self.assertEqual('cbfs', ent.name)
2238 self.assertEqual('cbfs', ent.etype)
2239 self.assertEqual(0x400, ent.size)
2240 self.assertEqual(0x100, ent.image_pos)
2241 self.assertEqual(None, ent.uncomp_size)
2242 self.assertEqual(0, ent.offset)
2243
2244 ent = entries[4]
2245 self.assertEqual(3, ent.indent)
2246 self.assertEqual('u-boot', ent.name)
2247 self.assertEqual('u-boot', ent.etype)
2248 self.assertEqual(len(U_BOOT_DATA), ent.size)
2249 self.assertEqual(0x138, ent.image_pos)
2250 self.assertEqual(None, ent.uncomp_size)
2251 self.assertEqual(0x38, ent.offset)
2252
2253 ent = entries[5]
2254 self.assertEqual(3, ent.indent)
2255 self.assertEqual('u-boot-dtb', ent.name)
2256 self.assertEqual('text', ent.etype)
2257 self.assertGreater(len(COMPRESS_DATA), ent.size)
2258 self.assertEqual(0x178, ent.image_pos)
2259 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2260 self.assertEqual(0x78, ent.offset)
2261
2262 ent = entries[6]
2263 self.assertEqual(2, ent.indent)
2264 self.assertEqual('u-boot-dtb', ent.name)
2265 self.assertEqual('u-boot-dtb', ent.etype)
2266 self.assertEqual(0x500, ent.image_pos)
2267 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2268 dtb_size = ent.size
2269 # Compressing this data expands it since headers are added
2270 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2271 self.assertEqual(0x400, ent.offset)
2272
2273 self.assertEqual(len(data), 0x100 + section_size)
2274 self.assertEqual(section_size, 0x400 + dtb_size)
2275
Simon Glasse1925fa2019-07-08 14:25:44 -06002276 def testFindFdtmap(self):
2277 """Test locating an FDT map in an image"""
2278 self._CheckLz4()
2279 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2280 image = control.images['image']
2281 entries = image.GetEntries()
2282 entry = entries['fdtmap']
2283 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2284
2285 def testFindFdtmapMissing(self):
2286 """Test failing to locate an FDP map"""
2287 data = self._DoReadFile('005_simple.dts')
2288 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2289
Simon Glass2d260032019-07-08 14:25:45 -06002290 def testFindImageHeader(self):
2291 """Test locating a image header"""
2292 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002293 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002294 image = control.images['image']
2295 entries = image.GetEntries()
2296 entry = entries['fdtmap']
2297 # The header should point to the FDT map
2298 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2299
2300 def testFindImageHeaderStart(self):
2301 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002302 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002303 image = control.images['image']
2304 entries = image.GetEntries()
2305 entry = entries['fdtmap']
2306 # The header should point to the FDT map
2307 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2308
2309 def testFindImageHeaderMissing(self):
2310 """Test failing to locate an image header"""
2311 data = self._DoReadFile('005_simple.dts')
2312 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2313
Simon Glassffded752019-07-08 14:25:46 -06002314 def testReadImage(self):
2315 """Test reading an image and accessing its FDT map"""
2316 self._CheckLz4()
2317 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2318 image_fname = tools.GetOutputFilename('image.bin')
2319 orig_image = control.images['image']
2320 image = Image.FromFile(image_fname)
2321 self.assertEqual(orig_image.GetEntries().keys(),
2322 image.GetEntries().keys())
2323
2324 orig_entry = orig_image.GetEntries()['fdtmap']
2325 entry = image.GetEntries()['fdtmap']
2326 self.assertEquals(orig_entry.offset, entry.offset)
2327 self.assertEquals(orig_entry.size, entry.size)
2328 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2329
2330 def testReadImageNoHeader(self):
2331 """Test accessing an image's FDT map without an image header"""
2332 self._CheckLz4()
2333 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2334 image_fname = tools.GetOutputFilename('image.bin')
2335 image = Image.FromFile(image_fname)
2336 self.assertTrue(isinstance(image, Image))
Simon Glass8beb11e2019-07-08 14:25:47 -06002337 self.assertEqual('image', image.image_name)
Simon Glassffded752019-07-08 14:25:46 -06002338
2339 def testReadImageFail(self):
2340 """Test failing to read an image image's FDT map"""
2341 self._DoReadFile('005_simple.dts')
2342 image_fname = tools.GetOutputFilename('image.bin')
2343 with self.assertRaises(ValueError) as e:
2344 image = Image.FromFile(image_fname)
2345 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002346
Simon Glass61f564d2019-07-08 14:25:48 -06002347 def testListCmd(self):
2348 """Test listing the files in an image using an Fdtmap"""
2349 self._CheckLz4()
2350 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2351
2352 # lz4 compression size differs depending on the version
2353 image = control.images['image']
2354 entries = image.GetEntries()
2355 section_size = entries['section'].size
2356 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2357 fdtmap_offset = entries['fdtmap'].offset
2358
2359 image_fname = tools.GetOutputFilename('image.bin')
2360 with test_util.capture_sys_output() as (stdout, stderr):
2361 self._DoBinman('ls', '-i', image_fname)
2362 lines = stdout.getvalue().splitlines()
2363 expected = [
2364'Name Image-pos Size Entry-type Offset Uncomp-size',
2365'----------------------------------------------------------------------',
2366'main-section 0 c00 section 0',
2367' u-boot 0 4 u-boot 0',
2368' section 100 %x section 100' % section_size,
2369' cbfs 100 400 cbfs 0',
2370' u-boot 138 4 u-boot 38',
2371' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2372' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glass1411ac82019-07-20 12:23:44 -06002373' fdtmap %x 3b4 fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002374 (fdtmap_offset, fdtmap_offset),
2375' image-header bf8 8 image-header bf8',
2376 ]
2377 self.assertEqual(expected, lines)
2378
2379 def testListCmdFail(self):
2380 """Test failing to list an image"""
2381 self._DoReadFile('005_simple.dts')
2382 image_fname = tools.GetOutputFilename('image.bin')
2383 with self.assertRaises(ValueError) as e:
2384 self._DoBinman('ls', '-i', image_fname)
2385 self.assertIn("Cannot find FDT map in image", str(e.exception))
2386
2387 def _RunListCmd(self, paths, expected):
2388 """List out entries and check the result
2389
2390 Args:
2391 paths: List of paths to pass to the list command
2392 expected: Expected list of filenames to be returned, in order
2393 """
2394 self._CheckLz4()
2395 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2396 image_fname = tools.GetOutputFilename('image.bin')
2397 image = Image.FromFile(image_fname)
2398 lines = image.GetListEntries(paths)[1]
2399 files = [line[0].strip() for line in lines[1:]]
2400 self.assertEqual(expected, files)
2401
2402 def testListCmdSection(self):
2403 """Test listing the files in a section"""
2404 self._RunListCmd(['section'],
2405 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2406
2407 def testListCmdFile(self):
2408 """Test listing a particular file"""
2409 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2410
2411 def testListCmdWildcard(self):
2412 """Test listing a wildcarded file"""
2413 self._RunListCmd(['*boot*'],
2414 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2415
2416 def testListCmdWildcardMulti(self):
2417 """Test listing a wildcarded file"""
2418 self._RunListCmd(['*cb*', '*head*'],
2419 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2420
2421 def testListCmdEmpty(self):
2422 """Test listing a wildcarded file"""
2423 self._RunListCmd(['nothing'], [])
2424
2425 def testListCmdPath(self):
2426 """Test listing the files in a sub-entry of a section"""
2427 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2428
Simon Glassf667e452019-07-08 14:25:50 -06002429 def _RunExtractCmd(self, entry_name, decomp=True):
2430 """Extract an entry from an image
2431
2432 Args:
2433 entry_name: Entry name to extract
2434 decomp: True to decompress the data if compressed, False to leave
2435 it in its raw uncompressed format
2436
2437 Returns:
2438 data from entry
2439 """
2440 self._CheckLz4()
2441 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2442 image_fname = tools.GetOutputFilename('image.bin')
2443 return control.ReadEntry(image_fname, entry_name, decomp)
2444
2445 def testExtractSimple(self):
2446 """Test extracting a single file"""
2447 data = self._RunExtractCmd('u-boot')
2448 self.assertEqual(U_BOOT_DATA, data)
2449
Simon Glass71ce0ba2019-07-08 14:25:52 -06002450 def testExtractSection(self):
2451 """Test extracting the files in a section"""
2452 data = self._RunExtractCmd('section')
2453 cbfs_data = data[:0x400]
2454 cbfs = cbfs_util.CbfsReader(cbfs_data)
2455 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2456 dtb_data = data[0x400:]
2457 dtb = self._decompress(dtb_data)
2458 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2459
2460 def testExtractCompressed(self):
2461 """Test extracting compressed data"""
2462 data = self._RunExtractCmd('section/u-boot-dtb')
2463 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2464
2465 def testExtractRaw(self):
2466 """Test extracting compressed data without decompressing it"""
2467 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2468 dtb = self._decompress(data)
2469 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2470
2471 def testExtractCbfs(self):
2472 """Test extracting CBFS data"""
2473 data = self._RunExtractCmd('section/cbfs/u-boot')
2474 self.assertEqual(U_BOOT_DATA, data)
2475
2476 def testExtractCbfsCompressed(self):
2477 """Test extracting CBFS compressed data"""
2478 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2479 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2480
2481 def testExtractCbfsRaw(self):
2482 """Test extracting CBFS compressed data without decompressing it"""
2483 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2484 dtb = tools.Decompress(data, 'lzma')
2485 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2486
Simon Glassf667e452019-07-08 14:25:50 -06002487 def testExtractBadEntry(self):
2488 """Test extracting a bad section path"""
2489 with self.assertRaises(ValueError) as e:
2490 self._RunExtractCmd('section/does-not-exist')
2491 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2492 str(e.exception))
2493
2494 def testExtractMissingFile(self):
2495 """Test extracting file that does not exist"""
2496 with self.assertRaises(IOError) as e:
2497 control.ReadEntry('missing-file', 'name')
2498
2499 def testExtractBadFile(self):
2500 """Test extracting an invalid file"""
2501 fname = os.path.join(self._indir, 'badfile')
2502 tools.WriteFile(fname, b'')
2503 with self.assertRaises(ValueError) as e:
2504 control.ReadEntry(fname, 'name')
2505
Simon Glass71ce0ba2019-07-08 14:25:52 -06002506 def testExtractCmd(self):
2507 """Test extracting a file fron an image on the command line"""
2508 self._CheckLz4()
2509 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2510 image_fname = tools.GetOutputFilename('image.bin')
2511 fname = os.path.join(self._indir, 'output.extact')
2512 with test_util.capture_sys_output() as (stdout, stderr):
2513 self._DoBinman('extract', '-i', image_fname, 'u-boot', '-f', fname)
2514 data = tools.ReadFile(fname)
2515 self.assertEqual(U_BOOT_DATA, data)
2516
2517 def testExtractOneEntry(self):
2518 """Test extracting a single entry fron an image """
2519 self._CheckLz4()
2520 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2521 image_fname = tools.GetOutputFilename('image.bin')
2522 fname = os.path.join(self._indir, 'output.extact')
2523 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2524 data = tools.ReadFile(fname)
2525 self.assertEqual(U_BOOT_DATA, data)
2526
2527 def _CheckExtractOutput(self, decomp):
2528 """Helper to test file output with and without decompression
2529
2530 Args:
2531 decomp: True to decompress entry data, False to output it raw
2532 """
2533 def _CheckPresent(entry_path, expect_data, expect_size=None):
2534 """Check and remove expected file
2535
2536 This checks the data/size of a file and removes the file both from
2537 the outfiles set and from the output directory. Once all files are
2538 processed, both the set and directory should be empty.
2539
2540 Args:
2541 entry_path: Entry path
2542 expect_data: Data to expect in file, or None to skip check
2543 expect_size: Size of data to expect in file, or None to skip
2544 """
2545 path = os.path.join(outdir, entry_path)
2546 data = tools.ReadFile(path)
2547 os.remove(path)
2548 if expect_data:
2549 self.assertEqual(expect_data, data)
2550 elif expect_size:
2551 self.assertEqual(expect_size, len(data))
2552 outfiles.remove(path)
2553
2554 def _CheckDirPresent(name):
2555 """Remove expected directory
2556
2557 This gives an error if the directory does not exist as expected
2558
2559 Args:
2560 name: Name of directory to remove
2561 """
2562 path = os.path.join(outdir, name)
2563 os.rmdir(path)
2564
2565 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2566 image_fname = tools.GetOutputFilename('image.bin')
2567 outdir = os.path.join(self._indir, 'extract')
2568 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2569
2570 # Create a set of all file that were output (should be 9)
2571 outfiles = set()
2572 for root, dirs, files in os.walk(outdir):
2573 outfiles |= set([os.path.join(root, fname) for fname in files])
2574 self.assertEqual(9, len(outfiles))
2575 self.assertEqual(9, len(einfos))
2576
2577 image = control.images['image']
2578 entries = image.GetEntries()
2579
2580 # Check the 9 files in various ways
2581 section = entries['section']
2582 section_entries = section.GetEntries()
2583 cbfs_entries = section_entries['cbfs'].GetEntries()
2584 _CheckPresent('u-boot', U_BOOT_DATA)
2585 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2586 dtb_len = EXTRACT_DTB_SIZE
2587 if not decomp:
2588 dtb_len = cbfs_entries['u-boot-dtb'].size
2589 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2590 if not decomp:
2591 dtb_len = section_entries['u-boot-dtb'].size
2592 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2593
2594 fdtmap = entries['fdtmap']
2595 _CheckPresent('fdtmap', fdtmap.data)
2596 hdr = entries['image-header']
2597 _CheckPresent('image-header', hdr.data)
2598
2599 _CheckPresent('section/root', section.data)
2600 cbfs = section_entries['cbfs']
2601 _CheckPresent('section/cbfs/root', cbfs.data)
2602 data = tools.ReadFile(image_fname)
2603 _CheckPresent('root', data)
2604
2605 # There should be no files left. Remove all the directories to check.
2606 # If there are any files/dirs remaining, one of these checks will fail.
2607 self.assertEqual(0, len(outfiles))
2608 _CheckDirPresent('section/cbfs')
2609 _CheckDirPresent('section')
2610 _CheckDirPresent('')
2611 self.assertFalse(os.path.exists(outdir))
2612
2613 def testExtractAllEntries(self):
2614 """Test extracting all entries"""
2615 self._CheckLz4()
2616 self._CheckExtractOutput(decomp=True)
2617
2618 def testExtractAllEntriesRaw(self):
2619 """Test extracting all entries without decompressing them"""
2620 self._CheckLz4()
2621 self._CheckExtractOutput(decomp=False)
2622
2623 def testExtractSelectedEntries(self):
2624 """Test extracting some entries"""
2625 self._CheckLz4()
2626 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2627 image_fname = tools.GetOutputFilename('image.bin')
2628 outdir = os.path.join(self._indir, 'extract')
2629 einfos = control.ExtractEntries(image_fname, None, outdir,
2630 ['*cb*', '*head*'])
2631
2632 # File output is tested by testExtractAllEntries(), so just check that
2633 # the expected entries are selected
2634 names = [einfo.name for einfo in einfos]
2635 self.assertEqual(names,
2636 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2637
2638 def testExtractNoEntryPaths(self):
2639 """Test extracting some entries"""
2640 self._CheckLz4()
2641 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2642 image_fname = tools.GetOutputFilename('image.bin')
2643 with self.assertRaises(ValueError) as e:
2644 control.ExtractEntries(image_fname, 'fname', None, [])
2645 self.assertIn('Must specify an entry path to write with -o',
2646 str(e.exception))
2647
2648 def testExtractTooManyEntryPaths(self):
2649 """Test extracting some entries"""
2650 self._CheckLz4()
2651 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2652 image_fname = tools.GetOutputFilename('image.bin')
2653 with self.assertRaises(ValueError) as e:
2654 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2655 self.assertIn('Must specify exactly one entry path to write with -o',
2656 str(e.exception))
2657
Simon Glasse2705fa2019-07-08 14:25:53 -06002658 def testPackAlignSection(self):
2659 """Test that sections can have alignment"""
2660 self._DoReadFile('131_pack_align_section.dts')
2661
2662 self.assertIn('image', control.images)
2663 image = control.images['image']
2664 entries = image.GetEntries()
2665 self.assertEqual(3, len(entries))
2666
2667 # First u-boot
2668 self.assertIn('u-boot', entries)
2669 entry = entries['u-boot']
2670 self.assertEqual(0, entry.offset)
2671 self.assertEqual(0, entry.image_pos)
2672 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2673 self.assertEqual(len(U_BOOT_DATA), entry.size)
2674
2675 # Section0
2676 self.assertIn('section0', entries)
2677 section0 = entries['section0']
2678 self.assertEqual(0x10, section0.offset)
2679 self.assertEqual(0x10, section0.image_pos)
2680 self.assertEqual(len(U_BOOT_DATA), section0.size)
2681
2682 # Second u-boot
2683 section_entries = section0.GetEntries()
2684 self.assertIn('u-boot', section_entries)
2685 entry = section_entries['u-boot']
2686 self.assertEqual(0, entry.offset)
2687 self.assertEqual(0x10, entry.image_pos)
2688 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2689 self.assertEqual(len(U_BOOT_DATA), entry.size)
2690
2691 # Section1
2692 self.assertIn('section1', entries)
2693 section1 = entries['section1']
2694 self.assertEqual(0x14, section1.offset)
2695 self.assertEqual(0x14, section1.image_pos)
2696 self.assertEqual(0x20, section1.size)
2697
2698 # Second u-boot
2699 section_entries = section1.GetEntries()
2700 self.assertIn('u-boot', section_entries)
2701 entry = section_entries['u-boot']
2702 self.assertEqual(0, entry.offset)
2703 self.assertEqual(0x14, entry.image_pos)
2704 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2705 self.assertEqual(len(U_BOOT_DATA), entry.size)
2706
2707 # Section2
2708 self.assertIn('section2', section_entries)
2709 section2 = section_entries['section2']
2710 self.assertEqual(0x4, section2.offset)
2711 self.assertEqual(0x18, section2.image_pos)
2712 self.assertEqual(4, section2.size)
2713
2714 # Third u-boot
2715 section_entries = section2.GetEntries()
2716 self.assertIn('u-boot', section_entries)
2717 entry = section_entries['u-boot']
2718 self.assertEqual(0, entry.offset)
2719 self.assertEqual(0x18, entry.image_pos)
2720 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2721 self.assertEqual(len(U_BOOT_DATA), entry.size)
2722
Simon Glass8beb11e2019-07-08 14:25:47 -06002723
Simon Glass9fc60b42017-11-12 21:52:22 -07002724if __name__ == "__main__":
2725 unittest.main()