blob: ceeee1dfe632be8afa70bd7961297acff16adb3d [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-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 Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassc585dd42020-04-17 18:09:03 -060010import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060011import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glass45d556d2020-07-09 18:39:45 -060014import re
Simon Glass57454f42016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
20
Simon Glassc585dd42020-04-17 18:09:03 -060021from binman import cbfs_util
22from binman import cmdline
23from binman import control
24from binman import elf
25from binman import elf_test
26from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060027from binman import state
28from dtoc import fdt
29from dtoc import fdt_util
30from binman.etype import fdtmap
31from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060032from binman.image import Image
Simon Glassa997ea52020-04-17 18:09:04 -060033from patman import command
34from patman import test_util
35from patman import tools
36from patman import tout
Simon Glass57454f42016-11-25 20:15:52 -070037
38# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060039U_BOOT_DATA = b'1234'
40U_BOOT_IMG_DATA = b'img'
Simon Glass4e353e22019-08-24 07:23:04 -060041U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
42U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glass303f62f2019-05-17 22:00:46 -060043BLOB_DATA = b'89'
44ME_DATA = b'0abcd'
45VGA_DATA = b'vga'
46U_BOOT_DTB_DATA = b'udtb'
47U_BOOT_SPL_DTB_DATA = b'spldtb'
48U_BOOT_TPL_DTB_DATA = b'tpldtb'
49X86_START16_DATA = b'start16'
50X86_START16_SPL_DATA = b'start16spl'
51X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060052X86_RESET16_DATA = b'reset16'
53X86_RESET16_SPL_DATA = b'reset16spl'
54X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060055PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
56U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
57U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
58U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
59FSP_DATA = b'fsp'
60CMC_DATA = b'cmc'
61VBT_DATA = b'vbt'
62MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060063TEXT_DATA = 'text'
64TEXT_DATA2 = 'text2'
65TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060066CROS_EC_RW_DATA = b'ecrw'
67GBB_DATA = b'gbbd'
68BMPBLK_DATA = b'bmp'
69VBLOCK_DATA = b'vblk'
70FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
71 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060072COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass303f62f2019-05-17 22:00:46 -060073REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060074FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060075FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060076FSP_T_DATA = b'fsp_t'
Simon Glassdb168d42018-07-17 13:25:39 -060077
Simon Glass2c6adba2019-07-20 12:23:47 -060078# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060079EXTRACT_DTB_SIZE = 0x3c9
80
Simon Glass2c6adba2019-07-20 12:23:47 -060081# Properties expected to be in the device tree when update_dtb is used
82BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
83
Simon Glassfb30e292019-07-20 12:23:51 -060084# Extra properties expected to be in the device tree when allow-repack is used
85REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
86
Simon Glass57454f42016-11-25 20:15:52 -070087
88class TestFunctional(unittest.TestCase):
89 """Functional tests for binman
90
91 Most of these use a sample .dts file to build an image and then check
92 that it looks correct. The sample files are in the test/ subdirectory
93 and are numbered.
94
95 For each entry type a very small test file is created using fixed
96 string contents. This makes it easy to test that things look right, and
97 debug problems.
98
99 In some cases a 'real' file must be used - these are also supplied in
100 the test/ diurectory.
101 """
102 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600103 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700104 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600105 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700106
Simon Glass57454f42016-11-25 20:15:52 -0700107 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600108 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
109 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700110
111 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600112 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700113
114 # Create some test files
115 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
116 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
117 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600118 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700119 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700120 TestFunctional._MakeInputFile('me.bin', ME_DATA)
121 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600122 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600123
Jagdish Gediya311d4842018-09-03 21:35:08 +0530124 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600125
Simon Glassabab18c2019-08-24 07:22:49 -0600126 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
127 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700128 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600129 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600130 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600131
132 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
133 X86_RESET16_DATA)
134 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
135 X86_RESET16_SPL_DATA)
136 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
137 X86_RESET16_TPL_DATA)
138
Simon Glass57454f42016-11-25 20:15:52 -0700139 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700140 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
141 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600142 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
143 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700144 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
145 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700146 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700147 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600148 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600149 TestFunctional._MakeInputDir('devkeys')
150 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600151 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600152 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600153 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600154 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700155
Simon Glassf6290892019-08-24 07:22:53 -0600156 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
157 elf_test.BuildElfTestFiles(cls._elf_testdir)
158
Simon Glass72232452016-11-25 20:15:53 -0700159 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600160 TestFunctional._MakeInputFile('u-boot',
161 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700162
163 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600164 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700165
Simon Glass862f8e22019-08-24 07:22:43 -0600166 shutil.copytree(cls.TestFile('files'),
167 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600168
Simon Glass7ba33592018-09-14 04:57:26 -0600169 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
170
Simon Glass1de34482019-07-08 13:18:53 -0600171 # Travis-CI may have an old lz4
Simon Glass862f8e22019-08-24 07:22:43 -0600172 cls.have_lz4 = True
Simon Glass1de34482019-07-08 13:18:53 -0600173 try:
174 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glasscc311ac2019-10-31 07:42:50 -0600175 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glass1de34482019-07-08 13:18:53 -0600176 except:
Simon Glass862f8e22019-08-24 07:22:43 -0600177 cls.have_lz4 = False
Simon Glass1de34482019-07-08 13:18:53 -0600178
Simon Glass57454f42016-11-25 20:15:52 -0700179 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600180 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700181 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600182 if cls.preserve_indir:
183 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600184 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600185 if cls._indir:
186 shutil.rmtree(cls._indir)
187 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700188
Simon Glass1c420c92019-07-08 13:18:49 -0600189 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600190 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600191 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600192 """Accept arguments controlling test execution
193
194 Args:
195 preserve_indir: Preserve the shared input directory used by all
196 tests in this class.
197 preserve_outdir: Preserve the output directories used by tests. Each
198 test has its own, so this is normally only useful when running a
199 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600200 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600201 """
202 cls.preserve_indir = preserve_indir
203 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600204 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600205 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600206
Simon Glass1de34482019-07-08 13:18:53 -0600207 def _CheckLz4(self):
208 if not self.have_lz4:
209 self.skipTest('lz4 --no-frame-crc not available')
210
Simon Glassee9d10d2019-07-20 12:24:09 -0600211 def _CleanupOutputDir(self):
212 """Remove the temporary output directory"""
213 if self.preserve_outdirs:
214 print('Preserving output dir: %s' % tools.outdir)
215 else:
216 tools._FinaliseForTest()
217
Simon Glass57454f42016-11-25 20:15:52 -0700218 def setUp(self):
219 # Enable this to turn on debugging output
220 # tout.Init(tout.DEBUG)
221 command.test_result = None
222
223 def tearDown(self):
224 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600225 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700226
Simon Glassb3d6fc72019-07-20 12:24:10 -0600227 def _SetupImageInTmpdir(self):
228 """Set up the output image in a new temporary directory
229
230 This is used when an image has been generated in the output directory,
231 but we want to run binman again. This will create a new output
232 directory and fail to delete the original one.
233
234 This creates a new temporary directory, copies the image to it (with a
235 new name) and removes the old output directory.
236
237 Returns:
238 Tuple:
239 Temporary directory to use
240 New image filename
241 """
242 image_fname = tools.GetOutputFilename('image.bin')
243 tmpdir = tempfile.mkdtemp(prefix='binman.')
244 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
245 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
246 self._CleanupOutputDir()
247 return tmpdir, updated_fname
248
Simon Glass8425a1f2018-07-17 13:25:48 -0600249 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600250 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600251 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
252 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
253 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
254
Simon Glass57454f42016-11-25 20:15:52 -0700255 def _RunBinman(self, *args, **kwargs):
256 """Run binman using the command line
257
258 Args:
259 Arguments to pass, as a list of strings
260 kwargs: Arguments to pass to Command.RunPipe()
261 """
262 result = command.RunPipe([[self._binman_pathname] + list(args)],
263 capture=True, capture_stderr=True, raise_on_error=False)
264 if result.return_code and kwargs.get('raise_on_error', True):
265 raise Exception("Error running '%s': %s" % (' '.join(args),
266 result.stdout + result.stderr))
267 return result
268
Simon Glassf46732a2019-07-08 14:25:29 -0600269 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700270 """Run binman using directly (in the same process)
271
272 Args:
273 Arguments to pass, as a list of strings
274 Returns:
275 Return value (0 for success)
276 """
Simon Glassf46732a2019-07-08 14:25:29 -0600277 argv = list(argv)
278 args = cmdline.ParseArgs(argv)
279 args.pager = 'binman-invalid-pager'
280 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700281
282 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600283 # args.verbosity = tout.DEBUG
284 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700285
Simon Glass91710b32018-07-17 13:25:32 -0600286 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600287 entry_args=None, images=None, use_real_dtb=False,
Simon Glass5d94cc62020-07-09 18:39:38 -0600288 verbosity=None, allow_missing=False):
Simon Glass57454f42016-11-25 20:15:52 -0700289 """Run binman with a given test file
290
291 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600292 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600293 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600294 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600295 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600296 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600297 entry_args: Dict of entry args to supply to binman
298 key: arg name
299 value: value of that arg
300 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600301 use_real_dtb: True to use the test file as the contents of
302 the u-boot-dtb entry. Normally this is not needed and the
303 test contents (the U_BOOT_DTB_DATA string) can be used.
304 But in some test we need the real contents.
305 verbosity: Verbosity level to use (0-3, None=don't set it)
306 allow_missing: Set the '--allow-missing' flag so that missing
307 external binaries just produce a warning instead of an error
Simon Glass57454f42016-11-25 20:15:52 -0700308 """
Simon Glassf46732a2019-07-08 14:25:29 -0600309 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700310 if debug:
311 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600312 if verbosity is not None:
313 args.append('-v%d' % verbosity)
314 elif self.verbosity:
315 args.append('-v%d' % self.verbosity)
316 if self.toolpath:
317 for path in self.toolpath:
318 args += ['--toolpath', path]
319 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600320 if map:
321 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600322 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600323 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600324 if not use_real_dtb:
325 args.append('--fake-dtb')
Simon Glass91710b32018-07-17 13:25:32 -0600326 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600327 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600328 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600329 if allow_missing:
330 args.append('-M')
Simon Glass3b376c32018-09-14 04:57:12 -0600331 if images:
332 for image in images:
333 args += ['-i', image]
Simon Glass075a45c2017-11-13 18:55:00 -0700334 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700335
336 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700337 """Set up a new test device-tree file
338
339 The given file is compiled and set up as the device tree to be used
340 for ths test.
341
342 Args:
343 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600344 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700345
346 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600347 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700348 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600349 tmpdir = tempfile.mkdtemp(prefix='binmant.')
350 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600351 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700352 data = fd.read()
353 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600354 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600355 return data
Simon Glass57454f42016-11-25 20:15:52 -0700356
Simon Glasse219aa42018-09-14 04:57:24 -0600357 def _GetDtbContentsForSplTpl(self, dtb_data, name):
358 """Create a version of the main DTB for SPL or SPL
359
360 For testing we don't actually have different versions of the DTB. With
361 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
362 we don't normally have any unwanted nodes.
363
364 We still want the DTBs for SPL and TPL to be different though, since
365 otherwise it is confusing to know which one we are looking at. So add
366 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600367
368 Args:
369 dtb_data: dtb data to modify (this should be a value devicetree)
370 name: Name of a new property to add
371
372 Returns:
373 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600374 """
375 dtb = fdt.Fdt.FromData(dtb_data)
376 dtb.Scan()
377 dtb.GetNode('/binman').AddZeroProp(name)
378 dtb.Sync(auto_resize=True)
379 dtb.Pack()
380 return dtb.GetContents()
381
Simon Glassa87014e2018-07-06 10:27:42 -0600382 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glasse219aa42018-09-14 04:57:24 -0600383 update_dtb=False, entry_args=None, reset_dtbs=True):
Simon Glass57454f42016-11-25 20:15:52 -0700384 """Run binman and return the resulting image
385
386 This runs binman with a given test file and then reads the resulting
387 output file. It is a shortcut function since most tests need to do
388 these steps.
389
390 Raises an assertion failure if binman returns a non-zero exit code.
391
392 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600393 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700394 use_real_dtb: True to use the test file as the contents of
395 the u-boot-dtb entry. Normally this is not needed and the
396 test contents (the U_BOOT_DTB_DATA string) can be used.
397 But in some test we need the real contents.
Simon Glass30732662018-06-01 09:38:20 -0600398 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600399 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600400 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600401 entry_args: Dict of entry args to supply to binman
402 key: arg name
403 value: value of that arg
404 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
405 function. If reset_dtbs is True, then the original test dtb
406 is written back before this function finishes
Simon Glass72232452016-11-25 20:15:53 -0700407
408 Returns:
409 Tuple:
410 Resulting image contents
411 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600412 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600413 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700414 """
Simon Glass72232452016-11-25 20:15:53 -0700415 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700416 # Use the compiled test file as the u-boot-dtb input
417 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700418 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600419
420 # For testing purposes, make a copy of the DT for SPL and TPL. Add
421 # a node indicating which it is, so aid verification.
422 for name in ['spl', 'tpl']:
423 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
424 outfile = os.path.join(self._indir, dtb_fname)
425 TestFunctional._MakeInputFile(dtb_fname,
426 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700427
428 try:
Simon Glass91710b32018-07-17 13:25:32 -0600429 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glasse219aa42018-09-14 04:57:24 -0600430 entry_args=entry_args, use_real_dtb=use_real_dtb)
Simon Glass57454f42016-11-25 20:15:52 -0700431 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600432 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700433
434 # Find the (only) image, read it and return its contents
435 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600436 image_fname = tools.GetOutputFilename('image.bin')
437 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600438 if map:
439 map_fname = tools.GetOutputFilename('image.map')
440 with open(map_fname) as fd:
441 map_data = fd.read()
442 else:
443 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600444 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600445 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700446 finally:
447 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600448 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600449 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700450
Simon Glass5b4bce32019-07-08 14:25:26 -0600451 def _DoReadFileRealDtb(self, fname):
452 """Run binman with a real .dtb file and return the resulting data
453
454 Args:
455 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
456
457 Returns:
458 Resulting image contents
459 """
460 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
461
Simon Glass72232452016-11-25 20:15:53 -0700462 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600463 """Helper function which discards the device-tree binary
464
465 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600466 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600467 use_real_dtb: True to use the test file as the contents of
468 the u-boot-dtb entry. Normally this is not needed and the
469 test contents (the U_BOOT_DTB_DATA string) can be used.
470 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600471
472 Returns:
473 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600474 """
Simon Glass72232452016-11-25 20:15:53 -0700475 return self._DoReadFileDtb(fname, use_real_dtb)[0]
476
Simon Glass57454f42016-11-25 20:15:52 -0700477 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600478 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700479 """Create a new test input file, creating directories as needed
480
481 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600482 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700483 contents: File contents to write in to the file
484 Returns:
485 Full pathname of file created
486 """
Simon Glass862f8e22019-08-24 07:22:43 -0600487 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700488 dirname = os.path.dirname(pathname)
489 if dirname and not os.path.exists(dirname):
490 os.makedirs(dirname)
491 with open(pathname, 'wb') as fd:
492 fd.write(contents)
493 return pathname
494
495 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600496 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600497 """Create a new test input directory, creating directories as needed
498
499 Args:
500 dirname: Directory name to create
501
502 Returns:
503 Full pathname of directory created
504 """
Simon Glass862f8e22019-08-24 07:22:43 -0600505 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600506 if not os.path.exists(pathname):
507 os.makedirs(pathname)
508 return pathname
509
510 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600511 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600512 """Set up an ELF file with a '_dt_ucode_base_size' symbol
513
514 Args:
515 Filename of ELF file to use as SPL
516 """
Simon Glass93a806f2019-08-24 07:22:59 -0600517 TestFunctional._MakeInputFile('spl/u-boot-spl',
518 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600519
520 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600521 def _SetupTplElf(cls, src_fname='bss_data'):
522 """Set up an ELF file with a '_dt_ucode_base_size' symbol
523
524 Args:
525 Filename of ELF file to use as TPL
526 """
527 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
528 tools.ReadFile(cls.ElfTestFile(src_fname)))
529
530 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600531 def _SetupDescriptor(cls):
532 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
533 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
534
535 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600536 def TestFile(cls, fname):
537 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700538
Simon Glassf6290892019-08-24 07:22:53 -0600539 @classmethod
540 def ElfTestFile(cls, fname):
541 return os.path.join(cls._elf_testdir, fname)
542
Simon Glass57454f42016-11-25 20:15:52 -0700543 def AssertInList(self, grep_list, target):
544 """Assert that at least one of a list of things is in a target
545
546 Args:
547 grep_list: List of strings to check
548 target: Target string
549 """
550 for grep in grep_list:
551 if grep in target:
552 return
Simon Glass848cdb52019-05-17 22:00:50 -0600553 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700554
555 def CheckNoGaps(self, entries):
556 """Check that all entries fit together without gaps
557
558 Args:
559 entries: List of entries to check
560 """
Simon Glasse8561af2018-08-01 15:22:37 -0600561 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700562 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600563 self.assertEqual(offset, entry.offset)
564 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700565
Simon Glass72232452016-11-25 20:15:53 -0700566 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600567 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700568
569 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600570 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700571
572 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600573 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700574 """
575 return struct.unpack('>L', dtb[4:8])[0]
576
Simon Glass0f621332019-07-08 14:25:27 -0600577 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600578 def AddNode(node, path):
579 if node.name != '/':
580 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600581 for prop in node.props.values():
582 if prop.name in prop_names:
583 prop_path = path + ':' + prop.name
584 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
585 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600586 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600587 AddNode(subnode, path)
588
589 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600590 AddNode(dtb.GetRoot(), '')
591 return tree
592
Simon Glass57454f42016-11-25 20:15:52 -0700593 def testRun(self):
594 """Test a basic run with valid args"""
595 result = self._RunBinman('-h')
596
597 def testFullHelp(self):
598 """Test that the full help is displayed with -H"""
599 result = self._RunBinman('-H')
600 help_file = os.path.join(self._binman_dir, 'README')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500601 # Remove possible extraneous strings
602 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
603 gothelp = result.stdout.replace(extra, '')
604 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700605 self.assertEqual(0, len(result.stderr))
606 self.assertEqual(0, result.return_code)
607
608 def testFullHelpInternal(self):
609 """Test that the full help is displayed with -H"""
610 try:
611 command.test_result = command.CommandResult()
612 result = self._DoBinman('-H')
613 help_file = os.path.join(self._binman_dir, 'README')
614 finally:
615 command.test_result = None
616
617 def testHelp(self):
618 """Test that the basic help is displayed with -h"""
619 result = self._RunBinman('-h')
620 self.assertTrue(len(result.stdout) > 200)
621 self.assertEqual(0, len(result.stderr))
622 self.assertEqual(0, result.return_code)
623
Simon Glass57454f42016-11-25 20:15:52 -0700624 def testBoard(self):
625 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600626 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700627 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassf46732a2019-07-08 14:25:29 -0600628 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700629 self.assertEqual(0, result)
630
631 def testNeedBoard(self):
632 """Test that we get an error when no board ius supplied"""
633 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600634 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700635 self.assertIn("Must provide a board to process (use -b <board>)",
636 str(e.exception))
637
638 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600639 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700640 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600641 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700642 # We get one error from libfdt, and a different one from fdtget.
643 self.AssertInList(["Couldn't open blob from 'missing_file'",
644 'No such file or directory'], str(e.exception))
645
646 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600647 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700648
649 Since this is a source file it should be compiled and the error
650 will come from the device-tree compiler (dtc).
651 """
652 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600653 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700654 self.assertIn("FATAL ERROR: Unable to parse input tree",
655 str(e.exception))
656
657 def testMissingNode(self):
658 """Test that a device tree without a 'binman' node generates an error"""
659 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600660 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700661 self.assertIn("does not have a 'binman' node", str(e.exception))
662
663 def testEmpty(self):
664 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600665 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700666 self.assertEqual(0, len(result.stderr))
667 self.assertEqual(0, result.return_code)
668
669 def testInvalidEntry(self):
670 """Test that an invalid entry is flagged"""
671 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600672 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600673 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700674 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
675 "'/binman/not-a-valid-type'", str(e.exception))
676
677 def testSimple(self):
678 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600679 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700680 self.assertEqual(U_BOOT_DATA, data)
681
Simon Glass075a45c2017-11-13 18:55:00 -0700682 def testSimpleDebug(self):
683 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600684 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700685
Simon Glass57454f42016-11-25 20:15:52 -0700686 def testDual(self):
687 """Test that we can handle creating two images
688
689 This also tests image padding.
690 """
Simon Glass511f6582018-10-01 12:22:30 -0600691 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700692 self.assertEqual(0, retcode)
693
694 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600695 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700696 fname = tools.GetOutputFilename('image1.bin')
697 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600698 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700699 data = fd.read()
700 self.assertEqual(U_BOOT_DATA, data)
701
702 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600703 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700704 fname = tools.GetOutputFilename('image2.bin')
705 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600706 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700707 data = fd.read()
708 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600709 self.assertEqual(tools.GetBytes(0, 3), data[:3])
710 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700711
712 def testBadAlign(self):
713 """Test that an invalid alignment value is detected"""
714 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600715 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700716 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
717 "of two", str(e.exception))
718
719 def testPackSimple(self):
720 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600721 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700722 self.assertEqual(0, retcode)
723 self.assertIn('image', control.images)
724 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600725 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700726 self.assertEqual(5, len(entries))
727
728 # First u-boot
729 self.assertIn('u-boot', entries)
730 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600731 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700732 self.assertEqual(len(U_BOOT_DATA), entry.size)
733
734 # Second u-boot, aligned to 16-byte boundary
735 self.assertIn('u-boot-align', entries)
736 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600737 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700738 self.assertEqual(len(U_BOOT_DATA), entry.size)
739
740 # Third u-boot, size 23 bytes
741 self.assertIn('u-boot-size', entries)
742 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600743 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700744 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
745 self.assertEqual(23, entry.size)
746
747 # Fourth u-boot, placed immediate after the above
748 self.assertIn('u-boot-next', entries)
749 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600750 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700751 self.assertEqual(len(U_BOOT_DATA), entry.size)
752
Simon Glasse8561af2018-08-01 15:22:37 -0600753 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700754 self.assertIn('u-boot-fixed', entries)
755 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600756 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700757 self.assertEqual(len(U_BOOT_DATA), entry.size)
758
Simon Glass39dd2152019-07-08 14:25:47 -0600759 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700760
761 def testPackExtra(self):
762 """Test that extra packing feature works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600763 retcode = self._DoTestFile('009_pack_extra.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700764
765 self.assertEqual(0, retcode)
766 self.assertIn('image', control.images)
767 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600768 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700769 self.assertEqual(5, len(entries))
770
771 # First u-boot with padding before and after
772 self.assertIn('u-boot', entries)
773 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600774 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700775 self.assertEqual(3, entry.pad_before)
776 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
777
778 # Second u-boot has an aligned size, but it has no effect
779 self.assertIn('u-boot-align-size-nop', entries)
780 entry = entries['u-boot-align-size-nop']
Simon Glasse8561af2018-08-01 15:22:37 -0600781 self.assertEqual(12, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700782 self.assertEqual(4, entry.size)
783
784 # Third u-boot has an aligned size too
785 self.assertIn('u-boot-align-size', entries)
786 entry = entries['u-boot-align-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600787 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700788 self.assertEqual(32, entry.size)
789
790 # Fourth u-boot has an aligned end
791 self.assertIn('u-boot-align-end', entries)
792 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600793 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700794 self.assertEqual(16, entry.size)
795
796 # Fifth u-boot immediately afterwards
797 self.assertIn('u-boot-align-both', entries)
798 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600799 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700800 self.assertEqual(64, entry.size)
801
802 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600803 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700804
805 def testPackAlignPowerOf2(self):
806 """Test that invalid entry alignment is detected"""
807 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600808 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700809 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
810 "of two", str(e.exception))
811
812 def testPackAlignSizePowerOf2(self):
813 """Test that invalid entry size alignment is detected"""
814 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600815 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700816 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
817 "power of two", str(e.exception))
818
819 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600820 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700821 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600822 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600823 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700824 "align 0x4 (4)", str(e.exception))
825
826 def testPackInvalidSizeAlign(self):
827 """Test that invalid entry size alignment is detected"""
828 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600829 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700830 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
831 "align-size 0x4 (4)", str(e.exception))
832
833 def testPackOverlap(self):
834 """Test that overlapping regions are detected"""
835 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600836 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600837 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700838 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
839 str(e.exception))
840
841 def testPackEntryOverflow(self):
842 """Test that entries that overflow their size are detected"""
843 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600844 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700845 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
846 "but entry size is 0x3 (3)", str(e.exception))
847
848 def testPackImageOverflow(self):
849 """Test that entries which overflow the image size are detected"""
850 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600851 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600852 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700853 "size 0x3 (3)", str(e.exception))
854
855 def testPackImageSize(self):
856 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600857 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700858 self.assertEqual(0, retcode)
859 self.assertIn('image', control.images)
860 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600861 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700862
863 def testPackImageSizeAlign(self):
864 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600865 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700866 self.assertEqual(0, retcode)
867 self.assertIn('image', control.images)
868 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600869 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700870
871 def testPackInvalidImageAlign(self):
872 """Test that invalid image alignment is detected"""
873 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600874 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600875 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700876 "align-size 0x8 (8)", str(e.exception))
877
878 def testPackAlignPowerOf2(self):
879 """Test that invalid image alignment is detected"""
880 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600881 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600882 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700883 "two", str(e.exception))
884
885 def testImagePadByte(self):
886 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600887 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600888 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600889 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
890 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700891
892 def testImageName(self):
893 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600894 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700895 self.assertEqual(0, retcode)
896 image = control.images['image1']
897 fname = tools.GetOutputFilename('test-name')
898 self.assertTrue(os.path.exists(fname))
899
900 image = control.images['image2']
901 fname = tools.GetOutputFilename('test-name.xx')
902 self.assertTrue(os.path.exists(fname))
903
904 def testBlobFilename(self):
905 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600906 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700907 self.assertEqual(BLOB_DATA, data)
908
909 def testPackSorted(self):
910 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600911 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600912 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600913 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
914 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700915
Simon Glasse8561af2018-08-01 15:22:37 -0600916 def testPackZeroOffset(self):
917 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -0700918 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600919 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600920 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700921 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
922 str(e.exception))
923
924 def testPackUbootDtb(self):
925 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -0600926 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -0700928
929 def testPackX86RomNoSize(self):
930 """Test that the end-at-4gb property requires a size property"""
931 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600932 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600933 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -0700934 "using end-at-4gb", str(e.exception))
935
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530936 def test4gbAndSkipAtStartTogether(self):
937 """Test that the end-at-4gb and skip-at-size property can't be used
938 together"""
939 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -0600940 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600941 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +0530942 "'skip-at-start'", str(e.exception))
943
Simon Glass72232452016-11-25 20:15:53 -0700944 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600945 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -0700946 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600947 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600948 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) is outside "
Simon Glasseca32212018-06-01 09:38:12 -0600949 "the section starting at 0xffffffe0 (4294967264)",
Simon Glass72232452016-11-25 20:15:53 -0700950 str(e.exception))
951
952 def testPackX86Rom(self):
953 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -0600954 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -0600955 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -0600956 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -0600957 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -0700958
959 def testPackX86RomMeNoDesc(self):
960 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -0600961 try:
Simon Glass14c596c2020-07-25 15:11:19 -0600962 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -0600963 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -0600964 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -0600965 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
966 str(e.exception))
967 finally:
968 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700969
970 def testPackX86RomBadDesc(self):
971 """Test that the Intel requires a descriptor entry"""
972 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -0600973 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600974 self.assertIn("Node '/binman/intel-me': No offset set with "
975 "offset-unset: should another entry provide this correct "
976 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -0700977
978 def testPackX86RomMe(self):
979 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -0600980 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -0600981 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
982 if data[:0x1000] != expected_desc:
983 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -0700984 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
985
986 def testPackVga(self):
987 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -0600988 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -0700989 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
990
991 def testPackStart16(self):
992 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -0600993 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -0700994 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
995
Jagdish Gediya311d4842018-09-03 21:35:08 +0530996 def testPackPowerpcMpc85xxBootpgResetvec(self):
997 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
998 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -0600999 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301000 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1001
Simon Glass6ba679c2018-07-06 10:27:17 -06001002 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001003 """Handle running a test for insertion of microcode
1004
1005 Args:
1006 dts_fname: Name of test .dts file
1007 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001008 ucode_second: True if the microsecond entry is second instead of
1009 third
Simon Glass820af1d2018-07-06 10:27:16 -06001010
1011 Returns:
1012 Tuple:
1013 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001014 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001015 in the above (two 4-byte words)
1016 """
Simon Glass3d274232017-11-12 21:52:27 -07001017 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001018
1019 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001020 if ucode_second:
1021 ucode_content = data[len(nodtb_data):]
1022 ucode_pos = len(nodtb_data)
1023 dtb_with_ucode = ucode_content[16:]
1024 fdt_len = self.GetFdtLen(dtb_with_ucode)
1025 else:
1026 dtb_with_ucode = data[len(nodtb_data):]
1027 fdt_len = self.GetFdtLen(dtb_with_ucode)
1028 ucode_content = dtb_with_ucode[fdt_len:]
1029 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001030 fname = tools.GetOutputFilename('test.dtb')
1031 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001032 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001033 dtb = fdt.FdtScan(fname)
1034 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001035 self.assertTrue(ucode)
1036 for node in ucode.subnodes:
1037 self.assertFalse(node.props.get('data'))
1038
Simon Glass72232452016-11-25 20:15:53 -07001039 # Check that the microcode appears immediately after the Fdt
1040 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001041 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001042 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1043 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001044 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001045
1046 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001047 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001048 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1049 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001050 u_boot = data[:len(nodtb_data)]
1051 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001052
1053 def testPackUbootMicrocode(self):
1054 """Test that x86 microcode can be handled correctly
1055
1056 We expect to see the following in the image, in order:
1057 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1058 place
1059 u-boot.dtb with the microcode removed
1060 the microcode
1061 """
Simon Glass511f6582018-10-01 12:22:30 -06001062 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001063 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001064 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1065 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001066
Simon Glassbac25c82017-05-27 07:38:26 -06001067 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001068 """Test that x86 microcode can be handled correctly
1069
1070 We expect to see the following in the image, in order:
1071 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1072 place
1073 u-boot.dtb with the microcode
1074 an empty microcode region
1075 """
1076 # We need the libfdt library to run this test since only that allows
1077 # finding the offset of a property. This is required by
1078 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001079 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001080
1081 second = data[len(U_BOOT_NODTB_DATA):]
1082
1083 fdt_len = self.GetFdtLen(second)
1084 third = second[fdt_len:]
1085 second = second[:fdt_len]
1086
Simon Glassbac25c82017-05-27 07:38:26 -06001087 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1088 self.assertIn(ucode_data, second)
1089 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001090
Simon Glassbac25c82017-05-27 07:38:26 -06001091 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001092 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001093 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1094 len(ucode_data))
1095 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001096 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1097 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001098
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001099 def testPackUbootSingleMicrocode(self):
1100 """Test that x86 microcode can be handled correctly with fdt_normal.
1101 """
Simon Glassbac25c82017-05-27 07:38:26 -06001102 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001103
Simon Glass996021e2016-11-25 20:15:54 -07001104 def testUBootImg(self):
1105 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001106 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001107 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001108
1109 def testNoMicrocode(self):
1110 """Test that a missing microcode region is detected"""
1111 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001112 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001113 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1114 "node found in ", str(e.exception))
1115
1116 def testMicrocodeWithoutNode(self):
1117 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1118 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001119 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001120 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1121 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1122
1123 def testMicrocodeWithoutNode2(self):
1124 """Test that a missing u-boot-ucode node is detected"""
1125 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001126 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001127 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1128 "microcode region u-boot-ucode", str(e.exception))
1129
1130 def testMicrocodeWithoutPtrInElf(self):
1131 """Test that a U-Boot binary without the microcode symbol is detected"""
1132 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001133 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001134 TestFunctional._MakeInputFile('u-boot',
1135 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001136
1137 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001138 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001139 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1140 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1141
1142 finally:
1143 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001144 TestFunctional._MakeInputFile('u-boot',
1145 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001146
1147 def testMicrocodeNotInImage(self):
1148 """Test that microcode must be placed within the image"""
1149 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001150 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001151 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1152 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001153 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001154
1155 def testWithoutMicrocode(self):
1156 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001157 TestFunctional._MakeInputFile('u-boot',
1158 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001159 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001160
1161 # Now check the device tree has no microcode
1162 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1163 second = data[len(U_BOOT_NODTB_DATA):]
1164
1165 fdt_len = self.GetFdtLen(second)
1166 self.assertEqual(dtb, second[:fdt_len])
1167
1168 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1169 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001170 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001171
1172 def testUnknownPosSize(self):
1173 """Test that microcode must be placed within the image"""
1174 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001175 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001176 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001177 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001178
1179 def testPackFsp(self):
1180 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001181 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001182 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1183
1184 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001185 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001186 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001187 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001188
1189 def testPackVbt(self):
1190 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001191 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001192 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001193
Simon Glass7f94e832017-11-12 21:52:25 -07001194 def testSplBssPad(self):
1195 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001196 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001197 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001198 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001199 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1200 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001201
Simon Glass04cda032018-10-01 21:12:42 -06001202 def testSplBssPadMissing(self):
1203 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001204 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001205 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001206 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001207 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1208 str(e.exception))
1209
Simon Glasse83679d2017-11-12 21:52:26 -07001210 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001211 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001212 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001213 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1214
Simon Glass6ba679c2018-07-06 10:27:17 -06001215 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1216 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001217
1218 We expect to see the following in the image, in order:
1219 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1220 correct place
1221 u-boot.dtb with the microcode removed
1222 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001223
1224 Args:
1225 dts: Device tree file to use for test
1226 ucode_second: True if the microsecond entry is second instead of
1227 third
Simon Glass3d274232017-11-12 21:52:27 -07001228 """
Simon Glass7057d022018-10-01 21:12:47 -06001229 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001230 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1231 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001232 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1233 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001234
Simon Glass6ba679c2018-07-06 10:27:17 -06001235 def testPackUbootSplMicrocode(self):
1236 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001237 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001238
1239 def testPackUbootSplMicrocodeReorder(self):
1240 """Test that order doesn't matter for microcode entries
1241
1242 This is the same as testPackUbootSplMicrocode but when we process the
1243 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1244 entry, so we reply on binman to try later.
1245 """
Simon Glass511f6582018-10-01 12:22:30 -06001246 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001247 ucode_second=True)
1248
Simon Glassa409c932017-11-12 21:52:28 -07001249 def testPackMrc(self):
1250 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001251 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001252 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1253
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001254 def testSplDtb(self):
1255 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001256 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001257 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1258
Simon Glass0a6da312017-11-13 18:54:56 -07001259 def testSplNoDtb(self):
1260 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001261 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001262 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1263
Simon Glass4ca8e042017-11-13 18:55:01 -07001264 def testSymbols(self):
1265 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass5d0c0262019-08-24 07:22:56 -06001266 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001267 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1268 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glasse8561af2018-08-01 15:22:37 -06001269 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001270
Simon Glass7057d022018-10-01 21:12:47 -06001271 self._SetupSplElf('u_boot_binman_syms')
Simon Glass511f6582018-10-01 12:22:30 -06001272 data = self._DoReadFile('053_symbols.dts')
Simon Glass72555fa2019-11-06 17:22:44 -07001273 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glass3f8ff012019-08-24 07:23:05 -06001274 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001275 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass3f8ff012019-08-24 07:23:05 -06001276 U_BOOT_SPL_DATA[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001277 self.assertEqual(expected, data)
1278
Simon Glasse76a3e62018-06-01 09:38:11 -06001279 def testPackUnitAddress(self):
1280 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001281 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001282 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1283
Simon Glassa91e1152018-06-01 09:38:16 -06001284 def testSections(self):
1285 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001286 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001287 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1288 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1289 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001290 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001291
Simon Glass30732662018-06-01 09:38:20 -06001292 def testMap(self):
1293 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001294 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001295 self.assertEqual('''ImagePos Offset Size Name
129600000000 00000000 00000028 main-section
129700000000 00000000 00000010 section@0
129800000000 00000000 00000004 u-boot
129900000010 00000010 00000010 section@1
130000000010 00000000 00000004 u-boot
130100000020 00000020 00000004 section@2
130200000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001303''', map_data)
1304
Simon Glass3b78d532018-06-01 09:38:21 -06001305 def testNamePrefix(self):
1306 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001307 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001308 self.assertEqual('''ImagePos Offset Size Name
130900000000 00000000 00000028 main-section
131000000000 00000000 00000010 section@0
131100000000 00000000 00000004 ro-u-boot
131200000010 00000010 00000010 section@1
131300000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001314''', map_data)
1315
Simon Glass6ba679c2018-07-06 10:27:17 -06001316 def testUnknownContents(self):
1317 """Test that obtaining the contents works as expected"""
1318 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001319 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001320 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001321 "processing of contents: remaining ["
1322 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001323
Simon Glass2e1169f2018-07-06 10:27:19 -06001324 def testBadChangeSize(self):
1325 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001326 try:
1327 state.SetAllowEntryExpansion(False)
1328 with self.assertRaises(ValueError) as e:
1329 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001330 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001331 str(e.exception))
1332 finally:
1333 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001334
Simon Glassa87014e2018-07-06 10:27:42 -06001335 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001336 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001337 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001338 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001339 dtb = fdt.Fdt(out_dtb_fname)
1340 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001341 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001342 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001343 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001344 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001345 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001346 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001347 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001348 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001349 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001350 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001351 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001352 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001353 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001354
Simon Glasse8561af2018-08-01 15:22:37 -06001355 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001356 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001357 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001358 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001359 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001360 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001361 'size': 40
1362 }, props)
1363
1364 def testUpdateFdtBad(self):
1365 """Test that we detect when ProcessFdt never completes"""
1366 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001367 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001368 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001369 '[<binman.etype._testing.Entry__testing',
1370 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001371
Simon Glass91710b32018-07-17 13:25:32 -06001372 def testEntryArgs(self):
1373 """Test passing arguments to entries from the command line"""
1374 entry_args = {
1375 'test-str-arg': 'test1',
1376 'test-int-arg': '456',
1377 }
Simon Glass511f6582018-10-01 12:22:30 -06001378 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001379 self.assertIn('image', control.images)
1380 entry = control.images['image'].GetEntries()['_testing']
1381 self.assertEqual('test0', entry.test_str_fdt)
1382 self.assertEqual('test1', entry.test_str_arg)
1383 self.assertEqual(123, entry.test_int_fdt)
1384 self.assertEqual(456, entry.test_int_arg)
1385
1386 def testEntryArgsMissing(self):
1387 """Test missing arguments and properties"""
1388 entry_args = {
1389 'test-int-arg': '456',
1390 }
Simon Glass511f6582018-10-01 12:22:30 -06001391 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001392 entry = control.images['image'].GetEntries()['_testing']
1393 self.assertEqual('test0', entry.test_str_fdt)
1394 self.assertEqual(None, entry.test_str_arg)
1395 self.assertEqual(None, entry.test_int_fdt)
1396 self.assertEqual(456, entry.test_int_arg)
1397
1398 def testEntryArgsRequired(self):
1399 """Test missing arguments and properties"""
1400 entry_args = {
1401 'test-int-arg': '456',
1402 }
1403 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001404 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001405 self.assertIn("Node '/binman/_testing': "
1406 'Missing required properties/entry args: test-str-arg, '
1407 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001408 str(e.exception))
1409
1410 def testEntryArgsInvalidFormat(self):
1411 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001412 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1413 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001414 with self.assertRaises(ValueError) as e:
1415 self._DoBinman(*args)
1416 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1417
1418 def testEntryArgsInvalidInteger(self):
1419 """Test that an invalid entry-argument integer is detected"""
1420 entry_args = {
1421 'test-int-arg': 'abc',
1422 }
1423 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001424 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001425 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1426 "'test-int-arg' (value 'abc') to integer",
1427 str(e.exception))
1428
1429 def testEntryArgsInvalidDatatype(self):
1430 """Test that an invalid entry-argument datatype is detected
1431
1432 This test could be written in entry_test.py except that it needs
1433 access to control.entry_args, which seems more than that module should
1434 be able to see.
1435 """
1436 entry_args = {
1437 'test-bad-datatype-arg': '12',
1438 }
1439 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001440 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001441 entry_args=entry_args)
1442 self.assertIn('GetArg() internal error: Unknown data type ',
1443 str(e.exception))
1444
Simon Glass2ca52032018-07-17 13:25:33 -06001445 def testText(self):
1446 """Test for a text entry type"""
1447 entry_args = {
1448 'test-id': TEXT_DATA,
1449 'test-id2': TEXT_DATA2,
1450 'test-id3': TEXT_DATA3,
1451 }
Simon Glass511f6582018-10-01 12:22:30 -06001452 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001453 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001454 expected = (tools.ToBytes(TEXT_DATA) +
1455 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1456 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001457 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001458 self.assertEqual(expected, data)
1459
Simon Glass969616c2018-07-17 13:25:36 -06001460 def testEntryDocs(self):
1461 """Test for creation of entry documentation"""
1462 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001463 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001464 self.assertTrue(len(stdout.getvalue()) > 0)
1465
1466 def testEntryDocsMissing(self):
1467 """Test handling of missing entry documentation"""
1468 with self.assertRaises(ValueError) as e:
1469 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001470 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001471 self.assertIn('Documentation is missing for modules: u_boot',
1472 str(e.exception))
1473
Simon Glass704784b2018-07-17 13:25:38 -06001474 def testFmap(self):
1475 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001476 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001477 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001478 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1479 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001480 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001481 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001482 self.assertEqual(1, fhdr.ver_major)
1483 self.assertEqual(0, fhdr.ver_minor)
1484 self.assertEqual(0, fhdr.base)
1485 self.assertEqual(16 + 16 +
1486 fmap_util.FMAP_HEADER_LEN +
1487 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001488 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass704784b2018-07-17 13:25:38 -06001489 self.assertEqual(3, fhdr.nareas)
1490 for fentry in fentries:
1491 self.assertEqual(0, fentry.flags)
1492
1493 self.assertEqual(0, fentries[0].offset)
1494 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001495 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass704784b2018-07-17 13:25:38 -06001496
1497 self.assertEqual(16, fentries[1].offset)
1498 self.assertEqual(4, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001499 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass704784b2018-07-17 13:25:38 -06001500
1501 self.assertEqual(32, fentries[2].offset)
1502 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1503 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001504 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass704784b2018-07-17 13:25:38 -06001505
Simon Glassdb168d42018-07-17 13:25:39 -06001506 def testBlobNamedByArg(self):
1507 """Test we can add a blob with the filename coming from an entry arg"""
1508 entry_args = {
1509 'cros-ec-rw-path': 'ecrw.bin',
1510 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001511 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001512
Simon Glass53f53992018-07-17 13:25:40 -06001513 def testFill(self):
1514 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001515 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001516 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001517 self.assertEqual(expected, data)
1518
1519 def testFillNoSize(self):
1520 """Test for an fill entry type with no size"""
1521 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001522 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001523 self.assertIn("'fill' entry must have a size property",
1524 str(e.exception))
1525
Simon Glassc1ae83c2018-07-17 13:25:44 -06001526 def _HandleGbbCommand(self, pipe_list):
1527 """Fake calls to the futility utility"""
1528 if pipe_list[0][0] == 'futility':
1529 fname = pipe_list[0][-1]
1530 # Append our GBB data to the file, which will happen every time the
1531 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001532 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001533 fd.write(GBB_DATA)
1534 return command.CommandResult()
1535
1536 def testGbb(self):
1537 """Test for the Chromium OS Google Binary Block"""
1538 command.test_result = self._HandleGbbCommand
1539 entry_args = {
1540 'keydir': 'devkeys',
1541 'bmpblk': 'bmpblk.bin',
1542 }
Simon Glass511f6582018-10-01 12:22:30 -06001543 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001544
1545 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001546 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1547 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001548 self.assertEqual(expected, data)
1549
1550 def testGbbTooSmall(self):
1551 """Test for the Chromium OS Google Binary Block being large enough"""
1552 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001553 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001554 self.assertIn("Node '/binman/gbb': GBB is too small",
1555 str(e.exception))
1556
1557 def testGbbNoSize(self):
1558 """Test for the Chromium OS Google Binary Block having a size"""
1559 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001560 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001561 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1562 str(e.exception))
1563
Simon Glass5c350162018-07-17 13:25:47 -06001564 def _HandleVblockCommand(self, pipe_list):
1565 """Fake calls to the futility utility"""
1566 if pipe_list[0][0] == 'futility':
1567 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001568 with open(fname, 'wb') as fd:
Simon Glass5c350162018-07-17 13:25:47 -06001569 fd.write(VBLOCK_DATA)
1570 return command.CommandResult()
1571
1572 def testVblock(self):
1573 """Test for the Chromium OS Verified Boot Block"""
1574 command.test_result = self._HandleVblockCommand
1575 entry_args = {
1576 'keydir': 'devkeys',
1577 }
Simon Glass511f6582018-10-01 12:22:30 -06001578 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001579 entry_args=entry_args)
1580 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1581 self.assertEqual(expected, data)
1582
1583 def testVblockNoContent(self):
1584 """Test we detect a vblock which has no content to sign"""
1585 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001586 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001587 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1588 'property', str(e.exception))
1589
1590 def testVblockBadPhandle(self):
1591 """Test that we detect a vblock with an invalid phandle in contents"""
1592 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001593 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001594 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1595 '1000', str(e.exception))
1596
1597 def testVblockBadEntry(self):
1598 """Test that we detect an entry that points to a non-entry"""
1599 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001600 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001601 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1602 "'other'", str(e.exception))
1603
Simon Glass8425a1f2018-07-17 13:25:48 -06001604 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001605 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001606 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001607 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001608 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001609 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1610
Simon Glass24b97442018-07-17 13:25:51 -06001611 def testUsesPos(self):
1612 """Test that the 'pos' property cannot be used anymore"""
1613 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001614 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001615 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1616 "'pos'", str(e.exception))
1617
Simon Glass274bf092018-09-14 04:57:08 -06001618 def testFillZero(self):
1619 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001620 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001621 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001622
Simon Glass267de432018-09-14 04:57:09 -06001623 def testTextMissing(self):
1624 """Test for a text entry type where there is no text"""
1625 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001626 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001627 self.assertIn("Node '/binman/text': No value provided for text label "
1628 "'test-id'", str(e.exception))
1629
Simon Glassed40e962018-09-14 04:57:10 -06001630 def testPackStart16Tpl(self):
1631 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001632 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001633 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1634
Simon Glass3b376c32018-09-14 04:57:12 -06001635 def testSelectImage(self):
1636 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001637 expected = 'Skipping images: image1'
1638
1639 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001640 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001641 with test_util.capture_sys_output() as (stdout, stderr):
1642 retcode = self._DoTestFile('006_dual_image.dts',
1643 verbosity=verbosity,
1644 images=['image2'])
1645 self.assertEqual(0, retcode)
1646 if verbosity:
1647 self.assertIn(expected, stdout.getvalue())
1648 else:
1649 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001650
Simon Glassb4595d82019-04-25 21:58:34 -06001651 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1652 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001653 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001654
Simon Glasse219aa42018-09-14 04:57:24 -06001655 def testUpdateFdtAll(self):
1656 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001657 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001658
1659 base_expected = {
1660 'section:image-pos': 0,
1661 'u-boot-tpl-dtb:size': 513,
1662 'u-boot-spl-dtb:size': 513,
1663 'u-boot-spl-dtb:offset': 493,
1664 'image-pos': 0,
1665 'section/u-boot-dtb:image-pos': 0,
1666 'u-boot-spl-dtb:image-pos': 493,
1667 'section/u-boot-dtb:size': 493,
1668 'u-boot-tpl-dtb:image-pos': 1006,
1669 'section/u-boot-dtb:offset': 0,
1670 'section:size': 493,
1671 'offset': 0,
1672 'section:offset': 0,
1673 'u-boot-tpl-dtb:offset': 1006,
1674 'size': 1519
1675 }
1676
1677 # We expect three device-tree files in the output, one after the other.
1678 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1679 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1680 # main U-Boot tree. All three should have the same postions and offset.
1681 start = 0
1682 for item in ['', 'spl', 'tpl']:
1683 dtb = fdt.Fdt.FromData(data[start:])
1684 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001685 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1686 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001687 expected = dict(base_expected)
1688 if item:
1689 expected[item] = 0
1690 self.assertEqual(expected, props)
1691 start += dtb._fdt_obj.totalsize()
1692
1693 def testUpdateFdtOutput(self):
1694 """Test that output DTB files are updated"""
1695 try:
Simon Glass511f6582018-10-01 12:22:30 -06001696 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001697 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1698
1699 # Unfortunately, compiling a source file always results in a file
1700 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001701 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001702 # binman as a file called u-boot.dtb. To fix this, copy the file
1703 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001704 start = 0
1705 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1706 'tpl/u-boot-tpl.dtb.out']:
1707 dtb = fdt.Fdt.FromData(data[start:])
1708 size = dtb._fdt_obj.totalsize()
1709 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1710 outdata = tools.ReadFile(pathname)
1711 name = os.path.split(fname)[0]
1712
1713 if name:
1714 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1715 else:
1716 orig_indata = dtb_data
1717 self.assertNotEqual(outdata, orig_indata,
1718 "Expected output file '%s' be updated" % pathname)
1719 self.assertEqual(outdata, data[start:start + size],
1720 "Expected output file '%s' to match output image" %
1721 pathname)
1722 start += size
1723 finally:
1724 self._ResetDtbs()
1725
Simon Glass7ba33592018-09-14 04:57:26 -06001726 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001727 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001728
1729 def testCompress(self):
1730 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001731 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001732 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001733 use_real_dtb=True, update_dtb=True)
1734 dtb = fdt.Fdt(out_dtb_fname)
1735 dtb.Scan()
1736 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1737 orig = self._decompress(data)
1738 self.assertEquals(COMPRESS_DATA, orig)
1739 expected = {
1740 'blob:uncomp-size': len(COMPRESS_DATA),
1741 'blob:size': len(data),
1742 'size': len(data),
1743 }
1744 self.assertEqual(expected, props)
1745
Simon Glassac6328c2018-09-14 04:57:28 -06001746 def testFiles(self):
1747 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001748 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001749 self.assertEqual(FILES_DATA, data)
1750
1751 def testFilesCompress(self):
1752 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001753 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001754 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001755
1756 image = control.images['image']
1757 entries = image.GetEntries()
1758 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001759 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001760
Simon Glass303f62f2019-05-17 22:00:46 -06001761 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001762 for i in range(1, 3):
1763 key = '%d.dat' % i
1764 start = entries[key].image_pos
1765 len = entries[key].size
1766 chunk = data[start:start + len]
1767 orig += self._decompress(chunk)
1768
1769 self.assertEqual(FILES_DATA, orig)
1770
1771 def testFilesMissing(self):
1772 """Test missing files"""
1773 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001774 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001775 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1776 'no files', str(e.exception))
1777
1778 def testFilesNoPattern(self):
1779 """Test missing files"""
1780 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001781 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001782 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1783 str(e.exception))
1784
Simon Glassfa79a812018-09-14 04:57:29 -06001785 def testExpandSize(self):
1786 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001787 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001788 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001789 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1790 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1791 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1792 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001793 self.assertEqual(expect, data)
1794 self.assertEqual('''ImagePos Offset Size Name
179500000000 00000000 00000028 main-section
179600000000 00000000 00000008 fill
179700000008 00000008 00000004 u-boot
17980000000c 0000000c 00000004 section
17990000000c 00000000 00000003 intel-mrc
180000000010 00000010 00000004 u-boot2
180100000014 00000014 0000000c section2
180200000014 00000000 00000008 fill
18030000001c 00000008 00000004 u-boot
180400000020 00000020 00000008 fill2
1805''', map_data)
1806
1807 def testExpandSizeBad(self):
1808 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001809 with test_util.capture_sys_output() as (stdout, stderr):
1810 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001811 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001812 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1813 'expanding entry', str(e.exception))
1814
Simon Glassae7cf032018-09-14 04:57:31 -06001815 def testHash(self):
1816 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001817 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001818 use_real_dtb=True, update_dtb=True)
1819 dtb = fdt.Fdt(out_dtb_fname)
1820 dtb.Scan()
1821 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1822 m = hashlib.sha256()
1823 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001824 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001825
1826 def testHashNoAlgo(self):
1827 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001828 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001829 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1830 'hash node', str(e.exception))
1831
1832 def testHashBadAlgo(self):
1833 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001834 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001835 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1836 str(e.exception))
1837
1838 def testHashSection(self):
1839 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001840 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001841 use_real_dtb=True, update_dtb=True)
1842 dtb = fdt.Fdt(out_dtb_fname)
1843 dtb.Scan()
1844 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1845 m = hashlib.sha256()
1846 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001847 m.update(tools.GetBytes(ord('a'), 16))
1848 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001849
Simon Glass3fb4f422018-09-14 04:57:32 -06001850 def testPackUBootTplMicrocode(self):
1851 """Test that x86 microcode can be handled correctly in TPL
1852
1853 We expect to see the following in the image, in order:
1854 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1855 place
1856 u-boot-tpl.dtb with the microcode removed
1857 the microcode
1858 """
Simon Glass3eb5b202019-08-24 07:23:00 -06001859 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06001860 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06001861 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001862 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1863 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06001864
Simon Glassc64aea52018-09-14 04:57:34 -06001865 def testFmapX86(self):
1866 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001867 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001868 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001869 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001870 self.assertEqual(expected, data[:32])
1871 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1872
1873 self.assertEqual(0x100, fhdr.image_size)
1874
1875 self.assertEqual(0, fentries[0].offset)
1876 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001877 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001878
1879 self.assertEqual(4, fentries[1].offset)
1880 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001881 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001882
1883 self.assertEqual(32, fentries[2].offset)
1884 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1885 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001886 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001887
1888 def testFmapX86Section(self):
1889 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001890 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001891 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001892 self.assertEqual(expected, data[:32])
1893 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1894
1895 self.assertEqual(0x100, fhdr.image_size)
1896
1897 self.assertEqual(0, fentries[0].offset)
1898 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001899 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001900
1901 self.assertEqual(4, fentries[1].offset)
1902 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001903 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001904
1905 self.assertEqual(36, fentries[2].offset)
1906 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1907 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001908 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001909
Simon Glassb1714232018-09-14 04:57:35 -06001910 def testElf(self):
1911 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001912 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06001913 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06001914 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001915 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001916 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001917
Simon Glass0d673792019-07-08 13:18:25 -06001918 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06001919 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06001920 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06001921 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06001922 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06001923 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06001924
Simon Glasscd817d52018-09-14 04:57:36 -06001925 def testPackOverlapMap(self):
1926 """Test that overlapping regions are detected"""
1927 with test_util.capture_sys_output() as (stdout, stderr):
1928 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001929 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06001930 map_fname = tools.GetOutputFilename('image.map')
1931 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
1932 stdout.getvalue())
1933
1934 # We should not get an inmage, but there should be a map file
1935 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
1936 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06001937 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06001938 self.assertEqual('''ImagePos Offset Size Name
1939<none> 00000000 00000007 main-section
1940<none> 00000000 00000004 u-boot
1941<none> 00000003 00000004 u-boot-align
1942''', map_data)
1943
Simon Glass0d673792019-07-08 13:18:25 -06001944 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06001945 """Test that an image with an Intel Reference code binary works"""
1946 data = self._DoReadFile('100_intel_refcode.dts')
1947 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
1948
Simon Glasseb023b32019-04-25 21:58:39 -06001949 def testSectionOffset(self):
1950 """Tests use of a section with an offset"""
1951 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
1952 map=True)
1953 self.assertEqual('''ImagePos Offset Size Name
195400000000 00000000 00000038 main-section
195500000004 00000004 00000010 section@0
195600000004 00000000 00000004 u-boot
195700000018 00000018 00000010 section@1
195800000018 00000000 00000004 u-boot
19590000002c 0000002c 00000004 section@2
19600000002c 00000000 00000004 u-boot
1961''', map_data)
1962 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06001963 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1964 tools.GetBytes(0x21, 12) +
1965 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1966 tools.GetBytes(0x61, 12) +
1967 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
1968 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06001969
Simon Glass1de34482019-07-08 13:18:53 -06001970 def testCbfsRaw(self):
1971 """Test base handling of a Coreboot Filesystem (CBFS)
1972
1973 The exact contents of the CBFS is verified by similar tests in
1974 cbfs_util_test.py. The tests here merely check that the files added to
1975 the CBFS can be found in the final image.
1976 """
1977 data = self._DoReadFile('102_cbfs_raw.dts')
1978 size = 0xb0
1979
1980 cbfs = cbfs_util.CbfsReader(data)
1981 self.assertEqual(size, cbfs.rom_size)
1982
1983 self.assertIn('u-boot-dtb', cbfs.files)
1984 cfile = cbfs.files['u-boot-dtb']
1985 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1986
1987 def testCbfsArch(self):
1988 """Test on non-x86 architecture"""
1989 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
1990 size = 0x100
1991
1992 cbfs = cbfs_util.CbfsReader(data)
1993 self.assertEqual(size, cbfs.rom_size)
1994
1995 self.assertIn('u-boot-dtb', cbfs.files)
1996 cfile = cbfs.files['u-boot-dtb']
1997 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
1998
1999 def testCbfsStage(self):
2000 """Tests handling of a Coreboot Filesystem (CBFS)"""
2001 if not elf.ELF_TOOLS:
2002 self.skipTest('Python elftools not available')
2003 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2004 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2005 size = 0xb0
2006
2007 data = self._DoReadFile('104_cbfs_stage.dts')
2008 cbfs = cbfs_util.CbfsReader(data)
2009 self.assertEqual(size, cbfs.rom_size)
2010
2011 self.assertIn('u-boot', cbfs.files)
2012 cfile = cbfs.files['u-boot']
2013 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2014
2015 def testCbfsRawCompress(self):
2016 """Test handling of compressing raw files"""
2017 self._CheckLz4()
2018 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2019 size = 0x140
2020
2021 cbfs = cbfs_util.CbfsReader(data)
2022 self.assertIn('u-boot', cbfs.files)
2023 cfile = cbfs.files['u-boot']
2024 self.assertEqual(COMPRESS_DATA, cfile.data)
2025
2026 def testCbfsBadArch(self):
2027 """Test handling of a bad architecture"""
2028 with self.assertRaises(ValueError) as e:
2029 self._DoReadFile('106_cbfs_bad_arch.dts')
2030 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2031
2032 def testCbfsNoSize(self):
2033 """Test handling of a missing size property"""
2034 with self.assertRaises(ValueError) as e:
2035 self._DoReadFile('107_cbfs_no_size.dts')
2036 self.assertIn('entry must have a size property', str(e.exception))
2037
2038 def testCbfsNoCOntents(self):
2039 """Test handling of a CBFS entry which does not provide contentsy"""
2040 with self.assertRaises(ValueError) as e:
2041 self._DoReadFile('108_cbfs_no_contents.dts')
2042 self.assertIn('Could not complete processing of contents',
2043 str(e.exception))
2044
2045 def testCbfsBadCompress(self):
2046 """Test handling of a bad architecture"""
2047 with self.assertRaises(ValueError) as e:
2048 self._DoReadFile('109_cbfs_bad_compress.dts')
2049 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2050 str(e.exception))
2051
2052 def testCbfsNamedEntries(self):
2053 """Test handling of named entries"""
2054 data = self._DoReadFile('110_cbfs_name.dts')
2055
2056 cbfs = cbfs_util.CbfsReader(data)
2057 self.assertIn('FRED', cbfs.files)
2058 cfile1 = cbfs.files['FRED']
2059 self.assertEqual(U_BOOT_DATA, cfile1.data)
2060
2061 self.assertIn('hello', cbfs.files)
2062 cfile2 = cbfs.files['hello']
2063 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2064
Simon Glass759af872019-07-08 13:18:54 -06002065 def _SetupIfwi(self, fname):
2066 """Set up to run an IFWI test
2067
2068 Args:
2069 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2070 """
2071 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002072 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002073
2074 # Intel Integrated Firmware Image (IFWI) file
2075 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2076 data = fd.read()
2077 TestFunctional._MakeInputFile(fname,data)
2078
2079 def _CheckIfwi(self, data):
2080 """Check that an image with an IFWI contains the correct output
2081
2082 Args:
2083 data: Conents of output file
2084 """
2085 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2086 if data[:0x1000] != expected_desc:
2087 self.fail('Expected descriptor binary at start of image')
2088
2089 # We expect to find the TPL wil in subpart IBBP entry IBBL
2090 image_fname = tools.GetOutputFilename('image.bin')
2091 tpl_fname = tools.GetOutputFilename('tpl.out')
2092 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2093 subpart='IBBP', entry_name='IBBL')
2094
2095 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002096 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002097
2098 def testPackX86RomIfwi(self):
2099 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2100 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002101 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002102 self._CheckIfwi(data)
2103
2104 def testPackX86RomIfwiNoDesc(self):
2105 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2106 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002107 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002108 self._CheckIfwi(data)
2109
2110 def testPackX86RomIfwiNoData(self):
2111 """Test that an x86 ROM with IFWI handles missing data"""
2112 self._SetupIfwi('ifwi.bin')
2113 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002114 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002115 self.assertIn('Could not complete processing of contents',
2116 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002117
Simon Glassc2f1aed2019-07-08 13:18:56 -06002118 def testCbfsOffset(self):
2119 """Test a CBFS with files at particular offsets
2120
2121 Like all CFBS tests, this is just checking the logic that calls
2122 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2123 """
2124 data = self._DoReadFile('114_cbfs_offset.dts')
2125 size = 0x200
2126
2127 cbfs = cbfs_util.CbfsReader(data)
2128 self.assertEqual(size, cbfs.rom_size)
2129
2130 self.assertIn('u-boot', cbfs.files)
2131 cfile = cbfs.files['u-boot']
2132 self.assertEqual(U_BOOT_DATA, cfile.data)
2133 self.assertEqual(0x40, cfile.cbfs_offset)
2134
2135 self.assertIn('u-boot-dtb', cbfs.files)
2136 cfile2 = cbfs.files['u-boot-dtb']
2137 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2138 self.assertEqual(0x140, cfile2.cbfs_offset)
2139
Simon Glass0f621332019-07-08 14:25:27 -06002140 def testFdtmap(self):
2141 """Test an FDT map can be inserted in the image"""
2142 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2143 fdtmap_data = data[len(U_BOOT_DATA):]
2144 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002145 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002146 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2147
2148 fdt_data = fdtmap_data[16:]
2149 dtb = fdt.Fdt.FromData(fdt_data)
2150 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002151 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002152 self.assertEqual({
2153 'image-pos': 0,
2154 'offset': 0,
2155 'u-boot:offset': 0,
2156 'u-boot:size': len(U_BOOT_DATA),
2157 'u-boot:image-pos': 0,
2158 'fdtmap:image-pos': 4,
2159 'fdtmap:offset': 4,
2160 'fdtmap:size': len(fdtmap_data),
2161 'size': len(data),
2162 }, props)
2163
2164 def testFdtmapNoMatch(self):
2165 """Check handling of an FDT map when the section cannot be found"""
2166 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2167
2168 # Mangle the section name, which should cause a mismatch between the
2169 # correct FDT path and the one expected by the section
2170 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002171 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002172 entries = image.GetEntries()
2173 fdtmap = entries['fdtmap']
2174 with self.assertRaises(ValueError) as e:
2175 fdtmap._GetFdtmap()
2176 self.assertIn("Cannot locate node for path '/binman-suffix'",
2177 str(e.exception))
2178
Simon Glasscec34ba2019-07-08 14:25:28 -06002179 def testFdtmapHeader(self):
2180 """Test an FDT map and image header can be inserted in the image"""
2181 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2182 fdtmap_pos = len(U_BOOT_DATA)
2183 fdtmap_data = data[fdtmap_pos:]
2184 fdt_data = fdtmap_data[16:]
2185 dtb = fdt.Fdt.FromData(fdt_data)
2186 fdt_size = dtb.GetFdtObj().totalsize()
2187 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002188 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002189 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2190 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2191
2192 def testFdtmapHeaderStart(self):
2193 """Test an image header can be inserted at the image start"""
2194 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2195 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2196 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002197 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002198 offset = struct.unpack('<I', hdr_data[4:])[0]
2199 self.assertEqual(fdtmap_pos, offset)
2200
2201 def testFdtmapHeaderPos(self):
2202 """Test an image header can be inserted at a chosen position"""
2203 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2204 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2205 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002206 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002207 offset = struct.unpack('<I', hdr_data[4:])[0]
2208 self.assertEqual(fdtmap_pos, offset)
2209
2210 def testHeaderMissingFdtmap(self):
2211 """Test an image header requires an fdtmap"""
2212 with self.assertRaises(ValueError) as e:
2213 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2214 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2215 str(e.exception))
2216
2217 def testHeaderNoLocation(self):
2218 """Test an image header with a no specified location is detected"""
2219 with self.assertRaises(ValueError) as e:
2220 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2221 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2222 str(e.exception))
2223
Simon Glasse61b6f62019-07-08 14:25:37 -06002224 def testEntryExpand(self):
2225 """Test expanding an entry after it is packed"""
2226 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002227 self.assertEqual(b'aaa', data[:3])
2228 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2229 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002230
2231 def testEntryExpandBad(self):
2232 """Test expanding an entry after it is packed, twice"""
2233 with self.assertRaises(ValueError) as e:
2234 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002235 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002236 str(e.exception))
2237
2238 def testEntryExpandSection(self):
2239 """Test expanding an entry within a section after it is packed"""
2240 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002241 self.assertEqual(b'aaa', data[:3])
2242 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2243 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002244
Simon Glass90d29682019-07-08 14:25:38 -06002245 def testCompressDtb(self):
2246 """Test that compress of device-tree files is supported"""
2247 self._CheckLz4()
2248 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2249 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2250 comp_data = data[len(U_BOOT_DATA):]
2251 orig = self._decompress(comp_data)
2252 dtb = fdt.Fdt.FromData(orig)
2253 dtb.Scan()
2254 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2255 expected = {
2256 'u-boot:size': len(U_BOOT_DATA),
2257 'u-boot-dtb:uncomp-size': len(orig),
2258 'u-boot-dtb:size': len(comp_data),
2259 'size': len(data),
2260 }
2261 self.assertEqual(expected, props)
2262
Simon Glass151bbbf2019-07-08 14:25:41 -06002263 def testCbfsUpdateFdt(self):
2264 """Test that we can update the device tree with CBFS offset/size info"""
2265 self._CheckLz4()
2266 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2267 update_dtb=True)
2268 dtb = fdt.Fdt(out_dtb_fname)
2269 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002270 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002271 del props['cbfs/u-boot:size']
2272 self.assertEqual({
2273 'offset': 0,
2274 'size': len(data),
2275 'image-pos': 0,
2276 'cbfs:offset': 0,
2277 'cbfs:size': len(data),
2278 'cbfs:image-pos': 0,
2279 'cbfs/u-boot:offset': 0x38,
2280 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2281 'cbfs/u-boot:image-pos': 0x38,
2282 'cbfs/u-boot-dtb:offset': 0xb8,
2283 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2284 'cbfs/u-boot-dtb:image-pos': 0xb8,
2285 }, props)
2286
Simon Glass3c9b4f22019-07-08 14:25:42 -06002287 def testCbfsBadType(self):
2288 """Test an image header with a no specified location is detected"""
2289 with self.assertRaises(ValueError) as e:
2290 self._DoReadFile('126_cbfs_bad_type.dts')
2291 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2292
Simon Glass6b156f82019-07-08 14:25:43 -06002293 def testList(self):
2294 """Test listing the files in an image"""
2295 self._CheckLz4()
2296 data = self._DoReadFile('127_list.dts')
2297 image = control.images['image']
2298 entries = image.BuildEntryList()
2299 self.assertEqual(7, len(entries))
2300
2301 ent = entries[0]
2302 self.assertEqual(0, ent.indent)
2303 self.assertEqual('main-section', ent.name)
2304 self.assertEqual('section', ent.etype)
2305 self.assertEqual(len(data), ent.size)
2306 self.assertEqual(0, ent.image_pos)
2307 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002308 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002309
2310 ent = entries[1]
2311 self.assertEqual(1, ent.indent)
2312 self.assertEqual('u-boot', ent.name)
2313 self.assertEqual('u-boot', ent.etype)
2314 self.assertEqual(len(U_BOOT_DATA), ent.size)
2315 self.assertEqual(0, ent.image_pos)
2316 self.assertEqual(None, ent.uncomp_size)
2317 self.assertEqual(0, ent.offset)
2318
2319 ent = entries[2]
2320 self.assertEqual(1, ent.indent)
2321 self.assertEqual('section', ent.name)
2322 self.assertEqual('section', ent.etype)
2323 section_size = ent.size
2324 self.assertEqual(0x100, ent.image_pos)
2325 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002326 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002327
2328 ent = entries[3]
2329 self.assertEqual(2, ent.indent)
2330 self.assertEqual('cbfs', ent.name)
2331 self.assertEqual('cbfs', ent.etype)
2332 self.assertEqual(0x400, ent.size)
2333 self.assertEqual(0x100, ent.image_pos)
2334 self.assertEqual(None, ent.uncomp_size)
2335 self.assertEqual(0, ent.offset)
2336
2337 ent = entries[4]
2338 self.assertEqual(3, ent.indent)
2339 self.assertEqual('u-boot', ent.name)
2340 self.assertEqual('u-boot', ent.etype)
2341 self.assertEqual(len(U_BOOT_DATA), ent.size)
2342 self.assertEqual(0x138, ent.image_pos)
2343 self.assertEqual(None, ent.uncomp_size)
2344 self.assertEqual(0x38, ent.offset)
2345
2346 ent = entries[5]
2347 self.assertEqual(3, ent.indent)
2348 self.assertEqual('u-boot-dtb', ent.name)
2349 self.assertEqual('text', ent.etype)
2350 self.assertGreater(len(COMPRESS_DATA), ent.size)
2351 self.assertEqual(0x178, ent.image_pos)
2352 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2353 self.assertEqual(0x78, ent.offset)
2354
2355 ent = entries[6]
2356 self.assertEqual(2, ent.indent)
2357 self.assertEqual('u-boot-dtb', ent.name)
2358 self.assertEqual('u-boot-dtb', ent.etype)
2359 self.assertEqual(0x500, ent.image_pos)
2360 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2361 dtb_size = ent.size
2362 # Compressing this data expands it since headers are added
2363 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2364 self.assertEqual(0x400, ent.offset)
2365
2366 self.assertEqual(len(data), 0x100 + section_size)
2367 self.assertEqual(section_size, 0x400 + dtb_size)
2368
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002369 def testFindFdtmap(self):
2370 """Test locating an FDT map in an image"""
2371 self._CheckLz4()
2372 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2373 image = control.images['image']
2374 entries = image.GetEntries()
2375 entry = entries['fdtmap']
2376 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2377
2378 def testFindFdtmapMissing(self):
2379 """Test failing to locate an FDP map"""
2380 data = self._DoReadFile('005_simple.dts')
2381 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2382
Simon Glassed39a3c2019-07-08 14:25:45 -06002383 def testFindImageHeader(self):
2384 """Test locating a image header"""
2385 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002386 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002387 image = control.images['image']
2388 entries = image.GetEntries()
2389 entry = entries['fdtmap']
2390 # The header should point to the FDT map
2391 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2392
2393 def testFindImageHeaderStart(self):
2394 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002395 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002396 image = control.images['image']
2397 entries = image.GetEntries()
2398 entry = entries['fdtmap']
2399 # The header should point to the FDT map
2400 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2401
2402 def testFindImageHeaderMissing(self):
2403 """Test failing to locate an image header"""
2404 data = self._DoReadFile('005_simple.dts')
2405 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2406
Simon Glassb8424fa2019-07-08 14:25:46 -06002407 def testReadImage(self):
2408 """Test reading an image and accessing its FDT map"""
2409 self._CheckLz4()
2410 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2411 image_fname = tools.GetOutputFilename('image.bin')
2412 orig_image = control.images['image']
2413 image = Image.FromFile(image_fname)
2414 self.assertEqual(orig_image.GetEntries().keys(),
2415 image.GetEntries().keys())
2416
2417 orig_entry = orig_image.GetEntries()['fdtmap']
2418 entry = image.GetEntries()['fdtmap']
2419 self.assertEquals(orig_entry.offset, entry.offset)
2420 self.assertEquals(orig_entry.size, entry.size)
2421 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2422
2423 def testReadImageNoHeader(self):
2424 """Test accessing an image's FDT map without an image header"""
2425 self._CheckLz4()
2426 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2427 image_fname = tools.GetOutputFilename('image.bin')
2428 image = Image.FromFile(image_fname)
2429 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002430 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002431
2432 def testReadImageFail(self):
2433 """Test failing to read an image image's FDT map"""
2434 self._DoReadFile('005_simple.dts')
2435 image_fname = tools.GetOutputFilename('image.bin')
2436 with self.assertRaises(ValueError) as e:
2437 image = Image.FromFile(image_fname)
2438 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002439
Simon Glassb2fd11d2019-07-08 14:25:48 -06002440 def testListCmd(self):
2441 """Test listing the files in an image using an Fdtmap"""
2442 self._CheckLz4()
2443 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2444
2445 # lz4 compression size differs depending on the version
2446 image = control.images['image']
2447 entries = image.GetEntries()
2448 section_size = entries['section'].size
2449 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2450 fdtmap_offset = entries['fdtmap'].offset
2451
Simon Glassb3d6fc72019-07-20 12:24:10 -06002452 try:
2453 tmpdir, updated_fname = self._SetupImageInTmpdir()
2454 with test_util.capture_sys_output() as (stdout, stderr):
2455 self._DoBinman('ls', '-i', updated_fname)
2456 finally:
2457 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002458 lines = stdout.getvalue().splitlines()
2459 expected = [
2460'Name Image-pos Size Entry-type Offset Uncomp-size',
2461'----------------------------------------------------------------------',
2462'main-section 0 c00 section 0',
2463' u-boot 0 4 u-boot 0',
2464' section 100 %x section 100' % section_size,
2465' cbfs 100 400 cbfs 0',
2466' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002467' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002468' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002469' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002470 (fdtmap_offset, fdtmap_offset),
2471' image-header bf8 8 image-header bf8',
2472 ]
2473 self.assertEqual(expected, lines)
2474
2475 def testListCmdFail(self):
2476 """Test failing to list an image"""
2477 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002478 try:
2479 tmpdir, updated_fname = self._SetupImageInTmpdir()
2480 with self.assertRaises(ValueError) as e:
2481 self._DoBinman('ls', '-i', updated_fname)
2482 finally:
2483 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002484 self.assertIn("Cannot find FDT map in image", str(e.exception))
2485
2486 def _RunListCmd(self, paths, expected):
2487 """List out entries and check the result
2488
2489 Args:
2490 paths: List of paths to pass to the list command
2491 expected: Expected list of filenames to be returned, in order
2492 """
2493 self._CheckLz4()
2494 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2495 image_fname = tools.GetOutputFilename('image.bin')
2496 image = Image.FromFile(image_fname)
2497 lines = image.GetListEntries(paths)[1]
2498 files = [line[0].strip() for line in lines[1:]]
2499 self.assertEqual(expected, files)
2500
2501 def testListCmdSection(self):
2502 """Test listing the files in a section"""
2503 self._RunListCmd(['section'],
2504 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2505
2506 def testListCmdFile(self):
2507 """Test listing a particular file"""
2508 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2509
2510 def testListCmdWildcard(self):
2511 """Test listing a wildcarded file"""
2512 self._RunListCmd(['*boot*'],
2513 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2514
2515 def testListCmdWildcardMulti(self):
2516 """Test listing a wildcarded file"""
2517 self._RunListCmd(['*cb*', '*head*'],
2518 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2519
2520 def testListCmdEmpty(self):
2521 """Test listing a wildcarded file"""
2522 self._RunListCmd(['nothing'], [])
2523
2524 def testListCmdPath(self):
2525 """Test listing the files in a sub-entry of a section"""
2526 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2527
Simon Glass4c613bf2019-07-08 14:25:50 -06002528 def _RunExtractCmd(self, entry_name, decomp=True):
2529 """Extract an entry from an image
2530
2531 Args:
2532 entry_name: Entry name to extract
2533 decomp: True to decompress the data if compressed, False to leave
2534 it in its raw uncompressed format
2535
2536 Returns:
2537 data from entry
2538 """
2539 self._CheckLz4()
2540 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2541 image_fname = tools.GetOutputFilename('image.bin')
2542 return control.ReadEntry(image_fname, entry_name, decomp)
2543
2544 def testExtractSimple(self):
2545 """Test extracting a single file"""
2546 data = self._RunExtractCmd('u-boot')
2547 self.assertEqual(U_BOOT_DATA, data)
2548
Simon Glass980a2842019-07-08 14:25:52 -06002549 def testExtractSection(self):
2550 """Test extracting the files in a section"""
2551 data = self._RunExtractCmd('section')
2552 cbfs_data = data[:0x400]
2553 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002554 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002555 dtb_data = data[0x400:]
2556 dtb = self._decompress(dtb_data)
2557 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2558
2559 def testExtractCompressed(self):
2560 """Test extracting compressed data"""
2561 data = self._RunExtractCmd('section/u-boot-dtb')
2562 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2563
2564 def testExtractRaw(self):
2565 """Test extracting compressed data without decompressing it"""
2566 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2567 dtb = self._decompress(data)
2568 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2569
2570 def testExtractCbfs(self):
2571 """Test extracting CBFS data"""
2572 data = self._RunExtractCmd('section/cbfs/u-boot')
2573 self.assertEqual(U_BOOT_DATA, data)
2574
2575 def testExtractCbfsCompressed(self):
2576 """Test extracting CBFS compressed data"""
2577 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2578 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2579
2580 def testExtractCbfsRaw(self):
2581 """Test extracting CBFS compressed data without decompressing it"""
2582 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002583 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002584 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2585
Simon Glass4c613bf2019-07-08 14:25:50 -06002586 def testExtractBadEntry(self):
2587 """Test extracting a bad section path"""
2588 with self.assertRaises(ValueError) as e:
2589 self._RunExtractCmd('section/does-not-exist')
2590 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2591 str(e.exception))
2592
2593 def testExtractMissingFile(self):
2594 """Test extracting file that does not exist"""
2595 with self.assertRaises(IOError) as e:
2596 control.ReadEntry('missing-file', 'name')
2597
2598 def testExtractBadFile(self):
2599 """Test extracting an invalid file"""
2600 fname = os.path.join(self._indir, 'badfile')
2601 tools.WriteFile(fname, b'')
2602 with self.assertRaises(ValueError) as e:
2603 control.ReadEntry(fname, 'name')
2604
Simon Glass980a2842019-07-08 14:25:52 -06002605 def testExtractCmd(self):
2606 """Test extracting a file fron an image on the command line"""
2607 self._CheckLz4()
2608 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002609 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002610 try:
2611 tmpdir, updated_fname = self._SetupImageInTmpdir()
2612 with test_util.capture_sys_output() as (stdout, stderr):
2613 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2614 '-f', fname)
2615 finally:
2616 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002617 data = tools.ReadFile(fname)
2618 self.assertEqual(U_BOOT_DATA, data)
2619
2620 def testExtractOneEntry(self):
2621 """Test extracting a single entry fron an image """
2622 self._CheckLz4()
2623 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2624 image_fname = tools.GetOutputFilename('image.bin')
2625 fname = os.path.join(self._indir, 'output.extact')
2626 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2627 data = tools.ReadFile(fname)
2628 self.assertEqual(U_BOOT_DATA, data)
2629
2630 def _CheckExtractOutput(self, decomp):
2631 """Helper to test file output with and without decompression
2632
2633 Args:
2634 decomp: True to decompress entry data, False to output it raw
2635 """
2636 def _CheckPresent(entry_path, expect_data, expect_size=None):
2637 """Check and remove expected file
2638
2639 This checks the data/size of a file and removes the file both from
2640 the outfiles set and from the output directory. Once all files are
2641 processed, both the set and directory should be empty.
2642
2643 Args:
2644 entry_path: Entry path
2645 expect_data: Data to expect in file, or None to skip check
2646 expect_size: Size of data to expect in file, or None to skip
2647 """
2648 path = os.path.join(outdir, entry_path)
2649 data = tools.ReadFile(path)
2650 os.remove(path)
2651 if expect_data:
2652 self.assertEqual(expect_data, data)
2653 elif expect_size:
2654 self.assertEqual(expect_size, len(data))
2655 outfiles.remove(path)
2656
2657 def _CheckDirPresent(name):
2658 """Remove expected directory
2659
2660 This gives an error if the directory does not exist as expected
2661
2662 Args:
2663 name: Name of directory to remove
2664 """
2665 path = os.path.join(outdir, name)
2666 os.rmdir(path)
2667
2668 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2669 image_fname = tools.GetOutputFilename('image.bin')
2670 outdir = os.path.join(self._indir, 'extract')
2671 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2672
2673 # Create a set of all file that were output (should be 9)
2674 outfiles = set()
2675 for root, dirs, files in os.walk(outdir):
2676 outfiles |= set([os.path.join(root, fname) for fname in files])
2677 self.assertEqual(9, len(outfiles))
2678 self.assertEqual(9, len(einfos))
2679
2680 image = control.images['image']
2681 entries = image.GetEntries()
2682
2683 # Check the 9 files in various ways
2684 section = entries['section']
2685 section_entries = section.GetEntries()
2686 cbfs_entries = section_entries['cbfs'].GetEntries()
2687 _CheckPresent('u-boot', U_BOOT_DATA)
2688 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2689 dtb_len = EXTRACT_DTB_SIZE
2690 if not decomp:
2691 dtb_len = cbfs_entries['u-boot-dtb'].size
2692 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2693 if not decomp:
2694 dtb_len = section_entries['u-boot-dtb'].size
2695 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2696
2697 fdtmap = entries['fdtmap']
2698 _CheckPresent('fdtmap', fdtmap.data)
2699 hdr = entries['image-header']
2700 _CheckPresent('image-header', hdr.data)
2701
2702 _CheckPresent('section/root', section.data)
2703 cbfs = section_entries['cbfs']
2704 _CheckPresent('section/cbfs/root', cbfs.data)
2705 data = tools.ReadFile(image_fname)
2706 _CheckPresent('root', data)
2707
2708 # There should be no files left. Remove all the directories to check.
2709 # If there are any files/dirs remaining, one of these checks will fail.
2710 self.assertEqual(0, len(outfiles))
2711 _CheckDirPresent('section/cbfs')
2712 _CheckDirPresent('section')
2713 _CheckDirPresent('')
2714 self.assertFalse(os.path.exists(outdir))
2715
2716 def testExtractAllEntries(self):
2717 """Test extracting all entries"""
2718 self._CheckLz4()
2719 self._CheckExtractOutput(decomp=True)
2720
2721 def testExtractAllEntriesRaw(self):
2722 """Test extracting all entries without decompressing them"""
2723 self._CheckLz4()
2724 self._CheckExtractOutput(decomp=False)
2725
2726 def testExtractSelectedEntries(self):
2727 """Test extracting some entries"""
2728 self._CheckLz4()
2729 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2730 image_fname = tools.GetOutputFilename('image.bin')
2731 outdir = os.path.join(self._indir, 'extract')
2732 einfos = control.ExtractEntries(image_fname, None, outdir,
2733 ['*cb*', '*head*'])
2734
2735 # File output is tested by testExtractAllEntries(), so just check that
2736 # the expected entries are selected
2737 names = [einfo.name for einfo in einfos]
2738 self.assertEqual(names,
2739 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2740
2741 def testExtractNoEntryPaths(self):
2742 """Test extracting some entries"""
2743 self._CheckLz4()
2744 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2745 image_fname = tools.GetOutputFilename('image.bin')
2746 with self.assertRaises(ValueError) as e:
2747 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002748 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002749 str(e.exception))
2750
2751 def testExtractTooManyEntryPaths(self):
2752 """Test extracting some entries"""
2753 self._CheckLz4()
2754 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2755 image_fname = tools.GetOutputFilename('image.bin')
2756 with self.assertRaises(ValueError) as e:
2757 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002758 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002759 str(e.exception))
2760
Simon Glass52d06212019-07-08 14:25:53 -06002761 def testPackAlignSection(self):
2762 """Test that sections can have alignment"""
2763 self._DoReadFile('131_pack_align_section.dts')
2764
2765 self.assertIn('image', control.images)
2766 image = control.images['image']
2767 entries = image.GetEntries()
2768 self.assertEqual(3, len(entries))
2769
2770 # First u-boot
2771 self.assertIn('u-boot', entries)
2772 entry = entries['u-boot']
2773 self.assertEqual(0, entry.offset)
2774 self.assertEqual(0, entry.image_pos)
2775 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2776 self.assertEqual(len(U_BOOT_DATA), entry.size)
2777
2778 # Section0
2779 self.assertIn('section0', entries)
2780 section0 = entries['section0']
2781 self.assertEqual(0x10, section0.offset)
2782 self.assertEqual(0x10, section0.image_pos)
2783 self.assertEqual(len(U_BOOT_DATA), section0.size)
2784
2785 # Second u-boot
2786 section_entries = section0.GetEntries()
2787 self.assertIn('u-boot', section_entries)
2788 entry = section_entries['u-boot']
2789 self.assertEqual(0, entry.offset)
2790 self.assertEqual(0x10, entry.image_pos)
2791 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2792 self.assertEqual(len(U_BOOT_DATA), entry.size)
2793
2794 # Section1
2795 self.assertIn('section1', entries)
2796 section1 = entries['section1']
2797 self.assertEqual(0x14, section1.offset)
2798 self.assertEqual(0x14, section1.image_pos)
2799 self.assertEqual(0x20, section1.size)
2800
2801 # Second u-boot
2802 section_entries = section1.GetEntries()
2803 self.assertIn('u-boot', section_entries)
2804 entry = section_entries['u-boot']
2805 self.assertEqual(0, entry.offset)
2806 self.assertEqual(0x14, entry.image_pos)
2807 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2808 self.assertEqual(len(U_BOOT_DATA), entry.size)
2809
2810 # Section2
2811 self.assertIn('section2', section_entries)
2812 section2 = section_entries['section2']
2813 self.assertEqual(0x4, section2.offset)
2814 self.assertEqual(0x18, section2.image_pos)
2815 self.assertEqual(4, section2.size)
2816
2817 # Third u-boot
2818 section_entries = section2.GetEntries()
2819 self.assertIn('u-boot', section_entries)
2820 entry = section_entries['u-boot']
2821 self.assertEqual(0, entry.offset)
2822 self.assertEqual(0x18, entry.image_pos)
2823 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2824 self.assertEqual(len(U_BOOT_DATA), entry.size)
2825
Simon Glassf8a54bc2019-07-20 12:23:56 -06002826 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2827 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06002828 """Replace an entry in an image
2829
2830 This writes the entry data to update it, then opens the updated file and
2831 returns the value that it now finds there.
2832
2833 Args:
2834 entry_name: Entry name to replace
2835 data: Data to replace it with
2836 decomp: True to compress the data if needed, False if data is
2837 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06002838 allow_resize: True to allow entries to change size, False to raise
2839 an exception
Simon Glass072959a2019-07-20 12:23:50 -06002840
2841 Returns:
2842 Tuple:
2843 data from entry
2844 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06002845 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06002846 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06002847 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06002848 update_dtb=True)[1]
2849
2850 self.assertIn('image', control.images)
2851 image = control.images['image']
2852 entries = image.GetEntries()
2853 orig_dtb_data = entries['u-boot-dtb'].data
2854 orig_fdtmap_data = entries['fdtmap'].data
2855
2856 image_fname = tools.GetOutputFilename('image.bin')
2857 updated_fname = tools.GetOutputFilename('image-updated.bin')
2858 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06002859 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2860 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06002861 data = control.ReadEntry(updated_fname, entry_name, decomp)
2862
Simon Glassf8a54bc2019-07-20 12:23:56 -06002863 # The DT data should not change unless resized:
2864 if not allow_resize:
2865 new_dtb_data = entries['u-boot-dtb'].data
2866 self.assertEqual(new_dtb_data, orig_dtb_data)
2867 new_fdtmap_data = entries['fdtmap'].data
2868 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06002869
Simon Glassf8a54bc2019-07-20 12:23:56 -06002870 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06002871
2872 def testReplaceSimple(self):
2873 """Test replacing a single file"""
2874 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06002875 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2876 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06002877 self.assertEqual(expected, data)
2878
2879 # Test that the state looks right. There should be an FDT for the fdtmap
2880 # that we jsut read back in, and it should match what we find in the
2881 # 'control' tables. Checking for an FDT that does not exist should
2882 # return None.
2883 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06002884 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06002885 self.assertEqual(expected_fdtmap, fdtmap)
2886
2887 dtb = state.GetFdtForEtype('fdtmap')
2888 self.assertEqual(dtb.GetContents(), fdtmap)
2889
2890 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2891 self.assertIsNone(missing_path)
2892 self.assertIsNone(missing_fdtmap)
2893
2894 missing_dtb = state.GetFdtForEtype('missing')
2895 self.assertIsNone(missing_dtb)
2896
2897 self.assertEqual('/binman', state.fdt_path_prefix)
2898
2899 def testReplaceResizeFail(self):
2900 """Test replacing a file by something larger"""
2901 expected = U_BOOT_DATA + b'x'
2902 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06002903 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2904 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06002905 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2906 str(e.exception))
2907
2908 def testReplaceMulti(self):
2909 """Test replacing entry data where multiple images are generated"""
2910 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
2911 update_dtb=True)[0]
2912 expected = b'x' * len(U_BOOT_DATA)
2913 updated_fname = tools.GetOutputFilename('image-updated.bin')
2914 tools.WriteFile(updated_fname, data)
2915 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06002916 control.WriteEntry(updated_fname, entry_name, expected,
2917 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06002918 data = control.ReadEntry(updated_fname, entry_name)
2919 self.assertEqual(expected, data)
2920
2921 # Check the state looks right.
2922 self.assertEqual('/binman/image', state.fdt_path_prefix)
2923
2924 # Now check we can write the first image
2925 image_fname = tools.GetOutputFilename('first-image.bin')
2926 updated_fname = tools.GetOutputFilename('first-updated.bin')
2927 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
2928 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06002929 control.WriteEntry(updated_fname, entry_name, expected,
2930 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06002931 data = control.ReadEntry(updated_fname, entry_name)
2932 self.assertEqual(expected, data)
2933
2934 # Check the state looks right.
2935 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06002936
Simon Glassfb30e292019-07-20 12:23:51 -06002937 def testUpdateFdtAllRepack(self):
2938 """Test that all device trees are updated with offset/size info"""
2939 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
2940 SECTION_SIZE = 0x300
2941 DTB_SIZE = 602
2942 FDTMAP_SIZE = 608
2943 base_expected = {
2944 'offset': 0,
2945 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
2946 'image-pos': 0,
2947 'section:offset': 0,
2948 'section:size': SECTION_SIZE,
2949 'section:image-pos': 0,
2950 'section/u-boot-dtb:offset': 4,
2951 'section/u-boot-dtb:size': 636,
2952 'section/u-boot-dtb:image-pos': 4,
2953 'u-boot-spl-dtb:offset': SECTION_SIZE,
2954 'u-boot-spl-dtb:size': DTB_SIZE,
2955 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
2956 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
2957 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
2958 'u-boot-tpl-dtb:size': DTB_SIZE,
2959 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
2960 'fdtmap:size': FDTMAP_SIZE,
2961 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
2962 }
2963 main_expected = {
2964 'section:orig-size': SECTION_SIZE,
2965 'section/u-boot-dtb:orig-offset': 4,
2966 }
2967
2968 # We expect three device-tree files in the output, with the first one
2969 # within a fixed-size section.
2970 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2971 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2972 # main U-Boot tree. All three should have the same positions and offset
2973 # except that the main tree should include the main_expected properties
2974 start = 4
2975 for item in ['', 'spl', 'tpl', None]:
2976 if item is None:
2977 start += 16 # Move past fdtmap header
2978 dtb = fdt.Fdt.FromData(data[start:])
2979 dtb.Scan()
2980 props = self._GetPropTree(dtb,
2981 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
2982 prefix='/' if item is None else '/binman/')
2983 expected = dict(base_expected)
2984 if item:
2985 expected[item] = 0
2986 else:
2987 # Main DTB and fdtdec should include the 'orig-' properties
2988 expected.update(main_expected)
2989 # Helpful for debugging:
2990 #for prop in sorted(props):
2991 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
2992 self.assertEqual(expected, props)
2993 if item == '':
2994 start = SECTION_SIZE
2995 else:
2996 start += dtb._fdt_obj.totalsize()
2997
Simon Glass11453762019-07-20 12:23:55 -06002998 def testFdtmapHeaderMiddle(self):
2999 """Test an FDT map in the middle of an image when it should be at end"""
3000 with self.assertRaises(ValueError) as e:
3001 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3002 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3003 str(e.exception))
3004
3005 def testFdtmapHeaderStartBad(self):
3006 """Test an FDT map in middle of an image when it should be at start"""
3007 with self.assertRaises(ValueError) as e:
3008 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3009 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3010 str(e.exception))
3011
3012 def testFdtmapHeaderEndBad(self):
3013 """Test an FDT map at the start of an image when it should be at end"""
3014 with self.assertRaises(ValueError) as e:
3015 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3016 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3017 str(e.exception))
3018
3019 def testFdtmapHeaderNoSize(self):
3020 """Test an image header at the end of an image with undefined size"""
3021 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3022
Simon Glassf8a54bc2019-07-20 12:23:56 -06003023 def testReplaceResize(self):
3024 """Test replacing a single file in an entry with a larger file"""
3025 expected = U_BOOT_DATA + b'x'
3026 data, _, image = self._RunReplaceCmd('u-boot', expected,
3027 dts='139_replace_repack.dts')
3028 self.assertEqual(expected, data)
3029
3030 entries = image.GetEntries()
3031 dtb_data = entries['u-boot-dtb'].data
3032 dtb = fdt.Fdt.FromData(dtb_data)
3033 dtb.Scan()
3034
3035 # The u-boot section should now be larger in the dtb
3036 node = dtb.GetNode('/binman/u-boot')
3037 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3038
3039 # Same for the fdtmap
3040 fdata = entries['fdtmap'].data
3041 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3042 fdtb.Scan()
3043 fnode = fdtb.GetNode('/u-boot')
3044 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3045
3046 def testReplaceResizeNoRepack(self):
3047 """Test replacing an entry with a larger file when not allowed"""
3048 expected = U_BOOT_DATA + b'x'
3049 with self.assertRaises(ValueError) as e:
3050 self._RunReplaceCmd('u-boot', expected)
3051 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3052 str(e.exception))
3053
Simon Glass9d8ee322019-07-20 12:23:58 -06003054 def testEntryShrink(self):
3055 """Test contracting an entry after it is packed"""
3056 try:
3057 state.SetAllowEntryContraction(True)
3058 data = self._DoReadFileDtb('140_entry_shrink.dts',
3059 update_dtb=True)[0]
3060 finally:
3061 state.SetAllowEntryContraction(False)
3062 self.assertEqual(b'a', data[:1])
3063 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3064 self.assertEqual(b'a', data[-1:])
3065
3066 def testEntryShrinkFail(self):
3067 """Test not being allowed to contract an entry after it is packed"""
3068 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3069
3070 # In this case there is a spare byte at the end of the data. The size of
3071 # the contents is only 1 byte but we still have the size before it
3072 # shrunk.
3073 self.assertEqual(b'a\0', data[:2])
3074 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3075 self.assertEqual(b'a\0', data[-2:])
3076
Simon Glass70e32982019-07-20 12:24:01 -06003077 def testDescriptorOffset(self):
3078 """Test that the Intel descriptor is always placed at at the start"""
3079 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3080 image = control.images['image']
3081 entries = image.GetEntries()
3082 desc = entries['intel-descriptor']
3083 self.assertEqual(0xff800000, desc.offset);
3084 self.assertEqual(0xff800000, desc.image_pos);
3085
Simon Glass37fdd142019-07-20 12:24:06 -06003086 def testReplaceCbfs(self):
3087 """Test replacing a single file in CBFS without changing the size"""
3088 self._CheckLz4()
3089 expected = b'x' * len(U_BOOT_DATA)
3090 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3091 updated_fname = tools.GetOutputFilename('image-updated.bin')
3092 tools.WriteFile(updated_fname, data)
3093 entry_name = 'section/cbfs/u-boot'
3094 control.WriteEntry(updated_fname, entry_name, expected,
3095 allow_resize=True)
3096 data = control.ReadEntry(updated_fname, entry_name)
3097 self.assertEqual(expected, data)
3098
3099 def testReplaceResizeCbfs(self):
3100 """Test replacing a single file in CBFS with one of a different size"""
3101 self._CheckLz4()
3102 expected = U_BOOT_DATA + b'x'
3103 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3104 updated_fname = tools.GetOutputFilename('image-updated.bin')
3105 tools.WriteFile(updated_fname, data)
3106 entry_name = 'section/cbfs/u-boot'
3107 control.WriteEntry(updated_fname, entry_name, expected,
3108 allow_resize=True)
3109 data = control.ReadEntry(updated_fname, entry_name)
3110 self.assertEqual(expected, data)
3111
Simon Glass30033c22019-07-20 12:24:15 -06003112 def _SetupForReplace(self):
3113 """Set up some files to use to replace entries
3114
3115 This generates an image, copies it to a new file, extracts all the files
3116 in it and updates some of them
3117
3118 Returns:
3119 List
3120 Image filename
3121 Output directory
3122 Expected values for updated entries, each a string
3123 """
3124 data = self._DoReadFileRealDtb('143_replace_all.dts')
3125
3126 updated_fname = tools.GetOutputFilename('image-updated.bin')
3127 tools.WriteFile(updated_fname, data)
3128
3129 outdir = os.path.join(self._indir, 'extract')
3130 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3131
3132 expected1 = b'x' + U_BOOT_DATA + b'y'
3133 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3134 tools.WriteFile(u_boot_fname1, expected1)
3135
3136 expected2 = b'a' + U_BOOT_DATA + b'b'
3137 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3138 tools.WriteFile(u_boot_fname2, expected2)
3139
3140 expected_text = b'not the same text'
3141 text_fname = os.path.join(outdir, 'text')
3142 tools.WriteFile(text_fname, expected_text)
3143
3144 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3145 dtb = fdt.FdtScan(dtb_fname)
3146 node = dtb.GetNode('/binman/text')
3147 node.AddString('my-property', 'the value')
3148 dtb.Sync(auto_resize=True)
3149 dtb.Flush()
3150
3151 return updated_fname, outdir, expected1, expected2, expected_text
3152
3153 def _CheckReplaceMultiple(self, entry_paths):
3154 """Handle replacing the contents of multiple entries
3155
3156 Args:
3157 entry_paths: List of entry paths to replace
3158
3159 Returns:
3160 List
3161 Dict of entries in the image:
3162 key: Entry name
3163 Value: Entry object
3164 Expected values for updated entries, each a string
3165 """
3166 updated_fname, outdir, expected1, expected2, expected_text = (
3167 self._SetupForReplace())
3168 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3169
3170 image = Image.FromFile(updated_fname)
3171 image.LoadData()
3172 return image.GetEntries(), expected1, expected2, expected_text
3173
3174 def testReplaceAll(self):
3175 """Test replacing the contents of all entries"""
3176 entries, expected1, expected2, expected_text = (
3177 self._CheckReplaceMultiple([]))
3178 data = entries['u-boot'].data
3179 self.assertEqual(expected1, data)
3180
3181 data = entries['u-boot2'].data
3182 self.assertEqual(expected2, data)
3183
3184 data = entries['text'].data
3185 self.assertEqual(expected_text, data)
3186
3187 # Check that the device tree is updated
3188 data = entries['u-boot-dtb'].data
3189 dtb = fdt.Fdt.FromData(data)
3190 dtb.Scan()
3191 node = dtb.GetNode('/binman/text')
3192 self.assertEqual('the value', node.props['my-property'].value)
3193
3194 def testReplaceSome(self):
3195 """Test replacing the contents of a few entries"""
3196 entries, expected1, expected2, expected_text = (
3197 self._CheckReplaceMultiple(['u-boot2', 'text']))
3198
3199 # This one should not change
3200 data = entries['u-boot'].data
3201 self.assertEqual(U_BOOT_DATA, data)
3202
3203 data = entries['u-boot2'].data
3204 self.assertEqual(expected2, data)
3205
3206 data = entries['text'].data
3207 self.assertEqual(expected_text, data)
3208
3209 def testReplaceCmd(self):
3210 """Test replacing a file fron an image on the command line"""
3211 self._DoReadFileRealDtb('143_replace_all.dts')
3212
3213 try:
3214 tmpdir, updated_fname = self._SetupImageInTmpdir()
3215
3216 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3217 expected = b'x' * len(U_BOOT_DATA)
3218 tools.WriteFile(fname, expected)
3219
3220 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3221 data = tools.ReadFile(updated_fname)
3222 self.assertEqual(expected, data[:len(expected)])
3223 map_fname = os.path.join(tmpdir, 'image-updated.map')
3224 self.assertFalse(os.path.exists(map_fname))
3225 finally:
3226 shutil.rmtree(tmpdir)
3227
3228 def testReplaceCmdSome(self):
3229 """Test replacing some files fron an image on the command line"""
3230 updated_fname, outdir, expected1, expected2, expected_text = (
3231 self._SetupForReplace())
3232
3233 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3234 'u-boot2', 'text')
3235
3236 tools.PrepareOutputDir(None)
3237 image = Image.FromFile(updated_fname)
3238 image.LoadData()
3239 entries = image.GetEntries()
3240
3241 # This one should not change
3242 data = entries['u-boot'].data
3243 self.assertEqual(U_BOOT_DATA, data)
3244
3245 data = entries['u-boot2'].data
3246 self.assertEqual(expected2, data)
3247
3248 data = entries['text'].data
3249 self.assertEqual(expected_text, data)
3250
3251 def testReplaceMissing(self):
3252 """Test replacing entries where the file is missing"""
3253 updated_fname, outdir, expected1, expected2, expected_text = (
3254 self._SetupForReplace())
3255
3256 # Remove one of the files, to generate a warning
3257 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3258 os.remove(u_boot_fname1)
3259
3260 with test_util.capture_sys_output() as (stdout, stderr):
3261 control.ReplaceEntries(updated_fname, None, outdir, [])
3262 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003263 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003264
3265 def testReplaceCmdMap(self):
3266 """Test replacing a file fron an image on the command line"""
3267 self._DoReadFileRealDtb('143_replace_all.dts')
3268
3269 try:
3270 tmpdir, updated_fname = self._SetupImageInTmpdir()
3271
3272 fname = os.path.join(self._indir, 'update-u-boot.bin')
3273 expected = b'x' * len(U_BOOT_DATA)
3274 tools.WriteFile(fname, expected)
3275
3276 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3277 '-f', fname, '-m')
3278 map_fname = os.path.join(tmpdir, 'image-updated.map')
3279 self.assertTrue(os.path.exists(map_fname))
3280 finally:
3281 shutil.rmtree(tmpdir)
3282
3283 def testReplaceNoEntryPaths(self):
3284 """Test replacing an entry without an entry path"""
3285 self._DoReadFileRealDtb('143_replace_all.dts')
3286 image_fname = tools.GetOutputFilename('image.bin')
3287 with self.assertRaises(ValueError) as e:
3288 control.ReplaceEntries(image_fname, 'fname', None, [])
3289 self.assertIn('Must specify an entry path to read with -f',
3290 str(e.exception))
3291
3292 def testReplaceTooManyEntryPaths(self):
3293 """Test extracting some entries"""
3294 self._DoReadFileRealDtb('143_replace_all.dts')
3295 image_fname = tools.GetOutputFilename('image.bin')
3296 with self.assertRaises(ValueError) as e:
3297 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3298 self.assertIn('Must specify exactly one entry path to write with -f',
3299 str(e.exception))
3300
Simon Glass0b074d62019-08-24 07:22:48 -06003301 def testPackReset16(self):
3302 """Test that an image with an x86 reset16 region can be created"""
3303 data = self._DoReadFile('144_x86_reset16.dts')
3304 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3305
3306 def testPackReset16Spl(self):
3307 """Test that an image with an x86 reset16-spl region can be created"""
3308 data = self._DoReadFile('145_x86_reset16_spl.dts')
3309 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3310
3311 def testPackReset16Tpl(self):
3312 """Test that an image with an x86 reset16-tpl region can be created"""
3313 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3314 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3315
Simon Glass232f90c2019-08-24 07:22:50 -06003316 def testPackIntelFit(self):
3317 """Test that an image with an Intel FIT and pointer can be created"""
3318 data = self._DoReadFile('147_intel_fit.dts')
3319 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3320 fit = data[16:32];
3321 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3322 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3323
3324 image = control.images['image']
3325 entries = image.GetEntries()
3326 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3327 self.assertEqual(expected_ptr, ptr)
3328
3329 def testPackIntelFitMissing(self):
3330 """Test detection of a FIT pointer with not FIT region"""
3331 with self.assertRaises(ValueError) as e:
3332 self._DoReadFile('148_intel_fit_missing.dts')
3333 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3334 str(e.exception))
3335
Simon Glass72555fa2019-11-06 17:22:44 -07003336 def _CheckSymbolsTplSection(self, dts, expected_vals):
3337 data = self._DoReadFile(dts)
3338 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003339 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003340 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003341 self.assertEqual(expected1, data[:upto1])
3342
3343 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003344 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003345 self.assertEqual(expected2, data[upto1:upto2])
3346
Simon Glass4e353e22019-08-24 07:23:04 -06003347 upto3 = 0x34 + len(U_BOOT_DATA)
3348 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003349 self.assertEqual(expected3, data[upto2:upto3])
3350
Simon Glass3f8ff012019-08-24 07:23:05 -06003351 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003352 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3353
3354 def testSymbolsTplSection(self):
3355 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3356 self._SetupSplElf('u_boot_binman_syms')
3357 self._SetupTplElf('u_boot_binman_syms')
3358 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3359 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3360
3361 def testSymbolsTplSectionX86(self):
3362 """Test binman can assign symbols in a section with end-at-4gb"""
3363 self._SetupSplElf('u_boot_binman_syms_x86')
3364 self._SetupTplElf('u_boot_binman_syms_x86')
3365 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3366 [0xffffff04, 0xffffff1c, 0xffffff34,
3367 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003368
Simon Glass98c59572019-08-24 07:23:03 -06003369 def testPackX86RomIfwiSectiom(self):
3370 """Test that a section can be placed in an IFWI region"""
3371 self._SetupIfwi('fitimage.bin')
3372 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3373 self._CheckIfwi(data)
3374
Simon Glassba7985d2019-08-24 07:23:07 -06003375 def testPackFspM(self):
3376 """Test that an image with a FSP memory-init binary can be created"""
3377 data = self._DoReadFile('152_intel_fsp_m.dts')
3378 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3379
Simon Glass4d9086d2019-10-20 21:31:35 -06003380 def testPackFspS(self):
3381 """Test that an image with a FSP silicon-init binary can be created"""
3382 data = self._DoReadFile('153_intel_fsp_s.dts')
3383 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003384
Simon Glass9ea87b22019-10-20 21:31:36 -06003385 def testPackFspT(self):
3386 """Test that an image with a FSP temp-ram-init binary can be created"""
3387 data = self._DoReadFile('154_intel_fsp_t.dts')
3388 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3389
Simon Glass48f3aad2020-07-09 18:39:31 -06003390 def testMkimage(self):
3391 """Test using mkimage to build an image"""
3392 data = self._DoReadFile('156_mkimage.dts')
3393
3394 # Just check that the data appears in the file somewhere
3395 self.assertIn(U_BOOT_SPL_DATA, data)
3396
Simon Glass5e560182020-07-09 18:39:36 -06003397 def testExtblob(self):
3398 """Test an image with an external blob"""
3399 data = self._DoReadFile('157_blob_ext.dts')
3400 self.assertEqual(REFCODE_DATA, data)
3401
3402 def testExtblobMissing(self):
3403 """Test an image with a missing external blob"""
3404 with self.assertRaises(ValueError) as e:
3405 self._DoReadFile('158_blob_ext_missing.dts')
3406 self.assertIn("Filename 'missing-file' not found in input path",
3407 str(e.exception))
3408
Simon Glass5d94cc62020-07-09 18:39:38 -06003409 def testExtblobMissingOk(self):
3410 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003411 with test_util.capture_sys_output() as (stdout, stderr):
3412 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3413 err = stderr.getvalue()
3414 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3415
3416 def testExtblobMissingOkSect(self):
3417 """Test an image with an missing external blob that is allowed"""
3418 with test_util.capture_sys_output() as (stdout, stderr):
3419 self._DoTestFile('159_blob_ext_missing_sect.dts',
3420 allow_missing=True)
3421 err = stderr.getvalue()
3422 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3423 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003424
Simon Glasse88cef92020-07-09 18:39:41 -06003425 def testPackX86RomMeMissingDesc(self):
3426 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003427 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003428 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003429 err = stderr.getvalue()
3430 self.assertRegex(err,
3431 "Image 'main-section'.*missing.*: intel-descriptor")
3432
3433 def testPackX86RomMissingIfwi(self):
3434 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3435 self._SetupIfwi('fitimage.bin')
3436 pathname = os.path.join(self._indir, 'fitimage.bin')
3437 os.remove(pathname)
3438 with test_util.capture_sys_output() as (stdout, stderr):
3439 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3440 err = stderr.getvalue()
3441 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3442
Simon Glassd70829a2020-07-09 18:39:42 -06003443 def testPackOverlap(self):
3444 """Test that zero-size overlapping regions are ignored"""
3445 self._DoTestFile('160_pack_overlap_zero.dts')
3446
Simon Glass45d556d2020-07-09 18:39:45 -06003447 def testSimpleFit(self):
3448 """Test an image with a FIT inside"""
3449 data = self._DoReadFile('161_fit.dts')
3450 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3451 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3452 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3453
3454 # The data should be inside the FIT
3455 dtb = fdt.Fdt.FromData(fit_data)
3456 dtb.Scan()
3457 fnode = dtb.GetNode('/images/kernel')
3458 self.assertIn('data', fnode.props)
3459
3460 fname = os.path.join(self._indir, 'fit_data.fit')
3461 tools.WriteFile(fname, fit_data)
3462 out = tools.Run('dumpimage', '-l', fname)
3463
3464 # Check a few features to make sure the plumbing works. We don't need
3465 # to test the operation of mkimage or dumpimage here. First convert the
3466 # output into a dict where the keys are the fields printed by dumpimage
3467 # and the values are a list of values for each field
3468 lines = out.splitlines()
3469
3470 # Converts "Compression: gzip compressed" into two groups:
3471 # 'Compression' and 'gzip compressed'
3472 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3473 vals = collections.defaultdict(list)
3474 for line in lines:
3475 mat = re_line.match(line)
3476 vals[mat.group(1)].append(mat.group(2))
3477
3478 self.assertEquals('FIT description: test-desc', lines[0])
3479 self.assertIn('Created:', lines[1])
3480 self.assertIn('Image 0 (kernel)', vals)
3481 self.assertIn('Hash value', vals)
3482 data_sizes = vals.get('Data Size')
3483 self.assertIsNotNone(data_sizes)
3484 self.assertEqual(2, len(data_sizes))
3485 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3486 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3487 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3488
3489 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003490 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003491 data = self._DoReadFile('162_fit_external.dts')
3492 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3493
3494 # The data should be outside the FIT
3495 dtb = fdt.Fdt.FromData(fit_data)
3496 dtb.Scan()
3497 fnode = dtb.GetNode('/images/kernel')
3498 self.assertNotIn('data', fnode.props)
Simon Glassfb30e292019-07-20 12:23:51 -06003499
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003500 def testSectionIgnoreHashSignature(self):
3501 """Test that sections ignore hash, signature nodes for its data"""
3502 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3503 expected = (U_BOOT_DATA + U_BOOT_DATA)
3504 self.assertEqual(expected, data)
3505
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003506 def testPadInSections(self):
3507 """Test pad-before, pad-after for entries in sections"""
3508 data = self._DoReadFile('166_pad_in_sections.dts')
3509 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3510 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3511 U_BOOT_DATA)
3512 self.assertEqual(expected, data)
3513
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003514 def testFitImageSubentryAlignment(self):
3515 """Test relative alignability of FIT image subentries"""
3516 entry_args = {
3517 'test-id': TEXT_DATA,
3518 }
3519 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3520 entry_args=entry_args)
3521 dtb = fdt.Fdt.FromData(data)
3522 dtb.Scan()
3523
3524 node = dtb.GetNode('/images/kernel')
3525 data = dtb.GetProps(node)["data"].bytes
3526 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3527 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3528 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3529 self.assertEqual(expected, data)
3530
3531 node = dtb.GetNode('/images/fdt-1')
3532 data = dtb.GetProps(node)["data"].bytes
3533 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3534 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3535 U_BOOT_DTB_DATA)
3536 self.assertEqual(expected, data)
3537
3538 def testFitExtblobMissingOk(self):
3539 """Test a FIT with a missing external blob that is allowed"""
3540 with test_util.capture_sys_output() as (stdout, stderr):
3541 self._DoTestFile('168_fit_missing_blob.dts',
3542 allow_missing=True)
3543 err = stderr.getvalue()
3544 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3545
Simon Glass21db0ff2020-09-01 05:13:54 -06003546 def testBlobNamedByArgMissing(self):
3547 """Test handling of a missing entry arg"""
3548 with self.assertRaises(ValueError) as e:
3549 self._DoReadFile('068_blob_named_by_arg.dts')
3550 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3551 str(e.exception))
3552
Simon Glassac599912017-11-12 21:52:22 -07003553if __name__ == "__main__":
3554 unittest.main()