blob: 51eab6fbfada9ea2edf3d9880034cf71c11ef4a7 [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 Glass53e22bf2019-08-24 07:22:53 -060026import elf_test
Simon Glass99ed4a22017-05-27 07:38:30 -060027import fdt
Simon Glasse1925fa2019-07-08 14:25:44 -060028from etype import fdtmap
Simon Glass2d260032019-07-08 14:25:45 -060029from etype import image_header
Simon Glass4f443042016-11-25 20:15:52 -070030import fdt_util
Simon Glass11e36cc2018-07-17 13:25:38 -060031import fmap_util
Simon Glassfd8d1f72018-07-17 13:25:36 -060032import test_util
Simon Glassc5ac1382019-07-08 13:18:54 -060033import gzip
Simon Glassffded752019-07-08 14:25:46 -060034from image import Image
Simon Glassc55a50f2018-09-14 04:57:19 -060035import state
Simon Glass4f443042016-11-25 20:15:52 -070036import tools
37import tout
38
39# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060040U_BOOT_DATA = b'1234'
41U_BOOT_IMG_DATA = b'img'
42U_BOOT_SPL_DATA = b'56780123456789abcde'
43U_BOOT_TPL_DATA = b'tpl'
44BLOB_DATA = b'89'
45ME_DATA = b'0abcd'
46VGA_DATA = b'vga'
47U_BOOT_DTB_DATA = b'udtb'
48U_BOOT_SPL_DTB_DATA = b'spldtb'
49U_BOOT_TPL_DTB_DATA = b'tpldtb'
50X86_START16_DATA = b'start16'
51X86_START16_SPL_DATA = b'start16spl'
52X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060053X86_RESET16_DATA = b'reset16'
54X86_RESET16_SPL_DATA = b'reset16spl'
55X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060056PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
57U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
58U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
59U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
60FSP_DATA = b'fsp'
61CMC_DATA = b'cmc'
62VBT_DATA = b'vbt'
63MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060064TEXT_DATA = 'text'
65TEXT_DATA2 = 'text2'
66TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060067CROS_EC_RW_DATA = b'ecrw'
68GBB_DATA = b'gbbd'
69BMPBLK_DATA = b'bmp'
70VBLOCK_DATA = b'vblk'
71FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
72 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060073COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassc6c10e72019-05-17 22:00:46 -060074REFCODE_DATA = b'refcode'
Simon Glassec127af2018-07-17 13:25:39 -060075
Simon Glass6ccbfcd2019-07-20 12:23:47 -060076# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -060077EXTRACT_DTB_SIZE = 0x3c9
78
Simon Glass6ccbfcd2019-07-20 12:23:47 -060079# Properties expected to be in the device tree when update_dtb is used
80BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
81
Simon Glass12bb1a92019-07-20 12:23:51 -060082# Extra properties expected to be in the device tree when allow-repack is used
83REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
84
Simon Glass4f443042016-11-25 20:15:52 -070085
86class TestFunctional(unittest.TestCase):
87 """Functional tests for binman
88
89 Most of these use a sample .dts file to build an image and then check
90 that it looks correct. The sample files are in the test/ subdirectory
91 and are numbered.
92
93 For each entry type a very small test file is created using fixed
94 string contents. This makes it easy to test that things look right, and
95 debug problems.
96
97 In some cases a 'real' file must be used - these are also supplied in
98 the test/ diurectory.
99 """
100 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600101 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700102 global entry
103 import entry
104
Simon Glass4f443042016-11-25 20:15:52 -0700105 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600106 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
107 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700108
109 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600110 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700111
112 # Create some test files
113 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
114 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
115 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600116 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700117 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700118 TestFunctional._MakeInputFile('me.bin', ME_DATA)
119 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600120 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600121
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530122 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600123
Simon Glass5e239182019-08-24 07:22:49 -0600124 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
125 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700126 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600127 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600128 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600129
130 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
131 X86_RESET16_DATA)
132 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
133 X86_RESET16_SPL_DATA)
134 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
135 X86_RESET16_TPL_DATA)
136
Simon Glass4f443042016-11-25 20:15:52 -0700137 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700138 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
139 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600140 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
141 U_BOOT_TPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700142 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
143 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700144 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700145 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600146 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600147 TestFunctional._MakeInputDir('devkeys')
148 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600149 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700150
Simon Glass53e22bf2019-08-24 07:22:53 -0600151 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
152 elf_test.BuildElfTestFiles(cls._elf_testdir)
153
Simon Glasse0ff8552016-11-25 20:15:53 -0700154 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600155 TestFunctional._MakeInputFile('u-boot',
156 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700157
158 # Intel flash descriptor file
Simon Glassb986b3b2019-08-24 07:22:43 -0600159 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
Simon Glasse0ff8552016-11-25 20:15:53 -0700160 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
161
Simon Glassb986b3b2019-08-24 07:22:43 -0600162 shutil.copytree(cls.TestFile('files'),
163 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600164
Simon Glass83d73c22018-09-14 04:57:26 -0600165 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
166
Simon Glassac62fba2019-07-08 13:18:53 -0600167 # Travis-CI may have an old lz4
Simon Glassb986b3b2019-08-24 07:22:43 -0600168 cls.have_lz4 = True
Simon Glassac62fba2019-07-08 13:18:53 -0600169 try:
170 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glassb986b3b2019-08-24 07:22:43 -0600171 os.path.join(cls._indir, 'u-boot.bin'))
Simon Glassac62fba2019-07-08 13:18:53 -0600172 except:
Simon Glassb986b3b2019-08-24 07:22:43 -0600173 cls.have_lz4 = False
Simon Glassac62fba2019-07-08 13:18:53 -0600174
Simon Glass4f443042016-11-25 20:15:52 -0700175 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600176 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700177 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600178 if cls.preserve_indir:
179 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600180 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600181 if cls._indir:
182 shutil.rmtree(cls._indir)
183 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700184
Simon Glassd5164a72019-07-08 13:18:49 -0600185 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600186 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600187 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600188 """Accept arguments controlling test execution
189
190 Args:
191 preserve_indir: Preserve the shared input directory used by all
192 tests in this class.
193 preserve_outdir: Preserve the output directories used by tests. Each
194 test has its own, so this is normally only useful when running a
195 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600196 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600197 """
198 cls.preserve_indir = preserve_indir
199 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600200 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600201 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600202
Simon Glassac62fba2019-07-08 13:18:53 -0600203 def _CheckLz4(self):
204 if not self.have_lz4:
205 self.skipTest('lz4 --no-frame-crc not available')
206
Simon Glassbf574f12019-07-20 12:24:09 -0600207 def _CleanupOutputDir(self):
208 """Remove the temporary output directory"""
209 if self.preserve_outdirs:
210 print('Preserving output dir: %s' % tools.outdir)
211 else:
212 tools._FinaliseForTest()
213
Simon Glass4f443042016-11-25 20:15:52 -0700214 def setUp(self):
215 # Enable this to turn on debugging output
216 # tout.Init(tout.DEBUG)
217 command.test_result = None
218
219 def tearDown(self):
220 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600221 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700222
Simon Glassf86a7362019-07-20 12:24:10 -0600223 def _SetupImageInTmpdir(self):
224 """Set up the output image in a new temporary directory
225
226 This is used when an image has been generated in the output directory,
227 but we want to run binman again. This will create a new output
228 directory and fail to delete the original one.
229
230 This creates a new temporary directory, copies the image to it (with a
231 new name) and removes the old output directory.
232
233 Returns:
234 Tuple:
235 Temporary directory to use
236 New image filename
237 """
238 image_fname = tools.GetOutputFilename('image.bin')
239 tmpdir = tempfile.mkdtemp(prefix='binman.')
240 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
241 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
242 self._CleanupOutputDir()
243 return tmpdir, updated_fname
244
Simon Glassb8ef5b62018-07-17 13:25:48 -0600245 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600246 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600247 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
248 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
249 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
250
Simon Glass4f443042016-11-25 20:15:52 -0700251 def _RunBinman(self, *args, **kwargs):
252 """Run binman using the command line
253
254 Args:
255 Arguments to pass, as a list of strings
256 kwargs: Arguments to pass to Command.RunPipe()
257 """
258 result = command.RunPipe([[self._binman_pathname] + list(args)],
259 capture=True, capture_stderr=True, raise_on_error=False)
260 if result.return_code and kwargs.get('raise_on_error', True):
261 raise Exception("Error running '%s': %s" % (' '.join(args),
262 result.stdout + result.stderr))
263 return result
264
Simon Glass53cd5d92019-07-08 14:25:29 -0600265 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700266 """Run binman using directly (in the same process)
267
268 Args:
269 Arguments to pass, as a list of strings
270 Returns:
271 Return value (0 for success)
272 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600273 argv = list(argv)
274 args = cmdline.ParseArgs(argv)
275 args.pager = 'binman-invalid-pager'
276 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700277
278 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600279 # args.verbosity = tout.DEBUG
280 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700281
Simon Glass53af22a2018-07-17 13:25:32 -0600282 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600283 entry_args=None, images=None, use_real_dtb=False,
284 verbosity=None):
Simon Glass4f443042016-11-25 20:15:52 -0700285 """Run binman with a given test file
286
287 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600288 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600289 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600290 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600291 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600292 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600293 entry_args: Dict of entry args to supply to binman
294 key: arg name
295 value: value of that arg
296 images: List of image names to build
Simon Glass4f443042016-11-25 20:15:52 -0700297 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600298 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700299 if debug:
300 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600301 if verbosity is not None:
302 args.append('-v%d' % verbosity)
303 elif self.verbosity:
304 args.append('-v%d' % self.verbosity)
305 if self.toolpath:
306 for path in self.toolpath:
307 args += ['--toolpath', path]
308 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600309 if map:
310 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600311 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600312 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600313 if not use_real_dtb:
314 args.append('--fake-dtb')
Simon Glass53af22a2018-07-17 13:25:32 -0600315 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600316 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600317 args.append('-a%s=%s' % (arg, value))
Simon Glass0bfa7b02018-09-14 04:57:12 -0600318 if images:
319 for image in images:
320 args += ['-i', image]
Simon Glass7fe91732017-11-13 18:55:00 -0700321 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700322
323 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700324 """Set up a new test device-tree file
325
326 The given file is compiled and set up as the device tree to be used
327 for ths test.
328
329 Args:
330 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600331 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700332
333 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600334 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700335 """
Simon Glassa004f292019-07-20 12:23:49 -0600336 tmpdir = tempfile.mkdtemp(prefix='binmant.')
337 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600338 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700339 data = fd.read()
340 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600341 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600342 return data
Simon Glass4f443042016-11-25 20:15:52 -0700343
Simon Glass6ed45ba2018-09-14 04:57:24 -0600344 def _GetDtbContentsForSplTpl(self, dtb_data, name):
345 """Create a version of the main DTB for SPL or SPL
346
347 For testing we don't actually have different versions of the DTB. With
348 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
349 we don't normally have any unwanted nodes.
350
351 We still want the DTBs for SPL and TPL to be different though, since
352 otherwise it is confusing to know which one we are looking at. So add
353 an 'spl' or 'tpl' property to the top-level node.
354 """
355 dtb = fdt.Fdt.FromData(dtb_data)
356 dtb.Scan()
357 dtb.GetNode('/binman').AddZeroProp(name)
358 dtb.Sync(auto_resize=True)
359 dtb.Pack()
360 return dtb.GetContents()
361
Simon Glass16b8d6b2018-07-06 10:27:42 -0600362 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600363 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass4f443042016-11-25 20:15:52 -0700364 """Run binman and return the resulting image
365
366 This runs binman with a given test file and then reads the resulting
367 output file. It is a shortcut function since most tests need to do
368 these steps.
369
370 Raises an assertion failure if binman returns a non-zero exit code.
371
372 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600373 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700374 use_real_dtb: True to use the test file as the contents of
375 the u-boot-dtb entry. Normally this is not needed and the
376 test contents (the U_BOOT_DTB_DATA string) can be used.
377 But in some test we need the real contents.
Simon Glass3b0c3822018-06-01 09:38:20 -0600378 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600379 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600380 tree before packing it into the image
Simon Glasse0ff8552016-11-25 20:15:53 -0700381
382 Returns:
383 Tuple:
384 Resulting image contents
385 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600386 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600387 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700388 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700389 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700390 # Use the compiled test file as the u-boot-dtb input
391 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700392 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600393
394 # For testing purposes, make a copy of the DT for SPL and TPL. Add
395 # a node indicating which it is, so aid verification.
396 for name in ['spl', 'tpl']:
397 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
398 outfile = os.path.join(self._indir, dtb_fname)
399 TestFunctional._MakeInputFile(dtb_fname,
400 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700401
402 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600403 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6ed45ba2018-09-14 04:57:24 -0600404 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass4f443042016-11-25 20:15:52 -0700405 self.assertEqual(0, retcode)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600406 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700407
408 # Find the (only) image, read it and return its contents
409 image = control.images['image']
Simon Glass16b8d6b2018-07-06 10:27:42 -0600410 image_fname = tools.GetOutputFilename('image.bin')
411 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600412 if map:
413 map_fname = tools.GetOutputFilename('image.map')
414 with open(map_fname) as fd:
415 map_data = fd.read()
416 else:
417 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600418 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600419 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700420 finally:
421 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600422 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600423 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700424
Simon Glass3c081312019-07-08 14:25:26 -0600425 def _DoReadFileRealDtb(self, fname):
426 """Run binman with a real .dtb file and return the resulting data
427
428 Args:
429 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
430
431 Returns:
432 Resulting image contents
433 """
434 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
435
Simon Glasse0ff8552016-11-25 20:15:53 -0700436 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600437 """Helper function which discards the device-tree binary
438
439 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600440 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600441 use_real_dtb: True to use the test file as the contents of
442 the u-boot-dtb entry. Normally this is not needed and the
443 test contents (the U_BOOT_DTB_DATA string) can be used.
444 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600445
446 Returns:
447 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600448 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700449 return self._DoReadFileDtb(fname, use_real_dtb)[0]
450
Simon Glass4f443042016-11-25 20:15:52 -0700451 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600452 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700453 """Create a new test input file, creating directories as needed
454
455 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600456 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700457 contents: File contents to write in to the file
458 Returns:
459 Full pathname of file created
460 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600461 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700462 dirname = os.path.dirname(pathname)
463 if dirname and not os.path.exists(dirname):
464 os.makedirs(dirname)
465 with open(pathname, 'wb') as fd:
466 fd.write(contents)
467 return pathname
468
469 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600470 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600471 """Create a new test input directory, creating directories as needed
472
473 Args:
474 dirname: Directory name to create
475
476 Returns:
477 Full pathname of directory created
478 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600479 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600480 if not os.path.exists(pathname):
481 os.makedirs(pathname)
482 return pathname
483
484 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600485 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600486 """Set up an ELF file with a '_dt_ucode_base_size' symbol
487
488 Args:
489 Filename of ELF file to use as SPL
490 """
Simon Glass53e22bf2019-08-24 07:22:53 -0600491 # TODO(sjg@chromium.org): Drop this when all Elf files use ElfTestFile()
Simon Glass1542c8b2019-08-24 07:22:56 -0600492 if src_fname in ['bss_data', 'u_boot_ucode_ptr', 'u_boot_no_ucode_ptr',
Simon Glasse9d2ee32019-08-24 07:22:57 -0600493 'u_boot_binman_syms', 'u_boot_binman_syms_size']:
Simon Glass53e22bf2019-08-24 07:22:53 -0600494 fname = cls.ElfTestFile(src_fname)
495 else:
496 fname = cls.TestFile(src_fname)
497 TestFunctional._MakeInputFile('spl/u-boot-spl', tools.ReadFile(fname))
Simon Glass11ae93e2018-10-01 21:12:47 -0600498
499 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600500 def TestFile(cls, fname):
501 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700502
Simon Glass53e22bf2019-08-24 07:22:53 -0600503 @classmethod
504 def ElfTestFile(cls, fname):
505 return os.path.join(cls._elf_testdir, fname)
506
Simon Glass4f443042016-11-25 20:15:52 -0700507 def AssertInList(self, grep_list, target):
508 """Assert that at least one of a list of things is in a target
509
510 Args:
511 grep_list: List of strings to check
512 target: Target string
513 """
514 for grep in grep_list:
515 if grep in target:
516 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600517 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700518
519 def CheckNoGaps(self, entries):
520 """Check that all entries fit together without gaps
521
522 Args:
523 entries: List of entries to check
524 """
Simon Glass3ab95982018-08-01 15:22:37 -0600525 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700526 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600527 self.assertEqual(offset, entry.offset)
528 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700529
Simon Glasse0ff8552016-11-25 20:15:53 -0700530 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600531 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700532
533 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600534 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700535
536 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600537 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700538 """
539 return struct.unpack('>L', dtb[4:8])[0]
540
Simon Glass086cec92019-07-08 14:25:27 -0600541 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600542 def AddNode(node, path):
543 if node.name != '/':
544 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600545 for prop in node.props.values():
546 if prop.name in prop_names:
547 prop_path = path + ':' + prop.name
548 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
549 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600550 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600551 AddNode(subnode, path)
552
553 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600554 AddNode(dtb.GetRoot(), '')
555 return tree
556
Simon Glass4f443042016-11-25 20:15:52 -0700557 def testRun(self):
558 """Test a basic run with valid args"""
559 result = self._RunBinman('-h')
560
561 def testFullHelp(self):
562 """Test that the full help is displayed with -H"""
563 result = self._RunBinman('-H')
564 help_file = os.path.join(self._binman_dir, 'README')
Tom Rini3759df02018-01-16 15:29:50 -0500565 # Remove possible extraneous strings
566 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
567 gothelp = result.stdout.replace(extra, '')
568 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700569 self.assertEqual(0, len(result.stderr))
570 self.assertEqual(0, result.return_code)
571
572 def testFullHelpInternal(self):
573 """Test that the full help is displayed with -H"""
574 try:
575 command.test_result = command.CommandResult()
576 result = self._DoBinman('-H')
577 help_file = os.path.join(self._binman_dir, 'README')
578 finally:
579 command.test_result = None
580
581 def testHelp(self):
582 """Test that the basic help is displayed with -h"""
583 result = self._RunBinman('-h')
584 self.assertTrue(len(result.stdout) > 200)
585 self.assertEqual(0, len(result.stderr))
586 self.assertEqual(0, result.return_code)
587
Simon Glass4f443042016-11-25 20:15:52 -0700588 def testBoard(self):
589 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600590 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700591 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass53cd5d92019-07-08 14:25:29 -0600592 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700593 self.assertEqual(0, result)
594
595 def testNeedBoard(self):
596 """Test that we get an error when no board ius supplied"""
597 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600598 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700599 self.assertIn("Must provide a board to process (use -b <board>)",
600 str(e.exception))
601
602 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600603 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700604 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600605 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700606 # We get one error from libfdt, and a different one from fdtget.
607 self.AssertInList(["Couldn't open blob from 'missing_file'",
608 'No such file or directory'], str(e.exception))
609
610 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600611 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700612
613 Since this is a source file it should be compiled and the error
614 will come from the device-tree compiler (dtc).
615 """
616 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600617 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700618 self.assertIn("FATAL ERROR: Unable to parse input tree",
619 str(e.exception))
620
621 def testMissingNode(self):
622 """Test that a device tree without a 'binman' node generates an error"""
623 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600624 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700625 self.assertIn("does not have a 'binman' node", str(e.exception))
626
627 def testEmpty(self):
628 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600629 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700630 self.assertEqual(0, len(result.stderr))
631 self.assertEqual(0, result.return_code)
632
633 def testInvalidEntry(self):
634 """Test that an invalid entry is flagged"""
635 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600636 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600637 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700638 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
639 "'/binman/not-a-valid-type'", str(e.exception))
640
641 def testSimple(self):
642 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600643 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700644 self.assertEqual(U_BOOT_DATA, data)
645
Simon Glass7fe91732017-11-13 18:55:00 -0700646 def testSimpleDebug(self):
647 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600648 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700649
Simon Glass4f443042016-11-25 20:15:52 -0700650 def testDual(self):
651 """Test that we can handle creating two images
652
653 This also tests image padding.
654 """
Simon Glass741f2d62018-10-01 12:22:30 -0600655 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700656 self.assertEqual(0, retcode)
657
658 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600659 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700660 fname = tools.GetOutputFilename('image1.bin')
661 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600662 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700663 data = fd.read()
664 self.assertEqual(U_BOOT_DATA, data)
665
666 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600667 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700668 fname = tools.GetOutputFilename('image2.bin')
669 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600670 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700671 data = fd.read()
672 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glasse6d85ff2019-05-14 15:53:47 -0600673 self.assertEqual(tools.GetBytes(0, 3), data[:3])
674 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700675
676 def testBadAlign(self):
677 """Test that an invalid alignment value is detected"""
678 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600679 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700680 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
681 "of two", str(e.exception))
682
683 def testPackSimple(self):
684 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600685 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700686 self.assertEqual(0, retcode)
687 self.assertIn('image', control.images)
688 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600689 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700690 self.assertEqual(5, len(entries))
691
692 # First u-boot
693 self.assertIn('u-boot', entries)
694 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600695 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700696 self.assertEqual(len(U_BOOT_DATA), entry.size)
697
698 # Second u-boot, aligned to 16-byte boundary
699 self.assertIn('u-boot-align', entries)
700 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600701 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700702 self.assertEqual(len(U_BOOT_DATA), entry.size)
703
704 # Third u-boot, size 23 bytes
705 self.assertIn('u-boot-size', entries)
706 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600707 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700708 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
709 self.assertEqual(23, entry.size)
710
711 # Fourth u-boot, placed immediate after the above
712 self.assertIn('u-boot-next', entries)
713 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600714 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700715 self.assertEqual(len(U_BOOT_DATA), entry.size)
716
Simon Glass3ab95982018-08-01 15:22:37 -0600717 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700718 self.assertIn('u-boot-fixed', entries)
719 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600720 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700721 self.assertEqual(len(U_BOOT_DATA), entry.size)
722
Simon Glass8beb11e2019-07-08 14:25:47 -0600723 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700724
725 def testPackExtra(self):
726 """Test that extra packing feature works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600727 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700728
729 self.assertEqual(0, retcode)
730 self.assertIn('image', control.images)
731 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600732 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700733 self.assertEqual(5, len(entries))
734
735 # First u-boot with padding before and after
736 self.assertIn('u-boot', entries)
737 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600738 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700739 self.assertEqual(3, entry.pad_before)
740 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
741
742 # Second u-boot has an aligned size, but it has no effect
743 self.assertIn('u-boot-align-size-nop', entries)
744 entry = entries['u-boot-align-size-nop']
Simon Glass3ab95982018-08-01 15:22:37 -0600745 self.assertEqual(12, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700746 self.assertEqual(4, entry.size)
747
748 # Third u-boot has an aligned size too
749 self.assertIn('u-boot-align-size', entries)
750 entry = entries['u-boot-align-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600751 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700752 self.assertEqual(32, entry.size)
753
754 # Fourth u-boot has an aligned end
755 self.assertIn('u-boot-align-end', entries)
756 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600757 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700758 self.assertEqual(16, entry.size)
759
760 # Fifth u-boot immediately afterwards
761 self.assertIn('u-boot-align-both', entries)
762 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600763 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700764 self.assertEqual(64, entry.size)
765
766 self.CheckNoGaps(entries)
Simon Glass8beb11e2019-07-08 14:25:47 -0600767 self.assertEqual(128, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700768
769 def testPackAlignPowerOf2(self):
770 """Test that invalid entry alignment is detected"""
771 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600772 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700773 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
774 "of two", str(e.exception))
775
776 def testPackAlignSizePowerOf2(self):
777 """Test that invalid entry size alignment is detected"""
778 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600779 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700780 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
781 "power of two", str(e.exception))
782
783 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600784 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -0700785 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600786 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600787 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700788 "align 0x4 (4)", str(e.exception))
789
790 def testPackInvalidSizeAlign(self):
791 """Test that invalid entry size alignment is detected"""
792 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600793 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700794 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
795 "align-size 0x4 (4)", str(e.exception))
796
797 def testPackOverlap(self):
798 """Test that overlapping regions are detected"""
799 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600800 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600801 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700802 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
803 str(e.exception))
804
805 def testPackEntryOverflow(self):
806 """Test that entries that overflow their size are detected"""
807 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600808 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700809 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
810 "but entry size is 0x3 (3)", str(e.exception))
811
812 def testPackImageOverflow(self):
813 """Test that entries which overflow the image size are detected"""
814 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600815 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600816 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -0700817 "size 0x3 (3)", str(e.exception))
818
819 def testPackImageSize(self):
820 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -0600821 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700822 self.assertEqual(0, retcode)
823 self.assertIn('image', control.images)
824 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600825 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700826
827 def testPackImageSizeAlign(self):
828 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600829 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700830 self.assertEqual(0, retcode)
831 self.assertIn('image', control.images)
832 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -0600833 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700834
835 def testPackInvalidImageAlign(self):
836 """Test that invalid image alignment is detected"""
837 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600838 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -0600839 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -0700840 "align-size 0x8 (8)", str(e.exception))
841
842 def testPackAlignPowerOf2(self):
843 """Test that invalid image alignment is detected"""
844 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600845 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600846 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -0700847 "two", str(e.exception))
848
849 def testImagePadByte(self):
850 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600851 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600852 data = self._DoReadFile('021_image_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600853 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
854 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700855
856 def testImageName(self):
857 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -0600858 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700859 self.assertEqual(0, retcode)
860 image = control.images['image1']
861 fname = tools.GetOutputFilename('test-name')
862 self.assertTrue(os.path.exists(fname))
863
864 image = control.images['image2']
865 fname = tools.GetOutputFilename('test-name.xx')
866 self.assertTrue(os.path.exists(fname))
867
868 def testBlobFilename(self):
869 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -0600870 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700871 self.assertEqual(BLOB_DATA, data)
872
873 def testPackSorted(self):
874 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600875 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600876 data = self._DoReadFile('024_sorted.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600877 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
878 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -0700879
Simon Glass3ab95982018-08-01 15:22:37 -0600880 def testPackZeroOffset(self):
881 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass4f443042016-11-25 20:15:52 -0700882 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600883 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600884 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -0700885 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
886 str(e.exception))
887
888 def testPackUbootDtb(self):
889 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -0600890 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700891 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700892
893 def testPackX86RomNoSize(self):
894 """Test that the end-at-4gb property requires a size property"""
895 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600896 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600897 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -0700898 "using end-at-4gb", str(e.exception))
899
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530900 def test4gbAndSkipAtStartTogether(self):
901 """Test that the end-at-4gb and skip-at-size property can't be used
902 together"""
903 with self.assertRaises(ValueError) as e:
904 self._DoTestFile('80_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -0600905 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +0530906 "'skip-at-start'", str(e.exception))
907
Simon Glasse0ff8552016-11-25 20:15:53 -0700908 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -0600909 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glasse0ff8552016-11-25 20:15:53 -0700910 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600911 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600912 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glass8f1da502018-06-01 09:38:12 -0600913 "the section starting at 0xffffffe0 (4294967264)",
Simon Glasse0ff8552016-11-25 20:15:53 -0700914 str(e.exception))
915
916 def testPackX86Rom(self):
917 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -0600918 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -0600919 data = self._DoReadFile('029_x86-rom.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -0600920 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 7) + U_BOOT_SPL_DATA +
921 tools.GetBytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -0700922
923 def testPackX86RomMeNoDesc(self):
924 """Test that an invalid Intel descriptor entry is detected"""
Simon Glassc6c10e72019-05-17 22:00:46 -0600925 TestFunctional._MakeInputFile('descriptor.bin', b'')
Simon Glasse0ff8552016-11-25 20:15:53 -0700926 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600927 self._DoTestFile('031_x86-rom-me.dts')
Simon Glass458be452019-07-08 13:18:32 -0600928 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
929 str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700930
931 def testPackX86RomBadDesc(self):
932 """Test that the Intel requires a descriptor entry"""
933 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600934 self._DoTestFile('030_x86-rom-me-no-desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -0600935 self.assertIn("Node '/binman/intel-me': No offset set with "
936 "offset-unset: should another entry provide this correct "
937 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -0700938
939 def testPackX86RomMe(self):
940 """Test that an x86 ROM with an ME region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600941 data = self._DoReadFile('031_x86-rom-me.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -0600942 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
943 if data[:0x1000] != expected_desc:
944 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -0700945 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
946
947 def testPackVga(self):
948 """Test that an image with a VGA binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600949 data = self._DoReadFile('032_intel-vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700950 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
951
952 def testPackStart16(self):
953 """Test that an image with an x86 start16 region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -0600954 data = self._DoReadFile('033_x86-start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -0700955 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
956
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530957 def testPackPowerpcMpc85xxBootpgResetvec(self):
958 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
959 created"""
960 data = self._DoReadFile('81_powerpc_mpc85xx_bootpg_resetvec.dts')
961 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
962
Simon Glass736bb0a2018-07-06 10:27:17 -0600963 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -0600964 """Handle running a test for insertion of microcode
965
966 Args:
967 dts_fname: Name of test .dts file
968 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -0600969 ucode_second: True if the microsecond entry is second instead of
970 third
Simon Glassadc57012018-07-06 10:27:16 -0600971
972 Returns:
973 Tuple:
974 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -0600975 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -0600976 in the above (two 4-byte words)
977 """
Simon Glass6b187df2017-11-12 21:52:27 -0700978 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -0700979
980 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -0600981 if ucode_second:
982 ucode_content = data[len(nodtb_data):]
983 ucode_pos = len(nodtb_data)
984 dtb_with_ucode = ucode_content[16:]
985 fdt_len = self.GetFdtLen(dtb_with_ucode)
986 else:
987 dtb_with_ucode = data[len(nodtb_data):]
988 fdt_len = self.GetFdtLen(dtb_with_ucode)
989 ucode_content = dtb_with_ucode[fdt_len:]
990 ucode_pos = len(nodtb_data) + fdt_len
Simon Glasse0ff8552016-11-25 20:15:53 -0700991 fname = tools.GetOutputFilename('test.dtb')
992 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -0600993 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -0600994 dtb = fdt.FdtScan(fname)
995 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -0700996 self.assertTrue(ucode)
997 for node in ucode.subnodes:
998 self.assertFalse(node.props.get('data'))
999
Simon Glasse0ff8552016-11-25 20:15:53 -07001000 # Check that the microcode appears immediately after the Fdt
1001 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001002 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001003 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1004 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001005 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001006
1007 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001008 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001009 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1010 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001011 u_boot = data[:len(nodtb_data)]
1012 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001013
1014 def testPackUbootMicrocode(self):
1015 """Test that x86 microcode can be handled correctly
1016
1017 We expect to see the following in the image, in order:
1018 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1019 place
1020 u-boot.dtb with the microcode removed
1021 the microcode
1022 """
Simon Glass741f2d62018-10-01 12:22:30 -06001023 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001024 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001025 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1026 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001027
Simon Glass160a7662017-05-27 07:38:26 -06001028 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001029 """Test that x86 microcode can be handled correctly
1030
1031 We expect to see the following in the image, in order:
1032 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1033 place
1034 u-boot.dtb with the microcode
1035 an empty microcode region
1036 """
1037 # We need the libfdt library to run this test since only that allows
1038 # finding the offset of a property. This is required by
1039 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001040 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001041
1042 second = data[len(U_BOOT_NODTB_DATA):]
1043
1044 fdt_len = self.GetFdtLen(second)
1045 third = second[fdt_len:]
1046 second = second[:fdt_len]
1047
Simon Glass160a7662017-05-27 07:38:26 -06001048 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1049 self.assertIn(ucode_data, second)
1050 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001051
Simon Glass160a7662017-05-27 07:38:26 -06001052 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001053 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001054 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1055 len(ucode_data))
1056 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001057 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1058 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001059
Simon Glass75db0862016-11-25 20:15:55 -07001060 def testPackUbootSingleMicrocode(self):
1061 """Test that x86 microcode can be handled correctly with fdt_normal.
1062 """
Simon Glass160a7662017-05-27 07:38:26 -06001063 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001064
Simon Glassc49deb82016-11-25 20:15:54 -07001065 def testUBootImg(self):
1066 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001067 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001068 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001069
1070 def testNoMicrocode(self):
1071 """Test that a missing microcode region is detected"""
1072 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001073 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001074 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1075 "node found in ", str(e.exception))
1076
1077 def testMicrocodeWithoutNode(self):
1078 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1079 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001080 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001081 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1082 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1083
1084 def testMicrocodeWithoutNode2(self):
1085 """Test that a missing u-boot-ucode node is detected"""
1086 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001087 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001088 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1089 "microcode region u-boot-ucode", str(e.exception))
1090
1091 def testMicrocodeWithoutPtrInElf(self):
1092 """Test that a U-Boot binary without the microcode symbol is detected"""
1093 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001094 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001095 TestFunctional._MakeInputFile('u-boot',
1096 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001097
1098 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001099 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001100 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1101 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1102
1103 finally:
1104 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001105 TestFunctional._MakeInputFile('u-boot',
1106 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001107
1108 def testMicrocodeNotInImage(self):
1109 """Test that microcode must be placed within the image"""
1110 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001111 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001112 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1113 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001114 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001115
1116 def testWithoutMicrocode(self):
1117 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001118 TestFunctional._MakeInputFile('u-boot',
1119 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001120 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001121
1122 # Now check the device tree has no microcode
1123 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1124 second = data[len(U_BOOT_NODTB_DATA):]
1125
1126 fdt_len = self.GetFdtLen(second)
1127 self.assertEqual(dtb, second[:fdt_len])
1128
1129 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1130 third = data[used_len:]
Simon Glasse6d85ff2019-05-14 15:53:47 -06001131 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001132
1133 def testUnknownPosSize(self):
1134 """Test that microcode must be placed within the image"""
1135 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001136 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001137 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001138 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001139
1140 def testPackFsp(self):
1141 """Test that an image with a FSP binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001142 data = self._DoReadFile('042_intel-fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001143 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1144
1145 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001146 """Test that an image with a CMC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001147 data = self._DoReadFile('043_intel-cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001148 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001149
1150 def testPackVbt(self):
1151 """Test that an image with a VBT binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001152 data = self._DoReadFile('046_intel-vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001153 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001154
Simon Glass56509842017-11-12 21:52:25 -07001155 def testSplBssPad(self):
1156 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001157 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001158 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001159 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001160 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1161 data)
Simon Glass56509842017-11-12 21:52:25 -07001162
Simon Glass86af5112018-10-01 21:12:42 -06001163 def testSplBssPadMissing(self):
1164 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001165 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001166 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001167 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001168 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1169 str(e.exception))
1170
Simon Glass87722132017-11-12 21:52:26 -07001171 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001172 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001173 data = self._DoReadFile('048_x86-start16-spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001174 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1175
Simon Glass736bb0a2018-07-06 10:27:17 -06001176 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1177 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001178
1179 We expect to see the following in the image, in order:
1180 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1181 correct place
1182 u-boot.dtb with the microcode removed
1183 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001184
1185 Args:
1186 dts: Device tree file to use for test
1187 ucode_second: True if the microsecond entry is second instead of
1188 third
Simon Glass6b187df2017-11-12 21:52:27 -07001189 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001190 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001191 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1192 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001193 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1194 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001195
Simon Glass736bb0a2018-07-06 10:27:17 -06001196 def testPackUbootSplMicrocode(self):
1197 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass741f2d62018-10-01 12:22:30 -06001198 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001199
1200 def testPackUbootSplMicrocodeReorder(self):
1201 """Test that order doesn't matter for microcode entries
1202
1203 This is the same as testPackUbootSplMicrocode but when we process the
1204 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1205 entry, so we reply on binman to try later.
1206 """
Simon Glass741f2d62018-10-01 12:22:30 -06001207 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001208 ucode_second=True)
1209
Simon Glassca4f4ff2017-11-12 21:52:28 -07001210 def testPackMrc(self):
1211 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001212 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001213 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1214
Simon Glass47419ea2017-11-13 18:54:55 -07001215 def testSplDtb(self):
1216 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001217 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001218 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1219
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001220 def testSplNoDtb(self):
1221 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001222 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001223 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1224
Simon Glass19790632017-11-13 18:55:01 -07001225 def testSymbols(self):
1226 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass1542c8b2019-08-24 07:22:56 -06001227 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001228 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1229 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass3ab95982018-08-01 15:22:37 -06001230 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass19790632017-11-13 18:55:01 -07001231
Simon Glass11ae93e2018-10-01 21:12:47 -06001232 self._SetupSplElf('u_boot_binman_syms')
Simon Glass741f2d62018-10-01 12:22:30 -06001233 data = self._DoReadFile('053_symbols.dts')
Simon Glass1542c8b2019-08-24 07:22:56 -06001234 sym_values = struct.pack('<LQL', 0, 24, 20)
Simon Glasse6d85ff2019-05-14 15:53:47 -06001235 expected = (sym_values + U_BOOT_SPL_DATA[16:] +
1236 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
1237 U_BOOT_SPL_DATA[16:])
Simon Glass19790632017-11-13 18:55:01 -07001238 self.assertEqual(expected, data)
1239
Simon Glassdd57c132018-06-01 09:38:11 -06001240 def testPackUnitAddress(self):
1241 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001242 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001243 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1244
Simon Glass18546952018-06-01 09:38:16 -06001245 def testSections(self):
1246 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001247 data = self._DoReadFile('055_sections.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001248 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1249 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1250 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001251 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001252
Simon Glass3b0c3822018-06-01 09:38:20 -06001253 def testMap(self):
1254 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001255 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001256 self.assertEqual('''ImagePos Offset Size Name
125700000000 00000000 00000028 main-section
125800000000 00000000 00000010 section@0
125900000000 00000000 00000004 u-boot
126000000010 00000010 00000010 section@1
126100000010 00000000 00000004 u-boot
126200000020 00000020 00000004 section@2
126300000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001264''', map_data)
1265
Simon Glassc8d48ef2018-06-01 09:38:21 -06001266 def testNamePrefix(self):
1267 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001268 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001269 self.assertEqual('''ImagePos Offset Size Name
127000000000 00000000 00000028 main-section
127100000000 00000000 00000010 section@0
127200000000 00000000 00000004 ro-u-boot
127300000010 00000010 00000010 section@1
127400000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001275''', map_data)
1276
Simon Glass736bb0a2018-07-06 10:27:17 -06001277 def testUnknownContents(self):
1278 """Test that obtaining the contents works as expected"""
1279 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001280 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001281 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass736bb0a2018-07-06 10:27:17 -06001282 "processing of contents: remaining [<_testing.Entry__testing ",
1283 str(e.exception))
1284
Simon Glass5c890232018-07-06 10:27:19 -06001285 def testBadChangeSize(self):
1286 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001287 try:
1288 state.SetAllowEntryExpansion(False)
1289 with self.assertRaises(ValueError) as e:
1290 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001291 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001292 str(e.exception))
1293 finally:
1294 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001295
Simon Glass16b8d6b2018-07-06 10:27:42 -06001296 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001297 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001298 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001299 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001300 dtb = fdt.Fdt(out_dtb_fname)
1301 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001302 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001303 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001304 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001305 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001306 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001307 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001308 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001309 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001310 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001311 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001312 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001313 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001314 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001315
Simon Glass3ab95982018-08-01 15:22:37 -06001316 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001317 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001318 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001319 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001320 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001321 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001322 'size': 40
1323 }, props)
1324
1325 def testUpdateFdtBad(self):
1326 """Test that we detect when ProcessFdt never completes"""
1327 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001328 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001329 self.assertIn('Could not complete processing of Fdt: remaining '
1330 '[<_testing.Entry__testing', str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001331
Simon Glass53af22a2018-07-17 13:25:32 -06001332 def testEntryArgs(self):
1333 """Test passing arguments to entries from the command line"""
1334 entry_args = {
1335 'test-str-arg': 'test1',
1336 'test-int-arg': '456',
1337 }
Simon Glass741f2d62018-10-01 12:22:30 -06001338 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001339 self.assertIn('image', control.images)
1340 entry = control.images['image'].GetEntries()['_testing']
1341 self.assertEqual('test0', entry.test_str_fdt)
1342 self.assertEqual('test1', entry.test_str_arg)
1343 self.assertEqual(123, entry.test_int_fdt)
1344 self.assertEqual(456, entry.test_int_arg)
1345
1346 def testEntryArgsMissing(self):
1347 """Test missing arguments and properties"""
1348 entry_args = {
1349 'test-int-arg': '456',
1350 }
Simon Glass741f2d62018-10-01 12:22:30 -06001351 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001352 entry = control.images['image'].GetEntries()['_testing']
1353 self.assertEqual('test0', entry.test_str_fdt)
1354 self.assertEqual(None, entry.test_str_arg)
1355 self.assertEqual(None, entry.test_int_fdt)
1356 self.assertEqual(456, entry.test_int_arg)
1357
1358 def testEntryArgsRequired(self):
1359 """Test missing arguments and properties"""
1360 entry_args = {
1361 'test-int-arg': '456',
1362 }
1363 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001364 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass53af22a2018-07-17 13:25:32 -06001365 self.assertIn("Node '/binman/_testing': Missing required "
1366 'properties/entry args: test-str-arg, test-int-fdt, test-int-arg',
1367 str(e.exception))
1368
1369 def testEntryArgsInvalidFormat(self):
1370 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001371 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1372 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001373 with self.assertRaises(ValueError) as e:
1374 self._DoBinman(*args)
1375 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1376
1377 def testEntryArgsInvalidInteger(self):
1378 """Test that an invalid entry-argument integer is detected"""
1379 entry_args = {
1380 'test-int-arg': 'abc',
1381 }
1382 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001383 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001384 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1385 "'test-int-arg' (value 'abc') to integer",
1386 str(e.exception))
1387
1388 def testEntryArgsInvalidDatatype(self):
1389 """Test that an invalid entry-argument datatype is detected
1390
1391 This test could be written in entry_test.py except that it needs
1392 access to control.entry_args, which seems more than that module should
1393 be able to see.
1394 """
1395 entry_args = {
1396 'test-bad-datatype-arg': '12',
1397 }
1398 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001399 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001400 entry_args=entry_args)
1401 self.assertIn('GetArg() internal error: Unknown data type ',
1402 str(e.exception))
1403
Simon Glassbb748372018-07-17 13:25:33 -06001404 def testText(self):
1405 """Test for a text entry type"""
1406 entry_args = {
1407 'test-id': TEXT_DATA,
1408 'test-id2': TEXT_DATA2,
1409 'test-id3': TEXT_DATA3,
1410 }
Simon Glass741f2d62018-10-01 12:22:30 -06001411 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001412 entry_args=entry_args)
Simon Glassc6c10e72019-05-17 22:00:46 -06001413 expected = (tools.ToBytes(TEXT_DATA) +
1414 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1415 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001416 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001417 self.assertEqual(expected, data)
1418
Simon Glassfd8d1f72018-07-17 13:25:36 -06001419 def testEntryDocs(self):
1420 """Test for creation of entry documentation"""
1421 with test_util.capture_sys_output() as (stdout, stderr):
1422 control.WriteEntryDocs(binman.GetEntryModules())
1423 self.assertTrue(len(stdout.getvalue()) > 0)
1424
1425 def testEntryDocsMissing(self):
1426 """Test handling of missing entry documentation"""
1427 with self.assertRaises(ValueError) as e:
1428 with test_util.capture_sys_output() as (stdout, stderr):
1429 control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot')
1430 self.assertIn('Documentation is missing for modules: u_boot',
1431 str(e.exception))
1432
Simon Glass11e36cc2018-07-17 13:25:38 -06001433 def testFmap(self):
1434 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001435 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001436 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001437 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1438 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001439 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001440 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001441 self.assertEqual(1, fhdr.ver_major)
1442 self.assertEqual(0, fhdr.ver_minor)
1443 self.assertEqual(0, fhdr.base)
1444 self.assertEqual(16 + 16 +
1445 fmap_util.FMAP_HEADER_LEN +
1446 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001447 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001448 self.assertEqual(3, fhdr.nareas)
1449 for fentry in fentries:
1450 self.assertEqual(0, fentry.flags)
1451
1452 self.assertEqual(0, fentries[0].offset)
1453 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001454 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001455
1456 self.assertEqual(16, fentries[1].offset)
1457 self.assertEqual(4, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001458 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001459
1460 self.assertEqual(32, fentries[2].offset)
1461 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1462 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001463 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass11e36cc2018-07-17 13:25:38 -06001464
Simon Glassec127af2018-07-17 13:25:39 -06001465 def testBlobNamedByArg(self):
1466 """Test we can add a blob with the filename coming from an entry arg"""
1467 entry_args = {
1468 'cros-ec-rw-path': 'ecrw.bin',
1469 }
Simon Glass741f2d62018-10-01 12:22:30 -06001470 data, _, _, _ = self._DoReadFileDtb('068_blob_named_by_arg.dts',
Simon Glassec127af2018-07-17 13:25:39 -06001471 entry_args=entry_args)
1472
Simon Glass3af8e492018-07-17 13:25:40 -06001473 def testFill(self):
1474 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001475 data = self._DoReadFile('069_fill.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001476 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001477 self.assertEqual(expected, data)
1478
1479 def testFillNoSize(self):
1480 """Test for an fill entry type with no size"""
1481 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001482 self._DoReadFile('070_fill_no_size.dts')
Simon Glass3af8e492018-07-17 13:25:40 -06001483 self.assertIn("'fill' entry must have a size property",
1484 str(e.exception))
1485
Simon Glass0ef87aa2018-07-17 13:25:44 -06001486 def _HandleGbbCommand(self, pipe_list):
1487 """Fake calls to the futility utility"""
1488 if pipe_list[0][0] == 'futility':
1489 fname = pipe_list[0][-1]
1490 # Append our GBB data to the file, which will happen every time the
1491 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001492 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001493 fd.write(GBB_DATA)
1494 return command.CommandResult()
1495
1496 def testGbb(self):
1497 """Test for the Chromium OS Google Binary Block"""
1498 command.test_result = self._HandleGbbCommand
1499 entry_args = {
1500 'keydir': 'devkeys',
1501 'bmpblk': 'bmpblk.bin',
1502 }
Simon Glass741f2d62018-10-01 12:22:30 -06001503 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001504
1505 # Since futility
Simon Glasse6d85ff2019-05-14 15:53:47 -06001506 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1507 tools.GetBytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001508 self.assertEqual(expected, data)
1509
1510 def testGbbTooSmall(self):
1511 """Test for the Chromium OS Google Binary Block being large enough"""
1512 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001513 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001514 self.assertIn("Node '/binman/gbb': GBB is too small",
1515 str(e.exception))
1516
1517 def testGbbNoSize(self):
1518 """Test for the Chromium OS Google Binary Block having a size"""
1519 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001520 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001521 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1522 str(e.exception))
1523
Simon Glass24d0d3c2018-07-17 13:25:47 -06001524 def _HandleVblockCommand(self, pipe_list):
1525 """Fake calls to the futility utility"""
1526 if pipe_list[0][0] == 'futility':
1527 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001528 with open(fname, 'wb') as fd:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001529 fd.write(VBLOCK_DATA)
1530 return command.CommandResult()
1531
1532 def testVblock(self):
1533 """Test for the Chromium OS Verified Boot Block"""
1534 command.test_result = self._HandleVblockCommand
1535 entry_args = {
1536 'keydir': 'devkeys',
1537 }
Simon Glass741f2d62018-10-01 12:22:30 -06001538 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001539 entry_args=entry_args)
1540 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1541 self.assertEqual(expected, data)
1542
1543 def testVblockNoContent(self):
1544 """Test we detect a vblock which has no content to sign"""
1545 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001546 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001547 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1548 'property', str(e.exception))
1549
1550 def testVblockBadPhandle(self):
1551 """Test that we detect a vblock with an invalid phandle in contents"""
1552 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001553 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001554 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1555 '1000', str(e.exception))
1556
1557 def testVblockBadEntry(self):
1558 """Test that we detect an entry that points to a non-entry"""
1559 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001560 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001561 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1562 "'other'", str(e.exception))
1563
Simon Glassb8ef5b62018-07-17 13:25:48 -06001564 def testTpl(self):
1565 """Test that an image with TPL and ots device tree can be created"""
1566 # ELF file with a '__bss_size' symbol
Simon Glass53e22bf2019-08-24 07:22:53 -06001567 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb8ef5b62018-07-17 13:25:48 -06001568 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001569 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001570 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1571
Simon Glass15a587c2018-07-17 13:25:51 -06001572 def testUsesPos(self):
1573 """Test that the 'pos' property cannot be used anymore"""
1574 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001575 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001576 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1577 "'pos'", str(e.exception))
1578
Simon Glassd178eab2018-09-14 04:57:08 -06001579 def testFillZero(self):
1580 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001581 data = self._DoReadFile('080_fill_empty.dts')
Simon Glasse6d85ff2019-05-14 15:53:47 -06001582 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001583
Simon Glass0b489362018-09-14 04:57:09 -06001584 def testTextMissing(self):
1585 """Test for a text entry type where there is no text"""
1586 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001587 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001588 self.assertIn("Node '/binman/text': No value provided for text label "
1589 "'test-id'", str(e.exception))
1590
Simon Glass35b384c2018-09-14 04:57:10 -06001591 def testPackStart16Tpl(self):
1592 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001593 data = self._DoReadFile('081_x86-start16-tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001594 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1595
Simon Glass0bfa7b02018-09-14 04:57:12 -06001596 def testSelectImage(self):
1597 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001598 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001599
Simon Glasseb833d82019-04-25 21:58:34 -06001600 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001601 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001602 with test_util.capture_sys_output() as (stdout, stderr):
1603 retcode = self._DoTestFile('006_dual_image.dts',
1604 verbosity=verbosity,
1605 images=['image2'])
1606 self.assertEqual(0, retcode)
1607 if verbosity:
1608 self.assertIn(expected, stdout.getvalue())
1609 else:
1610 self.assertNotIn(expected, stdout.getvalue())
1611
1612 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1613 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001614 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001615
Simon Glass6ed45ba2018-09-14 04:57:24 -06001616 def testUpdateFdtAll(self):
1617 """Test that all device trees are updated with offset/size info"""
Simon Glass3c081312019-07-08 14:25:26 -06001618 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001619
1620 base_expected = {
1621 'section:image-pos': 0,
1622 'u-boot-tpl-dtb:size': 513,
1623 'u-boot-spl-dtb:size': 513,
1624 'u-boot-spl-dtb:offset': 493,
1625 'image-pos': 0,
1626 'section/u-boot-dtb:image-pos': 0,
1627 'u-boot-spl-dtb:image-pos': 493,
1628 'section/u-boot-dtb:size': 493,
1629 'u-boot-tpl-dtb:image-pos': 1006,
1630 'section/u-boot-dtb:offset': 0,
1631 'section:size': 493,
1632 'offset': 0,
1633 'section:offset': 0,
1634 'u-boot-tpl-dtb:offset': 1006,
1635 'size': 1519
1636 }
1637
1638 # We expect three device-tree files in the output, one after the other.
1639 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1640 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1641 # main U-Boot tree. All three should have the same postions and offset.
1642 start = 0
1643 for item in ['', 'spl', 'tpl']:
1644 dtb = fdt.Fdt.FromData(data[start:])
1645 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001646 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1647 ['spl', 'tpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06001648 expected = dict(base_expected)
1649 if item:
1650 expected[item] = 0
1651 self.assertEqual(expected, props)
1652 start += dtb._fdt_obj.totalsize()
1653
1654 def testUpdateFdtOutput(self):
1655 """Test that output DTB files are updated"""
1656 try:
Simon Glass741f2d62018-10-01 12:22:30 -06001657 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06001658 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1659
1660 # Unfortunately, compiling a source file always results in a file
1661 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06001662 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06001663 # binman as a file called u-boot.dtb. To fix this, copy the file
1664 # over to the expected place.
1665 #tools.WriteFile(os.path.join(self._indir, 'u-boot.dtb'),
1666 #tools.ReadFile(tools.GetOutputFilename('source.dtb')))
1667 start = 0
1668 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1669 'tpl/u-boot-tpl.dtb.out']:
1670 dtb = fdt.Fdt.FromData(data[start:])
1671 size = dtb._fdt_obj.totalsize()
1672 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1673 outdata = tools.ReadFile(pathname)
1674 name = os.path.split(fname)[0]
1675
1676 if name:
1677 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1678 else:
1679 orig_indata = dtb_data
1680 self.assertNotEqual(outdata, orig_indata,
1681 "Expected output file '%s' be updated" % pathname)
1682 self.assertEqual(outdata, data[start:start + size],
1683 "Expected output file '%s' to match output image" %
1684 pathname)
1685 start += size
1686 finally:
1687 self._ResetDtbs()
1688
Simon Glass83d73c22018-09-14 04:57:26 -06001689 def _decompress(self, data):
Simon Glassff5c7e32019-07-08 13:18:42 -06001690 return tools.Decompress(data, 'lz4')
Simon Glass83d73c22018-09-14 04:57:26 -06001691
1692 def testCompress(self):
1693 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06001694 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001695 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06001696 use_real_dtb=True, update_dtb=True)
1697 dtb = fdt.Fdt(out_dtb_fname)
1698 dtb.Scan()
1699 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1700 orig = self._decompress(data)
1701 self.assertEquals(COMPRESS_DATA, orig)
1702 expected = {
1703 'blob:uncomp-size': len(COMPRESS_DATA),
1704 'blob:size': len(data),
1705 'size': len(data),
1706 }
1707 self.assertEqual(expected, props)
1708
Simon Glass0a98b282018-09-14 04:57:28 -06001709 def testFiles(self):
1710 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06001711 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001712 self.assertEqual(FILES_DATA, data)
1713
1714 def testFilesCompress(self):
1715 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06001716 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06001717 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001718
1719 image = control.images['image']
1720 entries = image.GetEntries()
1721 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06001722 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06001723
Simon Glassc6c10e72019-05-17 22:00:46 -06001724 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06001725 for i in range(1, 3):
1726 key = '%d.dat' % i
1727 start = entries[key].image_pos
1728 len = entries[key].size
1729 chunk = data[start:start + len]
1730 orig += self._decompress(chunk)
1731
1732 self.assertEqual(FILES_DATA, orig)
1733
1734 def testFilesMissing(self):
1735 """Test missing files"""
1736 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001737 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001738 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1739 'no files', str(e.exception))
1740
1741 def testFilesNoPattern(self):
1742 """Test missing files"""
1743 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001744 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06001745 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1746 str(e.exception))
1747
Simon Glassba64a0b2018-09-14 04:57:29 -06001748 def testExpandSize(self):
1749 """Test an expanding entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001750 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06001751 map=True)
Simon Glassc6c10e72019-05-17 22:00:46 -06001752 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1753 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1754 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1755 tools.GetBytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06001756 self.assertEqual(expect, data)
1757 self.assertEqual('''ImagePos Offset Size Name
175800000000 00000000 00000028 main-section
175900000000 00000000 00000008 fill
176000000008 00000008 00000004 u-boot
17610000000c 0000000c 00000004 section
17620000000c 00000000 00000003 intel-mrc
176300000010 00000010 00000004 u-boot2
176400000014 00000014 0000000c section2
176500000014 00000000 00000008 fill
17660000001c 00000008 00000004 u-boot
176700000020 00000020 00000008 fill2
1768''', map_data)
1769
1770 def testExpandSizeBad(self):
1771 """Test an expanding entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06001772 with test_util.capture_sys_output() as (stdout, stderr):
1773 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001774 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06001775 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1776 'expanding entry', str(e.exception))
1777
Simon Glasse0e5df92018-09-14 04:57:31 -06001778 def testHash(self):
1779 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001780 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001781 use_real_dtb=True, update_dtb=True)
1782 dtb = fdt.Fdt(out_dtb_fname)
1783 dtb.Scan()
1784 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1785 m = hashlib.sha256()
1786 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001787 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001788
1789 def testHashNoAlgo(self):
1790 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001791 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001792 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1793 'hash node', str(e.exception))
1794
1795 def testHashBadAlgo(self):
1796 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001797 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06001798 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1799 str(e.exception))
1800
1801 def testHashSection(self):
1802 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06001803 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06001804 use_real_dtb=True, update_dtb=True)
1805 dtb = fdt.Fdt(out_dtb_fname)
1806 dtb.Scan()
1807 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1808 m = hashlib.sha256()
1809 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001810 m.update(tools.GetBytes(ord('a'), 16))
1811 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06001812
Simon Glassf0253632018-09-14 04:57:32 -06001813 def testPackUBootTplMicrocode(self):
1814 """Test that x86 microcode can be handled correctly in TPL
1815
1816 We expect to see the following in the image, in order:
1817 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1818 place
1819 u-boot-tpl.dtb with the microcode removed
1820 the microcode
1821 """
Simon Glassf514d8f2019-08-24 07:22:54 -06001822 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
1823 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001824 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06001825 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001826 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1827 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06001828
Simon Glassf8f8df62018-09-14 04:57:34 -06001829 def testFmapX86(self):
1830 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001831 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06001832 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc6c10e72019-05-17 22:00:46 -06001833 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001834 self.assertEqual(expected, data[:32])
1835 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1836
1837 self.assertEqual(0x100, fhdr.image_size)
1838
1839 self.assertEqual(0, fentries[0].offset)
1840 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001841 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001842
1843 self.assertEqual(4, fentries[1].offset)
1844 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001845 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001846
1847 self.assertEqual(32, fentries[2].offset)
1848 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1849 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001850 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001851
1852 def testFmapX86Section(self):
1853 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001854 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc6c10e72019-05-17 22:00:46 -06001855 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06001856 self.assertEqual(expected, data[:32])
1857 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1858
1859 self.assertEqual(0x100, fhdr.image_size)
1860
1861 self.assertEqual(0, fentries[0].offset)
1862 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001863 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001864
1865 self.assertEqual(4, fentries[1].offset)
1866 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001867 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001868
1869 self.assertEqual(36, fentries[2].offset)
1870 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1871 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001872 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06001873
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001874 def testElf(self):
1875 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001876 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001877 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glass4c650252019-07-08 13:18:46 -06001878 TestFunctional._MakeInputFile('tpl/u-boot-tpl', fd.read())
Simon Glass53e22bf2019-08-24 07:22:53 -06001879 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001880 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001881 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001882
Simon Glass093d1682019-07-08 13:18:25 -06001883 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001884 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001885 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06001886 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001887 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06001888 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06001889
Simon Glass163ed6c2018-09-14 04:57:36 -06001890 def testPackOverlapMap(self):
1891 """Test that overlapping regions are detected"""
1892 with test_util.capture_sys_output() as (stdout, stderr):
1893 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001894 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass163ed6c2018-09-14 04:57:36 -06001895 map_fname = tools.GetOutputFilename('image.map')
1896 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1897 stdout.getvalue())
1898
1899 # We should not get an inmage, but there should be a map file
1900 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1901 self.assertTrue(os.path.exists(map_fname))
Simon Glasseb546ac2019-05-17 22:00:51 -06001902 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06001903 self.assertEqual('''ImagePos Offset Size Name
1904<none> 00000000 00000007 main-section
1905<none> 00000000 00000004 u-boot
1906<none> 00000003 00000004 u-boot-align
1907''', map_data)
1908
Simon Glass093d1682019-07-08 13:18:25 -06001909 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06001910 """Test that an image with an Intel Reference code binary works"""
1911 data = self._DoReadFile('100_intel_refcode.dts')
1912 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1913
Simon Glass9481c802019-04-25 21:58:39 -06001914 def testSectionOffset(self):
1915 """Tests use of a section with an offset"""
1916 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1917 map=True)
1918 self.assertEqual('''ImagePos Offset Size Name
191900000000 00000000 00000038 main-section
192000000004 00000004 00000010 section@0
192100000004 00000000 00000004 u-boot
192200000018 00000018 00000010 section@1
192300000018 00000000 00000004 u-boot
19240000002c 0000002c 00000004 section@2
19250000002c 00000000 00000004 u-boot
1926''', map_data)
1927 self.assertEqual(data,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001928 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1929 tools.GetBytes(0x21, 12) +
1930 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1931 tools.GetBytes(0x61, 12) +
1932 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1933 tools.GetBytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06001934
Simon Glassac62fba2019-07-08 13:18:53 -06001935 def testCbfsRaw(self):
1936 """Test base handling of a Coreboot Filesystem (CBFS)
1937
1938 The exact contents of the CBFS is verified by similar tests in
1939 cbfs_util_test.py. The tests here merely check that the files added to
1940 the CBFS can be found in the final image.
1941 """
1942 data = self._DoReadFile('102_cbfs_raw.dts')
1943 size = 0xb0
1944
1945 cbfs = cbfs_util.CbfsReader(data)
1946 self.assertEqual(size, cbfs.rom_size)
1947
1948 self.assertIn('u-boot-dtb', cbfs.files)
1949 cfile = cbfs.files['u-boot-dtb']
1950 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1951
1952 def testCbfsArch(self):
1953 """Test on non-x86 architecture"""
1954 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1955 size = 0x100
1956
1957 cbfs = cbfs_util.CbfsReader(data)
1958 self.assertEqual(size, cbfs.rom_size)
1959
1960 self.assertIn('u-boot-dtb', cbfs.files)
1961 cfile = cbfs.files['u-boot-dtb']
1962 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1963
1964 def testCbfsStage(self):
1965 """Tests handling of a Coreboot Filesystem (CBFS)"""
1966 if not elf.ELF_TOOLS:
1967 self.skipTest('Python elftools not available')
1968 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
1969 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
1970 size = 0xb0
1971
1972 data = self._DoReadFile('104_cbfs_stage.dts')
1973 cbfs = cbfs_util.CbfsReader(data)
1974 self.assertEqual(size, cbfs.rom_size)
1975
1976 self.assertIn('u-boot', cbfs.files)
1977 cfile = cbfs.files['u-boot']
1978 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
1979
1980 def testCbfsRawCompress(self):
1981 """Test handling of compressing raw files"""
1982 self._CheckLz4()
1983 data = self._DoReadFile('105_cbfs_raw_compress.dts')
1984 size = 0x140
1985
1986 cbfs = cbfs_util.CbfsReader(data)
1987 self.assertIn('u-boot', cbfs.files)
1988 cfile = cbfs.files['u-boot']
1989 self.assertEqual(COMPRESS_DATA, cfile.data)
1990
1991 def testCbfsBadArch(self):
1992 """Test handling of a bad architecture"""
1993 with self.assertRaises(ValueError) as e:
1994 self._DoReadFile('106_cbfs_bad_arch.dts')
1995 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
1996
1997 def testCbfsNoSize(self):
1998 """Test handling of a missing size property"""
1999 with self.assertRaises(ValueError) as e:
2000 self._DoReadFile('107_cbfs_no_size.dts')
2001 self.assertIn('entry must have a size property', str(e.exception))
2002
2003 def testCbfsNoCOntents(self):
2004 """Test handling of a CBFS entry which does not provide contentsy"""
2005 with self.assertRaises(ValueError) as e:
2006 self._DoReadFile('108_cbfs_no_contents.dts')
2007 self.assertIn('Could not complete processing of contents',
2008 str(e.exception))
2009
2010 def testCbfsBadCompress(self):
2011 """Test handling of a bad architecture"""
2012 with self.assertRaises(ValueError) as e:
2013 self._DoReadFile('109_cbfs_bad_compress.dts')
2014 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2015 str(e.exception))
2016
2017 def testCbfsNamedEntries(self):
2018 """Test handling of named entries"""
2019 data = self._DoReadFile('110_cbfs_name.dts')
2020
2021 cbfs = cbfs_util.CbfsReader(data)
2022 self.assertIn('FRED', cbfs.files)
2023 cfile1 = cbfs.files['FRED']
2024 self.assertEqual(U_BOOT_DATA, cfile1.data)
2025
2026 self.assertIn('hello', cbfs.files)
2027 cfile2 = cbfs.files['hello']
2028 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2029
Simon Glassc5ac1382019-07-08 13:18:54 -06002030 def _SetupIfwi(self, fname):
2031 """Set up to run an IFWI test
2032
2033 Args:
2034 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2035 """
2036 self._SetupSplElf()
2037
2038 # Intel Integrated Firmware Image (IFWI) file
2039 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2040 data = fd.read()
2041 TestFunctional._MakeInputFile(fname,data)
2042
2043 def _CheckIfwi(self, data):
2044 """Check that an image with an IFWI contains the correct output
2045
2046 Args:
2047 data: Conents of output file
2048 """
2049 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2050 if data[:0x1000] != expected_desc:
2051 self.fail('Expected descriptor binary at start of image')
2052
2053 # We expect to find the TPL wil in subpart IBBP entry IBBL
2054 image_fname = tools.GetOutputFilename('image.bin')
2055 tpl_fname = tools.GetOutputFilename('tpl.out')
2056 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2057 subpart='IBBP', entry_name='IBBL')
2058
2059 tpl_data = tools.ReadFile(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002060 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002061
2062 def testPackX86RomIfwi(self):
2063 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2064 self._SetupIfwi('fitimage.bin')
2065 data = self._DoReadFile('111_x86-rom-ifwi.dts')
2066 self._CheckIfwi(data)
2067
2068 def testPackX86RomIfwiNoDesc(self):
2069 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2070 self._SetupIfwi('ifwi.bin')
2071 data = self._DoReadFile('112_x86-rom-ifwi-nodesc.dts')
2072 self._CheckIfwi(data)
2073
2074 def testPackX86RomIfwiNoData(self):
2075 """Test that an x86 ROM with IFWI handles missing data"""
2076 self._SetupIfwi('ifwi.bin')
2077 with self.assertRaises(ValueError) as e:
2078 data = self._DoReadFile('113_x86-rom-ifwi-nodata.dts')
2079 self.assertIn('Could not complete processing of contents',
2080 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002081
Simon Glasse073d4e2019-07-08 13:18:56 -06002082 def testCbfsOffset(self):
2083 """Test a CBFS with files at particular offsets
2084
2085 Like all CFBS tests, this is just checking the logic that calls
2086 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2087 """
2088 data = self._DoReadFile('114_cbfs_offset.dts')
2089 size = 0x200
2090
2091 cbfs = cbfs_util.CbfsReader(data)
2092 self.assertEqual(size, cbfs.rom_size)
2093
2094 self.assertIn('u-boot', cbfs.files)
2095 cfile = cbfs.files['u-boot']
2096 self.assertEqual(U_BOOT_DATA, cfile.data)
2097 self.assertEqual(0x40, cfile.cbfs_offset)
2098
2099 self.assertIn('u-boot-dtb', cbfs.files)
2100 cfile2 = cbfs.files['u-boot-dtb']
2101 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2102 self.assertEqual(0x140, cfile2.cbfs_offset)
2103
Simon Glass086cec92019-07-08 14:25:27 -06002104 def testFdtmap(self):
2105 """Test an FDT map can be inserted in the image"""
2106 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2107 fdtmap_data = data[len(U_BOOT_DATA):]
2108 magic = fdtmap_data[:8]
2109 self.assertEqual('_FDTMAP_', magic)
2110 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2111
2112 fdt_data = fdtmap_data[16:]
2113 dtb = fdt.Fdt.FromData(fdt_data)
2114 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002115 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002116 self.assertEqual({
2117 'image-pos': 0,
2118 'offset': 0,
2119 'u-boot:offset': 0,
2120 'u-boot:size': len(U_BOOT_DATA),
2121 'u-boot:image-pos': 0,
2122 'fdtmap:image-pos': 4,
2123 'fdtmap:offset': 4,
2124 'fdtmap:size': len(fdtmap_data),
2125 'size': len(data),
2126 }, props)
2127
2128 def testFdtmapNoMatch(self):
2129 """Check handling of an FDT map when the section cannot be found"""
2130 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2131
2132 # Mangle the section name, which should cause a mismatch between the
2133 # correct FDT path and the one expected by the section
2134 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002135 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002136 entries = image.GetEntries()
2137 fdtmap = entries['fdtmap']
2138 with self.assertRaises(ValueError) as e:
2139 fdtmap._GetFdtmap()
2140 self.assertIn("Cannot locate node for path '/binman-suffix'",
2141 str(e.exception))
2142
Simon Glasscf228942019-07-08 14:25:28 -06002143 def testFdtmapHeader(self):
2144 """Test an FDT map and image header can be inserted in the image"""
2145 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2146 fdtmap_pos = len(U_BOOT_DATA)
2147 fdtmap_data = data[fdtmap_pos:]
2148 fdt_data = fdtmap_data[16:]
2149 dtb = fdt.Fdt.FromData(fdt_data)
2150 fdt_size = dtb.GetFdtObj().totalsize()
2151 hdr_data = data[-8:]
2152 self.assertEqual('BinM', hdr_data[:4])
2153 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2154 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2155
2156 def testFdtmapHeaderStart(self):
2157 """Test an image header can be inserted at the image start"""
2158 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2159 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2160 hdr_data = data[:8]
2161 self.assertEqual('BinM', hdr_data[:4])
2162 offset = struct.unpack('<I', hdr_data[4:])[0]
2163 self.assertEqual(fdtmap_pos, offset)
2164
2165 def testFdtmapHeaderPos(self):
2166 """Test an image header can be inserted at a chosen position"""
2167 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2168 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2169 hdr_data = data[0x80:0x88]
2170 self.assertEqual('BinM', hdr_data[:4])
2171 offset = struct.unpack('<I', hdr_data[4:])[0]
2172 self.assertEqual(fdtmap_pos, offset)
2173
2174 def testHeaderMissingFdtmap(self):
2175 """Test an image header requires an fdtmap"""
2176 with self.assertRaises(ValueError) as e:
2177 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2178 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2179 str(e.exception))
2180
2181 def testHeaderNoLocation(self):
2182 """Test an image header with a no specified location is detected"""
2183 with self.assertRaises(ValueError) as e:
2184 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2185 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2186 str(e.exception))
2187
Simon Glassc52c9e72019-07-08 14:25:37 -06002188 def testEntryExpand(self):
2189 """Test expanding an entry after it is packed"""
2190 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002191 self.assertEqual(b'aaa', data[:3])
2192 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2193 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002194
2195 def testEntryExpandBad(self):
2196 """Test expanding an entry after it is packed, twice"""
2197 with self.assertRaises(ValueError) as e:
2198 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002199 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002200 str(e.exception))
2201
2202 def testEntryExpandSection(self):
2203 """Test expanding an entry within a section after it is packed"""
2204 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002205 self.assertEqual(b'aaa', data[:3])
2206 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2207 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002208
Simon Glass6c223fd2019-07-08 14:25:38 -06002209 def testCompressDtb(self):
2210 """Test that compress of device-tree files is supported"""
2211 self._CheckLz4()
2212 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2213 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2214 comp_data = data[len(U_BOOT_DATA):]
2215 orig = self._decompress(comp_data)
2216 dtb = fdt.Fdt.FromData(orig)
2217 dtb.Scan()
2218 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2219 expected = {
2220 'u-boot:size': len(U_BOOT_DATA),
2221 'u-boot-dtb:uncomp-size': len(orig),
2222 'u-boot-dtb:size': len(comp_data),
2223 'size': len(data),
2224 }
2225 self.assertEqual(expected, props)
2226
Simon Glass69f7cb32019-07-08 14:25:41 -06002227 def testCbfsUpdateFdt(self):
2228 """Test that we can update the device tree with CBFS offset/size info"""
2229 self._CheckLz4()
2230 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2231 update_dtb=True)
2232 dtb = fdt.Fdt(out_dtb_fname)
2233 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002234 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002235 del props['cbfs/u-boot:size']
2236 self.assertEqual({
2237 'offset': 0,
2238 'size': len(data),
2239 'image-pos': 0,
2240 'cbfs:offset': 0,
2241 'cbfs:size': len(data),
2242 'cbfs:image-pos': 0,
2243 'cbfs/u-boot:offset': 0x38,
2244 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2245 'cbfs/u-boot:image-pos': 0x38,
2246 'cbfs/u-boot-dtb:offset': 0xb8,
2247 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2248 'cbfs/u-boot-dtb:image-pos': 0xb8,
2249 }, props)
2250
Simon Glass8a1ad062019-07-08 14:25:42 -06002251 def testCbfsBadType(self):
2252 """Test an image header with a no specified location is detected"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('126_cbfs_bad_type.dts')
2255 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2256
Simon Glass41b8ba02019-07-08 14:25:43 -06002257 def testList(self):
2258 """Test listing the files in an image"""
2259 self._CheckLz4()
2260 data = self._DoReadFile('127_list.dts')
2261 image = control.images['image']
2262 entries = image.BuildEntryList()
2263 self.assertEqual(7, len(entries))
2264
2265 ent = entries[0]
2266 self.assertEqual(0, ent.indent)
2267 self.assertEqual('main-section', ent.name)
2268 self.assertEqual('section', ent.etype)
2269 self.assertEqual(len(data), ent.size)
2270 self.assertEqual(0, ent.image_pos)
2271 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002272 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002273
2274 ent = entries[1]
2275 self.assertEqual(1, ent.indent)
2276 self.assertEqual('u-boot', ent.name)
2277 self.assertEqual('u-boot', ent.etype)
2278 self.assertEqual(len(U_BOOT_DATA), ent.size)
2279 self.assertEqual(0, ent.image_pos)
2280 self.assertEqual(None, ent.uncomp_size)
2281 self.assertEqual(0, ent.offset)
2282
2283 ent = entries[2]
2284 self.assertEqual(1, ent.indent)
2285 self.assertEqual('section', ent.name)
2286 self.assertEqual('section', ent.etype)
2287 section_size = ent.size
2288 self.assertEqual(0x100, ent.image_pos)
2289 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002290 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002291
2292 ent = entries[3]
2293 self.assertEqual(2, ent.indent)
2294 self.assertEqual('cbfs', ent.name)
2295 self.assertEqual('cbfs', ent.etype)
2296 self.assertEqual(0x400, ent.size)
2297 self.assertEqual(0x100, ent.image_pos)
2298 self.assertEqual(None, ent.uncomp_size)
2299 self.assertEqual(0, ent.offset)
2300
2301 ent = entries[4]
2302 self.assertEqual(3, ent.indent)
2303 self.assertEqual('u-boot', ent.name)
2304 self.assertEqual('u-boot', ent.etype)
2305 self.assertEqual(len(U_BOOT_DATA), ent.size)
2306 self.assertEqual(0x138, ent.image_pos)
2307 self.assertEqual(None, ent.uncomp_size)
2308 self.assertEqual(0x38, ent.offset)
2309
2310 ent = entries[5]
2311 self.assertEqual(3, ent.indent)
2312 self.assertEqual('u-boot-dtb', ent.name)
2313 self.assertEqual('text', ent.etype)
2314 self.assertGreater(len(COMPRESS_DATA), ent.size)
2315 self.assertEqual(0x178, ent.image_pos)
2316 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2317 self.assertEqual(0x78, ent.offset)
2318
2319 ent = entries[6]
2320 self.assertEqual(2, ent.indent)
2321 self.assertEqual('u-boot-dtb', ent.name)
2322 self.assertEqual('u-boot-dtb', ent.etype)
2323 self.assertEqual(0x500, ent.image_pos)
2324 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2325 dtb_size = ent.size
2326 # Compressing this data expands it since headers are added
2327 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2328 self.assertEqual(0x400, ent.offset)
2329
2330 self.assertEqual(len(data), 0x100 + section_size)
2331 self.assertEqual(section_size, 0x400 + dtb_size)
2332
Simon Glasse1925fa2019-07-08 14:25:44 -06002333 def testFindFdtmap(self):
2334 """Test locating an FDT map in an image"""
2335 self._CheckLz4()
2336 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2337 image = control.images['image']
2338 entries = image.GetEntries()
2339 entry = entries['fdtmap']
2340 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2341
2342 def testFindFdtmapMissing(self):
2343 """Test failing to locate an FDP map"""
2344 data = self._DoReadFile('005_simple.dts')
2345 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2346
Simon Glass2d260032019-07-08 14:25:45 -06002347 def testFindImageHeader(self):
2348 """Test locating a image header"""
2349 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002350 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002351 image = control.images['image']
2352 entries = image.GetEntries()
2353 entry = entries['fdtmap']
2354 # The header should point to the FDT map
2355 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2356
2357 def testFindImageHeaderStart(self):
2358 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002359 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002360 image = control.images['image']
2361 entries = image.GetEntries()
2362 entry = entries['fdtmap']
2363 # The header should point to the FDT map
2364 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2365
2366 def testFindImageHeaderMissing(self):
2367 """Test failing to locate an image header"""
2368 data = self._DoReadFile('005_simple.dts')
2369 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2370
Simon Glassffded752019-07-08 14:25:46 -06002371 def testReadImage(self):
2372 """Test reading an image and accessing its FDT map"""
2373 self._CheckLz4()
2374 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2375 image_fname = tools.GetOutputFilename('image.bin')
2376 orig_image = control.images['image']
2377 image = Image.FromFile(image_fname)
2378 self.assertEqual(orig_image.GetEntries().keys(),
2379 image.GetEntries().keys())
2380
2381 orig_entry = orig_image.GetEntries()['fdtmap']
2382 entry = image.GetEntries()['fdtmap']
2383 self.assertEquals(orig_entry.offset, entry.offset)
2384 self.assertEquals(orig_entry.size, entry.size)
2385 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2386
2387 def testReadImageNoHeader(self):
2388 """Test accessing an image's FDT map without an image header"""
2389 self._CheckLz4()
2390 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2391 image_fname = tools.GetOutputFilename('image.bin')
2392 image = Image.FromFile(image_fname)
2393 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002394 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002395
2396 def testReadImageFail(self):
2397 """Test failing to read an image image's FDT map"""
2398 self._DoReadFile('005_simple.dts')
2399 image_fname = tools.GetOutputFilename('image.bin')
2400 with self.assertRaises(ValueError) as e:
2401 image = Image.FromFile(image_fname)
2402 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002403
Simon Glass61f564d2019-07-08 14:25:48 -06002404 def testListCmd(self):
2405 """Test listing the files in an image using an Fdtmap"""
2406 self._CheckLz4()
2407 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2408
2409 # lz4 compression size differs depending on the version
2410 image = control.images['image']
2411 entries = image.GetEntries()
2412 section_size = entries['section'].size
2413 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2414 fdtmap_offset = entries['fdtmap'].offset
2415
Simon Glassf86a7362019-07-20 12:24:10 -06002416 try:
2417 tmpdir, updated_fname = self._SetupImageInTmpdir()
2418 with test_util.capture_sys_output() as (stdout, stderr):
2419 self._DoBinman('ls', '-i', updated_fname)
2420 finally:
2421 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002422 lines = stdout.getvalue().splitlines()
2423 expected = [
2424'Name Image-pos Size Entry-type Offset Uncomp-size',
2425'----------------------------------------------------------------------',
2426'main-section 0 c00 section 0',
2427' u-boot 0 4 u-boot 0',
2428' section 100 %x section 100' % section_size,
2429' cbfs 100 400 cbfs 0',
2430' u-boot 138 4 u-boot 38',
2431' u-boot-dtb 180 10f u-boot-dtb 80 3c9',
2432' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glass1411ac82019-07-20 12:23:44 -06002433' fdtmap %x 3b4 fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002434 (fdtmap_offset, fdtmap_offset),
2435' image-header bf8 8 image-header bf8',
2436 ]
2437 self.assertEqual(expected, lines)
2438
2439 def testListCmdFail(self):
2440 """Test failing to list an image"""
2441 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002442 try:
2443 tmpdir, updated_fname = self._SetupImageInTmpdir()
2444 with self.assertRaises(ValueError) as e:
2445 self._DoBinman('ls', '-i', updated_fname)
2446 finally:
2447 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002448 self.assertIn("Cannot find FDT map in image", str(e.exception))
2449
2450 def _RunListCmd(self, paths, expected):
2451 """List out entries and check the result
2452
2453 Args:
2454 paths: List of paths to pass to the list command
2455 expected: Expected list of filenames to be returned, in order
2456 """
2457 self._CheckLz4()
2458 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2459 image_fname = tools.GetOutputFilename('image.bin')
2460 image = Image.FromFile(image_fname)
2461 lines = image.GetListEntries(paths)[1]
2462 files = [line[0].strip() for line in lines[1:]]
2463 self.assertEqual(expected, files)
2464
2465 def testListCmdSection(self):
2466 """Test listing the files in a section"""
2467 self._RunListCmd(['section'],
2468 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2469
2470 def testListCmdFile(self):
2471 """Test listing a particular file"""
2472 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2473
2474 def testListCmdWildcard(self):
2475 """Test listing a wildcarded file"""
2476 self._RunListCmd(['*boot*'],
2477 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2478
2479 def testListCmdWildcardMulti(self):
2480 """Test listing a wildcarded file"""
2481 self._RunListCmd(['*cb*', '*head*'],
2482 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2483
2484 def testListCmdEmpty(self):
2485 """Test listing a wildcarded file"""
2486 self._RunListCmd(['nothing'], [])
2487
2488 def testListCmdPath(self):
2489 """Test listing the files in a sub-entry of a section"""
2490 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2491
Simon Glassf667e452019-07-08 14:25:50 -06002492 def _RunExtractCmd(self, entry_name, decomp=True):
2493 """Extract an entry from an image
2494
2495 Args:
2496 entry_name: Entry name to extract
2497 decomp: True to decompress the data if compressed, False to leave
2498 it in its raw uncompressed format
2499
2500 Returns:
2501 data from entry
2502 """
2503 self._CheckLz4()
2504 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2505 image_fname = tools.GetOutputFilename('image.bin')
2506 return control.ReadEntry(image_fname, entry_name, decomp)
2507
2508 def testExtractSimple(self):
2509 """Test extracting a single file"""
2510 data = self._RunExtractCmd('u-boot')
2511 self.assertEqual(U_BOOT_DATA, data)
2512
Simon Glass71ce0ba2019-07-08 14:25:52 -06002513 def testExtractSection(self):
2514 """Test extracting the files in a section"""
2515 data = self._RunExtractCmd('section')
2516 cbfs_data = data[:0x400]
2517 cbfs = cbfs_util.CbfsReader(cbfs_data)
2518 self.assertEqual(['u-boot', 'u-boot-dtb', ''], cbfs.files.keys())
2519 dtb_data = data[0x400:]
2520 dtb = self._decompress(dtb_data)
2521 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2522
2523 def testExtractCompressed(self):
2524 """Test extracting compressed data"""
2525 data = self._RunExtractCmd('section/u-boot-dtb')
2526 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2527
2528 def testExtractRaw(self):
2529 """Test extracting compressed data without decompressing it"""
2530 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2531 dtb = self._decompress(data)
2532 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2533
2534 def testExtractCbfs(self):
2535 """Test extracting CBFS data"""
2536 data = self._RunExtractCmd('section/cbfs/u-boot')
2537 self.assertEqual(U_BOOT_DATA, data)
2538
2539 def testExtractCbfsCompressed(self):
2540 """Test extracting CBFS compressed data"""
2541 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2542 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2543
2544 def testExtractCbfsRaw(self):
2545 """Test extracting CBFS compressed data without decompressing it"""
2546 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glasseb0f4a42019-07-20 12:24:06 -06002547 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002548 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2549
Simon Glassf667e452019-07-08 14:25:50 -06002550 def testExtractBadEntry(self):
2551 """Test extracting a bad section path"""
2552 with self.assertRaises(ValueError) as e:
2553 self._RunExtractCmd('section/does-not-exist')
2554 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2555 str(e.exception))
2556
2557 def testExtractMissingFile(self):
2558 """Test extracting file that does not exist"""
2559 with self.assertRaises(IOError) as e:
2560 control.ReadEntry('missing-file', 'name')
2561
2562 def testExtractBadFile(self):
2563 """Test extracting an invalid file"""
2564 fname = os.path.join(self._indir, 'badfile')
2565 tools.WriteFile(fname, b'')
2566 with self.assertRaises(ValueError) as e:
2567 control.ReadEntry(fname, 'name')
2568
Simon Glass71ce0ba2019-07-08 14:25:52 -06002569 def testExtractCmd(self):
2570 """Test extracting a file fron an image on the command line"""
2571 self._CheckLz4()
2572 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002573 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002574 try:
2575 tmpdir, updated_fname = self._SetupImageInTmpdir()
2576 with test_util.capture_sys_output() as (stdout, stderr):
2577 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2578 '-f', fname)
2579 finally:
2580 shutil.rmtree(tmpdir)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002581 data = tools.ReadFile(fname)
2582 self.assertEqual(U_BOOT_DATA, data)
2583
2584 def testExtractOneEntry(self):
2585 """Test extracting a single entry fron an image """
2586 self._CheckLz4()
2587 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2588 image_fname = tools.GetOutputFilename('image.bin')
2589 fname = os.path.join(self._indir, 'output.extact')
2590 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2591 data = tools.ReadFile(fname)
2592 self.assertEqual(U_BOOT_DATA, data)
2593
2594 def _CheckExtractOutput(self, decomp):
2595 """Helper to test file output with and without decompression
2596
2597 Args:
2598 decomp: True to decompress entry data, False to output it raw
2599 """
2600 def _CheckPresent(entry_path, expect_data, expect_size=None):
2601 """Check and remove expected file
2602
2603 This checks the data/size of a file and removes the file both from
2604 the outfiles set and from the output directory. Once all files are
2605 processed, both the set and directory should be empty.
2606
2607 Args:
2608 entry_path: Entry path
2609 expect_data: Data to expect in file, or None to skip check
2610 expect_size: Size of data to expect in file, or None to skip
2611 """
2612 path = os.path.join(outdir, entry_path)
2613 data = tools.ReadFile(path)
2614 os.remove(path)
2615 if expect_data:
2616 self.assertEqual(expect_data, data)
2617 elif expect_size:
2618 self.assertEqual(expect_size, len(data))
2619 outfiles.remove(path)
2620
2621 def _CheckDirPresent(name):
2622 """Remove expected directory
2623
2624 This gives an error if the directory does not exist as expected
2625
2626 Args:
2627 name: Name of directory to remove
2628 """
2629 path = os.path.join(outdir, name)
2630 os.rmdir(path)
2631
2632 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2633 image_fname = tools.GetOutputFilename('image.bin')
2634 outdir = os.path.join(self._indir, 'extract')
2635 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2636
2637 # Create a set of all file that were output (should be 9)
2638 outfiles = set()
2639 for root, dirs, files in os.walk(outdir):
2640 outfiles |= set([os.path.join(root, fname) for fname in files])
2641 self.assertEqual(9, len(outfiles))
2642 self.assertEqual(9, len(einfos))
2643
2644 image = control.images['image']
2645 entries = image.GetEntries()
2646
2647 # Check the 9 files in various ways
2648 section = entries['section']
2649 section_entries = section.GetEntries()
2650 cbfs_entries = section_entries['cbfs'].GetEntries()
2651 _CheckPresent('u-boot', U_BOOT_DATA)
2652 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2653 dtb_len = EXTRACT_DTB_SIZE
2654 if not decomp:
2655 dtb_len = cbfs_entries['u-boot-dtb'].size
2656 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2657 if not decomp:
2658 dtb_len = section_entries['u-boot-dtb'].size
2659 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2660
2661 fdtmap = entries['fdtmap']
2662 _CheckPresent('fdtmap', fdtmap.data)
2663 hdr = entries['image-header']
2664 _CheckPresent('image-header', hdr.data)
2665
2666 _CheckPresent('section/root', section.data)
2667 cbfs = section_entries['cbfs']
2668 _CheckPresent('section/cbfs/root', cbfs.data)
2669 data = tools.ReadFile(image_fname)
2670 _CheckPresent('root', data)
2671
2672 # There should be no files left. Remove all the directories to check.
2673 # If there are any files/dirs remaining, one of these checks will fail.
2674 self.assertEqual(0, len(outfiles))
2675 _CheckDirPresent('section/cbfs')
2676 _CheckDirPresent('section')
2677 _CheckDirPresent('')
2678 self.assertFalse(os.path.exists(outdir))
2679
2680 def testExtractAllEntries(self):
2681 """Test extracting all entries"""
2682 self._CheckLz4()
2683 self._CheckExtractOutput(decomp=True)
2684
2685 def testExtractAllEntriesRaw(self):
2686 """Test extracting all entries without decompressing them"""
2687 self._CheckLz4()
2688 self._CheckExtractOutput(decomp=False)
2689
2690 def testExtractSelectedEntries(self):
2691 """Test extracting some entries"""
2692 self._CheckLz4()
2693 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2694 image_fname = tools.GetOutputFilename('image.bin')
2695 outdir = os.path.join(self._indir, 'extract')
2696 einfos = control.ExtractEntries(image_fname, None, outdir,
2697 ['*cb*', '*head*'])
2698
2699 # File output is tested by testExtractAllEntries(), so just check that
2700 # the expected entries are selected
2701 names = [einfo.name for einfo in einfos]
2702 self.assertEqual(names,
2703 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2704
2705 def testExtractNoEntryPaths(self):
2706 """Test extracting some entries"""
2707 self._CheckLz4()
2708 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2709 image_fname = tools.GetOutputFilename('image.bin')
2710 with self.assertRaises(ValueError) as e:
2711 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06002712 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002713 str(e.exception))
2714
2715 def testExtractTooManyEntryPaths(self):
2716 """Test extracting some entries"""
2717 self._CheckLz4()
2718 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2719 image_fname = tools.GetOutputFilename('image.bin')
2720 with self.assertRaises(ValueError) as e:
2721 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06002722 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06002723 str(e.exception))
2724
Simon Glasse2705fa2019-07-08 14:25:53 -06002725 def testPackAlignSection(self):
2726 """Test that sections can have alignment"""
2727 self._DoReadFile('131_pack_align_section.dts')
2728
2729 self.assertIn('image', control.images)
2730 image = control.images['image']
2731 entries = image.GetEntries()
2732 self.assertEqual(3, len(entries))
2733
2734 # First u-boot
2735 self.assertIn('u-boot', entries)
2736 entry = entries['u-boot']
2737 self.assertEqual(0, entry.offset)
2738 self.assertEqual(0, entry.image_pos)
2739 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2740 self.assertEqual(len(U_BOOT_DATA), entry.size)
2741
2742 # Section0
2743 self.assertIn('section0', entries)
2744 section0 = entries['section0']
2745 self.assertEqual(0x10, section0.offset)
2746 self.assertEqual(0x10, section0.image_pos)
2747 self.assertEqual(len(U_BOOT_DATA), section0.size)
2748
2749 # Second u-boot
2750 section_entries = section0.GetEntries()
2751 self.assertIn('u-boot', section_entries)
2752 entry = section_entries['u-boot']
2753 self.assertEqual(0, entry.offset)
2754 self.assertEqual(0x10, entry.image_pos)
2755 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2756 self.assertEqual(len(U_BOOT_DATA), entry.size)
2757
2758 # Section1
2759 self.assertIn('section1', entries)
2760 section1 = entries['section1']
2761 self.assertEqual(0x14, section1.offset)
2762 self.assertEqual(0x14, section1.image_pos)
2763 self.assertEqual(0x20, section1.size)
2764
2765 # Second u-boot
2766 section_entries = section1.GetEntries()
2767 self.assertIn('u-boot', section_entries)
2768 entry = section_entries['u-boot']
2769 self.assertEqual(0, entry.offset)
2770 self.assertEqual(0x14, entry.image_pos)
2771 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2772 self.assertEqual(len(U_BOOT_DATA), entry.size)
2773
2774 # Section2
2775 self.assertIn('section2', section_entries)
2776 section2 = section_entries['section2']
2777 self.assertEqual(0x4, section2.offset)
2778 self.assertEqual(0x18, section2.image_pos)
2779 self.assertEqual(4, section2.size)
2780
2781 # Third u-boot
2782 section_entries = section2.GetEntries()
2783 self.assertIn('u-boot', section_entries)
2784 entry = section_entries['u-boot']
2785 self.assertEqual(0, entry.offset)
2786 self.assertEqual(0x18, entry.image_pos)
2787 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2788 self.assertEqual(len(U_BOOT_DATA), entry.size)
2789
Simon Glass51014aa2019-07-20 12:23:56 -06002790 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2791 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06002792 """Replace an entry in an image
2793
2794 This writes the entry data to update it, then opens the updated file and
2795 returns the value that it now finds there.
2796
2797 Args:
2798 entry_name: Entry name to replace
2799 data: Data to replace it with
2800 decomp: True to compress the data if needed, False if data is
2801 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06002802 allow_resize: True to allow entries to change size, False to raise
2803 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06002804
2805 Returns:
2806 Tuple:
2807 data from entry
2808 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06002809 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06002810 """
Simon Glass51014aa2019-07-20 12:23:56 -06002811 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06002812 update_dtb=True)[1]
2813
2814 self.assertIn('image', control.images)
2815 image = control.images['image']
2816 entries = image.GetEntries()
2817 orig_dtb_data = entries['u-boot-dtb'].data
2818 orig_fdtmap_data = entries['fdtmap'].data
2819
2820 image_fname = tools.GetOutputFilename('image.bin')
2821 updated_fname = tools.GetOutputFilename('image-updated.bin')
2822 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06002823 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2824 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06002825 data = control.ReadEntry(updated_fname, entry_name, decomp)
2826
Simon Glass51014aa2019-07-20 12:23:56 -06002827 # The DT data should not change unless resized:
2828 if not allow_resize:
2829 new_dtb_data = entries['u-boot-dtb'].data
2830 self.assertEqual(new_dtb_data, orig_dtb_data)
2831 new_fdtmap_data = entries['fdtmap'].data
2832 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06002833
Simon Glass51014aa2019-07-20 12:23:56 -06002834 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06002835
2836 def testReplaceSimple(self):
2837 """Test replacing a single file"""
2838 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06002839 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2840 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002841 self.assertEqual(expected, data)
2842
2843 # Test that the state looks right. There should be an FDT for the fdtmap
2844 # that we jsut read back in, and it should match what we find in the
2845 # 'control' tables. Checking for an FDT that does not exist should
2846 # return None.
2847 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06002848 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06002849 self.assertEqual(expected_fdtmap, fdtmap)
2850
2851 dtb = state.GetFdtForEtype('fdtmap')
2852 self.assertEqual(dtb.GetContents(), fdtmap)
2853
2854 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2855 self.assertIsNone(missing_path)
2856 self.assertIsNone(missing_fdtmap)
2857
2858 missing_dtb = state.GetFdtForEtype('missing')
2859 self.assertIsNone(missing_dtb)
2860
2861 self.assertEqual('/binman', state.fdt_path_prefix)
2862
2863 def testReplaceResizeFail(self):
2864 """Test replacing a file by something larger"""
2865 expected = U_BOOT_DATA + b'x'
2866 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06002867 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2868 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06002869 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2870 str(e.exception))
2871
2872 def testReplaceMulti(self):
2873 """Test replacing entry data where multiple images are generated"""
2874 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2875 update_dtb=True)[0]
2876 expected = b'x' * len(U_BOOT_DATA)
2877 updated_fname = tools.GetOutputFilename('image-updated.bin')
2878 tools.WriteFile(updated_fname, data)
2879 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002880 control.WriteEntry(updated_fname, entry_name, expected,
2881 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002882 data = control.ReadEntry(updated_fname, entry_name)
2883 self.assertEqual(expected, data)
2884
2885 # Check the state looks right.
2886 self.assertEqual('/binman/image', state.fdt_path_prefix)
2887
2888 # Now check we can write the first image
2889 image_fname = tools.GetOutputFilename('first-image.bin')
2890 updated_fname = tools.GetOutputFilename('first-updated.bin')
2891 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2892 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06002893 control.WriteEntry(updated_fname, entry_name, expected,
2894 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06002895 data = control.ReadEntry(updated_fname, entry_name)
2896 self.assertEqual(expected, data)
2897
2898 # Check the state looks right.
2899 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06002900
Simon Glass12bb1a92019-07-20 12:23:51 -06002901 def testUpdateFdtAllRepack(self):
2902 """Test that all device trees are updated with offset/size info"""
2903 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2904 SECTION_SIZE = 0x300
2905 DTB_SIZE = 602
2906 FDTMAP_SIZE = 608
2907 base_expected = {
2908 'offset': 0,
2909 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2910 'image-pos': 0,
2911 'section:offset': 0,
2912 'section:size': SECTION_SIZE,
2913 'section:image-pos': 0,
2914 'section/u-boot-dtb:offset': 4,
2915 'section/u-boot-dtb:size': 636,
2916 'section/u-boot-dtb:image-pos': 4,
2917 'u-boot-spl-dtb:offset': SECTION_SIZE,
2918 'u-boot-spl-dtb:size': DTB_SIZE,
2919 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2920 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2921 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2922 'u-boot-tpl-dtb:size': DTB_SIZE,
2923 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2924 'fdtmap:size': FDTMAP_SIZE,
2925 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2926 }
2927 main_expected = {
2928 'section:orig-size': SECTION_SIZE,
2929 'section/u-boot-dtb:orig-offset': 4,
2930 }
2931
2932 # We expect three device-tree files in the output, with the first one
2933 # within a fixed-size section.
2934 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2935 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2936 # main U-Boot tree. All three should have the same positions and offset
2937 # except that the main tree should include the main_expected properties
2938 start = 4
2939 for item in ['', 'spl', 'tpl', None]:
2940 if item is None:
2941 start += 16 # Move past fdtmap header
2942 dtb = fdt.Fdt.FromData(data[start:])
2943 dtb.Scan()
2944 props = self._GetPropTree(dtb,
2945 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2946 prefix='/' if item is None else '/binman/')
2947 expected = dict(base_expected)
2948 if item:
2949 expected[item] = 0
2950 else:
2951 # Main DTB and fdtdec should include the 'orig-' properties
2952 expected.update(main_expected)
2953 # Helpful for debugging:
2954 #for prop in sorted(props):
2955 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2956 self.assertEqual(expected, props)
2957 if item == '':
2958 start = SECTION_SIZE
2959 else:
2960 start += dtb._fdt_obj.totalsize()
2961
Simon Glasseba1f0c2019-07-20 12:23:55 -06002962 def testFdtmapHeaderMiddle(self):
2963 """Test an FDT map in the middle of an image when it should be at end"""
2964 with self.assertRaises(ValueError) as e:
2965 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
2966 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
2967 str(e.exception))
2968
2969 def testFdtmapHeaderStartBad(self):
2970 """Test an FDT map in middle of an image when it should be at start"""
2971 with self.assertRaises(ValueError) as e:
2972 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
2973 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
2974 str(e.exception))
2975
2976 def testFdtmapHeaderEndBad(self):
2977 """Test an FDT map at the start of an image when it should be at end"""
2978 with self.assertRaises(ValueError) as e:
2979 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
2980 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
2981 str(e.exception))
2982
2983 def testFdtmapHeaderNoSize(self):
2984 """Test an image header at the end of an image with undefined size"""
2985 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
2986
Simon Glass51014aa2019-07-20 12:23:56 -06002987 def testReplaceResize(self):
2988 """Test replacing a single file in an entry with a larger file"""
2989 expected = U_BOOT_DATA + b'x'
2990 data, _, image = self._RunReplaceCmd('u-boot', expected,
2991 dts='139_replace_repack.dts')
2992 self.assertEqual(expected, data)
2993
2994 entries = image.GetEntries()
2995 dtb_data = entries['u-boot-dtb'].data
2996 dtb = fdt.Fdt.FromData(dtb_data)
2997 dtb.Scan()
2998
2999 # The u-boot section should now be larger in the dtb
3000 node = dtb.GetNode('/binman/u-boot')
3001 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3002
3003 # Same for the fdtmap
3004 fdata = entries['fdtmap'].data
3005 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3006 fdtb.Scan()
3007 fnode = fdtb.GetNode('/u-boot')
3008 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3009
3010 def testReplaceResizeNoRepack(self):
3011 """Test replacing an entry with a larger file when not allowed"""
3012 expected = U_BOOT_DATA + b'x'
3013 with self.assertRaises(ValueError) as e:
3014 self._RunReplaceCmd('u-boot', expected)
3015 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3016 str(e.exception))
3017
Simon Glass61ec04f2019-07-20 12:23:58 -06003018 def testEntryShrink(self):
3019 """Test contracting an entry after it is packed"""
3020 try:
3021 state.SetAllowEntryContraction(True)
3022 data = self._DoReadFileDtb('140_entry_shrink.dts',
3023 update_dtb=True)[0]
3024 finally:
3025 state.SetAllowEntryContraction(False)
3026 self.assertEqual(b'a', data[:1])
3027 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3028 self.assertEqual(b'a', data[-1:])
3029
3030 def testEntryShrinkFail(self):
3031 """Test not being allowed to contract an entry after it is packed"""
3032 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3033
3034 # In this case there is a spare byte at the end of the data. The size of
3035 # the contents is only 1 byte but we still have the size before it
3036 # shrunk.
3037 self.assertEqual(b'a\0', data[:2])
3038 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3039 self.assertEqual(b'a\0', data[-2:])
3040
Simon Glass27145fd2019-07-20 12:24:01 -06003041 def testDescriptorOffset(self):
3042 """Test that the Intel descriptor is always placed at at the start"""
3043 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3044 image = control.images['image']
3045 entries = image.GetEntries()
3046 desc = entries['intel-descriptor']
3047 self.assertEqual(0xff800000, desc.offset);
3048 self.assertEqual(0xff800000, desc.image_pos);
3049
Simon Glasseb0f4a42019-07-20 12:24:06 -06003050 def testReplaceCbfs(self):
3051 """Test replacing a single file in CBFS without changing the size"""
3052 self._CheckLz4()
3053 expected = b'x' * len(U_BOOT_DATA)
3054 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3055 updated_fname = tools.GetOutputFilename('image-updated.bin')
3056 tools.WriteFile(updated_fname, data)
3057 entry_name = 'section/cbfs/u-boot'
3058 control.WriteEntry(updated_fname, entry_name, expected,
3059 allow_resize=True)
3060 data = control.ReadEntry(updated_fname, entry_name)
3061 self.assertEqual(expected, data)
3062
3063 def testReplaceResizeCbfs(self):
3064 """Test replacing a single file in CBFS with one of a different size"""
3065 self._CheckLz4()
3066 expected = U_BOOT_DATA + b'x'
3067 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3068 updated_fname = tools.GetOutputFilename('image-updated.bin')
3069 tools.WriteFile(updated_fname, data)
3070 entry_name = 'section/cbfs/u-boot'
3071 control.WriteEntry(updated_fname, entry_name, expected,
3072 allow_resize=True)
3073 data = control.ReadEntry(updated_fname, entry_name)
3074 self.assertEqual(expected, data)
3075
Simon Glassa6cb9952019-07-20 12:24:15 -06003076 def _SetupForReplace(self):
3077 """Set up some files to use to replace entries
3078
3079 This generates an image, copies it to a new file, extracts all the files
3080 in it and updates some of them
3081
3082 Returns:
3083 List
3084 Image filename
3085 Output directory
3086 Expected values for updated entries, each a string
3087 """
3088 data = self._DoReadFileRealDtb('143_replace_all.dts')
3089
3090 updated_fname = tools.GetOutputFilename('image-updated.bin')
3091 tools.WriteFile(updated_fname, data)
3092
3093 outdir = os.path.join(self._indir, 'extract')
3094 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3095
3096 expected1 = b'x' + U_BOOT_DATA + b'y'
3097 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3098 tools.WriteFile(u_boot_fname1, expected1)
3099
3100 expected2 = b'a' + U_BOOT_DATA + b'b'
3101 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3102 tools.WriteFile(u_boot_fname2, expected2)
3103
3104 expected_text = b'not the same text'
3105 text_fname = os.path.join(outdir, 'text')
3106 tools.WriteFile(text_fname, expected_text)
3107
3108 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3109 dtb = fdt.FdtScan(dtb_fname)
3110 node = dtb.GetNode('/binman/text')
3111 node.AddString('my-property', 'the value')
3112 dtb.Sync(auto_resize=True)
3113 dtb.Flush()
3114
3115 return updated_fname, outdir, expected1, expected2, expected_text
3116
3117 def _CheckReplaceMultiple(self, entry_paths):
3118 """Handle replacing the contents of multiple entries
3119
3120 Args:
3121 entry_paths: List of entry paths to replace
3122
3123 Returns:
3124 List
3125 Dict of entries in the image:
3126 key: Entry name
3127 Value: Entry object
3128 Expected values for updated entries, each a string
3129 """
3130 updated_fname, outdir, expected1, expected2, expected_text = (
3131 self._SetupForReplace())
3132 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3133
3134 image = Image.FromFile(updated_fname)
3135 image.LoadData()
3136 return image.GetEntries(), expected1, expected2, expected_text
3137
3138 def testReplaceAll(self):
3139 """Test replacing the contents of all entries"""
3140 entries, expected1, expected2, expected_text = (
3141 self._CheckReplaceMultiple([]))
3142 data = entries['u-boot'].data
3143 self.assertEqual(expected1, data)
3144
3145 data = entries['u-boot2'].data
3146 self.assertEqual(expected2, data)
3147
3148 data = entries['text'].data
3149 self.assertEqual(expected_text, data)
3150
3151 # Check that the device tree is updated
3152 data = entries['u-boot-dtb'].data
3153 dtb = fdt.Fdt.FromData(data)
3154 dtb.Scan()
3155 node = dtb.GetNode('/binman/text')
3156 self.assertEqual('the value', node.props['my-property'].value)
3157
3158 def testReplaceSome(self):
3159 """Test replacing the contents of a few entries"""
3160 entries, expected1, expected2, expected_text = (
3161 self._CheckReplaceMultiple(['u-boot2', 'text']))
3162
3163 # This one should not change
3164 data = entries['u-boot'].data
3165 self.assertEqual(U_BOOT_DATA, data)
3166
3167 data = entries['u-boot2'].data
3168 self.assertEqual(expected2, data)
3169
3170 data = entries['text'].data
3171 self.assertEqual(expected_text, data)
3172
3173 def testReplaceCmd(self):
3174 """Test replacing a file fron an image on the command line"""
3175 self._DoReadFileRealDtb('143_replace_all.dts')
3176
3177 try:
3178 tmpdir, updated_fname = self._SetupImageInTmpdir()
3179
3180 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3181 expected = b'x' * len(U_BOOT_DATA)
3182 tools.WriteFile(fname, expected)
3183
3184 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3185 data = tools.ReadFile(updated_fname)
3186 self.assertEqual(expected, data[:len(expected)])
3187 map_fname = os.path.join(tmpdir, 'image-updated.map')
3188 self.assertFalse(os.path.exists(map_fname))
3189 finally:
3190 shutil.rmtree(tmpdir)
3191
3192 def testReplaceCmdSome(self):
3193 """Test replacing some files fron an image on the command line"""
3194 updated_fname, outdir, expected1, expected2, expected_text = (
3195 self._SetupForReplace())
3196
3197 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3198 'u-boot2', 'text')
3199
3200 tools.PrepareOutputDir(None)
3201 image = Image.FromFile(updated_fname)
3202 image.LoadData()
3203 entries = image.GetEntries()
3204
3205 # This one should not change
3206 data = entries['u-boot'].data
3207 self.assertEqual(U_BOOT_DATA, data)
3208
3209 data = entries['u-boot2'].data
3210 self.assertEqual(expected2, data)
3211
3212 data = entries['text'].data
3213 self.assertEqual(expected_text, data)
3214
3215 def testReplaceMissing(self):
3216 """Test replacing entries where the file is missing"""
3217 updated_fname, outdir, expected1, expected2, expected_text = (
3218 self._SetupForReplace())
3219
3220 # Remove one of the files, to generate a warning
3221 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3222 os.remove(u_boot_fname1)
3223
3224 with test_util.capture_sys_output() as (stdout, stderr):
3225 control.ReplaceEntries(updated_fname, None, outdir, [])
3226 self.assertIn("Skipping entry '/u-boot' from missing file",
3227 stdout.getvalue())
3228
3229 def testReplaceCmdMap(self):
3230 """Test replacing a file fron an image on the command line"""
3231 self._DoReadFileRealDtb('143_replace_all.dts')
3232
3233 try:
3234 tmpdir, updated_fname = self._SetupImageInTmpdir()
3235
3236 fname = os.path.join(self._indir, 'update-u-boot.bin')
3237 expected = b'x' * len(U_BOOT_DATA)
3238 tools.WriteFile(fname, expected)
3239
3240 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3241 '-f', fname, '-m')
3242 map_fname = os.path.join(tmpdir, 'image-updated.map')
3243 self.assertTrue(os.path.exists(map_fname))
3244 finally:
3245 shutil.rmtree(tmpdir)
3246
3247 def testReplaceNoEntryPaths(self):
3248 """Test replacing an entry without an entry path"""
3249 self._DoReadFileRealDtb('143_replace_all.dts')
3250 image_fname = tools.GetOutputFilename('image.bin')
3251 with self.assertRaises(ValueError) as e:
3252 control.ReplaceEntries(image_fname, 'fname', None, [])
3253 self.assertIn('Must specify an entry path to read with -f',
3254 str(e.exception))
3255
3256 def testReplaceTooManyEntryPaths(self):
3257 """Test extracting some entries"""
3258 self._DoReadFileRealDtb('143_replace_all.dts')
3259 image_fname = tools.GetOutputFilename('image.bin')
3260 with self.assertRaises(ValueError) as e:
3261 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3262 self.assertIn('Must specify exactly one entry path to write with -f',
3263 str(e.exception))
3264
Simon Glass2250ee62019-08-24 07:22:48 -06003265 def testPackReset16(self):
3266 """Test that an image with an x86 reset16 region can be created"""
3267 data = self._DoReadFile('144_x86_reset16.dts')
3268 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3269
3270 def testPackReset16Spl(self):
3271 """Test that an image with an x86 reset16-spl region can be created"""
3272 data = self._DoReadFile('145_x86_reset16_spl.dts')
3273 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3274
3275 def testPackReset16Tpl(self):
3276 """Test that an image with an x86 reset16-tpl region can be created"""
3277 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3278 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3279
Simon Glass5af12072019-08-24 07:22:50 -06003280 def testPackIntelFit(self):
3281 """Test that an image with an Intel FIT and pointer can be created"""
3282 data = self._DoReadFile('147_intel_fit.dts')
3283 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3284 fit = data[16:32];
3285 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3286 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3287
3288 image = control.images['image']
3289 entries = image.GetEntries()
3290 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3291 self.assertEqual(expected_ptr, ptr)
3292
3293 def testPackIntelFitMissing(self):
3294 """Test detection of a FIT pointer with not FIT region"""
3295 with self.assertRaises(ValueError) as e:
3296 self._DoReadFile('148_intel_fit_missing.dts')
3297 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3298 str(e.exception))
3299
Simon Glass12bb1a92019-07-20 12:23:51 -06003300
Simon Glass9fc60b42017-11-12 21:52:22 -07003301if __name__ == "__main__":
3302 unittest.main()