blob: 0f3b70b3bb8e600c52cfe862bf64cbbe72b42c7c [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 Glassbf574f12019-07-20 12:24:09 -0600190 def _CleanupOutputDir(self):
191 """Remove the temporary output directory"""
192 if self.preserve_outdirs:
193 print('Preserving output dir: %s' % tools.outdir)
194 else:
195 tools._FinaliseForTest()
196
Simon Glass4f443042016-11-25 20:15:52 -0700197 def setUp(self):
198 # Enable this to turn on debugging output
199 # tout.Init(tout.DEBUG)
200 command.test_result = None
201
202 def tearDown(self):
203 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600204 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700205
Simon Glassf86a7362019-07-20 12:24:10 -0600206 def _SetupImageInTmpdir(self):
207 """Set up the output image in a new temporary directory
208
209 This is used when an image has been generated in the output directory,
210 but we want to run binman again. This will create a new output
211 directory and fail to delete the original one.
212
213 This creates a new temporary directory, copies the image to it (with a
214 new name) and removes the old output directory.
215
216 Returns:
217 Tuple:
218 Temporary directory to use
219 New image filename
220 """
221 image_fname = tools.GetOutputFilename('image.bin')
222 tmpdir = tempfile.mkdtemp(prefix='binman.')
223 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
224 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
225 self._CleanupOutputDir()
226 return tmpdir, updated_fname
227
Simon Glassb8ef5b62018-07-17 13:25:48 -0600228 @classmethod
229 def _ResetDtbs(self):
230 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
231 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
232 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
233
Simon Glass4f443042016-11-25 20:15:52 -0700234 def _RunBinman(self, *args, **kwargs):
235 """Run binman using the command line
236
237 Args:
238 Arguments to pass, as a list of strings
239 kwargs: Arguments to pass to Command.RunPipe()
240 """
241 result = command.RunPipe([[self._binman_pathname] + list(args)],
242 capture=True, capture_stderr=True, raise_on_error=False)
243 if result.return_code and kwargs.get('raise_on_error', True):
244 raise Exception("Error running '%s': %s" % (' '.join(args),
245 result.stdout + result.stderr))
246 return result
247
Simon Glass53cd5d92019-07-08 14:25:29 -0600248 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700249 """Run binman using directly (in the same process)
250
251 Args:
252 Arguments to pass, as a list of strings
253 Returns:
254 Return value (0 for success)
255 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600256 argv = list(argv)
257 args = cmdline.ParseArgs(argv)
258 args.pager = 'binman-invalid-pager'
259 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700260
261 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600262 # args.verbosity = tout.DEBUG
263 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700264
Simon Glass53af22a2018-07-17 13:25:32 -0600265 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600266 entry_args=None, images=None, use_real_dtb=False,
267 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700268 """Run binman with a given test file
269
270 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600271 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600272 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600273 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600274 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600275 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600276 entry_args: Dict of entry args to supply to binman
277 key: arg name
278 value: value of that arg
279 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700280 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600281 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700282 if debug:
283 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600284 if verbosity is not None:
285 args.append('-v%d' % verbosity)
286 elif self.verbosity:
287 args.append('-v%d' % self.verbosity)
288 if self.toolpath:
289 for path in self.toolpath:
290 args += ['--toolpath', path]
291 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600292 if map:
293 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600294 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600295 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600296 if not use_real_dtb:
297 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600298 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600299 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600300 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600301 if images:
302 for image in images:
303 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700304 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700305
306 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700307 """Set up a new test device-tree file
308
309 The given file is compiled and set up as the device tree to be used
310 for ths test.
311
312 Args:
313 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600314 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700315
316 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600317 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700318 """
Simon Glassa004f292019-07-20 12:23:49 -0600319 tmpdir = tempfile.mkdtemp(prefix='binmant.')
320 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600321 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700322 data = fd.read()
323 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600324 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600325 return data
Simon Glass4f443042016-11-25 20:15:52 -0700326
Simon Glass6ed45ba2018-09-14 04:57:24 -0600327 def _GetDtbContentsForSplTpl(self, dtb_data, name):
328 """Create a version of the main DTB for SPL or SPL
329
330 For testing we don't actually have different versions of the DTB. With
331 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
332 we don't normally have any unwanted nodes.
333
334 We still want the DTBs for SPL and TPL to be different though, since
335 otherwise it is confusing to know which one we are looking at. So add
336 an 'spl' or 'tpl' property to the top-level node.
337 """
338 dtb = fdt.Fdt.FromData(dtb_data)
339 dtb.Scan()
340 dtb.GetNode('/binman').AddZeroProp(name)
341 dtb.Sync(auto_resize=True)
342 dtb.Pack()
343 return dtb.GetContents()
344
Simon Glass16b8d6b2018-07-06 10:27:42 -0600345 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600346 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700347 """Run binman and return the resulting image
348
349 This runs binman with a given test file and then reads the resulting
350 output file. It is a shortcut function since most tests need to do
351 these steps.
352
353 Raises an assertion failure if binman returns a non-zero exit code.
354
355 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600356 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700357 use_real_dtb: True to use the test file as the contents of
358 the u-boot-dtb entry. Normally this is not needed and the
359 test contents (the U_BOOT_DTB_DATA string) can be used.
360 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600361 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600362 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600363 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700364
365 Returns:
366 Tuple:
367 Resulting image contents
368 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600369 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600370 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700371 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700372 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700373 # Use the compiled test file as the u-boot-dtb input
374 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700375 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600376
377 # For testing purposes, make a copy of the DT for SPL and TPL. Add
378 # a node indicating which it is, so aid verification.
379 for name in ['spl', 'tpl']:
380 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
381 outfile = os.path.join(self._indir, dtb_fname)
382 TestFunctional._MakeInputFile(dtb_fname,
383 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700384
385 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600386 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600387 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700388 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600389 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700390
391 # Find the (only) image, read it and return its contents
392 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600393 image_fname = tools.GetOutputFilename('image.bin')
394 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600395 if map:
396 map_fname = tools.GetOutputFilename('image.map')
397 with open(map_fname) as fd:
398 map_data = fd.read()
399 else:
400 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600401 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600402 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700403 finally:
404 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600405 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600406 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700407
Simon Glass3c081312019-07-08 14:25:26 -0600408 def _DoReadFileRealDtb(self, fname):
409 """Run binman with a real .dtb file and return the resulting data
410
411 Args:
412 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
413
414 Returns:
415 Resulting image contents
416 """
417 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
418
Simon Glasse0ff8552016-11-25 20:15:53 -0700419 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600420 """Helper function which discards the device-tree binary
421
422 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600423 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600424 use_real_dtb: True to use the test file as the contents of
425 the u-boot-dtb entry. Normally this is not needed and the
426 test contents (the U_BOOT_DTB_DATA string) can be used.
427 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600428
429 Returns:
430 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600431 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700432 return self._DoReadFileDtb(fname, use_real_dtb)[0]
433
Simon Glass4f443042016-11-25 20:15:52 -0700434 @classmethod
435 def _MakeInputFile(self, fname, contents):
436 """Create a new test input file, creating directories as needed
437
438 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600439 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700440 contents: File contents to write in to the file
441 Returns:
442 Full pathname of file created
443 """
444 pathname = os.path.join(self._indir, fname)
445 dirname = os.path.dirname(pathname)
446 if dirname and not os.path.exists(dirname):
447 os.makedirs(dirname)
448 with open(pathname, 'wb') as fd:
449 fd.write(contents)
450 return pathname
451
452 @classmethod
Simon Glass0ef87aa2018-07-17 13:25:44 -0600453 def _MakeInputDir(self, dirname):
454 """Create a new test input directory, creating directories as needed
455
456 Args:
457 dirname: Directory name to create
458
459 Returns:
460 Full pathname of directory created
461 """
462 pathname = os.path.join(self._indir, dirname)
463 if not os.path.exists(pathname):
464 os.makedirs(pathname)
465 return pathname
466
467 @classmethod
Simon Glass11ae93e2018-10-01 21:12:47 -0600468 def _SetupSplElf(self, src_fname='bss_data'):
469 """Set up an ELF file with a '_dt_ucode_base_size' symbol
470
471 Args:
472 Filename of ELF file to use as SPL
473 """
Simon Glass1d0ebf72019-05-14 15:53:42 -0600474 with open(self.TestFile(src_fname), 'rb') as fd:
Simon Glass11ae93e2018-10-01 21:12:47 -0600475 TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read())
476
477 @classmethod
Simon Glass4f443042016-11-25 20:15:52 -0700478 def TestFile(self, fname):
479 return os.path.join(self._binman_dir, 'test', fname)
480
481 def AssertInList(self, grep_list, target):
482 """Assert that at least one of a list of things is in a target
483
484 Args:
485 grep_list: List of strings to check
486 target: Target string
487 """
488 for grep in grep_list:
489 if grep in target:
490 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600491 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700492
493 def CheckNoGaps(self, entries):
494 """Check that all entries fit together without gaps
495
496 Args:
497 entries: List of entries to check
498 """
Simon Glass3ab95982018-08-01 15:22:37 -0600499 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700500 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600501 self.assertEqual(offset, entry.offset)
502 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700503
Simon Glasse0ff8552016-11-25 20:15:53 -0700504 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600505 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700506
507 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600508 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700509
510 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600511 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700512 """
513 return struct.unpack('>L', dtb[4:8])[0]
514
Simon Glass086cec92019-07-08 14:25:27 -0600515 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600516 def AddNode(node, path):
517 if node.name != '/':
518 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600519 for prop in node.props.values():
520 if prop.name in prop_names:
521 prop_path = path + ':' + prop.name
522 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
523 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600524 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600525 AddNode(subnode, path)
526
527 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600528 AddNode(dtb.GetRoot(), '')
529 return tree
530
Simon Glass4f443042016-11-25 20:15:52 -0700531 def testRun(self):
532 """Test a basic run with valid args"""
533 result = self._RunBinman('-h')
534
535 def testFullHelp(self):
536 """Test that the full help is displayed with -H"""
537 result = self._RunBinman('-H')
538 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500539 # Remove possible extraneous strings
540 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
541 gothelp = result.stdout.replace(extra, '')
542 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700543 self.assertEqual(0, len(result.stderr))
544 self.assertEqual(0, result.return_code)
545
546 def testFullHelpInternal(self):
547 """Test that the full help is displayed with -H"""
548 try:
549 command.test_result = command.CommandResult()
550 result = self._DoBinman('-H')
551 help_file = os.path.join(self._binman_dir, 'README')
552 finally:
553 command.test_result = None
554
555 def testHelp(self):
556 """Test that the basic help is displayed with -h"""
557 result = self._RunBinman('-h')
558 self.assertTrue(len(result.stdout) > 200)
559 self.assertEqual(0, len(result.stderr))
560 self.assertEqual(0, result.return_code)
561
Simon Glass4f443042016-11-25 20:15:52 -0700562 def testBoard(self):
563 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600564 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700565 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600566 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700567 self.assertEqual(0, result)
568
569 def testNeedBoard(self):
570 """Test that we get an error when no board ius supplied"""
571 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600572 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700573 self.assertIn("Must provide a board to process (use -b <board>)",
574 str(e.exception))
575
576 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600577 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700578 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600579 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700580 # We get one error from libfdt, and a different one from fdtget.
581 self.AssertInList(["Couldn't open blob from 'missing_file'",
582 'No such file or directory'], str(e.exception))
583
584 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600585 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700586
587 Since this is a source file it should be compiled and the error
588 will come from the device-tree compiler (dtc).
589 """
590 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600591 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700592 self.assertIn("FATAL ERROR: Unable to parse input tree",
593 str(e.exception))
594
595 def testMissingNode(self):
596 """Test that a device tree without a 'binman' node generates an error"""
597 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600598 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700599 self.assertIn("does not have a 'binman' node", str(e.exception))
600
601 def testEmpty(self):
602 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600603 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700604 self.assertEqual(0, len(result.stderr))
605 self.assertEqual(0, result.return_code)
606
607 def testInvalidEntry(self):
608 """Test that an invalid entry is flagged"""
609 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600610 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600611 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700612 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
613 "'/binman/not-a-valid-type'", str(e.exception))
614
615 def testSimple(self):
616 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600617 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700618 self.assertEqual(U_BOOT_DATA, data)
619
Simon Glass7fe91732017-11-13 18:55:00 -0700620 def testSimpleDebug(self):
621 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600622 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700623
Simon Glass4f443042016-11-25 20:15:52 -0700624 def testDual(self):
625 """Test that we can handle creating two images
626
627 This also tests image padding.
628 """
Simon Glass741f2d62018-10-01 12:22:30 -0600629 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700630 self.assertEqual(0, retcode)
631
632 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600633 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700634 fname = tools.GetOutputFilename('image1.bin')
635 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600636 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700637 data = fd.read()
638 self.assertEqual(U_BOOT_DATA, data)
639
640 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600641 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700642 fname = tools.GetOutputFilename('image2.bin')
643 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600644 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700645 data = fd.read()
646 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600647 self.assertEqual(tools.GetBytes(0, 3), data[:3])
648 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700649
650 def testBadAlign(self):
651 """Test that an invalid alignment value is detected"""
652 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600653 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700654 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
655 "of two", str(e.exception))
656
657 def testPackSimple(self):
658 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600659 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700660 self.assertEqual(0, retcode)
661 self.assertIn('image', control.images)
662 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600663 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700664 self.assertEqual(5, len(entries))
665
666 # First u-boot
667 self.assertIn('u-boot', entries)
668 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600669 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700670 self.assertEqual(len(U_BOOT_DATA), entry.size)
671
672 # Second u-boot, aligned to 16-byte boundary
673 self.assertIn('u-boot-align', entries)
674 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600675 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700676 self.assertEqual(len(U_BOOT_DATA), entry.size)
677
678 # Third u-boot, size 23 bytes
679 self.assertIn('u-boot-size', entries)
680 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600681 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700682 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
683 self.assertEqual(23, entry.size)
684
685 # Fourth u-boot, placed immediate after the above
686 self.assertIn('u-boot-next', entries)
687 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600688 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700689 self.assertEqual(len(U_BOOT_DATA), entry.size)
690
Simon Glass3ab95982018-08-01 15:22:37 -0600691 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700692 self.assertIn('u-boot-fixed', entries)
693 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600694 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700695 self.assertEqual(len(U_BOOT_DATA), entry.size)
696
Simon Glass8beb11e2019-07-08 14:25:47 -0600697 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700698
699 def testPackExtra(self):
700 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600701 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700702
703 self.assertEqual(0, retcode)
704 self.assertIn('image', control.images)
705 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600706 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700707 self.assertEqual(5, len(entries))
708
709 # First u-boot with padding before and after
710 self.assertIn('u-boot', entries)
711 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600712 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700713 self.assertEqual(3, entry.pad_before)
714 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
715
716 # Second u-boot has an aligned size, but it has no effect
717 self.assertIn('u-boot-align-size-nop', entries)
718 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600719 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700720 self.assertEqual(4, entry.size)
721
722 # Third u-boot has an aligned size too
723 self.assertIn('u-boot-align-size', entries)
724 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600725 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700726 self.assertEqual(32, entry.size)
727
728 # Fourth u-boot has an aligned end
729 self.assertIn('u-boot-align-end', entries)
730 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600731 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700732 self.assertEqual(16, entry.size)
733
734 # Fifth u-boot immediately afterwards
735 self.assertIn('u-boot-align-both', entries)
736 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600737 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700738 self.assertEqual(64, entry.size)
739
740 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600741 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700742
743 def testPackAlignPowerOf2(self):
744 """Test that invalid entry alignment is detected"""
745 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600746 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700747 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
748 "of two", str(e.exception))
749
750 def testPackAlignSizePowerOf2(self):
751 """Test that invalid entry size alignment is detected"""
752 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600753 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700754 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
755 "power of two", str(e.exception))
756
757 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600758 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700759 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600760 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600761 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700762 "align 0x4 (4)", str(e.exception))
763
764 def testPackInvalidSizeAlign(self):
765 """Test that invalid entry size alignment is detected"""
766 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600767 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700768 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
769 "align-size 0x4 (4)", str(e.exception))
770
771 def testPackOverlap(self):
772 """Test that overlapping regions are detected"""
773 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600774 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600775 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700776 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
777 str(e.exception))
778
779 def testPackEntryOverflow(self):
780 """Test that entries that overflow their size are detected"""
781 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600782 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700783 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
784 "but entry size is 0x3 (3)", str(e.exception))
785
786 def testPackImageOverflow(self):
787 """Test that entries which overflow the image size are detected"""
788 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600789 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600790 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700791 "size 0x3 (3)", str(e.exception))
792
793 def testPackImageSize(self):
794 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600795 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700796 self.assertEqual(0, retcode)
797 self.assertIn('image', control.images)
798 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600799 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700800
801 def testPackImageSizeAlign(self):
802 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600803 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700804 self.assertEqual(0, retcode)
805 self.assertIn('image', control.images)
806 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600807 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700808
809 def testPackInvalidImageAlign(self):
810 """Test that invalid image alignment is detected"""
811 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600812 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600813 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700814 "align-size 0x8 (8)", str(e.exception))
815
816 def testPackAlignPowerOf2(self):
817 """Test that invalid image alignment is detected"""
818 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600819 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600820 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700821 "two", str(e.exception))
822
823 def testImagePadByte(self):
824 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600825 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600826 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600827 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
828 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700829
830 def testImageName(self):
831 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600832 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700833 self.assertEqual(0, retcode)
834 image = control.images['image1']
835 fname = tools.GetOutputFilename('test-name')
836 self.assertTrue(os.path.exists(fname))
837
838 image = control.images['image2']
839 fname = tools.GetOutputFilename('test-name.xx')
840 self.assertTrue(os.path.exists(fname))
841
842 def testBlobFilename(self):
843 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600844 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700845 self.assertEqual(BLOB_DATA, data)
846
847 def testPackSorted(self):
848 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600849 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600850 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600851 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
852 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700853
Simon Glass3ab95982018-08-01 15:22:37 -0600854 def testPackZeroOffset(self):
855 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700856 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600857 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600858 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700859 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
860 str(e.exception))
861
862 def testPackUbootDtb(self):
863 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600864 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700865 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700866
867 def testPackX86RomNoSize(self):
868 """Test that the end-at-4gb property requires a size property"""
869 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600870 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600871 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700872 "using end-at-4gb", str(e.exception))
873
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530874 def test4gbAndSkipAtStartTogether(self):
875 """Test that the end-at-4gb and skip-at-size property can't be used
876 together"""
877 with self.assertRaises(ValueError) as e:
878 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600879 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530880 "'skip-at-start'", str(e.exception))
881
Simon Glasse0ff8552016-11-25 20:15:53 -0700882 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600883 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700884 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600885 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600886 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600887 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700888 str(e.exception))
889
890 def testPackX86Rom(self):
891 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600892 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600893 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600894 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
895 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700896
897 def testPackX86RomMeNoDesc(self):
898 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600899 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700900 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600901 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600902 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
903 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700904
905 def testPackX86RomBadDesc(self):
906 """Test that the Intel requires a descriptor entry"""
907 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600908 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600909 self.assertIn("Node '/binman/intel-me': No offset set with "
910 "offset-unset: should another entry provide this correct "
911 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700912
913 def testPackX86RomMe(self):
914 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600915 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600916 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
917 if data[:0x1000] != expected_desc:
918 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700919 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
920
921 def testPackVga(self):
922 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600923 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700924 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
925
926 def testPackStart16(self):
927 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600928 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700929 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
930
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530931 def testPackPowerpcMpc85xxBootpgResetvec(self):
932 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
933 created"""
934 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
935 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
936
Simon Glass736bb0a2018-07-06 10:27:17 -0600937 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600938 """Handle running a test for insertion of microcode
939
940 Args:
941 dts_fname: Name of test .dts file
942 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600943 ucode_second: True if the microsecond entry is second instead of
944 third
Simon Glassadc57012018-07-06 10:27:16 -0600945
946 Returns:
947 Tuple:
948 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600949 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600950 in the above (two 4-byte words)
951 """
Simon Glass6b187df2017-11-12 21:52:27 -0700952 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700953
954 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600955 if ucode_second:
956 ucode_content = data[len(nodtb_data):]
957 ucode_pos = len(nodtb_data)
958 dtb_with_ucode = ucode_content[16:]
959 fdt_len = self.GetFdtLen(dtb_with_ucode)
960 else:
961 dtb_with_ucode = data[len(nodtb_data):]
962 fdt_len = self.GetFdtLen(dtb_with_ucode)
963 ucode_content = dtb_with_ucode[fdt_len:]
964 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700965 fname = tools.GetOutputFilename('test.dtb')
966 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600967 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600968 dtb = fdt.FdtScan(fname)
969 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700970 self.assertTrue(ucode)
971 for node in ucode.subnodes:
972 self.assertFalse(node.props.get('data'))
973
Simon Glasse0ff8552016-11-25 20:15:53 -0700974 # Check that the microcode appears immediately after the Fdt
975 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -0700976 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -0700977 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
978 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -0600979 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -0700980
981 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -0600982 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -0700983 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
984 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -0600985 u_boot = data[:len(nodtb_data)]
986 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -0700987
988 def testPackUbootMicrocode(self):
989 """Test that x86 microcode can be handled correctly
990
991 We expect to see the following in the image, in order:
992 u-boot-nodtb.bin with a microcode pointer inserted at the correct
993 place
994 u-boot.dtb with the microcode removed
995 the microcode
996 """
Simon Glass741f2d62018-10-01 12:22:30 -0600997 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -0700998 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -0600999 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1000 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001001
Simon Glass160a7662017-05-27 07:38:26 -06001002 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001003 """Test that x86 microcode can be handled correctly
1004
1005 We expect to see the following in the image, in order:
1006 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1007 place
1008 u-boot.dtb with the microcode
1009 an empty microcode region
1010 """
1011 # We need the libfdt library to run this test since only that allows
1012 # finding the offset of a property. This is required by
1013 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001014 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001015
1016 second = data[len(U_BOOT_NODTB_DATA):]
1017
1018 fdt_len = self.GetFdtLen(second)
1019 third = second[fdt_len:]
1020 second = second[:fdt_len]
1021
Simon Glass160a7662017-05-27 07:38:26 -06001022 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1023 self.assertIn(ucode_data, second)
1024 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001025
Simon Glass160a7662017-05-27 07:38:26 -06001026 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001027 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001028 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1029 len(ucode_data))
1030 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001031 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1032 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001033
Simon Glass75db0862016-11-25 20:15:55 -07001034 def testPackUbootSingleMicrocode(self):
1035 """Test that x86 microcode can be handled correctly with fdt_normal.
1036 """
Simon Glass160a7662017-05-27 07:38:26 -06001037 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001038
Simon Glassc49deb82016-11-25 20:15:54 -07001039 def testUBootImg(self):
1040 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001041 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001042 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001043
1044 def testNoMicrocode(self):
1045 """Test that a missing microcode region is detected"""
1046 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001047 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001048 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1049 "node found in ", str(e.exception))
1050
1051 def testMicrocodeWithoutNode(self):
1052 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1053 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001054 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001055 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1056 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1057
1058 def testMicrocodeWithoutNode2(self):
1059 """Test that a missing u-boot-ucode node is detected"""
1060 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001061 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001062 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1063 "microcode region u-boot-ucode", str(e.exception))
1064
1065 def testMicrocodeWithoutPtrInElf(self):
1066 """Test that a U-Boot binary without the microcode symbol is detected"""
1067 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001068 try:
Simon Glass1d0ebf72019-05-14 15:53:42 -06001069 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001070 TestFunctional._MakeInputFile('u-boot', fd.read())
1071
1072 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001073 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001074 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1075 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1076
1077 finally:
1078 # Put the original file back
Simon Glass1d0ebf72019-05-14 15:53:42 -06001079 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001080 TestFunctional._MakeInputFile('u-boot', fd.read())
1081
1082 def testMicrocodeNotInImage(self):
1083 """Test that microcode must be placed within the image"""
1084 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001085 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001086 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1087 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001088 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001089
1090 def testWithoutMicrocode(self):
1091 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glass1d0ebf72019-05-14 15:53:42 -06001092 with open(self.TestFile('u_boot_no_ucode_ptr'), 'rb') as fd:
Simon Glass75db0862016-11-25 20:15:55 -07001093 TestFunctional._MakeInputFile('u-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001094 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001095
1096 # Now check the device tree has no microcode
1097 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1098 second = data[len(U_BOOT_NODTB_DATA):]
1099
1100 fdt_len = self.GetFdtLen(second)
1101 self.assertEqual(dtb, second[:fdt_len])
1102
1103 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1104 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001105 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001106
1107 def testUnknownPosSize(self):
1108 """Test that microcode must be placed within the image"""
1109 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001110 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001111 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001112 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001113
1114 def testPackFsp(self):
1115 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001116 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001117 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1118
1119 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001120 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001121 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001122 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001123
1124 def testPackVbt(self):
1125 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001126 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001127 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001128
Simon Glass56509842017-11-12 21:52:25 -07001129 def testSplBssPad(self):
1130 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001131 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001132 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001133 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001134 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1135 data)
Simon Glass56509842017-11-12 21:52:25 -07001136
Simon Glass86af5112018-10-01 21:12:42 -06001137 def testSplBssPadMissing(self):
1138 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001139 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001140 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001141 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001142 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1143 str(e.exception))
1144
Simon Glass87722132017-11-12 21:52:26 -07001145 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001146 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001147 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001148 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1149
Simon Glass736bb0a2018-07-06 10:27:17 -06001150 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1151 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001152
1153 We expect to see the following in the image, in order:
1154 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1155 correct place
1156 u-boot.dtb with the microcode removed
1157 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001158
1159 Args:
1160 dts: Device tree file to use for test
1161 ucode_second: True if the microsecond entry is second instead of
1162 third
Simon Glass6b187df2017-11-12 21:52:27 -07001163 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001164 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001165 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1166 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001167 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1168 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001169
Simon Glass736bb0a2018-07-06 10:27:17 -06001170 def testPackUbootSplMicrocode(self):
1171 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001172 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001173
1174 def testPackUbootSplMicrocodeReorder(self):
1175 """Test that order doesn't matter for microcode entries
1176
1177 This is the same as testPackUbootSplMicrocode but when we process the
1178 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1179 entry, so we reply on binman to try later.
1180 """
Simon Glass741f2d62018-10-01 12:22:30 -06001181 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001182 ucode_second=True)
1183
Simon Glassca4f4ff2017-11-12 21:52:28 -07001184 def testPackMrc(self):
1185 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001186 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001187 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1188
Simon Glass47419ea2017-11-13 18:54:55 -07001189 def testSplDtb(self):
1190 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001191 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001192 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1193
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001194 def testSplNoDtb(self):
1195 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001196 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001197 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1198
Simon Glass19790632017-11-13 18:55:01 -07001199 def testSymbols(self):
1200 """Test binman can assign symbols embedded in U-Boot"""
1201 elf_fname = self.TestFile('u_boot_binman_syms')
1202 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1203 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001204 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001205
Simon Glass11ae93e2018-10-01 21:12:47 -06001206 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001207 data = self._DoReadFile('053_symbols.dts')
Simon Glass19790632017-11-13 18:55:01 -07001208 sym_values = struct.pack('<LQL', 0x24 + 0, 0x24 + 24, 0x24 + 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001209 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1210 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1211 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001212 self.assertEqual(expected, data)
1213
Simon Glassdd57c132018-06-01 09:38:11 -06001214 def testPackUnitAddress(self):
1215 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001216 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001217 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1218
Simon Glass18546952018-06-01 09:38:16 -06001219 def testSections(self):
1220 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001221 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001222 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1223 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1224 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001225 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001226
Simon Glass3b0c3822018-06-01 09:38:20 -06001227 def testMap(self):
1228 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001229 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001230 self.assertEqual('''ImagePos Offset Size Name
123100000000 00000000 00000028 main-section
123200000000 00000000 00000010 section@0
123300000000 00000000 00000004 u-boot
123400000010 00000010 00000010 section@1
123500000010 00000000 00000004 u-boot
123600000020 00000020 00000004 section@2
123700000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001238''', map_data)
1239
Simon Glassc8d48ef2018-06-01 09:38:21 -06001240 def testNamePrefix(self):
1241 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001242 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001243 self.assertEqual('''ImagePos Offset Size Name
124400000000 00000000 00000028 main-section
124500000000 00000000 00000010 section@0
124600000000 00000000 00000004 ro-u-boot
124700000010 00000010 00000010 section@1
124800000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001249''', map_data)
1250
Simon Glass736bb0a2018-07-06 10:27:17 -06001251 def testUnknownContents(self):
1252 """Test that obtaining the contents works as expected"""
1253 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001254 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001255 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass736bb0a2018-07-06 10:27:17 -06001256 "processing of contents: remaining [<_testing.Entry__testing ",
1257 str(e.exception))
1258
Simon Glass5c890232018-07-06 10:27:19 -06001259 def testBadChangeSize(self):
1260 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001261 try:
1262 state.SetAllowEntryExpansion(False)
1263 with self.assertRaises(ValueError) as e:
1264 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001265 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001266 str(e.exception))
1267 finally:
1268 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001269
Simon Glass16b8d6b2018-07-06 10:27:42 -06001270 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001271 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001272 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001273 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001274 dtb = fdt.Fdt(out_dtb_fname)
1275 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001276 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001277 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001278 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001279 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001280 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001281 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001282 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001283 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001284 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001285 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001286 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001287 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001288 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001289
Simon Glass3ab95982018-08-01 15:22:37 -06001290 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001291 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001292 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001293 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001294 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001295 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001296 'size': 40
1297 }, props)
1298
1299 def testUpdateFdtBad(self):
1300 """Test that we detect when ProcessFdt never completes"""
1301 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001302 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001303 self.assertIn('Could not complete processing of Fdt: remaining '
1304 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001305
Simon Glass53af22a2018-07-17 13:25:32 -06001306 def testEntryArgs(self):
1307 """Test passing arguments to entries from the command line"""
1308 entry_args = {
1309 'test-str-arg': 'test1',
1310 'test-int-arg': '456',
1311 }
Simon Glass741f2d62018-10-01 12:22:30 -06001312 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001313 self.assertIn('image', control.images)
1314 entry = control.images['image'].GetEntries()['_testing']
1315 self.assertEqual('test0', entry.test_str_fdt)
1316 self.assertEqual('test1', entry.test_str_arg)
1317 self.assertEqual(123, entry.test_int_fdt)
1318 self.assertEqual(456, entry.test_int_arg)
1319
1320 def testEntryArgsMissing(self):
1321 """Test missing arguments and properties"""
1322 entry_args = {
1323 'test-int-arg': '456',
1324 }
Simon Glass741f2d62018-10-01 12:22:30 -06001325 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001326 entry = control.images['image'].GetEntries()['_testing']
1327 self.assertEqual('test0', entry.test_str_fdt)
1328 self.assertEqual(None, entry.test_str_arg)
1329 self.assertEqual(None, entry.test_int_fdt)
1330 self.assertEqual(456, entry.test_int_arg)
1331
1332 def testEntryArgsRequired(self):
1333 """Test missing arguments and properties"""
1334 entry_args = {
1335 'test-int-arg': '456',
1336 }
1337 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001338 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001339 self.assertIn("Node '/binman/_testing': Missing required "
1340 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1341 str(e.exception))
1342
1343 def testEntryArgsInvalidFormat(self):
1344 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001345 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1346 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001347 with self.assertRaises(ValueError) as e:
1348 self._DoBinman(*args)
1349 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1350
1351 def testEntryArgsInvalidInteger(self):
1352 """Test that an invalid entry-argument integer is detected"""
1353 entry_args = {
1354 'test-int-arg': 'abc',
1355 }
1356 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001357 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001358 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1359 "'test-int-arg' (value 'abc') to integer",
1360 str(e.exception))
1361
1362 def testEntryArgsInvalidDatatype(self):
1363 """Test that an invalid entry-argument datatype is detected
1364
1365 This test could be written in entry_test.py except that it needs
1366 access to control.entry_args, which seems more than that module should
1367 be able to see.
1368 """
1369 entry_args = {
1370 'test-bad-datatype-arg': '12',
1371 }
1372 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001373 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001374 entry_args=entry_args)
1375 self.assertIn('GetArg() internal error: Unknown data type ',
1376 str(e.exception))
1377
Simon Glassbb748372018-07-17 13:25:33 -06001378 def testText(self):
1379 """Test for a text entry type"""
1380 entry_args = {
1381 'test-id': TEXT_DATA,
1382 'test-id2': TEXT_DATA2,
1383 'test-id3': TEXT_DATA3,
1384 }
Simon Glass741f2d62018-10-01 12:22:30 -06001385 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001386 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001387 expected = (tools.ToBytes(TEXT_DATA) +
1388 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1389 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001390 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001391 self.assertEqual(expected, data)
1392
Simon Glassfd8d1f72018-07-17 13:25:36 -06001393 def testEntryDocs(self):
1394 """Test for creation of entry documentation"""
1395 with test_util.capture_sys_output() as (stdout, stderr):
1396 control.WriteEntryDocs(binman.GetEntryModules())
1397 self.assertTrue(len(stdout.getvalue()) > 0)
1398
1399 def testEntryDocsMissing(self):
1400 """Test handling of missing entry documentation"""
1401 with self.assertRaises(ValueError) as e:
1402 with test_util.capture_sys_output() as (stdout, stderr):
1403 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1404 self.assertIn('Documentation is missing for modules: u_boot',
1405 str(e.exception))
1406
Simon Glass11e36cc2018-07-17 13:25:38 -06001407 def testFmap(self):
1408 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001409 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001410 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001411 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1412 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001413 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001414 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001415 self.assertEqual(1, fhdr.ver_major)
1416 self.assertEqual(0, fhdr.ver_minor)
1417 self.assertEqual(0, fhdr.base)
1418 self.assertEqual(16 + 16 +
1419 fmap_util.FMAP_HEADER_LEN +
1420 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001421 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001422 self.assertEqual(3, fhdr.nareas)
1423 for fentry in fentries:
1424 self.assertEqual(0, fentry.flags)
1425
1426 self.assertEqual(0, fentries[0].offset)
1427 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001428 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001429
1430 self.assertEqual(16, fentries[1].offset)
1431 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001432 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001433
1434 self.assertEqual(32, fentries[2].offset)
1435 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1436 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001437 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001438
Simon Glassec127af2018-07-17 13:25:39 -06001439 def testBlobNamedByArg(self):
1440 """Test we can add a blob with the filename coming from an entry arg"""
1441 entry_args = {
1442 'cros-ec-rw-path': 'ecrw.bin',
1443 }
Simon Glass741f2d62018-10-01 12:22:30 -06001444 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001445 entry_args=entry_args)
1446
Simon Glass3af8e492018-07-17 13:25:40 -06001447 def testFill(self):
1448 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001449 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001450 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001451 self.assertEqual(expected, data)
1452
1453 def testFillNoSize(self):
1454 """Test for an fill entry type with no size"""
1455 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001456 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001457 self.assertIn("'fill' entry must have a size property",
1458 str(e.exception))
1459
Simon Glass0ef87aa2018-07-17 13:25:44 -06001460 def _HandleGbbCommand(self, pipe_list):
1461 """Fake calls to the futility utility"""
1462 if pipe_list[0][0] == 'futility':
1463 fname = pipe_list[0][-1]
1464 # Append our GBB data to the file, which will happen every time the
1465 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001466 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001467 fd.write(GBB_DATA)
1468 return command.CommandResult()
1469
1470 def testGbb(self):
1471 """Test for the Chromium OS Google Binary Block"""
1472 command.test_result = self._HandleGbbCommand
1473 entry_args = {
1474 'keydir': 'devkeys',
1475 'bmpblk': 'bmpblk.bin',
1476 }
Simon Glass741f2d62018-10-01 12:22:30 -06001477 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001478
1479 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001480 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1481 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001482 self.assertEqual(expected, data)
1483
1484 def testGbbTooSmall(self):
1485 """Test for the Chromium OS Google Binary Block being large enough"""
1486 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001487 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001488 self.assertIn("Node '/binman/gbb': GBB is too small",
1489 str(e.exception))
1490
1491 def testGbbNoSize(self):
1492 """Test for the Chromium OS Google Binary Block having a size"""
1493 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001494 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001495 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1496 str(e.exception))
1497
Simon Glass24d0d3c2018-07-17 13:25:47 -06001498 def _HandleVblockCommand(self, pipe_list):
1499 """Fake calls to the futility utility"""
1500 if pipe_list[0][0] == 'futility':
1501 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001502 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001503 fd.write(VBLOCK_DATA)
1504 return command.CommandResult()
1505
1506 def testVblock(self):
1507 """Test for the Chromium OS Verified Boot Block"""
1508 command.test_result = self._HandleVblockCommand
1509 entry_args = {
1510 'keydir': 'devkeys',
1511 }
Simon Glass741f2d62018-10-01 12:22:30 -06001512 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001513 entry_args=entry_args)
1514 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1515 self.assertEqual(expected, data)
1516
1517 def testVblockNoContent(self):
1518 """Test we detect a vblock which has no content to sign"""
1519 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001520 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001521 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1522 'property', str(e.exception))
1523
1524 def testVblockBadPhandle(self):
1525 """Test that we detect a vblock with an invalid phandle in contents"""
1526 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001527 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001528 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1529 '1000', str(e.exception))
1530
1531 def testVblockBadEntry(self):
1532 """Test that we detect an entry that points to a non-entry"""
1533 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001534 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001535 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1536 "'other'", str(e.exception))
1537
Simon Glassb8ef5b62018-07-17 13:25:48 -06001538 def testTpl(self):
1539 """Test that an image with TPL and ots device tree can be created"""
1540 # ELF file with a '__bss_size' symbol
Simon Glass1d0ebf72019-05-14 15:53:42 -06001541 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001542 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001543 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001544 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1545
Simon Glass15a587c2018-07-17 13:25:51 -06001546 def testUsesPos(self):
1547 """Test that the 'pos' property cannot be used anymore"""
1548 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001549 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001550 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1551 "'pos'", str(e.exception))
1552
Simon Glassd178eab2018-09-14 04:57:08 -06001553 def testFillZero(self):
1554 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001555 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001556 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001557
Simon Glass0b489362018-09-14 04:57:09 -06001558 def testTextMissing(self):
1559 """Test for a text entry type where there is no text"""
1560 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001561 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001562 self.assertIn("Node '/binman/text': No value provided for text label "
1563 "'test-id'", str(e.exception))
1564
Simon Glass35b384c2018-09-14 04:57:10 -06001565 def testPackStart16Tpl(self):
1566 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001567 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001568 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1569
Simon Glass0bfa7b02018-09-14 04:57:12 -06001570 def testSelectImage(self):
1571 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001572 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001573
Simon Glasseb833d82019-04-25 21:58:34 -06001574 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001575 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001576 with test_util.capture_sys_output() as (stdout, stderr):
1577 retcode = self._DoTestFile('006_dual_image.dts',
1578 verbosity=verbosity,
1579 images=['image2'])
1580 self.assertEqual(0, retcode)
1581 if verbosity:
1582 self.assertIn(expected, stdout.getvalue())
1583 else:
1584 self.assertNotIn(expected, stdout.getvalue())
1585
1586 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1587 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001588 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001589
Simon Glass6ed45ba2018-09-14 04:57:24 -06001590 def testUpdateFdtAll(self):
1591 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001592 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001593
1594 base_expected = {
1595 'section:image-pos': 0,
1596 'u-boot-tpl-dtb:size': 513,
1597 'u-boot-spl-dtb:size': 513,
1598 'u-boot-spl-dtb:offset': 493,
1599 'image-pos': 0,
1600 'section/u-boot-dtb:image-pos': 0,
1601 'u-boot-spl-dtb:image-pos': 493,
1602 'section/u-boot-dtb:size': 493,
1603 'u-boot-tpl-dtb:image-pos': 1006,
1604 'section/u-boot-dtb:offset': 0,
1605 'section:size': 493,
1606 'offset': 0,
1607 'section:offset': 0,
1608 'u-boot-tpl-dtb:offset': 1006,
1609 'size': 1519
1610 }
1611
1612 # We expect three device-tree files in the output, one after the other.
1613 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1614 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1615 # main U-Boot tree. All three should have the same postions and offset.
1616 start = 0
1617 for item in ['', 'spl', 'tpl']:
1618 dtb = fdt.Fdt.FromData(data[start:])
1619 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001620 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1621 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001622 expected = dict(base_expected)
1623 if item:
1624 expected[item] = 0
1625 self.assertEqual(expected, props)
1626 start += dtb._fdt_obj.totalsize()
1627
1628 def testUpdateFdtOutput(self):
1629 """Test that output DTB files are updated"""
1630 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001631 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001632 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1633
1634 # Unfortunately, compiling a source file always results in a file
1635 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001636 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001637 # binman as a file called u-boot.dtb. To fix this, copy the file
1638 # over to the expected place.
1639 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1640 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1641 start = 0
1642 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1643 'tpl/u-boot-tpl.dtb.out']:
1644 dtb = fdt.Fdt.FromData(data[start:])
1645 size = dtb._fdt_obj.totalsize()
1646 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1647 outdata = tools.ReadFile(pathname)
1648 name = os.path.split(fname)[0]
1649
1650 if name:
1651 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1652 else:
1653 orig_indata = dtb_data
1654 self.assertNotEqual(outdata, orig_indata,
1655 "Expected output file '%s' be updated" % pathname)
1656 self.assertEqual(outdata, data[start:start + size],
1657 "Expected output file '%s' to match output image" %
1658 pathname)
1659 start += size
1660 finally:
1661 self._ResetDtbs()
1662
Simon Glass83d73c22018-09-14 04:57:26 -06001663 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001664 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001665
1666 def testCompress(self):
1667 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001668 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001669 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001670 use_real_dtb=True, update_dtb=True)
1671 dtb = fdt.Fdt(out_dtb_fname)
1672 dtb.Scan()
1673 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1674 orig = self._decompress(data)
1675 self.assertEquals(COMPRESS_DATA, orig)
1676 expected = {
1677 'blob:uncomp-size': len(COMPRESS_DATA),
1678 'blob:size': len(data),
1679 'size': len(data),
1680 }
1681 self.assertEqual(expected, props)
1682
Simon Glass0a98b282018-09-14 04:57:28 -06001683 def testFiles(self):
1684 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001685 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001686 self.assertEqual(FILES_DATA, data)
1687
1688 def testFilesCompress(self):
1689 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001690 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001691 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001692
1693 image = control.images['image']
1694 entries = image.GetEntries()
1695 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001696 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001697
Simon Glassc6c10e72019-05-17 22:00:46 -06001698 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001699 for i in range(1, 3):
1700 key = '%d.dat' % i
1701 start = entries[key].image_pos
1702 len = entries[key].size
1703 chunk = data[start:start + len]
1704 orig += self._decompress(chunk)
1705
1706 self.assertEqual(FILES_DATA, orig)
1707
1708 def testFilesMissing(self):
1709 """Test missing files"""
1710 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001711 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001712 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1713 'no files', str(e.exception))
1714
1715 def testFilesNoPattern(self):
1716 """Test missing files"""
1717 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001718 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001719 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1720 str(e.exception))
1721
Simon Glassba64a0b2018-09-14 04:57:29 -06001722 def testExpandSize(self):
1723 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001724 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001725 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001726 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1727 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1728 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1729 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001730 self.assertEqual(expect, data)
1731 self.assertEqual('''ImagePos Offset Size Name
173200000000 00000000 00000028 main-section
173300000000 00000000 00000008 fill
173400000008 00000008 00000004 u-boot
17350000000c 0000000c 00000004 section
17360000000c 00000000 00000003 intel-mrc
173700000010 00000010 00000004 u-boot2
173800000014 00000014 0000000c section2
173900000014 00000000 00000008 fill
17400000001c 00000008 00000004 u-boot
174100000020 00000020 00000008 fill2
1742''', map_data)
1743
1744 def testExpandSizeBad(self):
1745 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001746 with test_util.capture_sys_output() as (stdout, stderr):
1747 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001748 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001749 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1750 'expanding entry', str(e.exception))
1751
Simon Glasse0e5df92018-09-14 04:57:31 -06001752 def testHash(self):
1753 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001754 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001755 use_real_dtb=True, update_dtb=True)
1756 dtb = fdt.Fdt(out_dtb_fname)
1757 dtb.Scan()
1758 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1759 m = hashlib.sha256()
1760 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001761 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001762
1763 def testHashNoAlgo(self):
1764 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001765 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001766 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1767 'hash node', str(e.exception))
1768
1769 def testHashBadAlgo(self):
1770 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001771 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001772 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1773 str(e.exception))
1774
1775 def testHashSection(self):
1776 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001777 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001778 use_real_dtb=True, update_dtb=True)
1779 dtb = fdt.Fdt(out_dtb_fname)
1780 dtb.Scan()
1781 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1782 m = hashlib.sha256()
1783 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001784 m.update(tools.GetBytes(ord('a'), 16))
1785 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001786
Simon Glassf0253632018-09-14 04:57:32 -06001787 def testPackUBootTplMicrocode(self):
1788 """Test that x86 microcode can be handled correctly in TPL
1789
1790 We expect to see the following in the image, in order:
1791 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1792 place
1793 u-boot-tpl.dtb with the microcode removed
1794 the microcode
1795 """
Simon Glass1d0ebf72019-05-14 15:53:42 -06001796 with open(self.TestFile('u_boot_ucode_ptr'), 'rb') as fd:
Simon Glassf0253632018-09-14 04:57:32 -06001797 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001798 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001799 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001800 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1801 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001802
Simon Glassf8f8df62018-09-14 04:57:34 -06001803 def testFmapX86(self):
1804 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001805 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001806 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001807 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001808 self.assertEqual(expected, data[:32])
1809 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1810
1811 self.assertEqual(0x100, fhdr.image_size)
1812
1813 self.assertEqual(0, fentries[0].offset)
1814 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001815 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001816
1817 self.assertEqual(4, fentries[1].offset)
1818 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001819 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001820
1821 self.assertEqual(32, fentries[2].offset)
1822 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1823 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001824 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001825
1826 def testFmapX86Section(self):
1827 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001828 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001829 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001830 self.assertEqual(expected, data[:32])
1831 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1832
1833 self.assertEqual(0x100, fhdr.image_size)
1834
1835 self.assertEqual(0, fentries[0].offset)
1836 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001837 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001838
1839 self.assertEqual(4, fentries[1].offset)
1840 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001841 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001842
1843 self.assertEqual(36, fentries[2].offset)
1844 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1845 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001846 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001847
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001848 def testElf(self):
1849 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001850 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001851 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001852 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
1853 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001854 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001855 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001856
Simon Glass093d1682019-07-08 13:18:25 -06001857 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001858 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001859 self._SetupSplElf()
Simon Glass1d0ebf72019-05-14 15:53:42 -06001860 with open(self.TestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001861 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001862 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001863
Simon Glass163ed6c2018-09-14 04:57:36 -06001864 def testPackOverlapMap(self):
1865 """Test that overlapping regions are detected"""
1866 with test_util.capture_sys_output() as (stdout, stderr):
1867 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001868 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001869 map_fname = tools.GetOutputFilename('image.map')
1870 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1871 stdout.getvalue())
1872
1873 # We should not get an inmage, but there should be a map file
1874 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1875 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001876 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001877 self.assertEqual('''ImagePos Offset Size Name
1878<none> 00000000 00000007 main-section
1879<none> 00000000 00000004 u-boot
1880<none> 00000003 00000004 u-boot-align
1881''', map_data)
1882
Simon Glass093d1682019-07-08 13:18:25 -06001883 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001884 """Test that an image with an Intel Reference code binary works"""
1885 data = self._DoReadFile('100_intel_refcode.dts')
1886 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1887
Simon Glass9481c802019-04-25 21:58:39 -06001888 def testSectionOffset(self):
1889 """Tests use of a section with an offset"""
1890 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1891 map=True)
1892 self.assertEqual('''ImagePos Offset Size Name
189300000000 00000000 00000038 main-section
189400000004 00000004 00000010 section@0
189500000004 00000000 00000004 u-boot
189600000018 00000018 00000010 section@1
189700000018 00000000 00000004 u-boot
18980000002c 0000002c 00000004 section@2
18990000002c 00000000 00000004 u-boot
1900''', map_data)
1901 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001902 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1903 tools.GetBytes(0x21, 12) +
1904 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1905 tools.GetBytes(0x61, 12) +
1906 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1907 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001908
Simon Glassac62fba2019-07-08 13:18:53 -06001909 def testCbfsRaw(self):
1910 """Test base handling of a Coreboot Filesystem (CBFS)
1911
1912 The exact contents of the CBFS is verified by similar tests in
1913 cbfs_util_test.py. The tests here merely check that the files added to
1914 the CBFS can be found in the final image.
1915 """
1916 data = self._DoReadFile('102_cbfs_raw.dts')
1917 size = 0xb0
1918
1919 cbfs = cbfs_util.CbfsReader(data)
1920 self.assertEqual(size, cbfs.rom_size)
1921
1922 self.assertIn('u-boot-dtb', cbfs.files)
1923 cfile = cbfs.files['u-boot-dtb']
1924 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1925
1926 def testCbfsArch(self):
1927 """Test on non-x86 architecture"""
1928 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1929 size = 0x100
1930
1931 cbfs = cbfs_util.CbfsReader(data)
1932 self.assertEqual(size, cbfs.rom_size)
1933
1934 self.assertIn('u-boot-dtb', cbfs.files)
1935 cfile = cbfs.files['u-boot-dtb']
1936 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1937
1938 def testCbfsStage(self):
1939 """Tests handling of a Coreboot Filesystem (CBFS)"""
1940 if not elf.ELF_TOOLS:
1941 self.skipTest('Python elftools not available')
1942 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1943 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1944 size = 0xb0
1945
1946 data = self._DoReadFile('104_cbfs_stage.dts')
1947 cbfs = cbfs_util.CbfsReader(data)
1948 self.assertEqual(size, cbfs.rom_size)
1949
1950 self.assertIn('u-boot', cbfs.files)
1951 cfile = cbfs.files['u-boot']
1952 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1953
1954 def testCbfsRawCompress(self):
1955 """Test handling of compressing raw files"""
1956 self._CheckLz4()
1957 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1958 size = 0x140
1959
1960 cbfs = cbfs_util.CbfsReader(data)
1961 self.assertIn('u-boot', cbfs.files)
1962 cfile = cbfs.files['u-boot']
1963 self.assertEqual(COMPRESS_DATA, cfile.data)
1964
1965 def testCbfsBadArch(self):
1966 """Test handling of a bad architecture"""
1967 with self.assertRaises(ValueError) as e:
1968 self._DoReadFile('106_cbfs_bad_arch.dts')
1969 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1970
1971 def testCbfsNoSize(self):
1972 """Test handling of a missing size property"""
1973 with self.assertRaises(ValueError) as e:
1974 self._DoReadFile('107_cbfs_no_size.dts')
1975 self.assertIn('entry must have a size property', str(e.exception))
1976
1977 def testCbfsNoCOntents(self):
1978 """Test handling of a CBFS entry which does not provide contentsy"""
1979 with self.assertRaises(ValueError) as e:
1980 self._DoReadFile('108_cbfs_no_contents.dts')
1981 self.assertIn('Could not complete processing of contents',
1982 str(e.exception))
1983
1984 def testCbfsBadCompress(self):
1985 """Test handling of a bad architecture"""
1986 with self.assertRaises(ValueError) as e:
1987 self._DoReadFile('109_cbfs_bad_compress.dts')
1988 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
1989 str(e.exception))
1990
1991 def testCbfsNamedEntries(self):
1992 """Test handling of named entries"""
1993 data = self._DoReadFile('110_cbfs_name.dts')
1994
1995 cbfs = cbfs_util.CbfsReader(data)
1996 self.assertIn('FRED', cbfs.files)
1997 cfile1 = cbfs.files['FRED']
1998 self.assertEqual(U_BOOT_DATA, cfile1.data)
1999
2000 self.assertIn('hello', cbfs.files)
2001 cfile2 = cbfs.files['hello']
2002 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2003
Simon Glassc5ac1382019-07-08 13:18:54 -06002004 def _SetupIfwi(self, fname):
2005 """Set up to run an IFWI test
2006
2007 Args:
2008 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2009 """
2010 self._SetupSplElf()
2011
2012 # Intel Integrated Firmware Image (IFWI) file
2013 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2014 data = fd.read()
2015 TestFunctional._MakeInputFile(fname,data)
2016
2017 def _CheckIfwi(self, data):
2018 """Check that an image with an IFWI contains the correct output
2019
2020 Args:
2021 data: Conents of output file
2022 """
2023 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2024 if data[:0x1000] != expected_desc:
2025 self.fail('Expected descriptor binary at start of image')
2026
2027 # We expect to find the TPL wil in subpart IBBP entry IBBL
2028 image_fname = tools.GetOutputFilename('image.bin')
2029 tpl_fname = tools.GetOutputFilename('tpl.out')
2030 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2031 subpart='IBBP', entry_name='IBBL')
2032
2033 tpl_data = tools.ReadFile(tpl_fname)
2034 self.assertEqual(tpl_data[:len(U_BOOT_TPL_DATA)], U_BOOT_TPL_DATA)
2035
2036 def testPackX86RomIfwi(self):
2037 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2038 self._SetupIfwi('fitimage.bin')
2039 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2040 self._CheckIfwi(data)
2041
2042 def testPackX86RomIfwiNoDesc(self):
2043 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2044 self._SetupIfwi('ifwi.bin')
2045 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2046 self._CheckIfwi(data)
2047
2048 def testPackX86RomIfwiNoData(self):
2049 """Test that an x86 ROM with IFWI handles missing data"""
2050 self._SetupIfwi('ifwi.bin')
2051 with self.assertRaises(ValueError) as e:
2052 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2053 self.assertIn('Could not complete processing of contents',
2054 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002055
Simon Glasse073d4e2019-07-08 13:18:56 -06002056 def testCbfsOffset(self):
2057 """Test a CBFS with files at particular offsets
2058
2059 Like all CFBS tests, this is just checking the logic that calls
2060 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2061 """
2062 data = self._DoReadFile('114_cbfs_offset.dts')
2063 size = 0x200
2064
2065 cbfs = cbfs_util.CbfsReader(data)
2066 self.assertEqual(size, cbfs.rom_size)
2067
2068 self.assertIn('u-boot', cbfs.files)
2069 cfile = cbfs.files['u-boot']
2070 self.assertEqual(U_BOOT_DATA, cfile.data)
2071 self.assertEqual(0x40, cfile.cbfs_offset)
2072
2073 self.assertIn('u-boot-dtb', cbfs.files)
2074 cfile2 = cbfs.files['u-boot-dtb']
2075 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2076 self.assertEqual(0x140, cfile2.cbfs_offset)
2077
Simon Glass086cec92019-07-08 14:25:27 -06002078 def testFdtmap(self):
2079 """Test an FDT map can be inserted in the image"""
2080 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2081 fdtmap_data = data[len(U_BOOT_DATA):]
2082 magic = fdtmap_data[:8]
2083 self.assertEqual('_FDTMAP_', magic)
2084 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2085
2086 fdt_data = fdtmap_data[16:]
2087 dtb = fdt.Fdt.FromData(fdt_data)
2088 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002089 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002090 self.assertEqual({
2091 'image-pos': 0,
2092 'offset': 0,
2093 'u-boot:offset': 0,
2094 'u-boot:size': len(U_BOOT_DATA),
2095 'u-boot:image-pos': 0,
2096 'fdtmap:image-pos': 4,
2097 'fdtmap:offset': 4,
2098 'fdtmap:size': len(fdtmap_data),
2099 'size': len(data),
2100 }, props)
2101
2102 def testFdtmapNoMatch(self):
2103 """Check handling of an FDT map when the section cannot be found"""
2104 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2105
2106 # Mangle the section name, which should cause a mismatch between the
2107 # correct FDT path and the one expected by the section
2108 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002109 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002110 entries = image.GetEntries()
2111 fdtmap = entries['fdtmap']
2112 with self.assertRaises(ValueError) as e:
2113 fdtmap._GetFdtmap()
2114 self.assertIn("Cannot locate node for path '/binman-suffix'",
2115 str(e.exception))
2116
Simon Glasscf228942019-07-08 14:25:28 -06002117 def testFdtmapHeader(self):
2118 """Test an FDT map and image header can be inserted in the image"""
2119 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2120 fdtmap_pos = len(U_BOOT_DATA)
2121 fdtmap_data = data[fdtmap_pos:]
2122 fdt_data = fdtmap_data[16:]
2123 dtb = fdt.Fdt.FromData(fdt_data)
2124 fdt_size = dtb.GetFdtObj().totalsize()
2125 hdr_data = data[-8:]
2126 self.assertEqual('BinM', hdr_data[:4])
2127 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2128 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2129
2130 def testFdtmapHeaderStart(self):
2131 """Test an image header can be inserted at the image start"""
2132 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2133 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2134 hdr_data = data[:8]
2135 self.assertEqual('BinM', hdr_data[:4])
2136 offset = struct.unpack('<I', hdr_data[4:])[0]
2137 self.assertEqual(fdtmap_pos, offset)
2138
2139 def testFdtmapHeaderPos(self):
2140 """Test an image header can be inserted at a chosen position"""
2141 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2142 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2143 hdr_data = data[0x80:0x88]
2144 self.assertEqual('BinM', hdr_data[:4])
2145 offset = struct.unpack('<I', hdr_data[4:])[0]
2146 self.assertEqual(fdtmap_pos, offset)
2147
2148 def testHeaderMissingFdtmap(self):
2149 """Test an image header requires an fdtmap"""
2150 with self.assertRaises(ValueError) as e:
2151 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2152 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2153 str(e.exception))
2154
2155 def testHeaderNoLocation(self):
2156 """Test an image header with a no specified location is detected"""
2157 with self.assertRaises(ValueError) as e:
2158 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2159 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2160 str(e.exception))
2161
Simon Glassc52c9e72019-07-08 14:25:37 -06002162 def testEntryExpand(self):
2163 """Test expanding an entry after it is packed"""
2164 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002165 self.assertEqual(b'aaa', data[:3])
2166 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2167 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002168
2169 def testEntryExpandBad(self):
2170 """Test expanding an entry after it is packed, twice"""
2171 with self.assertRaises(ValueError) as e:
2172 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002173 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002174 str(e.exception))
2175
2176 def testEntryExpandSection(self):
2177 """Test expanding an entry within a section after it is packed"""
2178 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002179 self.assertEqual(b'aaa', data[:3])
2180 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2181 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002182
Simon Glass6c223fd2019-07-08 14:25:38 -06002183 def testCompressDtb(self):
2184 """Test that compress of device-tree files is supported"""
2185 self._CheckLz4()
2186 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2187 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2188 comp_data = data[len(U_BOOT_DATA):]
2189 orig = self._decompress(comp_data)
2190 dtb = fdt.Fdt.FromData(orig)
2191 dtb.Scan()
2192 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2193 expected = {
2194 'u-boot:size': len(U_BOOT_DATA),
2195 'u-boot-dtb:uncomp-size': len(orig),
2196 'u-boot-dtb:size': len(comp_data),
2197 'size': len(data),
2198 }
2199 self.assertEqual(expected, props)
2200
Simon Glass69f7cb32019-07-08 14:25:41 -06002201 def testCbfsUpdateFdt(self):
2202 """Test that we can update the device tree with CBFS offset/size info"""
2203 self._CheckLz4()
2204 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2205 update_dtb=True)
2206 dtb = fdt.Fdt(out_dtb_fname)
2207 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002208 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002209 del props['cbfs/u-boot:size']
2210 self.assertEqual({
2211 'offset': 0,
2212 'size': len(data),
2213 'image-pos': 0,
2214 'cbfs:offset': 0,
2215 'cbfs:size': len(data),
2216 'cbfs:image-pos': 0,
2217 'cbfs/u-boot:offset': 0x38,
2218 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2219 'cbfs/u-boot:image-pos': 0x38,
2220 'cbfs/u-boot-dtb:offset': 0xb8,
2221 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2222 'cbfs/u-boot-dtb:image-pos': 0xb8,
2223 }, props)
2224
Simon Glass8a1ad062019-07-08 14:25:42 -06002225 def testCbfsBadType(self):
2226 """Test an image header with a no specified location is detected"""
2227 with self.assertRaises(ValueError) as e:
2228 self._DoReadFile('126_cbfs_bad_type.dts')
2229 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2230
Simon Glass41b8ba02019-07-08 14:25:43 -06002231 def testList(self):
2232 """Test listing the files in an image"""
2233 self._CheckLz4()
2234 data = self._DoReadFile('127_list.dts')
2235 image = control.images['image']
2236 entries = image.BuildEntryList()
2237 self.assertEqual(7, len(entries))
2238
2239 ent = entries[0]
2240 self.assertEqual(0, ent.indent)
2241 self.assertEqual('main-section', ent.name)
2242 self.assertEqual('section', ent.etype)
2243 self.assertEqual(len(data), ent.size)
2244 self.assertEqual(0, ent.image_pos)
2245 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002246 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002247
2248 ent = entries[1]
2249 self.assertEqual(1, 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(0, ent.image_pos)
2254 self.assertEqual(None, ent.uncomp_size)
2255 self.assertEqual(0, ent.offset)
2256
2257 ent = entries[2]
2258 self.assertEqual(1, ent.indent)
2259 self.assertEqual('section', ent.name)
2260 self.assertEqual('section', ent.etype)
2261 section_size = ent.size
2262 self.assertEqual(0x100, ent.image_pos)
2263 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002264 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002265
2266 ent = entries[3]
2267 self.assertEqual(2, ent.indent)
2268 self.assertEqual('cbfs', ent.name)
2269 self.assertEqual('cbfs', ent.etype)
2270 self.assertEqual(0x400, ent.size)
2271 self.assertEqual(0x100, ent.image_pos)
2272 self.assertEqual(None, ent.uncomp_size)
2273 self.assertEqual(0, ent.offset)
2274
2275 ent = entries[4]
2276 self.assertEqual(3, ent.indent)
2277 self.assertEqual('u-boot', ent.name)
2278 self.assertEqual('u-boot', ent.etype)
2279 self.assertEqual(len(U_BOOT_DATA), ent.size)
2280 self.assertEqual(0x138, ent.image_pos)
2281 self.assertEqual(None, ent.uncomp_size)
2282 self.assertEqual(0x38, ent.offset)
2283
2284 ent = entries[5]
2285 self.assertEqual(3, ent.indent)
2286 self.assertEqual('u-boot-dtb', ent.name)
2287 self.assertEqual('text', ent.etype)
2288 self.assertGreater(len(COMPRESS_DATA), ent.size)
2289 self.assertEqual(0x178, ent.image_pos)
2290 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2291 self.assertEqual(0x78, ent.offset)
2292
2293 ent = entries[6]
2294 self.assertEqual(2, ent.indent)
2295 self.assertEqual('u-boot-dtb', ent.name)
2296 self.assertEqual('u-boot-dtb', ent.etype)
2297 self.assertEqual(0x500, ent.image_pos)
2298 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2299 dtb_size = ent.size
2300 # Compressing this data expands it since headers are added
2301 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2302 self.assertEqual(0x400, ent.offset)
2303
2304 self.assertEqual(len(data), 0x100 + section_size)
2305 self.assertEqual(section_size, 0x400 + dtb_size)
2306
Simon Glasse1925fa2019-07-08 14:25:44 -06002307 def testFindFdtmap(self):
2308 """Test locating an FDT map in an image"""
2309 self._CheckLz4()
2310 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2311 image = control.images['image']
2312 entries = image.GetEntries()
2313 entry = entries['fdtmap']
2314 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2315
2316 def testFindFdtmapMissing(self):
2317 """Test failing to locate an FDP map"""
2318 data = self._DoReadFile('005_simple.dts')
2319 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2320
Simon Glass2d260032019-07-08 14:25:45 -06002321 def testFindImageHeader(self):
2322 """Test locating a image header"""
2323 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002324 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002325 image = control.images['image']
2326 entries = image.GetEntries()
2327 entry = entries['fdtmap']
2328 # The header should point to the FDT map
2329 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2330
2331 def testFindImageHeaderStart(self):
2332 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002333 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002334 image = control.images['image']
2335 entries = image.GetEntries()
2336 entry = entries['fdtmap']
2337 # The header should point to the FDT map
2338 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2339
2340 def testFindImageHeaderMissing(self):
2341 """Test failing to locate an image header"""
2342 data = self._DoReadFile('005_simple.dts')
2343 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2344
Simon Glassffded752019-07-08 14:25:46 -06002345 def testReadImage(self):
2346 """Test reading an image and accessing its FDT map"""
2347 self._CheckLz4()
2348 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2349 image_fname = tools.GetOutputFilename('image.bin')
2350 orig_image = control.images['image']
2351 image = Image.FromFile(image_fname)
2352 self.assertEqual(orig_image.GetEntries().keys(),
2353 image.GetEntries().keys())
2354
2355 orig_entry = orig_image.GetEntries()['fdtmap']
2356 entry = image.GetEntries()['fdtmap']
2357 self.assertEquals(orig_entry.offset, entry.offset)
2358 self.assertEquals(orig_entry.size, entry.size)
2359 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2360
2361 def testReadImageNoHeader(self):
2362 """Test accessing an image's FDT map without an image header"""
2363 self._CheckLz4()
2364 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2365 image_fname = tools.GetOutputFilename('image.bin')
2366 image = Image.FromFile(image_fname)
2367 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002368 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002369
2370 def testReadImageFail(self):
2371 """Test failing to read an image image's FDT map"""
2372 self._DoReadFile('005_simple.dts')
2373 image_fname = tools.GetOutputFilename('image.bin')
2374 with self.assertRaises(ValueError) as e:
2375 image = Image.FromFile(image_fname)
2376 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002377
Simon Glass61f564d2019-07-08 14:25:48 -06002378 def testListCmd(self):
2379 """Test listing the files in an image using an Fdtmap"""
2380 self._CheckLz4()
2381 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2382
2383 # lz4 compression size differs depending on the version
2384 image = control.images['image']
2385 entries = image.GetEntries()
2386 section_size = entries['section'].size
2387 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2388 fdtmap_offset = entries['fdtmap'].offset
2389
Simon Glassf86a7362019-07-20 12:24:10 -06002390 try:
2391 tmpdir, updated_fname = self._SetupImageInTmpdir()
2392 with test_util.capture_sys_output() as (stdout, stderr):
2393 self._DoBinman('ls', '-i', updated_fname)
2394 finally:
2395 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002396 lines = stdout.getvalue().splitlines()
2397 expected = [
2398'Name Image-pos Size Entry-type Offset Uncomp-size',
2399'----------------------------------------------------------------------',
2400'main-section 0 c00 section 0',
2401' u-boot 0 4 u-boot 0',
2402' section 100 %x section 100' % section_size,
2403' cbfs 100 400 cbfs 0',
2404' u-boot 138 4 u-boot 38',
2405' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2406' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glass1411ac82019-07-20 12:23:44 -06002407' fdtmap %x 3b4 fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002408 (fdtmap_offset, fdtmap_offset),
2409' image-header bf8 8 image-header bf8',
2410 ]
2411 self.assertEqual(expected, lines)
2412
2413 def testListCmdFail(self):
2414 """Test failing to list an image"""
2415 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002416 try:
2417 tmpdir, updated_fname = self._SetupImageInTmpdir()
2418 with self.assertRaises(ValueError) as e:
2419 self._DoBinman('ls', '-i', updated_fname)
2420 finally:
2421 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002422 self.assertIn("Cannot find FDT map in image", str(e.exception))
2423
2424 def _RunListCmd(self, paths, expected):
2425 """List out entries and check the result
2426
2427 Args:
2428 paths: List of paths to pass to the list command
2429 expected: Expected list of filenames to be returned, in order
2430 """
2431 self._CheckLz4()
2432 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2433 image_fname = tools.GetOutputFilename('image.bin')
2434 image = Image.FromFile(image_fname)
2435 lines = image.GetListEntries(paths)[1]
2436 files = [line[0].strip() for line in lines[1:]]
2437 self.assertEqual(expected, files)
2438
2439 def testListCmdSection(self):
2440 """Test listing the files in a section"""
2441 self._RunListCmd(['section'],
2442 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2443
2444 def testListCmdFile(self):
2445 """Test listing a particular file"""
2446 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2447
2448 def testListCmdWildcard(self):
2449 """Test listing a wildcarded file"""
2450 self._RunListCmd(['*boot*'],
2451 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2452
2453 def testListCmdWildcardMulti(self):
2454 """Test listing a wildcarded file"""
2455 self._RunListCmd(['*cb*', '*head*'],
2456 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2457
2458 def testListCmdEmpty(self):
2459 """Test listing a wildcarded file"""
2460 self._RunListCmd(['nothing'], [])
2461
2462 def testListCmdPath(self):
2463 """Test listing the files in a sub-entry of a section"""
2464 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2465
Simon Glassf667e452019-07-08 14:25:50 -06002466 def _RunExtractCmd(self, entry_name, decomp=True):
2467 """Extract an entry from an image
2468
2469 Args:
2470 entry_name: Entry name to extract
2471 decomp: True to decompress the data if compressed, False to leave
2472 it in its raw uncompressed format
2473
2474 Returns:
2475 data from entry
2476 """
2477 self._CheckLz4()
2478 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2479 image_fname = tools.GetOutputFilename('image.bin')
2480 return control.ReadEntry(image_fname, entry_name, decomp)
2481
2482 def testExtractSimple(self):
2483 """Test extracting a single file"""
2484 data = self._RunExtractCmd('u-boot')
2485 self.assertEqual(U_BOOT_DATA, data)
2486
Simon Glass71ce0ba2019-07-08 14:25:52 -06002487 def testExtractSection(self):
2488 """Test extracting the files in a section"""
2489 data = self._RunExtractCmd('section')
2490 cbfs_data = data[:0x400]
2491 cbfs = cbfs_util.CbfsReader(cbfs_data)
2492 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2493 dtb_data = data[0x400:]
2494 dtb = self._decompress(dtb_data)
2495 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2496
2497 def testExtractCompressed(self):
2498 """Test extracting compressed data"""
2499 data = self._RunExtractCmd('section/u-boot-dtb')
2500 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2501
2502 def testExtractRaw(self):
2503 """Test extracting compressed data without decompressing it"""
2504 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2505 dtb = self._decompress(data)
2506 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2507
2508 def testExtractCbfs(self):
2509 """Test extracting CBFS data"""
2510 data = self._RunExtractCmd('section/cbfs/u-boot')
2511 self.assertEqual(U_BOOT_DATA, data)
2512
2513 def testExtractCbfsCompressed(self):
2514 """Test extracting CBFS compressed data"""
2515 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2516 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2517
2518 def testExtractCbfsRaw(self):
2519 """Test extracting CBFS compressed data without decompressing it"""
2520 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002521 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002522 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2523
Simon Glassf667e452019-07-08 14:25:50 -06002524 def testExtractBadEntry(self):
2525 """Test extracting a bad section path"""
2526 with self.assertRaises(ValueError) as e:
2527 self._RunExtractCmd('section/does-not-exist')
2528 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2529 str(e.exception))
2530
2531 def testExtractMissingFile(self):
2532 """Test extracting file that does not exist"""
2533 with self.assertRaises(IOError) as e:
2534 control.ReadEntry('missing-file', 'name')
2535
2536 def testExtractBadFile(self):
2537 """Test extracting an invalid file"""
2538 fname = os.path.join(self._indir, 'badfile')
2539 tools.WriteFile(fname, b'')
2540 with self.assertRaises(ValueError) as e:
2541 control.ReadEntry(fname, 'name')
2542
Simon Glass71ce0ba2019-07-08 14:25:52 -06002543 def testExtractCmd(self):
2544 """Test extracting a file fron an image on the command line"""
2545 self._CheckLz4()
2546 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002547 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002548 try:
2549 tmpdir, updated_fname = self._SetupImageInTmpdir()
2550 with test_util.capture_sys_output() as (stdout, stderr):
2551 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2552 '-f', fname)
2553 finally:
2554 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002555 data = tools.ReadFile(fname)
2556 self.assertEqual(U_BOOT_DATA, data)
2557
2558 def testExtractOneEntry(self):
2559 """Test extracting a single entry fron an image """
2560 self._CheckLz4()
2561 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2562 image_fname = tools.GetOutputFilename('image.bin')
2563 fname = os.path.join(self._indir, 'output.extact')
2564 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2565 data = tools.ReadFile(fname)
2566 self.assertEqual(U_BOOT_DATA, data)
2567
2568 def _CheckExtractOutput(self, decomp):
2569 """Helper to test file output with and without decompression
2570
2571 Args:
2572 decomp: True to decompress entry data, False to output it raw
2573 """
2574 def _CheckPresent(entry_path, expect_data, expect_size=None):
2575 """Check and remove expected file
2576
2577 This checks the data/size of a file and removes the file both from
2578 the outfiles set and from the output directory. Once all files are
2579 processed, both the set and directory should be empty.
2580
2581 Args:
2582 entry_path: Entry path
2583 expect_data: Data to expect in file, or None to skip check
2584 expect_size: Size of data to expect in file, or None to skip
2585 """
2586 path = os.path.join(outdir, entry_path)
2587 data = tools.ReadFile(path)
2588 os.remove(path)
2589 if expect_data:
2590 self.assertEqual(expect_data, data)
2591 elif expect_size:
2592 self.assertEqual(expect_size, len(data))
2593 outfiles.remove(path)
2594
2595 def _CheckDirPresent(name):
2596 """Remove expected directory
2597
2598 This gives an error if the directory does not exist as expected
2599
2600 Args:
2601 name: Name of directory to remove
2602 """
2603 path = os.path.join(outdir, name)
2604 os.rmdir(path)
2605
2606 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2607 image_fname = tools.GetOutputFilename('image.bin')
2608 outdir = os.path.join(self._indir, 'extract')
2609 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2610
2611 # Create a set of all file that were output (should be 9)
2612 outfiles = set()
2613 for root, dirs, files in os.walk(outdir):
2614 outfiles |= set([os.path.join(root, fname) for fname in files])
2615 self.assertEqual(9, len(outfiles))
2616 self.assertEqual(9, len(einfos))
2617
2618 image = control.images['image']
2619 entries = image.GetEntries()
2620
2621 # Check the 9 files in various ways
2622 section = entries['section']
2623 section_entries = section.GetEntries()
2624 cbfs_entries = section_entries['cbfs'].GetEntries()
2625 _CheckPresent('u-boot', U_BOOT_DATA)
2626 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2627 dtb_len = EXTRACT_DTB_SIZE
2628 if not decomp:
2629 dtb_len = cbfs_entries['u-boot-dtb'].size
2630 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2631 if not decomp:
2632 dtb_len = section_entries['u-boot-dtb'].size
2633 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2634
2635 fdtmap = entries['fdtmap']
2636 _CheckPresent('fdtmap', fdtmap.data)
2637 hdr = entries['image-header']
2638 _CheckPresent('image-header', hdr.data)
2639
2640 _CheckPresent('section/root', section.data)
2641 cbfs = section_entries['cbfs']
2642 _CheckPresent('section/cbfs/root', cbfs.data)
2643 data = tools.ReadFile(image_fname)
2644 _CheckPresent('root', data)
2645
2646 # There should be no files left. Remove all the directories to check.
2647 # If there are any files/dirs remaining, one of these checks will fail.
2648 self.assertEqual(0, len(outfiles))
2649 _CheckDirPresent('section/cbfs')
2650 _CheckDirPresent('section')
2651 _CheckDirPresent('')
2652 self.assertFalse(os.path.exists(outdir))
2653
2654 def testExtractAllEntries(self):
2655 """Test extracting all entries"""
2656 self._CheckLz4()
2657 self._CheckExtractOutput(decomp=True)
2658
2659 def testExtractAllEntriesRaw(self):
2660 """Test extracting all entries without decompressing them"""
2661 self._CheckLz4()
2662 self._CheckExtractOutput(decomp=False)
2663
2664 def testExtractSelectedEntries(self):
2665 """Test extracting some entries"""
2666 self._CheckLz4()
2667 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2668 image_fname = tools.GetOutputFilename('image.bin')
2669 outdir = os.path.join(self._indir, 'extract')
2670 einfos = control.ExtractEntries(image_fname, None, outdir,
2671 ['*cb*', '*head*'])
2672
2673 # File output is tested by testExtractAllEntries(), so just check that
2674 # the expected entries are selected
2675 names = [einfo.name for einfo in einfos]
2676 self.assertEqual(names,
2677 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2678
2679 def testExtractNoEntryPaths(self):
2680 """Test extracting some entries"""
2681 self._CheckLz4()
2682 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2683 image_fname = tools.GetOutputFilename('image.bin')
2684 with self.assertRaises(ValueError) as e:
2685 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002686 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002687 str(e.exception))
2688
2689 def testExtractTooManyEntryPaths(self):
2690 """Test extracting some entries"""
2691 self._CheckLz4()
2692 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2693 image_fname = tools.GetOutputFilename('image.bin')
2694 with self.assertRaises(ValueError) as e:
2695 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002696 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002697 str(e.exception))
2698
Simon Glasse2705fa2019-07-08 14:25:53 -06002699 def testPackAlignSection(self):
2700 """Test that sections can have alignment"""
2701 self._DoReadFile('131_pack_align_section.dts')
2702
2703 self.assertIn('image', control.images)
2704 image = control.images['image']
2705 entries = image.GetEntries()
2706 self.assertEqual(3, len(entries))
2707
2708 # First u-boot
2709 self.assertIn('u-boot', entries)
2710 entry = entries['u-boot']
2711 self.assertEqual(0, entry.offset)
2712 self.assertEqual(0, entry.image_pos)
2713 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2714 self.assertEqual(len(U_BOOT_DATA), entry.size)
2715
2716 # Section0
2717 self.assertIn('section0', entries)
2718 section0 = entries['section0']
2719 self.assertEqual(0x10, section0.offset)
2720 self.assertEqual(0x10, section0.image_pos)
2721 self.assertEqual(len(U_BOOT_DATA), section0.size)
2722
2723 # Second u-boot
2724 section_entries = section0.GetEntries()
2725 self.assertIn('u-boot', section_entries)
2726 entry = section_entries['u-boot']
2727 self.assertEqual(0, entry.offset)
2728 self.assertEqual(0x10, entry.image_pos)
2729 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2730 self.assertEqual(len(U_BOOT_DATA), entry.size)
2731
2732 # Section1
2733 self.assertIn('section1', entries)
2734 section1 = entries['section1']
2735 self.assertEqual(0x14, section1.offset)
2736 self.assertEqual(0x14, section1.image_pos)
2737 self.assertEqual(0x20, section1.size)
2738
2739 # Second u-boot
2740 section_entries = section1.GetEntries()
2741 self.assertIn('u-boot', section_entries)
2742 entry = section_entries['u-boot']
2743 self.assertEqual(0, entry.offset)
2744 self.assertEqual(0x14, entry.image_pos)
2745 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2746 self.assertEqual(len(U_BOOT_DATA), entry.size)
2747
2748 # Section2
2749 self.assertIn('section2', section_entries)
2750 section2 = section_entries['section2']
2751 self.assertEqual(0x4, section2.offset)
2752 self.assertEqual(0x18, section2.image_pos)
2753 self.assertEqual(4, section2.size)
2754
2755 # Third u-boot
2756 section_entries = section2.GetEntries()
2757 self.assertIn('u-boot', section_entries)
2758 entry = section_entries['u-boot']
2759 self.assertEqual(0, entry.offset)
2760 self.assertEqual(0x18, entry.image_pos)
2761 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2762 self.assertEqual(len(U_BOOT_DATA), entry.size)
2763
Simon Glass51014aa2019-07-20 12:23:56 -06002764 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2765 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002766 """Replace an entry in an image
2767
2768 This writes the entry data to update it, then opens the updated file and
2769 returns the value that it now finds there.
2770
2771 Args:
2772 entry_name: Entry name to replace
2773 data: Data to replace it with
2774 decomp: True to compress the data if needed, False if data is
2775 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002776 allow_resize: True to allow entries to change size, False to raise
2777 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002778
2779 Returns:
2780 Tuple:
2781 data from entry
2782 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002783 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002784 """
Simon Glass51014aa2019-07-20 12:23:56 -06002785 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002786 update_dtb=True)[1]
2787
2788 self.assertIn('image', control.images)
2789 image = control.images['image']
2790 entries = image.GetEntries()
2791 orig_dtb_data = entries['u-boot-dtb'].data
2792 orig_fdtmap_data = entries['fdtmap'].data
2793
2794 image_fname = tools.GetOutputFilename('image.bin')
2795 updated_fname = tools.GetOutputFilename('image-updated.bin')
2796 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002797 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2798 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002799 data = control.ReadEntry(updated_fname, entry_name, decomp)
2800
Simon Glass51014aa2019-07-20 12:23:56 -06002801 # The DT data should not change unless resized:
2802 if not allow_resize:
2803 new_dtb_data = entries['u-boot-dtb'].data
2804 self.assertEqual(new_dtb_data, orig_dtb_data)
2805 new_fdtmap_data = entries['fdtmap'].data
2806 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002807
Simon Glass51014aa2019-07-20 12:23:56 -06002808 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002809
2810 def testReplaceSimple(self):
2811 """Test replacing a single file"""
2812 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002813 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2814 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002815 self.assertEqual(expected, data)
2816
2817 # Test that the state looks right. There should be an FDT for the fdtmap
2818 # that we jsut read back in, and it should match what we find in the
2819 # 'control' tables. Checking for an FDT that does not exist should
2820 # return None.
2821 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002822 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002823 self.assertEqual(expected_fdtmap, fdtmap)
2824
2825 dtb = state.GetFdtForEtype('fdtmap')
2826 self.assertEqual(dtb.GetContents(), fdtmap)
2827
2828 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2829 self.assertIsNone(missing_path)
2830 self.assertIsNone(missing_fdtmap)
2831
2832 missing_dtb = state.GetFdtForEtype('missing')
2833 self.assertIsNone(missing_dtb)
2834
2835 self.assertEqual('/binman', state.fdt_path_prefix)
2836
2837 def testReplaceResizeFail(self):
2838 """Test replacing a file by something larger"""
2839 expected = U_BOOT_DATA + b'x'
2840 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002841 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2842 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002843 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2844 str(e.exception))
2845
2846 def testReplaceMulti(self):
2847 """Test replacing entry data where multiple images are generated"""
2848 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2849 update_dtb=True)[0]
2850 expected = b'x' * len(U_BOOT_DATA)
2851 updated_fname = tools.GetOutputFilename('image-updated.bin')
2852 tools.WriteFile(updated_fname, data)
2853 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002854 control.WriteEntry(updated_fname, entry_name, expected,
2855 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002856 data = control.ReadEntry(updated_fname, entry_name)
2857 self.assertEqual(expected, data)
2858
2859 # Check the state looks right.
2860 self.assertEqual('/binman/image', state.fdt_path_prefix)
2861
2862 # Now check we can write the first image
2863 image_fname = tools.GetOutputFilename('first-image.bin')
2864 updated_fname = tools.GetOutputFilename('first-updated.bin')
2865 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2866 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002867 control.WriteEntry(updated_fname, entry_name, expected,
2868 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002869 data = control.ReadEntry(updated_fname, entry_name)
2870 self.assertEqual(expected, data)
2871
2872 # Check the state looks right.
2873 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002874
Simon Glass12bb1a92019-07-20 12:23:51 -06002875 def testUpdateFdtAllRepack(self):
2876 """Test that all device trees are updated with offset/size info"""
2877 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2878 SECTION_SIZE = 0x300
2879 DTB_SIZE = 602
2880 FDTMAP_SIZE = 608
2881 base_expected = {
2882 'offset': 0,
2883 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2884 'image-pos': 0,
2885 'section:offset': 0,
2886 'section:size': SECTION_SIZE,
2887 'section:image-pos': 0,
2888 'section/u-boot-dtb:offset': 4,
2889 'section/u-boot-dtb:size': 636,
2890 'section/u-boot-dtb:image-pos': 4,
2891 'u-boot-spl-dtb:offset': SECTION_SIZE,
2892 'u-boot-spl-dtb:size': DTB_SIZE,
2893 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2894 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2895 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2896 'u-boot-tpl-dtb:size': DTB_SIZE,
2897 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2898 'fdtmap:size': FDTMAP_SIZE,
2899 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2900 }
2901 main_expected = {
2902 'section:orig-size': SECTION_SIZE,
2903 'section/u-boot-dtb:orig-offset': 4,
2904 }
2905
2906 # We expect three device-tree files in the output, with the first one
2907 # within a fixed-size section.
2908 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2909 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2910 # main U-Boot tree. All three should have the same positions and offset
2911 # except that the main tree should include the main_expected properties
2912 start = 4
2913 for item in ['', 'spl', 'tpl', None]:
2914 if item is None:
2915 start += 16 # Move past fdtmap header
2916 dtb = fdt.Fdt.FromData(data[start:])
2917 dtb.Scan()
2918 props = self._GetPropTree(dtb,
2919 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2920 prefix='/' if item is None else '/binman/')
2921 expected = dict(base_expected)
2922 if item:
2923 expected[item] = 0
2924 else:
2925 # Main DTB and fdtdec should include the 'orig-' properties
2926 expected.update(main_expected)
2927 # Helpful for debugging:
2928 #for prop in sorted(props):
2929 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2930 self.assertEqual(expected, props)
2931 if item == '':
2932 start = SECTION_SIZE
2933 else:
2934 start += dtb._fdt_obj.totalsize()
2935
Simon Glasseba1f0c2019-07-20 12:23:55 -06002936 def testFdtmapHeaderMiddle(self):
2937 """Test an FDT map in the middle of an image when it should be at end"""
2938 with self.assertRaises(ValueError) as e:
2939 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2940 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2941 str(e.exception))
2942
2943 def testFdtmapHeaderStartBad(self):
2944 """Test an FDT map in middle of an image when it should be at start"""
2945 with self.assertRaises(ValueError) as e:
2946 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2947 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2948 str(e.exception))
2949
2950 def testFdtmapHeaderEndBad(self):
2951 """Test an FDT map at the start of an image when it should be at end"""
2952 with self.assertRaises(ValueError) as e:
2953 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2954 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2955 str(e.exception))
2956
2957 def testFdtmapHeaderNoSize(self):
2958 """Test an image header at the end of an image with undefined size"""
2959 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2960
Simon Glass51014aa2019-07-20 12:23:56 -06002961 def testReplaceResize(self):
2962 """Test replacing a single file in an entry with a larger file"""
2963 expected = U_BOOT_DATA + b'x'
2964 data, _, image = self._RunReplaceCmd('u-boot', expected,
2965 dts='139_replace_repack.dts')
2966 self.assertEqual(expected, data)
2967
2968 entries = image.GetEntries()
2969 dtb_data = entries['u-boot-dtb'].data
2970 dtb = fdt.Fdt.FromData(dtb_data)
2971 dtb.Scan()
2972
2973 # The u-boot section should now be larger in the dtb
2974 node = dtb.GetNode('/binman/u-boot')
2975 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
2976
2977 # Same for the fdtmap
2978 fdata = entries['fdtmap'].data
2979 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
2980 fdtb.Scan()
2981 fnode = fdtb.GetNode('/u-boot')
2982 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
2983
2984 def testReplaceResizeNoRepack(self):
2985 """Test replacing an entry with a larger file when not allowed"""
2986 expected = U_BOOT_DATA + b'x'
2987 with self.assertRaises(ValueError) as e:
2988 self._RunReplaceCmd('u-boot', expected)
2989 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
2990 str(e.exception))
2991
Simon Glass61ec04f2019-07-20 12:23:58 -06002992 def testEntryShrink(self):
2993 """Test contracting an entry after it is packed"""
2994 try:
2995 state.SetAllowEntryContraction(True)
2996 data = self._DoReadFileDtb('140_entry_shrink.dts',
2997 update_dtb=True)[0]
2998 finally:
2999 state.SetAllowEntryContraction(False)
3000 self.assertEqual(b'a', data[:1])
3001 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3002 self.assertEqual(b'a', data[-1:])
3003
3004 def testEntryShrinkFail(self):
3005 """Test not being allowed to contract an entry after it is packed"""
3006 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3007
3008 # In this case there is a spare byte at the end of the data. The size of
3009 # the contents is only 1 byte but we still have the size before it
3010 # shrunk.
3011 self.assertEqual(b'a\0', data[:2])
3012 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3013 self.assertEqual(b'a\0', data[-2:])
3014
Simon Glass27145fd2019-07-20 12:24:01 -06003015 def testDescriptorOffset(self):
3016 """Test that the Intel descriptor is always placed at at the start"""
3017 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3018 image = control.images['image']
3019 entries = image.GetEntries()
3020 desc = entries['intel-descriptor']
3021 self.assertEqual(0xff800000, desc.offset);
3022 self.assertEqual(0xff800000, desc.image_pos);
3023
Simon Glasseb0f4a42019-07-20 12:24:06 -06003024 def testReplaceCbfs(self):
3025 """Test replacing a single file in CBFS without changing the size"""
3026 self._CheckLz4()
3027 expected = b'x' * len(U_BOOT_DATA)
3028 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3029 updated_fname = tools.GetOutputFilename('image-updated.bin')
3030 tools.WriteFile(updated_fname, data)
3031 entry_name = 'section/cbfs/u-boot'
3032 control.WriteEntry(updated_fname, entry_name, expected,
3033 allow_resize=True)
3034 data = control.ReadEntry(updated_fname, entry_name)
3035 self.assertEqual(expected, data)
3036
3037 def testReplaceResizeCbfs(self):
3038 """Test replacing a single file in CBFS with one of a different size"""
3039 self._CheckLz4()
3040 expected = U_BOOT_DATA + b'x'
3041 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3042 updated_fname = tools.GetOutputFilename('image-updated.bin')
3043 tools.WriteFile(updated_fname, data)
3044 entry_name = 'section/cbfs/u-boot'
3045 control.WriteEntry(updated_fname, entry_name, expected,
3046 allow_resize=True)
3047 data = control.ReadEntry(updated_fname, entry_name)
3048 self.assertEqual(expected, data)
3049
Simon Glassa6cb9952019-07-20 12:24:15 -06003050 def _SetupForReplace(self):
3051 """Set up some files to use to replace entries
3052
3053 This generates an image, copies it to a new file, extracts all the files
3054 in it and updates some of them
3055
3056 Returns:
3057 List
3058 Image filename
3059 Output directory
3060 Expected values for updated entries, each a string
3061 """
3062 data = self._DoReadFileRealDtb('143_replace_all.dts')
3063
3064 updated_fname = tools.GetOutputFilename('image-updated.bin')
3065 tools.WriteFile(updated_fname, data)
3066
3067 outdir = os.path.join(self._indir, 'extract')
3068 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3069
3070 expected1 = b'x' + U_BOOT_DATA + b'y'
3071 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3072 tools.WriteFile(u_boot_fname1, expected1)
3073
3074 expected2 = b'a' + U_BOOT_DATA + b'b'
3075 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3076 tools.WriteFile(u_boot_fname2, expected2)
3077
3078 expected_text = b'not the same text'
3079 text_fname = os.path.join(outdir, 'text')
3080 tools.WriteFile(text_fname, expected_text)
3081
3082 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3083 dtb = fdt.FdtScan(dtb_fname)
3084 node = dtb.GetNode('/binman/text')
3085 node.AddString('my-property', 'the value')
3086 dtb.Sync(auto_resize=True)
3087 dtb.Flush()
3088
3089 return updated_fname, outdir, expected1, expected2, expected_text
3090
3091 def _CheckReplaceMultiple(self, entry_paths):
3092 """Handle replacing the contents of multiple entries
3093
3094 Args:
3095 entry_paths: List of entry paths to replace
3096
3097 Returns:
3098 List
3099 Dict of entries in the image:
3100 key: Entry name
3101 Value: Entry object
3102 Expected values for updated entries, each a string
3103 """
3104 updated_fname, outdir, expected1, expected2, expected_text = (
3105 self._SetupForReplace())
3106 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3107
3108 image = Image.FromFile(updated_fname)
3109 image.LoadData()
3110 return image.GetEntries(), expected1, expected2, expected_text
3111
3112 def testReplaceAll(self):
3113 """Test replacing the contents of all entries"""
3114 entries, expected1, expected2, expected_text = (
3115 self._CheckReplaceMultiple([]))
3116 data = entries['u-boot'].data
3117 self.assertEqual(expected1, data)
3118
3119 data = entries['u-boot2'].data
3120 self.assertEqual(expected2, data)
3121
3122 data = entries['text'].data
3123 self.assertEqual(expected_text, data)
3124
3125 # Check that the device tree is updated
3126 data = entries['u-boot-dtb'].data
3127 dtb = fdt.Fdt.FromData(data)
3128 dtb.Scan()
3129 node = dtb.GetNode('/binman/text')
3130 self.assertEqual('the value', node.props['my-property'].value)
3131
3132 def testReplaceSome(self):
3133 """Test replacing the contents of a few entries"""
3134 entries, expected1, expected2, expected_text = (
3135 self._CheckReplaceMultiple(['u-boot2', 'text']))
3136
3137 # This one should not change
3138 data = entries['u-boot'].data
3139 self.assertEqual(U_BOOT_DATA, data)
3140
3141 data = entries['u-boot2'].data
3142 self.assertEqual(expected2, data)
3143
3144 data = entries['text'].data
3145 self.assertEqual(expected_text, data)
3146
3147 def testReplaceCmd(self):
3148 """Test replacing a file fron an image on the command line"""
3149 self._DoReadFileRealDtb('143_replace_all.dts')
3150
3151 try:
3152 tmpdir, updated_fname = self._SetupImageInTmpdir()
3153
3154 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3155 expected = b'x' * len(U_BOOT_DATA)
3156 tools.WriteFile(fname, expected)
3157
3158 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3159 data = tools.ReadFile(updated_fname)
3160 self.assertEqual(expected, data[:len(expected)])
3161 map_fname = os.path.join(tmpdir, 'image-updated.map')
3162 self.assertFalse(os.path.exists(map_fname))
3163 finally:
3164 shutil.rmtree(tmpdir)
3165
3166 def testReplaceCmdSome(self):
3167 """Test replacing some files fron an image on the command line"""
3168 updated_fname, outdir, expected1, expected2, expected_text = (
3169 self._SetupForReplace())
3170
3171 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3172 'u-boot2', 'text')
3173
3174 tools.PrepareOutputDir(None)
3175 image = Image.FromFile(updated_fname)
3176 image.LoadData()
3177 entries = image.GetEntries()
3178
3179 # This one should not change
3180 data = entries['u-boot'].data
3181 self.assertEqual(U_BOOT_DATA, data)
3182
3183 data = entries['u-boot2'].data
3184 self.assertEqual(expected2, data)
3185
3186 data = entries['text'].data
3187 self.assertEqual(expected_text, data)
3188
3189 def testReplaceMissing(self):
3190 """Test replacing entries where the file is missing"""
3191 updated_fname, outdir, expected1, expected2, expected_text = (
3192 self._SetupForReplace())
3193
3194 # Remove one of the files, to generate a warning
3195 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3196 os.remove(u_boot_fname1)
3197
3198 with test_util.capture_sys_output() as (stdout, stderr):
3199 control.ReplaceEntries(updated_fname, None, outdir, [])
3200 self.assertIn("Skipping entry '/u-boot' from missing file",
3201 stdout.getvalue())
3202
3203 def testReplaceCmdMap(self):
3204 """Test replacing a file fron an image on the command line"""
3205 self._DoReadFileRealDtb('143_replace_all.dts')
3206
3207 try:
3208 tmpdir, updated_fname = self._SetupImageInTmpdir()
3209
3210 fname = os.path.join(self._indir, 'update-u-boot.bin')
3211 expected = b'x' * len(U_BOOT_DATA)
3212 tools.WriteFile(fname, expected)
3213
3214 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3215 '-f', fname, '-m')
3216 map_fname = os.path.join(tmpdir, 'image-updated.map')
3217 self.assertTrue(os.path.exists(map_fname))
3218 finally:
3219 shutil.rmtree(tmpdir)
3220
3221 def testReplaceNoEntryPaths(self):
3222 """Test replacing an entry without an entry path"""
3223 self._DoReadFileRealDtb('143_replace_all.dts')
3224 image_fname = tools.GetOutputFilename('image.bin')
3225 with self.assertRaises(ValueError) as e:
3226 control.ReplaceEntries(image_fname, 'fname', None, [])
3227 self.assertIn('Must specify an entry path to read with -f',
3228 str(e.exception))
3229
3230 def testReplaceTooManyEntryPaths(self):
3231 """Test extracting some entries"""
3232 self._DoReadFileRealDtb('143_replace_all.dts')
3233 image_fname = tools.GetOutputFilename('image.bin')
3234 with self.assertRaises(ValueError) as e:
3235 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3236 self.assertIn('Must specify exactly one entry path to write with -f',
3237 str(e.exception))
3238
Simon Glass12bb1a92019-07-20 12:23:51 -06003239
Simon Glass9fc60b42017-11-12 21:52:22 -07003240if __name__ == "__main__":
3241 unittest.main()