blob: 64c6c0abae1b9adefba69a7636390fe754886632 [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 Glass12bb1a92019-07-20 12:23:51 -060078# Extra properties expected to be in the device tree when allow-repack is used
79REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
80
Simon Glass4f443042016-11-25 20:15:52 -070081
82class TestFunctional(unittest.TestCase):
83 """Functional tests for binman
84
85 Most of these use a sample .dts file to build an image and then check
86 that it looks correct. The sample files are in the test/ subdirectory
87 and are numbered.
88
89 For each entry type a very small test file is created using fixed
90 string contents. This makes it easy to test that things look right, and
91 debug problems.
92
93 In some cases a 'real' file must be used - these are also supplied in
94 the test/ diurectory.
95 """
96 @classmethod
97 def setUpClass(self):
Simon Glass4d5994f2017-11-12 21:52:20 -070098 global entry
99 import entry
100
Simon Glass4f443042016-11-25 20:15:52 -0700101 # Handle the case where argv[0] is 'python'
102 self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
103 self._binman_pathname = os.path.join(self._binman_dir, 'binman')
104
105 # Create a temporary directory for input files
106 self._indir = tempfile.mkdtemp(prefix='binmant.')
107
108 # Create some test files
109 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
110 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
111 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600112 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700113 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700114 TestFunctional._MakeInputFile('me.bin', ME_DATA)
115 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600116 self._ResetDtbs()
Simon Glasse0ff8552016-11-25 20:15:53 -0700117 TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA)
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530118 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass87722132017-11-12 21:52:26 -0700119 TestFunctional._MakeInputFile('spl/u-boot-x86-16bit-spl.bin',
120 X86_START16_SPL_DATA)
Simon Glass35b384c2018-09-14 04:57:10 -0600121 TestFunctional._MakeInputFile('tpl/u-boot-x86-16bit-tpl.bin',
122 X86_START16_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700123 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700124 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
125 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600126 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
127 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700128 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
129 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700130 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700131 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600132 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600133 TestFunctional._MakeInputDir('devkeys')
134 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600135 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700136
Simon Glasse0ff8552016-11-25 20:15:53 -0700137 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -0600138 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700139 TestFunctional._MakeInputFile('u-boot', fd.read())
140
141 # Intel flash descriptor file
Simon Glass1d0ebf72019-05-14 15:53:42 -0600142 with open(self.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700143 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
144
Simon Glass0a98b282018-09-14 04:57:28 -0600145 shutil.copytree(self.TestFile('files'),
146 os.path.join(self._indir, 'files'))
147
Simon Glass83d73c22018-09-14 04:57:26 -0600148 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
149
Simon Glassac62fba2019-07-08 13:18:53 -0600150 # Travis-CI may have an old lz4
151 self.have_lz4 = True
152 try:
153 tools.Run('lz4', '--no-frame-crc', '-c',
154 os.path.join(self._indir, 'u-boot.bin'))
155 except:
156 self.have_lz4 = False
157
Simon Glass4f443042016-11-25 20:15:52 -0700158 @classmethod
159 def tearDownClass(self):
160 """Remove the temporary input directory and its contents"""
Simon Glassd5164a72019-07-08 13:18:49 -0600161 if self.preserve_indir:
162 print('Preserving input dir: %s' % self._indir)
163 else:
164 if self._indir:
165 shutil.rmtree(self._indir)
Simon Glass4f443042016-11-25 20:15:52 -0700166 self._indir = None
167
Simon Glassd5164a72019-07-08 13:18:49 -0600168 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600169 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600170 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600171 """Accept arguments controlling test execution
172
173 Args:
174 preserve_indir: Preserve the shared input directory used by all
175 tests in this class.
176 preserve_outdir: Preserve the output directories used by tests. Each
177 test has its own, so this is normally only useful when running a
178 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600179 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600180 """
181 cls.preserve_indir = preserve_indir
182 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600183 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600184 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600185
Simon Glassac62fba2019-07-08 13:18:53 -0600186 def _CheckLz4(self):
187 if not self.have_lz4:
188 self.skipTest('lz4 --no-frame-crc not available')
189
Simon Glass4f443042016-11-25 20:15:52 -0700190 def setUp(self):
191 # Enable this to turn on debugging output
192 # tout.Init(tout.DEBUG)
193 command.test_result = None
194
195 def tearDown(self):
196 """Remove the temporary output directory"""
Simon Glassd5164a72019-07-08 13:18:49 -0600197 if self.preserve_outdirs:
198 print('Preserving output dir: %s' % tools.outdir)
199 else:
200 tools._FinaliseForTest()
Simon Glass4f443042016-11-25 20:15:52 -0700201
Simon Glassb8ef5b62018-07-17 13:25:48 -0600202 @classmethod
203 def _ResetDtbs(self):
204 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
205 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
206 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
207
Simon Glass4f443042016-11-25 20:15:52 -0700208 def _RunBinman(self, *args, **kwargs):
209 """Run binman using the command line
210
211 Args:
212 Arguments to pass, as a list of strings
213 kwargs: Arguments to pass to Command.RunPipe()
214 """
215 result = command.RunPipe([[self._binman_pathname] + list(args)],
216 capture=True, capture_stderr=True, raise_on_error=False)
217 if result.return_code and kwargs.get('raise_on_error', True):
218 raise Exception("Error running '%s': %s" % (' '.join(args),
219 result.stdout + result.stderr))
220 return result
221
Simon Glass53cd5d92019-07-08 14:25:29 -0600222 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700223 """Run binman using directly (in the same process)
224
225 Args:
226 Arguments to pass, as a list of strings
227 Returns:
228 Return value (0 for success)
229 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600230 argv = list(argv)
231 args = cmdline.ParseArgs(argv)
232 args.pager = 'binman-invalid-pager'
233 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700234
235 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600236 # args.verbosity = tout.DEBUG
237 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700238
Simon Glass53af22a2018-07-17 13:25:32 -0600239 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600240 entry_args=None, images=None, use_real_dtb=False,
241 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700242 """Run binman with a given test file
243
244 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600245 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600246 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600247 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600248 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600249 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600250 entry_args: Dict of entry args to supply to binman
251 key: arg name
252 value: value of that arg
253 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700254 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600255 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700256 if debug:
257 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600258 if verbosity is not None:
259 args.append('-v%d' % verbosity)
260 elif self.verbosity:
261 args.append('-v%d' % self.verbosity)
262 if self.toolpath:
263 for path in self.toolpath:
264 args += ['--toolpath', path]
265 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600266 if map:
267 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600268 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600269 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600270 if not use_real_dtb:
271 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600272 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600273 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600274 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600275 if images:
276 for image in images:
277 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700278 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700279
280 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700281 """Set up a new test device-tree file
282
283 The given file is compiled and set up as the device tree to be used
284 for ths test.
285
286 Args:
287 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600288 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700289
290 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600291 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700292 """
Simon Glassa004f292019-07-20 12:23:49 -0600293 tmpdir = tempfile.mkdtemp(prefix='binmant.')
294 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600295 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700296 data = fd.read()
297 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600298 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600299 return data
Simon Glass4f443042016-11-25 20:15:52 -0700300
Simon Glass6ed45ba2018-09-14 04:57:24 -0600301 def _GetDtbContentsForSplTpl(self, dtb_data, name):
302 """Create a version of the main DTB for SPL or SPL
303
304 For testing we don't actually have different versions of the DTB. With
305 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
306 we don't normally have any unwanted nodes.
307
308 We still want the DTBs for SPL and TPL to be different though, since
309 otherwise it is confusing to know which one we are looking at. So add
310 an 'spl' or 'tpl' property to the top-level node.
311 """
312 dtb = fdt.Fdt.FromData(dtb_data)
313 dtb.Scan()
314 dtb.GetNode('/binman').AddZeroProp(name)
315 dtb.Sync(auto_resize=True)
316 dtb.Pack()
317 return dtb.GetContents()
318
Simon Glass16b8d6b2018-07-06 10:27:42 -0600319 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600320 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700321 """Run binman and return the resulting image
322
323 This runs binman with a given test file and then reads the resulting
324 output file. It is a shortcut function since most tests need to do
325 these steps.
326
327 Raises an assertion failure if binman returns a non-zero exit code.
328
329 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600330 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700331 use_real_dtb: True to use the test file as the contents of
332 the u-boot-dtb entry. Normally this is not needed and the
333 test contents (the U_BOOT_DTB_DATA string) can be used.
334 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600335 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600336 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600337 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700338
339 Returns:
340 Tuple:
341 Resulting image contents
342 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600343 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600344 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700345 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700346 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700347 # Use the compiled test file as the u-boot-dtb input
348 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700349 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600350
351 # For testing purposes, make a copy of the DT for SPL and TPL. Add
352 # a node indicating which it is, so aid verification.
353 for name in ['spl', 'tpl']:
354 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
355 outfile = os.path.join(self._indir, dtb_fname)
356 TestFunctional._MakeInputFile(dtb_fname,
357 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700358
359 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600360 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600361 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700362 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600363 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700364
365 # Find the (only) image, read it and return its contents
366 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600367 image_fname = tools.GetOutputFilename('image.bin')
368 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600369 if map:
370 map_fname = tools.GetOutputFilename('image.map')
371 with open(map_fname) as fd:
372 map_data = fd.read()
373 else:
374 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600375 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600376 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700377 finally:
378 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600379 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600380 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700381
Simon Glass3c081312019-07-08 14:25:26 -0600382 def _DoReadFileRealDtb(self, fname):
383 """Run binman with a real .dtb file and return the resulting data
384
385 Args:
386 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
387
388 Returns:
389 Resulting image contents
390 """
391 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
392
Simon Glasse0ff8552016-11-25 20:15:53 -0700393 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600394 """Helper function which discards the device-tree binary
395
396 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600397 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600398 use_real_dtb: True to use the test file as the contents of
399 the u-boot-dtb entry. Normally this is not needed and the
400 test contents (the U_BOOT_DTB_DATA string) can be used.
401 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600402
403 Returns:
404 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600405 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700406 return self._DoReadFileDtb(fname, use_real_dtb)[0]
407
Simon Glass4f443042016-11-25 20:15:52 -0700408 @classmethod
409 def _MakeInputFile(self, fname, contents):
410 """Create a new test input file, creating directories as needed
411
412 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600413 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700414 contents: File contents to write in to the file
415 Returns:
416 Full pathname of file created
417 """
418 pathname = os.path.join(self._indir, fname)
419 dirname = os.path.dirname(pathname)
420 if dirname and not os.path.exists(dirname):
421 os.makedirs(dirname)
422 with open(pathname, 'wb') as fd:
423 fd.write(contents)
424 return pathname
425
426 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600427 def _MakeInputDir(self, dirname):
428 """Create a new test input directory, creating directories as needed
429
430 Args:
431 dirname: Directory name to create
432
433 Returns:
434 Full pathname of directory created
435 """
436 pathname = os.path.join(self._indir, dirname)
437 if not os.path.exists(pathname):
438 os.makedirs(pathname)
439 return pathname
440
441 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600442 def _SetupSplElf(self, src_fname='bss_data'):
443 """Set up an ELF file with a '_dt_ucode_base_size' symbol
444
445 Args:
446 Filename of ELF file to use as SPL
447 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600448 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600449 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
450
451 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700452 def TestFile(self, fname):
453 return os.path.join(self._binman_dir, 'test', fname)
454
455 def AssertInList(self, grep_list, target):
456 """Assert that at least one of a list of things is in a target
457
458 Args:
459 grep_list: List of strings to check
460 target: Target string
461 """
462 for grep in grep_list:
463 if grep in target:
464 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600465 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700466
467 def CheckNoGaps(self, entries):
468 """Check that all entries fit together without gaps
469
470 Args:
471 entries: List of entries to check
472 """
Simon Glass3ab95982018-08-01 15:22:37 -0600473 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700474 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600475 self.assertEqual(offset, entry.offset)
476 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700477
Simon Glasse0ff8552016-11-25 20:15:53 -0700478 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600479 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700480
481 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600482 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700483
484 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600485 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700486 """
487 return struct.unpack('>L', dtb[4:8])[0]
488
Simon Glass086cec92019-07-08 14:25:27 -0600489 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600490 def AddNode(node, path):
491 if node.name != '/':
492 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600493 for prop in node.props.values():
494 if prop.name in prop_names:
495 prop_path = path + ':' + prop.name
496 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
497 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600498 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600499 AddNode(subnode, path)
500
501 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600502 AddNode(dtb.GetRoot(), '')
503 return tree
504
Simon Glass4f443042016-11-25 20:15:52 -0700505 def testRun(self):
506 """Test a basic run with valid args"""
507 result = self._RunBinman('-h')
508
509 def testFullHelp(self):
510 """Test that the full help is displayed with -H"""
511 result = self._RunBinman('-H')
512 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500513 # Remove possible extraneous strings
514 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
515 gothelp = result.stdout.replace(extra, '')
516 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700517 self.assertEqual(0, len(result.stderr))
518 self.assertEqual(0, result.return_code)
519
520 def testFullHelpInternal(self):
521 """Test that the full help is displayed with -H"""
522 try:
523 command.test_result = command.CommandResult()
524 result = self._DoBinman('-H')
525 help_file = os.path.join(self._binman_dir, 'README')
526 finally:
527 command.test_result = None
528
529 def testHelp(self):
530 """Test that the basic help is displayed with -h"""
531 result = self._RunBinman('-h')
532 self.assertTrue(len(result.stdout) > 200)
533 self.assertEqual(0, len(result.stderr))
534 self.assertEqual(0, result.return_code)
535
Simon Glass4f443042016-11-25 20:15:52 -0700536 def testBoard(self):
537 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600538 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700539 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600540 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700541 self.assertEqual(0, result)
542
543 def testNeedBoard(self):
544 """Test that we get an error when no board ius supplied"""
545 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600546 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700547 self.assertIn("Must provide a board to process (use -b <board>)",
548 str(e.exception))
549
550 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600551 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700552 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600553 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700554 # We get one error from libfdt, and a different one from fdtget.
555 self.AssertInList(["Couldn't open blob from 'missing_file'",
556 'No such file or directory'], str(e.exception))
557
558 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600559 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700560
561 Since this is a source file it should be compiled and the error
562 will come from the device-tree compiler (dtc).
563 """
564 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600565 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700566 self.assertIn("FATAL ERROR: Unable to parse input tree",
567 str(e.exception))
568
569 def testMissingNode(self):
570 """Test that a device tree without a 'binman' node generates an error"""
571 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600572 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700573 self.assertIn("does not have a 'binman' node", str(e.exception))
574
575 def testEmpty(self):
576 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600577 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700578 self.assertEqual(0, len(result.stderr))
579 self.assertEqual(0, result.return_code)
580
581 def testInvalidEntry(self):
582 """Test that an invalid entry is flagged"""
583 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600584 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600585 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700586 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
587 "'/binman/not-a-valid-type'", str(e.exception))
588
589 def testSimple(self):
590 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600591 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700592 self.assertEqual(U_BOOT_DATA, data)
593
Simon Glass7fe91732017-11-13 18:55:00 -0700594 def testSimpleDebug(self):
595 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600596 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700597
Simon Glass4f443042016-11-25 20:15:52 -0700598 def testDual(self):
599 """Test that we can handle creating two images
600
601 This also tests image padding.
602 """
Simon Glass741f2d62018-10-01 12:22:30 -0600603 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700604 self.assertEqual(0, retcode)
605
606 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600607 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700608 fname = tools.GetOutputFilename('image1.bin')
609 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600610 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700611 data = fd.read()
612 self.assertEqual(U_BOOT_DATA, data)
613
614 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600615 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700616 fname = tools.GetOutputFilename('image2.bin')
617 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600618 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700619 data = fd.read()
620 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600621 self.assertEqual(tools.GetBytes(0, 3), data[:3])
622 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700623
624 def testBadAlign(self):
625 """Test that an invalid alignment value is detected"""
626 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600627 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700628 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
629 "of two", str(e.exception))
630
631 def testPackSimple(self):
632 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600633 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700634 self.assertEqual(0, retcode)
635 self.assertIn('image', control.images)
636 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600637 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700638 self.assertEqual(5, len(entries))
639
640 # First u-boot
641 self.assertIn('u-boot', entries)
642 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600643 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700644 self.assertEqual(len(U_BOOT_DATA), entry.size)
645
646 # Second u-boot, aligned to 16-byte boundary
647 self.assertIn('u-boot-align', entries)
648 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600649 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700650 self.assertEqual(len(U_BOOT_DATA), entry.size)
651
652 # Third u-boot, size 23 bytes
653 self.assertIn('u-boot-size', entries)
654 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600655 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700656 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
657 self.assertEqual(23, entry.size)
658
659 # Fourth u-boot, placed immediate after the above
660 self.assertIn('u-boot-next', entries)
661 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600662 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700663 self.assertEqual(len(U_BOOT_DATA), entry.size)
664
Simon Glass3ab95982018-08-01 15:22:37 -0600665 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700666 self.assertIn('u-boot-fixed', entries)
667 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600668 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700669 self.assertEqual(len(U_BOOT_DATA), entry.size)
670
Simon Glass8beb11e2019-07-08 14:25:47 -0600671 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700672
673 def testPackExtra(self):
674 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600675 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700676
677 self.assertEqual(0, retcode)
678 self.assertIn('image', control.images)
679 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600680 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700681 self.assertEqual(5, len(entries))
682
683 # First u-boot with padding before and after
684 self.assertIn('u-boot', entries)
685 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600686 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700687 self.assertEqual(3, entry.pad_before)
688 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
689
690 # Second u-boot has an aligned size, but it has no effect
691 self.assertIn('u-boot-align-size-nop', entries)
692 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600693 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700694 self.assertEqual(4, entry.size)
695
696 # Third u-boot has an aligned size too
697 self.assertIn('u-boot-align-size', entries)
698 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600699 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700700 self.assertEqual(32, entry.size)
701
702 # Fourth u-boot has an aligned end
703 self.assertIn('u-boot-align-end', entries)
704 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600705 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700706 self.assertEqual(16, entry.size)
707
708 # Fifth u-boot immediately afterwards
709 self.assertIn('u-boot-align-both', entries)
710 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600711 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700712 self.assertEqual(64, entry.size)
713
714 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600715 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700716
717 def testPackAlignPowerOf2(self):
718 """Test that invalid entry alignment is detected"""
719 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600720 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700721 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
722 "of two", str(e.exception))
723
724 def testPackAlignSizePowerOf2(self):
725 """Test that invalid entry size alignment is detected"""
726 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600727 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700728 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
729 "power of two", str(e.exception))
730
731 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600732 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700733 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600734 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600735 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700736 "align 0x4 (4)", str(e.exception))
737
738 def testPackInvalidSizeAlign(self):
739 """Test that invalid entry size alignment is detected"""
740 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600741 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700742 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
743 "align-size 0x4 (4)", str(e.exception))
744
745 def testPackOverlap(self):
746 """Test that overlapping regions are detected"""
747 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600748 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600749 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700750 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
751 str(e.exception))
752
753 def testPackEntryOverflow(self):
754 """Test that entries that overflow their size are detected"""
755 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600756 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700757 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
758 "but entry size is 0x3 (3)", str(e.exception))
759
760 def testPackImageOverflow(self):
761 """Test that entries which overflow the image size are detected"""
762 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600763 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600764 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700765 "size 0x3 (3)", str(e.exception))
766
767 def testPackImageSize(self):
768 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600769 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700770 self.assertEqual(0, retcode)
771 self.assertIn('image', control.images)
772 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600773 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700774
775 def testPackImageSizeAlign(self):
776 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600777 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700778 self.assertEqual(0, retcode)
779 self.assertIn('image', control.images)
780 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600781 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700782
783 def testPackInvalidImageAlign(self):
784 """Test that invalid image alignment is detected"""
785 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600786 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600787 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700788 "align-size 0x8 (8)", str(e.exception))
789
790 def testPackAlignPowerOf2(self):
791 """Test that invalid image alignment is detected"""
792 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600793 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600794 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700795 "two", str(e.exception))
796
797 def testImagePadByte(self):
798 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600799 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600800 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600801 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
802 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700803
804 def testImageName(self):
805 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600806 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700807 self.assertEqual(0, retcode)
808 image = control.images['image1']
809 fname = tools.GetOutputFilename('test-name')
810 self.assertTrue(os.path.exists(fname))
811
812 image = control.images['image2']
813 fname = tools.GetOutputFilename('test-name.xx')
814 self.assertTrue(os.path.exists(fname))
815
816 def testBlobFilename(self):
817 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600818 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700819 self.assertEqual(BLOB_DATA, data)
820
821 def testPackSorted(self):
822 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600823 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600824 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600825 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
826 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700827
Simon Glass3ab95982018-08-01 15:22:37 -0600828 def testPackZeroOffset(self):
829 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700830 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600831 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600832 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700833 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
834 str(e.exception))
835
836 def testPackUbootDtb(self):
837 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600838 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700839 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700840
841 def testPackX86RomNoSize(self):
842 """Test that the end-at-4gb property requires a size property"""
843 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600844 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600845 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700846 "using end-at-4gb", str(e.exception))
847
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530848 def test4gbAndSkipAtStartTogether(self):
849 """Test that the end-at-4gb and skip-at-size property can't be used
850 together"""
851 with self.assertRaises(ValueError) as e:
852 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600853 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530854 "'skip-at-start'", str(e.exception))
855
Simon Glasse0ff8552016-11-25 20:15:53 -0700856 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600857 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700858 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600859 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600860 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600861 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700862 str(e.exception))
863
864 def testPackX86Rom(self):
865 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600866 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600867 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600868 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
869 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700870
871 def testPackX86RomMeNoDesc(self):
872 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600873 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700874 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600875 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600876 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
877 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700878
879 def testPackX86RomBadDesc(self):
880 """Test that the Intel requires a descriptor entry"""
881 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600882 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600883 self.assertIn("Node '/binman/intel-me': No offset set with "
884 "offset-unset: should another entry provide this correct "
885 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700886
887 def testPackX86RomMe(self):
888 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600889 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600890 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
891 if data[:0x1000] != expected_desc:
892 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700893 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
894
895 def testPackVga(self):
896 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600897 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700898 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
899
900 def testPackStart16(self):
901 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600902 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700903 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
904
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530905 def testPackPowerpcMpc85xxBootpgResetvec(self):
906 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
907 created"""
908 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
909 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
910
Simon Glass736bb0a2018-07-06 10:27:17 -0600911 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600912 """Handle running a test for insertion of microcode
913
914 Args:
915 dts_fname: Name of test .dts file
916 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600917 ucode_second: True if the microsecond entry is second instead of
918 third
Simon Glassadc57012018-07-06 10:27:16 -0600919
920 Returns:
921 Tuple:
922 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600923 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600924 in the above (two 4-byte words)
925 """
Simon Glass6b187df2017-11-12 21:52:27 -0700926 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700927
928 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600929 if ucode_second:
930 ucode_content = data[len(nodtb_data):]
931 ucode_pos = len(nodtb_data)
932 dtb_with_ucode = ucode_content[16:]
933 fdt_len = self.GetFdtLen(dtb_with_ucode)
934 else:
935 dtb_with_ucode = data[len(nodtb_data):]
936 fdt_len = self.GetFdtLen(dtb_with_ucode)
937 ucode_content = dtb_with_ucode[fdt_len:]
938 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700939 fname = tools.GetOutputFilename('test.dtb')
940 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600941 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600942 dtb = fdt.FdtScan(fname)
943 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700944 self.assertTrue(ucode)
945 for node in ucode.subnodes:
946 self.assertFalse(node.props.get('data'))
947
Simon Glasse0ff8552016-11-25 20:15:53 -0700948 # Check that the microcode appears immediately after the Fdt
949 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700950 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700951 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
952 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600953 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700954
955 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600956 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700957 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
958 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600959 u_boot = data[:len(nodtb_data)]
960 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700961
962 def testPackUbootMicrocode(self):
963 """Test that x86 microcode can be handled correctly
964
965 We expect to see the following in the image, in order:
966 u-boot-nodtb.bin with a microcode pointer inserted at the correct
967 place
968 u-boot.dtb with the microcode removed
969 the microcode
970 """
Simon Glass741f2d62018-10-01 12:22:30 -0600971 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700972 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600973 self.assertEqual(b'nodtb with microcode' + pos_and_size +
974 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -0700975
Simon Glass160a7662017-05-27 07:38:26 -0600976 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -0700977 """Test that x86 microcode can be handled correctly
978
979 We expect to see the following in the image, in order:
980 u-boot-nodtb.bin with a microcode pointer inserted at the correct
981 place
982 u-boot.dtb with the microcode
983 an empty microcode region
984 """
985 # We need the libfdt library to run this test since only that allows
986 # finding the offset of a property. This is required by
987 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -0600988 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700989
990 second = data[len(U_BOOT_NODTB_DATA):]
991
992 fdt_len = self.GetFdtLen(second)
993 third = second[fdt_len:]
994 second = second[:fdt_len]
995
Simon Glass160a7662017-05-27 07:38:26 -0600996 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
997 self.assertIn(ucode_data, second)
998 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700999
Simon Glass160a7662017-05-27 07:38:26 -06001000 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001001 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001002 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1003 len(ucode_data))
1004 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001005 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1006 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001007
Simon Glass75db0862016-11-25 20:15:55 -07001008 def testPackUbootSingleMicrocode(self):
1009 """Test that x86 microcode can be handled correctly with fdt_normal.
1010 """
Simon Glass160a7662017-05-27 07:38:26 -06001011 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001012
Simon Glassc49deb82016-11-25 20:15:54 -07001013 def testUBootImg(self):
1014 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001015 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001016 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001017
1018 def testNoMicrocode(self):
1019 """Test that a missing microcode region is detected"""
1020 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001021 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001022 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1023 "node found in ", str(e.exception))
1024
1025 def testMicrocodeWithoutNode(self):
1026 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1027 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001028 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001029 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1030 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1031
1032 def testMicrocodeWithoutNode2(self):
1033 """Test that a missing u-boot-ucode node is detected"""
1034 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001035 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001036 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1037 "microcode region u-boot-ucode", str(e.exception))
1038
1039 def testMicrocodeWithoutPtrInElf(self):
1040 """Test that a U-Boot binary without the microcode symbol is detected"""
1041 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001042 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001043 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001044 TestFunctional._MakeInputFile('u-boot', fd.read())
1045
1046 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001047 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001048 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1049 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1050
1051 finally:
1052 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -06001053 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001054 TestFunctional._MakeInputFile('u-boot', fd.read())
1055
1056 def testMicrocodeNotInImage(self):
1057 """Test that microcode must be placed within the image"""
1058 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001059 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001060 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1061 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001062 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001063
1064 def testWithoutMicrocode(self):
1065 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001066 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001067 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001068 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001069
1070 # Now check the device tree has no microcode
1071 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1072 second = data[len(U_BOOT_NODTB_DATA):]
1073
1074 fdt_len = self.GetFdtLen(second)
1075 self.assertEqual(dtb, second[:fdt_len])
1076
1077 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1078 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001079 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001080
1081 def testUnknownPosSize(self):
1082 """Test that microcode must be placed within the image"""
1083 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001084 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001085 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001086 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001087
1088 def testPackFsp(self):
1089 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001090 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001091 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1092
1093 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001094 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001095 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001096 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001097
1098 def testPackVbt(self):
1099 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001100 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001101 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001102
Simon Glass56509842017-11-12 21:52:25 -07001103 def testSplBssPad(self):
1104 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001105 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001106 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001107 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001108 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1109 data)
Simon Glass56509842017-11-12 21:52:25 -07001110
Simon Glass86af5112018-10-01 21:12:42 -06001111 def testSplBssPadMissing(self):
1112 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001113 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001114 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001115 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001116 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1117 str(e.exception))
1118
Simon Glass87722132017-11-12 21:52:26 -07001119 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001120 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001121 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001122 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1123
Simon Glass736bb0a2018-07-06 10:27:17 -06001124 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1125 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001126
1127 We expect to see the following in the image, in order:
1128 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1129 correct place
1130 u-boot.dtb with the microcode removed
1131 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001132
1133 Args:
1134 dts: Device tree file to use for test
1135 ucode_second: True if the microsecond entry is second instead of
1136 third
Simon Glass6b187df2017-11-12 21:52:27 -07001137 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001138 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001139 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1140 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001141 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1142 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001143
Simon Glass736bb0a2018-07-06 10:27:17 -06001144 def testPackUbootSplMicrocode(self):
1145 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001146 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001147
1148 def testPackUbootSplMicrocodeReorder(self):
1149 """Test that order doesn't matter for microcode entries
1150
1151 This is the same as testPackUbootSplMicrocode but when we process the
1152 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1153 entry, so we reply on binman to try later.
1154 """
Simon Glass741f2d62018-10-01 12:22:30 -06001155 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001156 ucode_second=True)
1157
Simon Glassca4f4ff2017-11-12 21:52:28 -07001158 def testPackMrc(self):
1159 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001160 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001161 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1162
Simon Glass47419ea2017-11-13 18:54:55 -07001163 def testSplDtb(self):
1164 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001165 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001166 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1167
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001168 def testSplNoDtb(self):
1169 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001170 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001171 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1172
Simon Glass19790632017-11-13 18:55:01 -07001173 def testSymbols(self):
1174 """Test binman can assign symbols embedded in U-Boot"""
1175 elf_fname = self.TestFile('u_boot_binman_syms')
1176 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1177 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001178 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001179
Simon Glass11ae93e2018-10-01 21:12:47 -06001180 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001181 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001182 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001183 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1184 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1185 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001186 self.assertEqual(expected, data)
1187
Simon Glassdd57c132018-06-01 09:38:11 -06001188 def testPackUnitAddress(self):
1189 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001190 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001191 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1192
Simon Glass18546952018-06-01 09:38:16 -06001193 def testSections(self):
1194 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001195 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001196 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1197 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1198 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001199 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001200
Simon Glass3b0c3822018-06-01 09:38:20 -06001201 def testMap(self):
1202 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001203 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001204 self.assertEqual('''ImagePos Offset Size Name
120500000000 00000000 00000028 main-section
120600000000 00000000 00000010 section@0
120700000000 00000000 00000004 u-boot
120800000010 00000010 00000010 section@1
120900000010 00000000 00000004 u-boot
121000000020 00000020 00000004 section@2
121100000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001212''', map_data)
1213
Simon Glassc8d48ef2018-06-01 09:38:21 -06001214 def testNamePrefix(self):
1215 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001216 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001217 self.assertEqual('''ImagePos Offset Size Name
121800000000 00000000 00000028 main-section
121900000000 00000000 00000010 section@0
122000000000 00000000 00000004 ro-u-boot
122100000010 00000010 00000010 section@1
122200000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001223''', map_data)
1224
Simon Glass736bb0a2018-07-06 10:27:17 -06001225 def testUnknownContents(self):
1226 """Test that obtaining the contents works as expected"""
1227 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001228 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001229 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass736bb0a2018-07-06 10:27:17 -06001230 "processing of contents: remaining [<_testing.Entry__testing ",
1231 str(e.exception))
1232
Simon Glass5c890232018-07-06 10:27:19 -06001233 def testBadChangeSize(self):
1234 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001235 try:
1236 state.SetAllowEntryExpansion(False)
1237 with self.assertRaises(ValueError) as e:
1238 self._DoReadFile('059_change_size.dts', True)
1239 self.assertIn("Node '/binman/_testing': Cannot update entry size from 1 to 2",
1240 str(e.exception))
1241 finally:
1242 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001243
Simon Glass16b8d6b2018-07-06 10:27:42 -06001244 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001245 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001246 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001247 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001248 dtb = fdt.Fdt(out_dtb_fname)
1249 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001250 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001251 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001252 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001253 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001254 '_testing:offset': 32,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001255 '_testing:size': 1,
Simon Glassdbf6be92018-08-01 15:22:42 -06001256 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001257 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001258 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001259 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001260 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001261 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001262 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001263
Simon Glass3ab95982018-08-01 15:22:37 -06001264 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001265 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001266 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001267 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001268 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001269 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001270 'size': 40
1271 }, props)
1272
1273 def testUpdateFdtBad(self):
1274 """Test that we detect when ProcessFdt never completes"""
1275 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001276 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001277 self.assertIn('Could not complete processing of Fdt: remaining '
1278 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001279
Simon Glass53af22a2018-07-17 13:25:32 -06001280 def testEntryArgs(self):
1281 """Test passing arguments to entries from the command line"""
1282 entry_args = {
1283 'test-str-arg': 'test1',
1284 'test-int-arg': '456',
1285 }
Simon Glass741f2d62018-10-01 12:22:30 -06001286 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001287 self.assertIn('image', control.images)
1288 entry = control.images['image'].GetEntries()['_testing']
1289 self.assertEqual('test0', entry.test_str_fdt)
1290 self.assertEqual('test1', entry.test_str_arg)
1291 self.assertEqual(123, entry.test_int_fdt)
1292 self.assertEqual(456, entry.test_int_arg)
1293
1294 def testEntryArgsMissing(self):
1295 """Test missing arguments and properties"""
1296 entry_args = {
1297 'test-int-arg': '456',
1298 }
Simon Glass741f2d62018-10-01 12:22:30 -06001299 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001300 entry = control.images['image'].GetEntries()['_testing']
1301 self.assertEqual('test0', entry.test_str_fdt)
1302 self.assertEqual(None, entry.test_str_arg)
1303 self.assertEqual(None, entry.test_int_fdt)
1304 self.assertEqual(456, entry.test_int_arg)
1305
1306 def testEntryArgsRequired(self):
1307 """Test missing arguments and properties"""
1308 entry_args = {
1309 'test-int-arg': '456',
1310 }
1311 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001312 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001313 self.assertIn("Node '/binman/_testing': Missing required "
1314 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1315 str(e.exception))
1316
1317 def testEntryArgsInvalidFormat(self):
1318 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001319 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1320 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001321 with self.assertRaises(ValueError) as e:
1322 self._DoBinman(*args)
1323 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1324
1325 def testEntryArgsInvalidInteger(self):
1326 """Test that an invalid entry-argument integer is detected"""
1327 entry_args = {
1328 'test-int-arg': 'abc',
1329 }
1330 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001331 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001332 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1333 "'test-int-arg' (value 'abc') to integer",
1334 str(e.exception))
1335
1336 def testEntryArgsInvalidDatatype(self):
1337 """Test that an invalid entry-argument datatype is detected
1338
1339 This test could be written in entry_test.py except that it needs
1340 access to control.entry_args, which seems more than that module should
1341 be able to see.
1342 """
1343 entry_args = {
1344 'test-bad-datatype-arg': '12',
1345 }
1346 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001347 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001348 entry_args=entry_args)
1349 self.assertIn('GetArg() internal error: Unknown data type ',
1350 str(e.exception))
1351
Simon Glassbb748372018-07-17 13:25:33 -06001352 def testText(self):
1353 """Test for a text entry type"""
1354 entry_args = {
1355 'test-id': TEXT_DATA,
1356 'test-id2': TEXT_DATA2,
1357 'test-id3': TEXT_DATA3,
1358 }
Simon Glass741f2d62018-10-01 12:22:30 -06001359 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001360 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001361 expected = (tools.ToBytes(TEXT_DATA) +
1362 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1363 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001364 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001365 self.assertEqual(expected, data)
1366
Simon Glassfd8d1f72018-07-17 13:25:36 -06001367 def testEntryDocs(self):
1368 """Test for creation of entry documentation"""
1369 with test_util.capture_sys_output() as (stdout, stderr):
1370 control.WriteEntryDocs(binman.GetEntryModules())
1371 self.assertTrue(len(stdout.getvalue()) > 0)
1372
1373 def testEntryDocsMissing(self):
1374 """Test handling of missing entry documentation"""
1375 with self.assertRaises(ValueError) as e:
1376 with test_util.capture_sys_output() as (stdout, stderr):
1377 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1378 self.assertIn('Documentation is missing for modules: u_boot',
1379 str(e.exception))
1380
Simon Glass11e36cc2018-07-17 13:25:38 -06001381 def testFmap(self):
1382 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001383 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001384 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001385 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1386 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001387 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001388 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001389 self.assertEqual(1, fhdr.ver_major)
1390 self.assertEqual(0, fhdr.ver_minor)
1391 self.assertEqual(0, fhdr.base)
1392 self.assertEqual(16 + 16 +
1393 fmap_util.FMAP_HEADER_LEN +
1394 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001395 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001396 self.assertEqual(3, fhdr.nareas)
1397 for fentry in fentries:
1398 self.assertEqual(0, fentry.flags)
1399
1400 self.assertEqual(0, fentries[0].offset)
1401 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001402 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001403
1404 self.assertEqual(16, fentries[1].offset)
1405 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001406 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001407
1408 self.assertEqual(32, fentries[2].offset)
1409 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1410 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001411 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001412
Simon Glassec127af2018-07-17 13:25:39 -06001413 def testBlobNamedByArg(self):
1414 """Test we can add a blob with the filename coming from an entry arg"""
1415 entry_args = {
1416 'cros-ec-rw-path': 'ecrw.bin',
1417 }
Simon Glass741f2d62018-10-01 12:22:30 -06001418 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001419 entry_args=entry_args)
1420
Simon Glass3af8e492018-07-17 13:25:40 -06001421 def testFill(self):
1422 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001423 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001424 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001425 self.assertEqual(expected, data)
1426
1427 def testFillNoSize(self):
1428 """Test for an fill entry type with no size"""
1429 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001430 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001431 self.assertIn("'fill' entry must have a size property",
1432 str(e.exception))
1433
Simon Glass0ef87aa2018-07-17 13:25:44 -06001434 def _HandleGbbCommand(self, pipe_list):
1435 """Fake calls to the futility utility"""
1436 if pipe_list[0][0] == 'futility':
1437 fname = pipe_list[0][-1]
1438 # Append our GBB data to the file, which will happen every time the
1439 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001440 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001441 fd.write(GBB_DATA)
1442 return command.CommandResult()
1443
1444 def testGbb(self):
1445 """Test for the Chromium OS Google Binary Block"""
1446 command.test_result = self._HandleGbbCommand
1447 entry_args = {
1448 'keydir': 'devkeys',
1449 'bmpblk': 'bmpblk.bin',
1450 }
Simon Glass741f2d62018-10-01 12:22:30 -06001451 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001452
1453 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001454 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1455 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001456 self.assertEqual(expected, data)
1457
1458 def testGbbTooSmall(self):
1459 """Test for the Chromium OS Google Binary Block being large enough"""
1460 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001461 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001462 self.assertIn("Node '/binman/gbb': GBB is too small",
1463 str(e.exception))
1464
1465 def testGbbNoSize(self):
1466 """Test for the Chromium OS Google Binary Block having a size"""
1467 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001468 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001469 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1470 str(e.exception))
1471
Simon Glass24d0d3c2018-07-17 13:25:47 -06001472 def _HandleVblockCommand(self, pipe_list):
1473 """Fake calls to the futility utility"""
1474 if pipe_list[0][0] == 'futility':
1475 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001476 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001477 fd.write(VBLOCK_DATA)
1478 return command.CommandResult()
1479
1480 def testVblock(self):
1481 """Test for the Chromium OS Verified Boot Block"""
1482 command.test_result = self._HandleVblockCommand
1483 entry_args = {
1484 'keydir': 'devkeys',
1485 }
Simon Glass741f2d62018-10-01 12:22:30 -06001486 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001487 entry_args=entry_args)
1488 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1489 self.assertEqual(expected, data)
1490
1491 def testVblockNoContent(self):
1492 """Test we detect a vblock which has no content to sign"""
1493 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001494 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001495 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1496 'property', str(e.exception))
1497
1498 def testVblockBadPhandle(self):
1499 """Test that we detect a vblock with an invalid phandle in contents"""
1500 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001501 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001502 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1503 '1000', str(e.exception))
1504
1505 def testVblockBadEntry(self):
1506 """Test that we detect an entry that points to a non-entry"""
1507 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001508 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001509 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1510 "'other'", str(e.exception))
1511
Simon Glassb8ef5b62018-07-17 13:25:48 -06001512 def testTpl(self):
1513 """Test that an image with TPL and ots device tree can be created"""
1514 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001515 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001516 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001517 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001518 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1519
Simon Glass15a587c2018-07-17 13:25:51 -06001520 def testUsesPos(self):
1521 """Test that the 'pos' property cannot be used anymore"""
1522 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001523 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001524 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1525 "'pos'", str(e.exception))
1526
Simon Glassd178eab2018-09-14 04:57:08 -06001527 def testFillZero(self):
1528 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001529 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001530 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001531
Simon Glass0b489362018-09-14 04:57:09 -06001532 def testTextMissing(self):
1533 """Test for a text entry type where there is no text"""
1534 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001535 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001536 self.assertIn("Node '/binman/text': No value provided for text label "
1537 "'test-id'", str(e.exception))
1538
Simon Glass35b384c2018-09-14 04:57:10 -06001539 def testPackStart16Tpl(self):
1540 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001541 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001542 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1543
Simon Glass0bfa7b02018-09-14 04:57:12 -06001544 def testSelectImage(self):
1545 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001546 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001547
Simon Glasseb833d82019-04-25 21:58:34 -06001548 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001549 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001550 with test_util.capture_sys_output() as (stdout, stderr):
1551 retcode = self._DoTestFile('006_dual_image.dts',
1552 verbosity=verbosity,
1553 images=['image2'])
1554 self.assertEqual(0, retcode)
1555 if verbosity:
1556 self.assertIn(expected, stdout.getvalue())
1557 else:
1558 self.assertNotIn(expected, stdout.getvalue())
1559
1560 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1561 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glass0bfa7b02018-09-14 04:57:12 -06001562
Simon Glass6ed45ba2018-09-14 04:57:24 -06001563 def testUpdateFdtAll(self):
1564 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001565 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001566
1567 base_expected = {
1568 'section:image-pos': 0,
1569 'u-boot-tpl-dtb:size': 513,
1570 'u-boot-spl-dtb:size': 513,
1571 'u-boot-spl-dtb:offset': 493,
1572 'image-pos': 0,
1573 'section/u-boot-dtb:image-pos': 0,
1574 'u-boot-spl-dtb:image-pos': 493,
1575 'section/u-boot-dtb:size': 493,
1576 'u-boot-tpl-dtb:image-pos': 1006,
1577 'section/u-boot-dtb:offset': 0,
1578 'section:size': 493,
1579 'offset': 0,
1580 'section:offset': 0,
1581 'u-boot-tpl-dtb:offset': 1006,
1582 'size': 1519
1583 }
1584
1585 # We expect three device-tree files in the output, one after the other.
1586 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1587 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1588 # main U-Boot tree. All three should have the same postions and offset.
1589 start = 0
1590 for item in ['', 'spl', 'tpl']:
1591 dtb = fdt.Fdt.FromData(data[start:])
1592 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001593 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1594 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001595 expected = dict(base_expected)
1596 if item:
1597 expected[item] = 0
1598 self.assertEqual(expected, props)
1599 start += dtb._fdt_obj.totalsize()
1600
1601 def testUpdateFdtOutput(self):
1602 """Test that output DTB files are updated"""
1603 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001604 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001605 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1606
1607 # Unfortunately, compiling a source file always results in a file
1608 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001609 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001610 # binman as a file called u-boot.dtb. To fix this, copy the file
1611 # over to the expected place.
1612 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1613 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1614 start = 0
1615 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1616 'tpl/u-boot-tpl.dtb.out']:
1617 dtb = fdt.Fdt.FromData(data[start:])
1618 size = dtb._fdt_obj.totalsize()
1619 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1620 outdata = tools.ReadFile(pathname)
1621 name = os.path.split(fname)[0]
1622
1623 if name:
1624 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1625 else:
1626 orig_indata = dtb_data
1627 self.assertNotEqual(outdata, orig_indata,
1628 "Expected output file '%s' be updated" % pathname)
1629 self.assertEqual(outdata, data[start:start + size],
1630 "Expected output file '%s' to match output image" %
1631 pathname)
1632 start += size
1633 finally:
1634 self._ResetDtbs()
1635
Simon Glass83d73c22018-09-14 04:57:26 -06001636 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001637 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001638
1639 def testCompress(self):
1640 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001641 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001642 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001643 use_real_dtb=True, update_dtb=True)
1644 dtb = fdt.Fdt(out_dtb_fname)
1645 dtb.Scan()
1646 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1647 orig = self._decompress(data)
1648 self.assertEquals(COMPRESS_DATA, orig)
1649 expected = {
1650 'blob:uncomp-size': len(COMPRESS_DATA),
1651 'blob:size': len(data),
1652 'size': len(data),
1653 }
1654 self.assertEqual(expected, props)
1655
Simon Glass0a98b282018-09-14 04:57:28 -06001656 def testFiles(self):
1657 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001658 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001659 self.assertEqual(FILES_DATA, data)
1660
1661 def testFilesCompress(self):
1662 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001663 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001664 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001665
1666 image = control.images['image']
1667 entries = image.GetEntries()
1668 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001669 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001670
Simon Glassc6c10e72019-05-17 22:00:46 -06001671 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001672 for i in range(1, 3):
1673 key = '%d.dat' % i
1674 start = entries[key].image_pos
1675 len = entries[key].size
1676 chunk = data[start:start + len]
1677 orig += self._decompress(chunk)
1678
1679 self.assertEqual(FILES_DATA, orig)
1680
1681 def testFilesMissing(self):
1682 """Test missing files"""
1683 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001684 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001685 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1686 'no files', str(e.exception))
1687
1688 def testFilesNoPattern(self):
1689 """Test missing files"""
1690 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001691 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001692 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1693 str(e.exception))
1694
Simon Glassba64a0b2018-09-14 04:57:29 -06001695 def testExpandSize(self):
1696 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001697 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001698 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001699 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1700 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1701 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1702 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001703 self.assertEqual(expect, data)
1704 self.assertEqual('''ImagePos Offset Size Name
170500000000 00000000 00000028 main-section
170600000000 00000000 00000008 fill
170700000008 00000008 00000004 u-boot
17080000000c 0000000c 00000004 section
17090000000c 00000000 00000003 intel-mrc
171000000010 00000010 00000004 u-boot2
171100000014 00000014 0000000c section2
171200000014 00000000 00000008 fill
17130000001c 00000008 00000004 u-boot
171400000020 00000020 00000008 fill2
1715''', map_data)
1716
1717 def testExpandSizeBad(self):
1718 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001719 with test_util.capture_sys_output() as (stdout, stderr):
1720 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001721 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001722 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1723 'expanding entry', str(e.exception))
1724
Simon Glasse0e5df92018-09-14 04:57:31 -06001725 def testHash(self):
1726 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001727 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001728 use_real_dtb=True, update_dtb=True)
1729 dtb = fdt.Fdt(out_dtb_fname)
1730 dtb.Scan()
1731 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1732 m = hashlib.sha256()
1733 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001734 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001735
1736 def testHashNoAlgo(self):
1737 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001738 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001739 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1740 'hash node', str(e.exception))
1741
1742 def testHashBadAlgo(self):
1743 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001744 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001745 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1746 str(e.exception))
1747
1748 def testHashSection(self):
1749 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001750 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001751 use_real_dtb=True, update_dtb=True)
1752 dtb = fdt.Fdt(out_dtb_fname)
1753 dtb.Scan()
1754 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1755 m = hashlib.sha256()
1756 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001757 m.update(tools.GetBytes(ord('a'), 16))
1758 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001759
Simon Glassf0253632018-09-14 04:57:32 -06001760 def testPackUBootTplMicrocode(self):
1761 """Test that x86 microcode can be handled correctly in TPL
1762
1763 We expect to see the following in the image, in order:
1764 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1765 place
1766 u-boot-tpl.dtb with the microcode removed
1767 the microcode
1768 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001769 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001770 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001771 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001772 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001773 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1774 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001775
Simon Glassf8f8df62018-09-14 04:57:34 -06001776 def testFmapX86(self):
1777 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001778 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001779 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001780 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001781 self.assertEqual(expected, data[:32])
1782 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1783
1784 self.assertEqual(0x100, fhdr.image_size)
1785
1786 self.assertEqual(0, fentries[0].offset)
1787 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001788 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001789
1790 self.assertEqual(4, fentries[1].offset)
1791 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001792 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001793
1794 self.assertEqual(32, fentries[2].offset)
1795 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1796 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001797 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001798
1799 def testFmapX86Section(self):
1800 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001801 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001802 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001803 self.assertEqual(expected, data[:32])
1804 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1805
1806 self.assertEqual(0x100, fhdr.image_size)
1807
1808 self.assertEqual(0, fentries[0].offset)
1809 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001810 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001811
1812 self.assertEqual(4, fentries[1].offset)
1813 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001814 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001815
1816 self.assertEqual(36, fentries[2].offset)
1817 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1818 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001819 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001820
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001821 def testElf(self):
1822 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001823 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001824 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001825 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1826 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001827 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001828 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001829
Simon Glass093d1682019-07-08 13:18:25 -06001830 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001831 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001832 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001833 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001834 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001835 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001836
Simon Glass163ed6c2018-09-14 04:57:36 -06001837 def testPackOverlapMap(self):
1838 """Test that overlapping regions are detected"""
1839 with test_util.capture_sys_output() as (stdout, stderr):
1840 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001841 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001842 map_fname = tools.GetOutputFilename('image.map')
1843 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1844 stdout.getvalue())
1845
1846 # We should not get an inmage, but there should be a map file
1847 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1848 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001849 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001850 self.assertEqual('''ImagePos Offset Size Name
1851<none> 00000000 00000007 main-section
1852<none> 00000000 00000004 u-boot
1853<none> 00000003 00000004 u-boot-align
1854''', map_data)
1855
Simon Glass093d1682019-07-08 13:18:25 -06001856 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001857 """Test that an image with an Intel Reference code binary works"""
1858 data = self._DoReadFile('100_intel_refcode.dts')
1859 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1860
Simon Glass9481c802019-04-25 21:58:39 -06001861 def testSectionOffset(self):
1862 """Tests use of a section with an offset"""
1863 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1864 map=True)
1865 self.assertEqual('''ImagePos Offset Size Name
186600000000 00000000 00000038 main-section
186700000004 00000004 00000010 section@0
186800000004 00000000 00000004 u-boot
186900000018 00000018 00000010 section@1
187000000018 00000000 00000004 u-boot
18710000002c 0000002c 00000004 section@2
18720000002c 00000000 00000004 u-boot
1873''', map_data)
1874 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001875 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1876 tools.GetBytes(0x21, 12) +
1877 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1878 tools.GetBytes(0x61, 12) +
1879 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1880 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001881
Simon Glassac62fba2019-07-08 13:18:53 -06001882 def testCbfsRaw(self):
1883 """Test base handling of a Coreboot Filesystem (CBFS)
1884
1885 The exact contents of the CBFS is verified by similar tests in
1886 cbfs_util_test.py. The tests here merely check that the files added to
1887 the CBFS can be found in the final image.
1888 """
1889 data = self._DoReadFile('102_cbfs_raw.dts')
1890 size = 0xb0
1891
1892 cbfs = cbfs_util.CbfsReader(data)
1893 self.assertEqual(size, cbfs.rom_size)
1894
1895 self.assertIn('u-boot-dtb', cbfs.files)
1896 cfile = cbfs.files['u-boot-dtb']
1897 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1898
1899 def testCbfsArch(self):
1900 """Test on non-x86 architecture"""
1901 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1902 size = 0x100
1903
1904 cbfs = cbfs_util.CbfsReader(data)
1905 self.assertEqual(size, cbfs.rom_size)
1906
1907 self.assertIn('u-boot-dtb', cbfs.files)
1908 cfile = cbfs.files['u-boot-dtb']
1909 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1910
1911 def testCbfsStage(self):
1912 """Tests handling of a Coreboot Filesystem (CBFS)"""
1913 if not elf.ELF_TOOLS:
1914 self.skipTest('Python elftools not available')
1915 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1916 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1917 size = 0xb0
1918
1919 data = self._DoReadFile('104_cbfs_stage.dts')
1920 cbfs = cbfs_util.CbfsReader(data)
1921 self.assertEqual(size, cbfs.rom_size)
1922
1923 self.assertIn('u-boot', cbfs.files)
1924 cfile = cbfs.files['u-boot']
1925 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1926
1927 def testCbfsRawCompress(self):
1928 """Test handling of compressing raw files"""
1929 self._CheckLz4()
1930 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1931 size = 0x140
1932
1933 cbfs = cbfs_util.CbfsReader(data)
1934 self.assertIn('u-boot', cbfs.files)
1935 cfile = cbfs.files['u-boot']
1936 self.assertEqual(COMPRESS_DATA, cfile.data)
1937
1938 def testCbfsBadArch(self):
1939 """Test handling of a bad architecture"""
1940 with self.assertRaises(ValueError) as e:
1941 self._DoReadFile('106_cbfs_bad_arch.dts')
1942 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1943
1944 def testCbfsNoSize(self):
1945 """Test handling of a missing size property"""
1946 with self.assertRaises(ValueError) as e:
1947 self._DoReadFile('107_cbfs_no_size.dts')
1948 self.assertIn('entry must have a size property', str(e.exception))
1949
1950 def testCbfsNoCOntents(self):
1951 """Test handling of a CBFS entry which does not provide contentsy"""
1952 with self.assertRaises(ValueError) as e:
1953 self._DoReadFile('108_cbfs_no_contents.dts')
1954 self.assertIn('Could not complete processing of contents',
1955 str(e.exception))
1956
1957 def testCbfsBadCompress(self):
1958 """Test handling of a bad architecture"""
1959 with self.assertRaises(ValueError) as e:
1960 self._DoReadFile('109_cbfs_bad_compress.dts')
1961 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1962 str(e.exception))
1963
1964 def testCbfsNamedEntries(self):
1965 """Test handling of named entries"""
1966 data = self._DoReadFile('110_cbfs_name.dts')
1967
1968 cbfs = cbfs_util.CbfsReader(data)
1969 self.assertIn('FRED', cbfs.files)
1970 cfile1 = cbfs.files['FRED']
1971 self.assertEqual(U_BOOT_DATA, cfile1.data)
1972
1973 self.assertIn('hello', cbfs.files)
1974 cfile2 = cbfs.files['hello']
1975 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
1976
Simon Glassc5ac1382019-07-08 13:18:54 -06001977 def _SetupIfwi(self, fname):
1978 """Set up to run an IFWI test
1979
1980 Args:
1981 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
1982 """
1983 self._SetupSplElf()
1984
1985 # Intel Integrated Firmware Image (IFWI) file
1986 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
1987 data = fd.read()
1988 TestFunctional._MakeInputFile(fname,data)
1989
1990 def _CheckIfwi(self, data):
1991 """Check that an image with an IFWI contains the correct output
1992
1993 Args:
1994 data: Conents of output file
1995 """
1996 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1997 if data[:0x1000] != expected_desc:
1998 self.fail('Expected descriptor binary at start of image')
1999
2000 # We expect to find the TPL wil in subpart IBBP entry IBBL
2001 image_fname = tools.GetOutputFilename('image.bin')
2002 tpl_fname = tools.GetOutputFilename('tpl.out')
2003 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2004 subpart='IBBP', entry_name='IBBL')
2005
2006 tpl_data = tools.ReadFile(tpl_fname)
2007 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2008
2009 def testPackX86RomIfwi(self):
2010 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2011 self._SetupIfwi('fitimage.bin')
2012 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2013 self._CheckIfwi(data)
2014
2015 def testPackX86RomIfwiNoDesc(self):
2016 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2017 self._SetupIfwi('ifwi.bin')
2018 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2019 self._CheckIfwi(data)
2020
2021 def testPackX86RomIfwiNoData(self):
2022 """Test that an x86 ROM with IFWI handles missing data"""
2023 self._SetupIfwi('ifwi.bin')
2024 with self.assertRaises(ValueError) as e:
2025 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2026 self.assertIn('Could not complete processing of contents',
2027 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002028
Simon Glasse073d4e2019-07-08 13:18:56 -06002029 def testCbfsOffset(self):
2030 """Test a CBFS with files at particular offsets
2031
2032 Like all CFBS tests, this is just checking the logic that calls
2033 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2034 """
2035 data = self._DoReadFile('114_cbfs_offset.dts')
2036 size = 0x200
2037
2038 cbfs = cbfs_util.CbfsReader(data)
2039 self.assertEqual(size, cbfs.rom_size)
2040
2041 self.assertIn('u-boot', cbfs.files)
2042 cfile = cbfs.files['u-boot']
2043 self.assertEqual(U_BOOT_DATA, cfile.data)
2044 self.assertEqual(0x40, cfile.cbfs_offset)
2045
2046 self.assertIn('u-boot-dtb', cbfs.files)
2047 cfile2 = cbfs.files['u-boot-dtb']
2048 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2049 self.assertEqual(0x140, cfile2.cbfs_offset)
2050
Simon Glass086cec92019-07-08 14:25:27 -06002051 def testFdtmap(self):
2052 """Test an FDT map can be inserted in the image"""
2053 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2054 fdtmap_data = data[len(U_BOOT_DATA):]
2055 magic = fdtmap_data[:8]
2056 self.assertEqual('_FDTMAP_', magic)
2057 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2058
2059 fdt_data = fdtmap_data[16:]
2060 dtb = fdt.Fdt.FromData(fdt_data)
2061 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002062 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002063 self.assertEqual({
2064 'image-pos': 0,
2065 'offset': 0,
2066 'u-boot:offset': 0,
2067 'u-boot:size': len(U_BOOT_DATA),
2068 'u-boot:image-pos': 0,
2069 'fdtmap:image-pos': 4,
2070 'fdtmap:offset': 4,
2071 'fdtmap:size': len(fdtmap_data),
2072 'size': len(data),
2073 }, props)
2074
2075 def testFdtmapNoMatch(self):
2076 """Check handling of an FDT map when the section cannot be found"""
2077 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2078
2079 # Mangle the section name, which should cause a mismatch between the
2080 # correct FDT path and the one expected by the section
2081 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002082 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002083 entries = image.GetEntries()
2084 fdtmap = entries['fdtmap']
2085 with self.assertRaises(ValueError) as e:
2086 fdtmap._GetFdtmap()
2087 self.assertIn("Cannot locate node for path '/binman-suffix'",
2088 str(e.exception))
2089
Simon Glasscf228942019-07-08 14:25:28 -06002090 def testFdtmapHeader(self):
2091 """Test an FDT map and image header can be inserted in the image"""
2092 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2093 fdtmap_pos = len(U_BOOT_DATA)
2094 fdtmap_data = data[fdtmap_pos:]
2095 fdt_data = fdtmap_data[16:]
2096 dtb = fdt.Fdt.FromData(fdt_data)
2097 fdt_size = dtb.GetFdtObj().totalsize()
2098 hdr_data = data[-8:]
2099 self.assertEqual('BinM', hdr_data[:4])
2100 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2101 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2102
2103 def testFdtmapHeaderStart(self):
2104 """Test an image header can be inserted at the image start"""
2105 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2106 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2107 hdr_data = data[:8]
2108 self.assertEqual('BinM', hdr_data[:4])
2109 offset = struct.unpack('<I', hdr_data[4:])[0]
2110 self.assertEqual(fdtmap_pos, offset)
2111
2112 def testFdtmapHeaderPos(self):
2113 """Test an image header can be inserted at a chosen position"""
2114 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2115 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2116 hdr_data = data[0x80:0x88]
2117 self.assertEqual('BinM', hdr_data[:4])
2118 offset = struct.unpack('<I', hdr_data[4:])[0]
2119 self.assertEqual(fdtmap_pos, offset)
2120
2121 def testHeaderMissingFdtmap(self):
2122 """Test an image header requires an fdtmap"""
2123 with self.assertRaises(ValueError) as e:
2124 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2125 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2126 str(e.exception))
2127
2128 def testHeaderNoLocation(self):
2129 """Test an image header with a no specified location is detected"""
2130 with self.assertRaises(ValueError) as e:
2131 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2132 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2133 str(e.exception))
2134
Simon Glassc52c9e72019-07-08 14:25:37 -06002135 def testEntryExpand(self):
2136 """Test expanding an entry after it is packed"""
2137 data = self._DoReadFile('121_entry_expand.dts')
2138 self.assertEqual(b'aa', data[:2])
2139 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2140 self.assertEqual(b'aa', data[-2:])
2141
2142 def testEntryExpandBad(self):
2143 """Test expanding an entry after it is packed, twice"""
2144 with self.assertRaises(ValueError) as e:
2145 self._DoReadFile('122_entry_expand_twice.dts')
2146 self.assertIn("Image '/binman': Entries expanded after packing",
2147 str(e.exception))
2148
2149 def testEntryExpandSection(self):
2150 """Test expanding an entry within a section after it is packed"""
2151 data = self._DoReadFile('123_entry_expand_section.dts')
2152 self.assertEqual(b'aa', data[:2])
2153 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
2154 self.assertEqual(b'aa', data[-2:])
2155
Simon Glass6c223fd2019-07-08 14:25:38 -06002156 def testCompressDtb(self):
2157 """Test that compress of device-tree files is supported"""
2158 self._CheckLz4()
2159 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2160 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2161 comp_data = data[len(U_BOOT_DATA):]
2162 orig = self._decompress(comp_data)
2163 dtb = fdt.Fdt.FromData(orig)
2164 dtb.Scan()
2165 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2166 expected = {
2167 'u-boot:size': len(U_BOOT_DATA),
2168 'u-boot-dtb:uncomp-size': len(orig),
2169 'u-boot-dtb:size': len(comp_data),
2170 'size': len(data),
2171 }
2172 self.assertEqual(expected, props)
2173
Simon Glass69f7cb32019-07-08 14:25:41 -06002174 def testCbfsUpdateFdt(self):
2175 """Test that we can update the device tree with CBFS offset/size info"""
2176 self._CheckLz4()
2177 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2178 update_dtb=True)
2179 dtb = fdt.Fdt(out_dtb_fname)
2180 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002181 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002182 del props['cbfs/u-boot:size']
2183 self.assertEqual({
2184 'offset': 0,
2185 'size': len(data),
2186 'image-pos': 0,
2187 'cbfs:offset': 0,
2188 'cbfs:size': len(data),
2189 'cbfs:image-pos': 0,
2190 'cbfs/u-boot:offset': 0x38,
2191 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2192 'cbfs/u-boot:image-pos': 0x38,
2193 'cbfs/u-boot-dtb:offset': 0xb8,
2194 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2195 'cbfs/u-boot-dtb:image-pos': 0xb8,
2196 }, props)
2197
Simon Glass8a1ad062019-07-08 14:25:42 -06002198 def testCbfsBadType(self):
2199 """Test an image header with a no specified location is detected"""
2200 with self.assertRaises(ValueError) as e:
2201 self._DoReadFile('126_cbfs_bad_type.dts')
2202 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2203
Simon Glass41b8ba02019-07-08 14:25:43 -06002204 def testList(self):
2205 """Test listing the files in an image"""
2206 self._CheckLz4()
2207 data = self._DoReadFile('127_list.dts')
2208 image = control.images['image']
2209 entries = image.BuildEntryList()
2210 self.assertEqual(7, len(entries))
2211
2212 ent = entries[0]
2213 self.assertEqual(0, ent.indent)
2214 self.assertEqual('main-section', ent.name)
2215 self.assertEqual('section', ent.etype)
2216 self.assertEqual(len(data), ent.size)
2217 self.assertEqual(0, ent.image_pos)
2218 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002219 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002220
2221 ent = entries[1]
2222 self.assertEqual(1, ent.indent)
2223 self.assertEqual('u-boot', ent.name)
2224 self.assertEqual('u-boot', ent.etype)
2225 self.assertEqual(len(U_BOOT_DATA), ent.size)
2226 self.assertEqual(0, ent.image_pos)
2227 self.assertEqual(None, ent.uncomp_size)
2228 self.assertEqual(0, ent.offset)
2229
2230 ent = entries[2]
2231 self.assertEqual(1, ent.indent)
2232 self.assertEqual('section', ent.name)
2233 self.assertEqual('section', ent.etype)
2234 section_size = ent.size
2235 self.assertEqual(0x100, ent.image_pos)
2236 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002237 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002238
2239 ent = entries[3]
2240 self.assertEqual(2, ent.indent)
2241 self.assertEqual('cbfs', ent.name)
2242 self.assertEqual('cbfs', ent.etype)
2243 self.assertEqual(0x400, ent.size)
2244 self.assertEqual(0x100, ent.image_pos)
2245 self.assertEqual(None, ent.uncomp_size)
2246 self.assertEqual(0, ent.offset)
2247
2248 ent = entries[4]
2249 self.assertEqual(3, ent.indent)
2250 self.assertEqual('u-boot', ent.name)
2251 self.assertEqual('u-boot', ent.etype)
2252 self.assertEqual(len(U_BOOT_DATA), ent.size)
2253 self.assertEqual(0x138, ent.image_pos)
2254 self.assertEqual(None, ent.uncomp_size)
2255 self.assertEqual(0x38, ent.offset)
2256
2257 ent = entries[5]
2258 self.assertEqual(3, ent.indent)
2259 self.assertEqual('u-boot-dtb', ent.name)
2260 self.assertEqual('text', ent.etype)
2261 self.assertGreater(len(COMPRESS_DATA), ent.size)
2262 self.assertEqual(0x178, ent.image_pos)
2263 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2264 self.assertEqual(0x78, ent.offset)
2265
2266 ent = entries[6]
2267 self.assertEqual(2, ent.indent)
2268 self.assertEqual('u-boot-dtb', ent.name)
2269 self.assertEqual('u-boot-dtb', ent.etype)
2270 self.assertEqual(0x500, ent.image_pos)
2271 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2272 dtb_size = ent.size
2273 # Compressing this data expands it since headers are added
2274 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2275 self.assertEqual(0x400, ent.offset)
2276
2277 self.assertEqual(len(data), 0x100 + section_size)
2278 self.assertEqual(section_size, 0x400 + dtb_size)
2279
Simon Glasse1925fa2019-07-08 14:25:44 -06002280 def testFindFdtmap(self):
2281 """Test locating an FDT map in an image"""
2282 self._CheckLz4()
2283 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2284 image = control.images['image']
2285 entries = image.GetEntries()
2286 entry = entries['fdtmap']
2287 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2288
2289 def testFindFdtmapMissing(self):
2290 """Test failing to locate an FDP map"""
2291 data = self._DoReadFile('005_simple.dts')
2292 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2293
Simon Glass2d260032019-07-08 14:25:45 -06002294 def testFindImageHeader(self):
2295 """Test locating a image header"""
2296 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002297 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002298 image = control.images['image']
2299 entries = image.GetEntries()
2300 entry = entries['fdtmap']
2301 # The header should point to the FDT map
2302 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2303
2304 def testFindImageHeaderStart(self):
2305 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002306 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002307 image = control.images['image']
2308 entries = image.GetEntries()
2309 entry = entries['fdtmap']
2310 # The header should point to the FDT map
2311 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2312
2313 def testFindImageHeaderMissing(self):
2314 """Test failing to locate an image header"""
2315 data = self._DoReadFile('005_simple.dts')
2316 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2317
Simon Glassffded752019-07-08 14:25:46 -06002318 def testReadImage(self):
2319 """Test reading an image and accessing its FDT map"""
2320 self._CheckLz4()
2321 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2322 image_fname = tools.GetOutputFilename('image.bin')
2323 orig_image = control.images['image']
2324 image = Image.FromFile(image_fname)
2325 self.assertEqual(orig_image.GetEntries().keys(),
2326 image.GetEntries().keys())
2327
2328 orig_entry = orig_image.GetEntries()['fdtmap']
2329 entry = image.GetEntries()['fdtmap']
2330 self.assertEquals(orig_entry.offset, entry.offset)
2331 self.assertEquals(orig_entry.size, entry.size)
2332 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2333
2334 def testReadImageNoHeader(self):
2335 """Test accessing an image's FDT map without an image header"""
2336 self._CheckLz4()
2337 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2338 image_fname = tools.GetOutputFilename('image.bin')
2339 image = Image.FromFile(image_fname)
2340 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002341 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002342
2343 def testReadImageFail(self):
2344 """Test failing to read an image image's FDT map"""
2345 self._DoReadFile('005_simple.dts')
2346 image_fname = tools.GetOutputFilename('image.bin')
2347 with self.assertRaises(ValueError) as e:
2348 image = Image.FromFile(image_fname)
2349 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002350
Simon Glass61f564d2019-07-08 14:25:48 -06002351 def testListCmd(self):
2352 """Test listing the files in an image using an Fdtmap"""
2353 self._CheckLz4()
2354 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2355
2356 # lz4 compression size differs depending on the version
2357 image = control.images['image']
2358 entries = image.GetEntries()
2359 section_size = entries['section'].size
2360 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2361 fdtmap_offset = entries['fdtmap'].offset
2362
2363 image_fname = tools.GetOutputFilename('image.bin')
2364 with test_util.capture_sys_output() as (stdout, stderr):
2365 self._DoBinman('ls', '-i', image_fname)
2366 lines = stdout.getvalue().splitlines()
2367 expected = [
2368'Name Image-pos Size Entry-type Offset Uncomp-size',
2369'----------------------------------------------------------------------',
2370'main-section 0 c00 section 0',
2371' u-boot 0 4 u-boot 0',
2372' section 100 %x section 100' % section_size,
2373' cbfs 100 400 cbfs 0',
2374' u-boot 138 4 u-boot 38',
2375' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2376' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glass1411ac82019-07-20 12:23:44 -06002377' fdtmap %x 3b4 fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002378 (fdtmap_offset, fdtmap_offset),
2379' image-header bf8 8 image-header bf8',
2380 ]
2381 self.assertEqual(expected, lines)
2382
2383 def testListCmdFail(self):
2384 """Test failing to list an image"""
2385 self._DoReadFile('005_simple.dts')
2386 image_fname = tools.GetOutputFilename('image.bin')
2387 with self.assertRaises(ValueError) as e:
2388 self._DoBinman('ls', '-i', image_fname)
2389 self.assertIn("Cannot find FDT map in image", str(e.exception))
2390
2391 def _RunListCmd(self, paths, expected):
2392 """List out entries and check the result
2393
2394 Args:
2395 paths: List of paths to pass to the list command
2396 expected: Expected list of filenames to be returned, in order
2397 """
2398 self._CheckLz4()
2399 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2400 image_fname = tools.GetOutputFilename('image.bin')
2401 image = Image.FromFile(image_fname)
2402 lines = image.GetListEntries(paths)[1]
2403 files = [line[0].strip() for line in lines[1:]]
2404 self.assertEqual(expected, files)
2405
2406 def testListCmdSection(self):
2407 """Test listing the files in a section"""
2408 self._RunListCmd(['section'],
2409 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2410
2411 def testListCmdFile(self):
2412 """Test listing a particular file"""
2413 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2414
2415 def testListCmdWildcard(self):
2416 """Test listing a wildcarded file"""
2417 self._RunListCmd(['*boot*'],
2418 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2419
2420 def testListCmdWildcardMulti(self):
2421 """Test listing a wildcarded file"""
2422 self._RunListCmd(['*cb*', '*head*'],
2423 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2424
2425 def testListCmdEmpty(self):
2426 """Test listing a wildcarded file"""
2427 self._RunListCmd(['nothing'], [])
2428
2429 def testListCmdPath(self):
2430 """Test listing the files in a sub-entry of a section"""
2431 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2432
Simon Glassf667e452019-07-08 14:25:50 -06002433 def _RunExtractCmd(self, entry_name, decomp=True):
2434 """Extract an entry from an image
2435
2436 Args:
2437 entry_name: Entry name to extract
2438 decomp: True to decompress the data if compressed, False to leave
2439 it in its raw uncompressed format
2440
2441 Returns:
2442 data from entry
2443 """
2444 self._CheckLz4()
2445 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2446 image_fname = tools.GetOutputFilename('image.bin')
2447 return control.ReadEntry(image_fname, entry_name, decomp)
2448
2449 def testExtractSimple(self):
2450 """Test extracting a single file"""
2451 data = self._RunExtractCmd('u-boot')
2452 self.assertEqual(U_BOOT_DATA, data)
2453
Simon Glass71ce0ba2019-07-08 14:25:52 -06002454 def testExtractSection(self):
2455 """Test extracting the files in a section"""
2456 data = self._RunExtractCmd('section')
2457 cbfs_data = data[:0x400]
2458 cbfs = cbfs_util.CbfsReader(cbfs_data)
2459 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2460 dtb_data = data[0x400:]
2461 dtb = self._decompress(dtb_data)
2462 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2463
2464 def testExtractCompressed(self):
2465 """Test extracting compressed data"""
2466 data = self._RunExtractCmd('section/u-boot-dtb')
2467 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2468
2469 def testExtractRaw(self):
2470 """Test extracting compressed data without decompressing it"""
2471 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2472 dtb = self._decompress(data)
2473 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2474
2475 def testExtractCbfs(self):
2476 """Test extracting CBFS data"""
2477 data = self._RunExtractCmd('section/cbfs/u-boot')
2478 self.assertEqual(U_BOOT_DATA, data)
2479
2480 def testExtractCbfsCompressed(self):
2481 """Test extracting CBFS compressed data"""
2482 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2483 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2484
2485 def testExtractCbfsRaw(self):
2486 """Test extracting CBFS compressed data without decompressing it"""
2487 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
2488 dtb = tools.Decompress(data, 'lzma')
2489 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2490
Simon Glassf667e452019-07-08 14:25:50 -06002491 def testExtractBadEntry(self):
2492 """Test extracting a bad section path"""
2493 with self.assertRaises(ValueError) as e:
2494 self._RunExtractCmd('section/does-not-exist')
2495 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2496 str(e.exception))
2497
2498 def testExtractMissingFile(self):
2499 """Test extracting file that does not exist"""
2500 with self.assertRaises(IOError) as e:
2501 control.ReadEntry('missing-file', 'name')
2502
2503 def testExtractBadFile(self):
2504 """Test extracting an invalid file"""
2505 fname = os.path.join(self._indir, 'badfile')
2506 tools.WriteFile(fname, b'')
2507 with self.assertRaises(ValueError) as e:
2508 control.ReadEntry(fname, 'name')
2509
Simon Glass71ce0ba2019-07-08 14:25:52 -06002510 def testExtractCmd(self):
2511 """Test extracting a file fron an image on the command line"""
2512 self._CheckLz4()
2513 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2514 image_fname = tools.GetOutputFilename('image.bin')
2515 fname = os.path.join(self._indir, 'output.extact')
2516 with test_util.capture_sys_output() as (stdout, stderr):
2517 self._DoBinman('extract', '-i', image_fname, 'u-boot', '-f', fname)
2518 data = tools.ReadFile(fname)
2519 self.assertEqual(U_BOOT_DATA, data)
2520
2521 def testExtractOneEntry(self):
2522 """Test extracting a single entry fron an image """
2523 self._CheckLz4()
2524 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2525 image_fname = tools.GetOutputFilename('image.bin')
2526 fname = os.path.join(self._indir, 'output.extact')
2527 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2528 data = tools.ReadFile(fname)
2529 self.assertEqual(U_BOOT_DATA, data)
2530
2531 def _CheckExtractOutput(self, decomp):
2532 """Helper to test file output with and without decompression
2533
2534 Args:
2535 decomp: True to decompress entry data, False to output it raw
2536 """
2537 def _CheckPresent(entry_path, expect_data, expect_size=None):
2538 """Check and remove expected file
2539
2540 This checks the data/size of a file and removes the file both from
2541 the outfiles set and from the output directory. Once all files are
2542 processed, both the set and directory should be empty.
2543
2544 Args:
2545 entry_path: Entry path
2546 expect_data: Data to expect in file, or None to skip check
2547 expect_size: Size of data to expect in file, or None to skip
2548 """
2549 path = os.path.join(outdir, entry_path)
2550 data = tools.ReadFile(path)
2551 os.remove(path)
2552 if expect_data:
2553 self.assertEqual(expect_data, data)
2554 elif expect_size:
2555 self.assertEqual(expect_size, len(data))
2556 outfiles.remove(path)
2557
2558 def _CheckDirPresent(name):
2559 """Remove expected directory
2560
2561 This gives an error if the directory does not exist as expected
2562
2563 Args:
2564 name: Name of directory to remove
2565 """
2566 path = os.path.join(outdir, name)
2567 os.rmdir(path)
2568
2569 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2570 image_fname = tools.GetOutputFilename('image.bin')
2571 outdir = os.path.join(self._indir, 'extract')
2572 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2573
2574 # Create a set of all file that were output (should be 9)
2575 outfiles = set()
2576 for root, dirs, files in os.walk(outdir):
2577 outfiles |= set([os.path.join(root, fname) for fname in files])
2578 self.assertEqual(9, len(outfiles))
2579 self.assertEqual(9, len(einfos))
2580
2581 image = control.images['image']
2582 entries = image.GetEntries()
2583
2584 # Check the 9 files in various ways
2585 section = entries['section']
2586 section_entries = section.GetEntries()
2587 cbfs_entries = section_entries['cbfs'].GetEntries()
2588 _CheckPresent('u-boot', U_BOOT_DATA)
2589 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2590 dtb_len = EXTRACT_DTB_SIZE
2591 if not decomp:
2592 dtb_len = cbfs_entries['u-boot-dtb'].size
2593 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2594 if not decomp:
2595 dtb_len = section_entries['u-boot-dtb'].size
2596 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2597
2598 fdtmap = entries['fdtmap']
2599 _CheckPresent('fdtmap', fdtmap.data)
2600 hdr = entries['image-header']
2601 _CheckPresent('image-header', hdr.data)
2602
2603 _CheckPresent('section/root', section.data)
2604 cbfs = section_entries['cbfs']
2605 _CheckPresent('section/cbfs/root', cbfs.data)
2606 data = tools.ReadFile(image_fname)
2607 _CheckPresent('root', data)
2608
2609 # There should be no files left. Remove all the directories to check.
2610 # If there are any files/dirs remaining, one of these checks will fail.
2611 self.assertEqual(0, len(outfiles))
2612 _CheckDirPresent('section/cbfs')
2613 _CheckDirPresent('section')
2614 _CheckDirPresent('')
2615 self.assertFalse(os.path.exists(outdir))
2616
2617 def testExtractAllEntries(self):
2618 """Test extracting all entries"""
2619 self._CheckLz4()
2620 self._CheckExtractOutput(decomp=True)
2621
2622 def testExtractAllEntriesRaw(self):
2623 """Test extracting all entries without decompressing them"""
2624 self._CheckLz4()
2625 self._CheckExtractOutput(decomp=False)
2626
2627 def testExtractSelectedEntries(self):
2628 """Test extracting some entries"""
2629 self._CheckLz4()
2630 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2631 image_fname = tools.GetOutputFilename('image.bin')
2632 outdir = os.path.join(self._indir, 'extract')
2633 einfos = control.ExtractEntries(image_fname, None, outdir,
2634 ['*cb*', '*head*'])
2635
2636 # File output is tested by testExtractAllEntries(), so just check that
2637 # the expected entries are selected
2638 names = [einfo.name for einfo in einfos]
2639 self.assertEqual(names,
2640 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2641
2642 def testExtractNoEntryPaths(self):
2643 """Test extracting some entries"""
2644 self._CheckLz4()
2645 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2646 image_fname = tools.GetOutputFilename('image.bin')
2647 with self.assertRaises(ValueError) as e:
2648 control.ExtractEntries(image_fname, 'fname', None, [])
2649 self.assertIn('Must specify an entry path to write with -o',
2650 str(e.exception))
2651
2652 def testExtractTooManyEntryPaths(self):
2653 """Test extracting some entries"""
2654 self._CheckLz4()
2655 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2656 image_fname = tools.GetOutputFilename('image.bin')
2657 with self.assertRaises(ValueError) as e:
2658 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
2659 self.assertIn('Must specify exactly one entry path to write with -o',
2660 str(e.exception))
2661
Simon Glasse2705fa2019-07-08 14:25:53 -06002662 def testPackAlignSection(self):
2663 """Test that sections can have alignment"""
2664 self._DoReadFile('131_pack_align_section.dts')
2665
2666 self.assertIn('image', control.images)
2667 image = control.images['image']
2668 entries = image.GetEntries()
2669 self.assertEqual(3, len(entries))
2670
2671 # First u-boot
2672 self.assertIn('u-boot', entries)
2673 entry = entries['u-boot']
2674 self.assertEqual(0, entry.offset)
2675 self.assertEqual(0, entry.image_pos)
2676 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2677 self.assertEqual(len(U_BOOT_DATA), entry.size)
2678
2679 # Section0
2680 self.assertIn('section0', entries)
2681 section0 = entries['section0']
2682 self.assertEqual(0x10, section0.offset)
2683 self.assertEqual(0x10, section0.image_pos)
2684 self.assertEqual(len(U_BOOT_DATA), section0.size)
2685
2686 # Second u-boot
2687 section_entries = section0.GetEntries()
2688 self.assertIn('u-boot', section_entries)
2689 entry = section_entries['u-boot']
2690 self.assertEqual(0, entry.offset)
2691 self.assertEqual(0x10, entry.image_pos)
2692 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2693 self.assertEqual(len(U_BOOT_DATA), entry.size)
2694
2695 # Section1
2696 self.assertIn('section1', entries)
2697 section1 = entries['section1']
2698 self.assertEqual(0x14, section1.offset)
2699 self.assertEqual(0x14, section1.image_pos)
2700 self.assertEqual(0x20, section1.size)
2701
2702 # Second u-boot
2703 section_entries = section1.GetEntries()
2704 self.assertIn('u-boot', section_entries)
2705 entry = section_entries['u-boot']
2706 self.assertEqual(0, entry.offset)
2707 self.assertEqual(0x14, entry.image_pos)
2708 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2709 self.assertEqual(len(U_BOOT_DATA), entry.size)
2710
2711 # Section2
2712 self.assertIn('section2', section_entries)
2713 section2 = section_entries['section2']
2714 self.assertEqual(0x4, section2.offset)
2715 self.assertEqual(0x18, section2.image_pos)
2716 self.assertEqual(4, section2.size)
2717
2718 # Third u-boot
2719 section_entries = section2.GetEntries()
2720 self.assertIn('u-boot', section_entries)
2721 entry = section_entries['u-boot']
2722 self.assertEqual(0, entry.offset)
2723 self.assertEqual(0x18, entry.image_pos)
2724 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2725 self.assertEqual(len(U_BOOT_DATA), entry.size)
2726
Simon Glass51014aa2019-07-20 12:23:56 -06002727 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2728 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002729 """Replace an entry in an image
2730
2731 This writes the entry data to update it, then opens the updated file and
2732 returns the value that it now finds there.
2733
2734 Args:
2735 entry_name: Entry name to replace
2736 data: Data to replace it with
2737 decomp: True to compress the data if needed, False if data is
2738 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002739 allow_resize: True to allow entries to change size, False to raise
2740 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002741
2742 Returns:
2743 Tuple:
2744 data from entry
2745 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002746 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002747 """
Simon Glass51014aa2019-07-20 12:23:56 -06002748 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002749 update_dtb=True)[1]
2750
2751 self.assertIn('image', control.images)
2752 image = control.images['image']
2753 entries = image.GetEntries()
2754 orig_dtb_data = entries['u-boot-dtb'].data
2755 orig_fdtmap_data = entries['fdtmap'].data
2756
2757 image_fname = tools.GetOutputFilename('image.bin')
2758 updated_fname = tools.GetOutputFilename('image-updated.bin')
2759 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002760 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2761 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002762 data = control.ReadEntry(updated_fname, entry_name, decomp)
2763
Simon Glass51014aa2019-07-20 12:23:56 -06002764 # The DT data should not change unless resized:
2765 if not allow_resize:
2766 new_dtb_data = entries['u-boot-dtb'].data
2767 self.assertEqual(new_dtb_data, orig_dtb_data)
2768 new_fdtmap_data = entries['fdtmap'].data
2769 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002770
Simon Glass51014aa2019-07-20 12:23:56 -06002771 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002772
2773 def testReplaceSimple(self):
2774 """Test replacing a single file"""
2775 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002776 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2777 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002778 self.assertEqual(expected, data)
2779
2780 # Test that the state looks right. There should be an FDT for the fdtmap
2781 # that we jsut read back in, and it should match what we find in the
2782 # 'control' tables. Checking for an FDT that does not exist should
2783 # return None.
2784 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002785 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002786 self.assertEqual(expected_fdtmap, fdtmap)
2787
2788 dtb = state.GetFdtForEtype('fdtmap')
2789 self.assertEqual(dtb.GetContents(), fdtmap)
2790
2791 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2792 self.assertIsNone(missing_path)
2793 self.assertIsNone(missing_fdtmap)
2794
2795 missing_dtb = state.GetFdtForEtype('missing')
2796 self.assertIsNone(missing_dtb)
2797
2798 self.assertEqual('/binman', state.fdt_path_prefix)
2799
2800 def testReplaceResizeFail(self):
2801 """Test replacing a file by something larger"""
2802 expected = U_BOOT_DATA + b'x'
2803 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002804 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2805 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002806 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2807 str(e.exception))
2808
2809 def testReplaceMulti(self):
2810 """Test replacing entry data where multiple images are generated"""
2811 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2812 update_dtb=True)[0]
2813 expected = b'x' * len(U_BOOT_DATA)
2814 updated_fname = tools.GetOutputFilename('image-updated.bin')
2815 tools.WriteFile(updated_fname, data)
2816 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002817 control.WriteEntry(updated_fname, entry_name, expected,
2818 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002819 data = control.ReadEntry(updated_fname, entry_name)
2820 self.assertEqual(expected, data)
2821
2822 # Check the state looks right.
2823 self.assertEqual('/binman/image', state.fdt_path_prefix)
2824
2825 # Now check we can write the first image
2826 image_fname = tools.GetOutputFilename('first-image.bin')
2827 updated_fname = tools.GetOutputFilename('first-updated.bin')
2828 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2829 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002830 control.WriteEntry(updated_fname, entry_name, expected,
2831 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002832 data = control.ReadEntry(updated_fname, entry_name)
2833 self.assertEqual(expected, data)
2834
2835 # Check the state looks right.
2836 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002837
Simon Glass12bb1a92019-07-20 12:23:51 -06002838 def testUpdateFdtAllRepack(self):
2839 """Test that all device trees are updated with offset/size info"""
2840 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2841 SECTION_SIZE = 0x300
2842 DTB_SIZE = 602
2843 FDTMAP_SIZE = 608
2844 base_expected = {
2845 'offset': 0,
2846 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2847 'image-pos': 0,
2848 'section:offset': 0,
2849 'section:size': SECTION_SIZE,
2850 'section:image-pos': 0,
2851 'section/u-boot-dtb:offset': 4,
2852 'section/u-boot-dtb:size': 636,
2853 'section/u-boot-dtb:image-pos': 4,
2854 'u-boot-spl-dtb:offset': SECTION_SIZE,
2855 'u-boot-spl-dtb:size': DTB_SIZE,
2856 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2857 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2858 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2859 'u-boot-tpl-dtb:size': DTB_SIZE,
2860 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2861 'fdtmap:size': FDTMAP_SIZE,
2862 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2863 }
2864 main_expected = {
2865 'section:orig-size': SECTION_SIZE,
2866 'section/u-boot-dtb:orig-offset': 4,
2867 }
2868
2869 # We expect three device-tree files in the output, with the first one
2870 # within a fixed-size section.
2871 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2872 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2873 # main U-Boot tree. All three should have the same positions and offset
2874 # except that the main tree should include the main_expected properties
2875 start = 4
2876 for item in ['', 'spl', 'tpl', None]:
2877 if item is None:
2878 start += 16 # Move past fdtmap header
2879 dtb = fdt.Fdt.FromData(data[start:])
2880 dtb.Scan()
2881 props = self._GetPropTree(dtb,
2882 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2883 prefix='/' if item is None else '/binman/')
2884 expected = dict(base_expected)
2885 if item:
2886 expected[item] = 0
2887 else:
2888 # Main DTB and fdtdec should include the 'orig-' properties
2889 expected.update(main_expected)
2890 # Helpful for debugging:
2891 #for prop in sorted(props):
2892 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2893 self.assertEqual(expected, props)
2894 if item == '':
2895 start = SECTION_SIZE
2896 else:
2897 start += dtb._fdt_obj.totalsize()
2898
Simon Glasseba1f0c2019-07-20 12:23:55 -06002899 def testFdtmapHeaderMiddle(self):
2900 """Test an FDT map in the middle of an image when it should be at end"""
2901 with self.assertRaises(ValueError) as e:
2902 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2903 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2904 str(e.exception))
2905
2906 def testFdtmapHeaderStartBad(self):
2907 """Test an FDT map in middle of an image when it should be at start"""
2908 with self.assertRaises(ValueError) as e:
2909 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2910 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2911 str(e.exception))
2912
2913 def testFdtmapHeaderEndBad(self):
2914 """Test an FDT map at the start of an image when it should be at end"""
2915 with self.assertRaises(ValueError) as e:
2916 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2917 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2918 str(e.exception))
2919
2920 def testFdtmapHeaderNoSize(self):
2921 """Test an image header at the end of an image with undefined size"""
2922 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2923
Simon Glass51014aa2019-07-20 12:23:56 -06002924 def testReplaceResize(self):
2925 """Test replacing a single file in an entry with a larger file"""
2926 expected = U_BOOT_DATA + b'x'
2927 data, _, image = self._RunReplaceCmd('u-boot', expected,
2928 dts='139_replace_repack.dts')
2929 self.assertEqual(expected, data)
2930
2931 entries = image.GetEntries()
2932 dtb_data = entries['u-boot-dtb'].data
2933 dtb = fdt.Fdt.FromData(dtb_data)
2934 dtb.Scan()
2935
2936 # The u-boot section should now be larger in the dtb
2937 node = dtb.GetNode('/binman/u-boot')
2938 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
2939
2940 # Same for the fdtmap
2941 fdata = entries['fdtmap'].data
2942 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
2943 fdtb.Scan()
2944 fnode = fdtb.GetNode('/u-boot')
2945 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
2946
2947 def testReplaceResizeNoRepack(self):
2948 """Test replacing an entry with a larger file when not allowed"""
2949 expected = U_BOOT_DATA + b'x'
2950 with self.assertRaises(ValueError) as e:
2951 self._RunReplaceCmd('u-boot', expected)
2952 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
2953 str(e.exception))
2954
Simon Glass12bb1a92019-07-20 12:23:51 -06002955
Simon Glass9fc60b42017-11-12 21:52:22 -07002956if __name__ == "__main__":
2957 unittest.main()