blob: e753a342c8f808666dde0630b045b24014f3ca50 [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 Glassd92c8362020-10-26 17:40:25 -060073COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060074REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060075FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060076FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060077FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060078ATF_BL31_DATA = b'bl31'
Samuel Holland9d8cc632020-10-21 21:12:15 -050079SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060080TEST_FDT1_DATA = b'fdt1'
81TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060082ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060083
84# Subdirectory of the input dir to use to put test FDTs
85TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060086
Simon Glass2c6adba2019-07-20 12:23:47 -060087# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060088EXTRACT_DTB_SIZE = 0x3c9
89
Simon Glass2c6adba2019-07-20 12:23:47 -060090# Properties expected to be in the device tree when update_dtb is used
91BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
92
Simon Glassfb30e292019-07-20 12:23:51 -060093# Extra properties expected to be in the device tree when allow-repack is used
94REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
95
Simon Glass57454f42016-11-25 20:15:52 -070096
97class TestFunctional(unittest.TestCase):
98 """Functional tests for binman
99
100 Most of these use a sample .dts file to build an image and then check
101 that it looks correct. The sample files are in the test/ subdirectory
102 and are numbered.
103
104 For each entry type a very small test file is created using fixed
105 string contents. This makes it easy to test that things look right, and
106 debug problems.
107
108 In some cases a 'real' file must be used - these are also supplied in
109 the test/ diurectory.
110 """
111 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600112 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700113 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600114 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700115
Simon Glass57454f42016-11-25 20:15:52 -0700116 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600117 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
118 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700119
120 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600121 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700122
123 # Create some test files
124 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
125 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
126 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600127 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700128 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700129 TestFunctional._MakeInputFile('me.bin', ME_DATA)
130 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600131 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600132
Jagdish Gediya311d4842018-09-03 21:35:08 +0530133 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600134
Simon Glassabab18c2019-08-24 07:22:49 -0600135 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
136 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700137 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600138 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600139 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600140
141 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
142 X86_RESET16_DATA)
143 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
144 X86_RESET16_SPL_DATA)
145 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
146 X86_RESET16_TPL_DATA)
147
Simon Glass57454f42016-11-25 20:15:52 -0700148 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700149 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
150 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600151 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
152 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700153 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
154 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700155 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700156 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600157 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600158 TestFunctional._MakeInputDir('devkeys')
159 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600160 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600161 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600162 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600163 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700164
Simon Glassf6290892019-08-24 07:22:53 -0600165 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
166 elf_test.BuildElfTestFiles(cls._elf_testdir)
167
Simon Glass72232452016-11-25 20:15:53 -0700168 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600169 TestFunctional._MakeInputFile('u-boot',
170 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700171
172 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600173 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700174
Simon Glass862f8e22019-08-24 07:22:43 -0600175 shutil.copytree(cls.TestFile('files'),
176 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600177
Simon Glass7ba33592018-09-14 04:57:26 -0600178 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600179 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600180 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500181 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600182
Simon Glassa435cd12020-09-01 05:13:59 -0600183 # Add a few .dtb files for testing
184 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
185 TEST_FDT1_DATA)
186 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
187 TEST_FDT2_DATA)
188
Simon Glassa0729502020-09-06 10:35:33 -0600189 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
190
Simon Glass1de34482019-07-08 13:18:53 -0600191 # Travis-CI may have an old lz4
Simon Glass862f8e22019-08-24 07:22:43 -0600192 cls.have_lz4 = True
Simon Glass1de34482019-07-08 13:18:53 -0600193 try:
194 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glasscc311ac2019-10-31 07:42:50 -0600195 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glass1de34482019-07-08 13:18:53 -0600196 except:
Simon Glass862f8e22019-08-24 07:22:43 -0600197 cls.have_lz4 = False
Simon Glass1de34482019-07-08 13:18:53 -0600198
Simon Glass57454f42016-11-25 20:15:52 -0700199 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600200 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700201 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600202 if cls.preserve_indir:
203 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600204 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600205 if cls._indir:
206 shutil.rmtree(cls._indir)
207 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700208
Simon Glass1c420c92019-07-08 13:18:49 -0600209 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600210 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600211 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600212 """Accept arguments controlling test execution
213
214 Args:
215 preserve_indir: Preserve the shared input directory used by all
216 tests in this class.
217 preserve_outdir: Preserve the output directories used by tests. Each
218 test has its own, so this is normally only useful when running a
219 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600220 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600221 """
222 cls.preserve_indir = preserve_indir
223 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600224 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600225 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600226
Simon Glass1de34482019-07-08 13:18:53 -0600227 def _CheckLz4(self):
228 if not self.have_lz4:
229 self.skipTest('lz4 --no-frame-crc not available')
230
Simon Glassee9d10d2019-07-20 12:24:09 -0600231 def _CleanupOutputDir(self):
232 """Remove the temporary output directory"""
233 if self.preserve_outdirs:
234 print('Preserving output dir: %s' % tools.outdir)
235 else:
236 tools._FinaliseForTest()
237
Simon Glass57454f42016-11-25 20:15:52 -0700238 def setUp(self):
239 # Enable this to turn on debugging output
240 # tout.Init(tout.DEBUG)
241 command.test_result = None
242
243 def tearDown(self):
244 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600245 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700246
Simon Glassb3d6fc72019-07-20 12:24:10 -0600247 def _SetupImageInTmpdir(self):
248 """Set up the output image in a new temporary directory
249
250 This is used when an image has been generated in the output directory,
251 but we want to run binman again. This will create a new output
252 directory and fail to delete the original one.
253
254 This creates a new temporary directory, copies the image to it (with a
255 new name) and removes the old output directory.
256
257 Returns:
258 Tuple:
259 Temporary directory to use
260 New image filename
261 """
262 image_fname = tools.GetOutputFilename('image.bin')
263 tmpdir = tempfile.mkdtemp(prefix='binman.')
264 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
265 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
266 self._CleanupOutputDir()
267 return tmpdir, updated_fname
268
Simon Glass8425a1f2018-07-17 13:25:48 -0600269 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600270 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600271 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
272 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
273 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
274
Simon Glass57454f42016-11-25 20:15:52 -0700275 def _RunBinman(self, *args, **kwargs):
276 """Run binman using the command line
277
278 Args:
279 Arguments to pass, as a list of strings
280 kwargs: Arguments to pass to Command.RunPipe()
281 """
282 result = command.RunPipe([[self._binman_pathname] + list(args)],
283 capture=True, capture_stderr=True, raise_on_error=False)
284 if result.return_code and kwargs.get('raise_on_error', True):
285 raise Exception("Error running '%s': %s" % (' '.join(args),
286 result.stdout + result.stderr))
287 return result
288
Simon Glassf46732a2019-07-08 14:25:29 -0600289 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700290 """Run binman using directly (in the same process)
291
292 Args:
293 Arguments to pass, as a list of strings
294 Returns:
295 Return value (0 for success)
296 """
Simon Glassf46732a2019-07-08 14:25:29 -0600297 argv = list(argv)
298 args = cmdline.ParseArgs(argv)
299 args.pager = 'binman-invalid-pager'
300 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700301
302 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600303 # args.verbosity = tout.DEBUG
304 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700305
Simon Glass91710b32018-07-17 13:25:32 -0600306 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600307 entry_args=None, images=None, use_real_dtb=False,
Simon Glassa435cd12020-09-01 05:13:59 -0600308 verbosity=None, allow_missing=False, extra_indirs=None):
Simon Glass57454f42016-11-25 20:15:52 -0700309 """Run binman with a given test file
310
311 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600312 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600313 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600314 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600315 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600316 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600317 entry_args: Dict of entry args to supply to binman
318 key: arg name
319 value: value of that arg
320 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600321 use_real_dtb: True to use the test file as the contents of
322 the u-boot-dtb entry. Normally this is not needed and the
323 test contents (the U_BOOT_DTB_DATA string) can be used.
324 But in some test we need the real contents.
325 verbosity: Verbosity level to use (0-3, None=don't set it)
326 allow_missing: Set the '--allow-missing' flag so that missing
327 external binaries just produce a warning instead of an error
Simon Glassa435cd12020-09-01 05:13:59 -0600328 extra_indirs: Extra input directories to add using -I
Simon Glass57454f42016-11-25 20:15:52 -0700329 """
Simon Glassf46732a2019-07-08 14:25:29 -0600330 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700331 if debug:
332 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600333 if verbosity is not None:
334 args.append('-v%d' % verbosity)
335 elif self.verbosity:
336 args.append('-v%d' % self.verbosity)
337 if self.toolpath:
338 for path in self.toolpath:
339 args += ['--toolpath', path]
340 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600341 if map:
342 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600343 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600344 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600345 if not use_real_dtb:
346 args.append('--fake-dtb')
Simon Glass91710b32018-07-17 13:25:32 -0600347 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600348 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600349 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600350 if allow_missing:
351 args.append('-M')
Simon Glass3b376c32018-09-14 04:57:12 -0600352 if images:
353 for image in images:
354 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600355 if extra_indirs:
356 for indir in extra_indirs:
357 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700358 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700359
360 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700361 """Set up a new test device-tree file
362
363 The given file is compiled and set up as the device tree to be used
364 for ths test.
365
366 Args:
367 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600368 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700369
370 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600371 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700372 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600373 tmpdir = tempfile.mkdtemp(prefix='binmant.')
374 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600375 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700376 data = fd.read()
377 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600378 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600379 return data
Simon Glass57454f42016-11-25 20:15:52 -0700380
Simon Glasse219aa42018-09-14 04:57:24 -0600381 def _GetDtbContentsForSplTpl(self, dtb_data, name):
382 """Create a version of the main DTB for SPL or SPL
383
384 For testing we don't actually have different versions of the DTB. With
385 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
386 we don't normally have any unwanted nodes.
387
388 We still want the DTBs for SPL and TPL to be different though, since
389 otherwise it is confusing to know which one we are looking at. So add
390 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600391
392 Args:
393 dtb_data: dtb data to modify (this should be a value devicetree)
394 name: Name of a new property to add
395
396 Returns:
397 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600398 """
399 dtb = fdt.Fdt.FromData(dtb_data)
400 dtb.Scan()
401 dtb.GetNode('/binman').AddZeroProp(name)
402 dtb.Sync(auto_resize=True)
403 dtb.Pack()
404 return dtb.GetContents()
405
Simon Glassa87014e2018-07-06 10:27:42 -0600406 def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False,
Simon Glassa435cd12020-09-01 05:13:59 -0600407 update_dtb=False, entry_args=None, reset_dtbs=True,
408 extra_indirs=None):
Simon Glass57454f42016-11-25 20:15:52 -0700409 """Run binman and return the resulting image
410
411 This runs binman with a given test file and then reads the resulting
412 output file. It is a shortcut function since most tests need to do
413 these steps.
414
415 Raises an assertion failure if binman returns a non-zero exit code.
416
417 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600418 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700419 use_real_dtb: True to use the test file as the contents of
420 the u-boot-dtb entry. Normally this is not needed and the
421 test contents (the U_BOOT_DTB_DATA string) can be used.
422 But in some test we need the real contents.
Simon Glass30732662018-06-01 09:38:20 -0600423 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600424 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600425 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600426 entry_args: Dict of entry args to supply to binman
427 key: arg name
428 value: value of that arg
429 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
430 function. If reset_dtbs is True, then the original test dtb
431 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600432 extra_indirs: Extra input directories to add using -I
Simon Glass72232452016-11-25 20:15:53 -0700433
434 Returns:
435 Tuple:
436 Resulting image contents
437 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600438 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600439 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700440 """
Simon Glass72232452016-11-25 20:15:53 -0700441 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700442 # Use the compiled test file as the u-boot-dtb input
443 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700444 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600445
446 # For testing purposes, make a copy of the DT for SPL and TPL. Add
447 # a node indicating which it is, so aid verification.
448 for name in ['spl', 'tpl']:
449 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
450 outfile = os.path.join(self._indir, dtb_fname)
451 TestFunctional._MakeInputFile(dtb_fname,
452 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700453
454 try:
Simon Glass91710b32018-07-17 13:25:32 -0600455 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600456 entry_args=entry_args, use_real_dtb=use_real_dtb,
457 extra_indirs=extra_indirs)
Simon Glass57454f42016-11-25 20:15:52 -0700458 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600459 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700460
461 # Find the (only) image, read it and return its contents
462 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600463 image_fname = tools.GetOutputFilename('image.bin')
464 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600465 if map:
466 map_fname = tools.GetOutputFilename('image.map')
467 with open(map_fname) as fd:
468 map_data = fd.read()
469 else:
470 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600471 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600472 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700473 finally:
474 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600475 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600476 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700477
Simon Glass5b4bce32019-07-08 14:25:26 -0600478 def _DoReadFileRealDtb(self, fname):
479 """Run binman with a real .dtb file and return the resulting data
480
481 Args:
482 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
483
484 Returns:
485 Resulting image contents
486 """
487 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
488
Simon Glass72232452016-11-25 20:15:53 -0700489 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600490 """Helper function which discards the device-tree binary
491
492 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600493 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600494 use_real_dtb: True to use the test file as the contents of
495 the u-boot-dtb entry. Normally this is not needed and the
496 test contents (the U_BOOT_DTB_DATA string) can be used.
497 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600498
499 Returns:
500 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600501 """
Simon Glass72232452016-11-25 20:15:53 -0700502 return self._DoReadFileDtb(fname, use_real_dtb)[0]
503
Simon Glass57454f42016-11-25 20:15:52 -0700504 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600505 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700506 """Create a new test input file, creating directories as needed
507
508 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600509 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700510 contents: File contents to write in to the file
511 Returns:
512 Full pathname of file created
513 """
Simon Glass862f8e22019-08-24 07:22:43 -0600514 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700515 dirname = os.path.dirname(pathname)
516 if dirname and not os.path.exists(dirname):
517 os.makedirs(dirname)
518 with open(pathname, 'wb') as fd:
519 fd.write(contents)
520 return pathname
521
522 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600523 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600524 """Create a new test input directory, creating directories as needed
525
526 Args:
527 dirname: Directory name to create
528
529 Returns:
530 Full pathname of directory created
531 """
Simon Glass862f8e22019-08-24 07:22:43 -0600532 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600533 if not os.path.exists(pathname):
534 os.makedirs(pathname)
535 return pathname
536
537 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600538 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600539 """Set up an ELF file with a '_dt_ucode_base_size' symbol
540
541 Args:
542 Filename of ELF file to use as SPL
543 """
Simon Glass93a806f2019-08-24 07:22:59 -0600544 TestFunctional._MakeInputFile('spl/u-boot-spl',
545 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600546
547 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600548 def _SetupTplElf(cls, src_fname='bss_data'):
549 """Set up an ELF file with a '_dt_ucode_base_size' symbol
550
551 Args:
552 Filename of ELF file to use as TPL
553 """
554 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
555 tools.ReadFile(cls.ElfTestFile(src_fname)))
556
557 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600558 def _SetupDescriptor(cls):
559 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
560 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
561
562 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600563 def TestFile(cls, fname):
564 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700565
Simon Glassf6290892019-08-24 07:22:53 -0600566 @classmethod
567 def ElfTestFile(cls, fname):
568 return os.path.join(cls._elf_testdir, fname)
569
Simon Glass57454f42016-11-25 20:15:52 -0700570 def AssertInList(self, grep_list, target):
571 """Assert that at least one of a list of things is in a target
572
573 Args:
574 grep_list: List of strings to check
575 target: Target string
576 """
577 for grep in grep_list:
578 if grep in target:
579 return
Simon Glass848cdb52019-05-17 22:00:50 -0600580 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700581
582 def CheckNoGaps(self, entries):
583 """Check that all entries fit together without gaps
584
585 Args:
586 entries: List of entries to check
587 """
Simon Glasse8561af2018-08-01 15:22:37 -0600588 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700589 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600590 self.assertEqual(offset, entry.offset)
591 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700592
Simon Glass72232452016-11-25 20:15:53 -0700593 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600594 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700595
596 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600597 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700598
599 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600600 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700601 """
602 return struct.unpack('>L', dtb[4:8])[0]
603
Simon Glass0f621332019-07-08 14:25:27 -0600604 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600605 def AddNode(node, path):
606 if node.name != '/':
607 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600608 for prop in node.props.values():
609 if prop.name in prop_names:
610 prop_path = path + ':' + prop.name
611 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
612 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600613 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600614 AddNode(subnode, path)
615
616 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600617 AddNode(dtb.GetRoot(), '')
618 return tree
619
Simon Glass57454f42016-11-25 20:15:52 -0700620 def testRun(self):
621 """Test a basic run with valid args"""
622 result = self._RunBinman('-h')
623
624 def testFullHelp(self):
625 """Test that the full help is displayed with -H"""
626 result = self._RunBinman('-H')
627 help_file = os.path.join(self._binman_dir, 'README')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500628 # Remove possible extraneous strings
629 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
630 gothelp = result.stdout.replace(extra, '')
631 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700632 self.assertEqual(0, len(result.stderr))
633 self.assertEqual(0, result.return_code)
634
635 def testFullHelpInternal(self):
636 """Test that the full help is displayed with -H"""
637 try:
638 command.test_result = command.CommandResult()
639 result = self._DoBinman('-H')
640 help_file = os.path.join(self._binman_dir, 'README')
641 finally:
642 command.test_result = None
643
644 def testHelp(self):
645 """Test that the basic help is displayed with -h"""
646 result = self._RunBinman('-h')
647 self.assertTrue(len(result.stdout) > 200)
648 self.assertEqual(0, len(result.stderr))
649 self.assertEqual(0, result.return_code)
650
Simon Glass57454f42016-11-25 20:15:52 -0700651 def testBoard(self):
652 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600653 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700654 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassf46732a2019-07-08 14:25:29 -0600655 result = self._DoBinman('build', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700656 self.assertEqual(0, result)
657
658 def testNeedBoard(self):
659 """Test that we get an error when no board ius supplied"""
660 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600661 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700662 self.assertIn("Must provide a board to process (use -b <board>)",
663 str(e.exception))
664
665 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600666 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700667 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600668 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700669 # We get one error from libfdt, and a different one from fdtget.
670 self.AssertInList(["Couldn't open blob from 'missing_file'",
671 'No such file or directory'], str(e.exception))
672
673 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600674 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700675
676 Since this is a source file it should be compiled and the error
677 will come from the device-tree compiler (dtc).
678 """
679 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600680 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700681 self.assertIn("FATAL ERROR: Unable to parse input tree",
682 str(e.exception))
683
684 def testMissingNode(self):
685 """Test that a device tree without a 'binman' node generates an error"""
686 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600687 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700688 self.assertIn("does not have a 'binman' node", str(e.exception))
689
690 def testEmpty(self):
691 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600692 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700693 self.assertEqual(0, len(result.stderr))
694 self.assertEqual(0, result.return_code)
695
696 def testInvalidEntry(self):
697 """Test that an invalid entry is flagged"""
698 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600699 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600700 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700701 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
702 "'/binman/not-a-valid-type'", str(e.exception))
703
704 def testSimple(self):
705 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600706 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700707 self.assertEqual(U_BOOT_DATA, data)
708
Simon Glass075a45c2017-11-13 18:55:00 -0700709 def testSimpleDebug(self):
710 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600711 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700712
Simon Glass57454f42016-11-25 20:15:52 -0700713 def testDual(self):
714 """Test that we can handle creating two images
715
716 This also tests image padding.
717 """
Simon Glass511f6582018-10-01 12:22:30 -0600718 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700719 self.assertEqual(0, retcode)
720
721 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600722 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700723 fname = tools.GetOutputFilename('image1.bin')
724 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600725 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700726 data = fd.read()
727 self.assertEqual(U_BOOT_DATA, data)
728
729 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600730 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700731 fname = tools.GetOutputFilename('image2.bin')
732 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600733 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700734 data = fd.read()
735 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600736 self.assertEqual(tools.GetBytes(0, 3), data[:3])
737 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700738
739 def testBadAlign(self):
740 """Test that an invalid alignment value is detected"""
741 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600742 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700743 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
744 "of two", str(e.exception))
745
746 def testPackSimple(self):
747 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600748 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700749 self.assertEqual(0, retcode)
750 self.assertIn('image', control.images)
751 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600752 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700753 self.assertEqual(5, len(entries))
754
755 # First u-boot
756 self.assertIn('u-boot', entries)
757 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600758 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700759 self.assertEqual(len(U_BOOT_DATA), entry.size)
760
761 # Second u-boot, aligned to 16-byte boundary
762 self.assertIn('u-boot-align', entries)
763 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600764 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700765 self.assertEqual(len(U_BOOT_DATA), entry.size)
766
767 # Third u-boot, size 23 bytes
768 self.assertIn('u-boot-size', entries)
769 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600770 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700771 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
772 self.assertEqual(23, entry.size)
773
774 # Fourth u-boot, placed immediate after the above
775 self.assertIn('u-boot-next', entries)
776 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600777 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700778 self.assertEqual(len(U_BOOT_DATA), entry.size)
779
Simon Glasse8561af2018-08-01 15:22:37 -0600780 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700781 self.assertIn('u-boot-fixed', entries)
782 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600783 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700784 self.assertEqual(len(U_BOOT_DATA), entry.size)
785
Simon Glass39dd2152019-07-08 14:25:47 -0600786 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700787
788 def testPackExtra(self):
789 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600790 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
791 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700792
Simon Glass57454f42016-11-25 20:15:52 -0700793 self.assertIn('image', control.images)
794 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600795 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700796 self.assertEqual(5, len(entries))
797
798 # First u-boot with padding before and after
799 self.assertIn('u-boot', entries)
800 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600801 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700802 self.assertEqual(3, entry.pad_before)
803 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600804 self.assertEqual(U_BOOT_DATA, entry.data)
805 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
806 tools.GetBytes(0, 5), data[:entry.size])
807 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700808
809 # Second u-boot has an aligned size, but it has no effect
810 self.assertIn('u-boot-align-size-nop', entries)
811 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600812 self.assertEqual(pos, entry.offset)
813 self.assertEqual(len(U_BOOT_DATA), entry.size)
814 self.assertEqual(U_BOOT_DATA, entry.data)
815 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
816 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700817
818 # Third u-boot has an aligned size too
819 self.assertIn('u-boot-align-size', entries)
820 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600821 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700822 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600823 self.assertEqual(U_BOOT_DATA, entry.data)
824 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
825 data[pos:pos + entry.size])
826 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700827
828 # Fourth u-boot has an aligned end
829 self.assertIn('u-boot-align-end', entries)
830 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600831 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600833 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
834 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
835 data[pos:pos + entry.size])
836 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700837
838 # Fifth u-boot immediately afterwards
839 self.assertIn('u-boot-align-both', entries)
840 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600841 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700842 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600843 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
844 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
845 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700846
847 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600848 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700849
Simon Glassafb9caa2020-10-26 17:40:10 -0600850 dtb = fdt.Fdt(out_dtb_fname)
851 dtb.Scan()
852 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
853 expected = {
854 'image-pos': 0,
855 'offset': 0,
856 'size': 128,
857
858 'u-boot:image-pos': 0,
859 'u-boot:offset': 0,
860 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
861
862 'u-boot-align-size-nop:image-pos': 12,
863 'u-boot-align-size-nop:offset': 12,
864 'u-boot-align-size-nop:size': 4,
865
866 'u-boot-align-size:image-pos': 16,
867 'u-boot-align-size:offset': 16,
868 'u-boot-align-size:size': 32,
869
870 'u-boot-align-end:image-pos': 48,
871 'u-boot-align-end:offset': 48,
872 'u-boot-align-end:size': 16,
873
874 'u-boot-align-both:image-pos': 64,
875 'u-boot-align-both:offset': 64,
876 'u-boot-align-both:size': 64,
877 }
878 self.assertEqual(expected, props)
879
Simon Glass57454f42016-11-25 20:15:52 -0700880 def testPackAlignPowerOf2(self):
881 """Test that invalid entry alignment is detected"""
882 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600883 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700884 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
885 "of two", str(e.exception))
886
887 def testPackAlignSizePowerOf2(self):
888 """Test that invalid entry size alignment is detected"""
889 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600890 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700891 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
892 "power of two", str(e.exception))
893
894 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600895 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600897 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600898 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700899 "align 0x4 (4)", str(e.exception))
900
901 def testPackInvalidSizeAlign(self):
902 """Test that invalid entry size alignment is detected"""
903 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600904 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700905 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
906 "align-size 0x4 (4)", str(e.exception))
907
908 def testPackOverlap(self):
909 """Test that overlapping regions are detected"""
910 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600911 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600912 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700913 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
914 str(e.exception))
915
916 def testPackEntryOverflow(self):
917 """Test that entries that overflow their size are detected"""
918 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600919 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700920 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
921 "but entry size is 0x3 (3)", str(e.exception))
922
923 def testPackImageOverflow(self):
924 """Test that entries which overflow the image size are detected"""
925 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600926 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600927 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700928 "size 0x3 (3)", str(e.exception))
929
930 def testPackImageSize(self):
931 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600932 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700933 self.assertEqual(0, retcode)
934 self.assertIn('image', control.images)
935 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600936 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700937
938 def testPackImageSizeAlign(self):
939 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600940 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700941 self.assertEqual(0, retcode)
942 self.assertIn('image', control.images)
943 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600944 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700945
946 def testPackInvalidImageAlign(self):
947 """Test that invalid image alignment is detected"""
948 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600949 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600950 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700951 "align-size 0x8 (8)", str(e.exception))
952
953 def testPackAlignPowerOf2(self):
954 """Test that invalid image alignment is detected"""
955 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600956 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600957 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700958 "two", str(e.exception))
959
960 def testImagePadByte(self):
961 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600962 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600963 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600964 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
965 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700966
967 def testImageName(self):
968 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600969 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700970 self.assertEqual(0, retcode)
971 image = control.images['image1']
972 fname = tools.GetOutputFilename('test-name')
973 self.assertTrue(os.path.exists(fname))
974
975 image = control.images['image2']
976 fname = tools.GetOutputFilename('test-name.xx')
977 self.assertTrue(os.path.exists(fname))
978
979 def testBlobFilename(self):
980 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600981 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700982 self.assertEqual(BLOB_DATA, data)
983
984 def testPackSorted(self):
985 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600986 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600987 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600988 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
989 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700990
Simon Glasse8561af2018-08-01 15:22:37 -0600991 def testPackZeroOffset(self):
992 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -0700993 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600994 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600995 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700996 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
997 str(e.exception))
998
999 def testPackUbootDtb(self):
1000 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001001 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001002 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001003
1004 def testPackX86RomNoSize(self):
1005 """Test that the end-at-4gb property requires a size property"""
1006 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001007 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001008 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001009 "using end-at-4gb", str(e.exception))
1010
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301011 def test4gbAndSkipAtStartTogether(self):
1012 """Test that the end-at-4gb and skip-at-size property can't be used
1013 together"""
1014 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001015 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001016 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301017 "'skip-at-start'", str(e.exception))
1018
Simon Glass72232452016-11-25 20:15:53 -07001019 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001020 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001021 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001022 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001023 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1024 "is outside the section '/binman' starting at "
1025 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001026 str(e.exception))
1027
1028 def testPackX86Rom(self):
1029 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001030 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001031 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -06001032 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -06001033 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001034
1035 def testPackX86RomMeNoDesc(self):
1036 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001037 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001038 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001039 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001040 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001041 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1042 str(e.exception))
1043 finally:
1044 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001045
1046 def testPackX86RomBadDesc(self):
1047 """Test that the Intel requires a descriptor entry"""
1048 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001049 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001050 self.assertIn("Node '/binman/intel-me': No offset set with "
1051 "offset-unset: should another entry provide this correct "
1052 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001053
1054 def testPackX86RomMe(self):
1055 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001056 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -06001057 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1058 if data[:0x1000] != expected_desc:
1059 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001060 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1061
1062 def testPackVga(self):
1063 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001064 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001065 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1066
1067 def testPackStart16(self):
1068 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001069 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001070 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1071
Jagdish Gediya311d4842018-09-03 21:35:08 +05301072 def testPackPowerpcMpc85xxBootpgResetvec(self):
1073 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1074 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001075 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301076 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1077
Simon Glass6ba679c2018-07-06 10:27:17 -06001078 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001079 """Handle running a test for insertion of microcode
1080
1081 Args:
1082 dts_fname: Name of test .dts file
1083 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001084 ucode_second: True if the microsecond entry is second instead of
1085 third
Simon Glass820af1d2018-07-06 10:27:16 -06001086
1087 Returns:
1088 Tuple:
1089 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001090 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001091 in the above (two 4-byte words)
1092 """
Simon Glass3d274232017-11-12 21:52:27 -07001093 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001094
1095 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001096 if ucode_second:
1097 ucode_content = data[len(nodtb_data):]
1098 ucode_pos = len(nodtb_data)
1099 dtb_with_ucode = ucode_content[16:]
1100 fdt_len = self.GetFdtLen(dtb_with_ucode)
1101 else:
1102 dtb_with_ucode = data[len(nodtb_data):]
1103 fdt_len = self.GetFdtLen(dtb_with_ucode)
1104 ucode_content = dtb_with_ucode[fdt_len:]
1105 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001106 fname = tools.GetOutputFilename('test.dtb')
1107 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001108 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001109 dtb = fdt.FdtScan(fname)
1110 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001111 self.assertTrue(ucode)
1112 for node in ucode.subnodes:
1113 self.assertFalse(node.props.get('data'))
1114
Simon Glass72232452016-11-25 20:15:53 -07001115 # Check that the microcode appears immediately after the Fdt
1116 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001117 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001118 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1119 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001120 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001121
1122 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001123 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001124 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1125 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001126 u_boot = data[:len(nodtb_data)]
1127 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001128
1129 def testPackUbootMicrocode(self):
1130 """Test that x86 microcode can be handled correctly
1131
1132 We expect to see the following in the image, in order:
1133 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1134 place
1135 u-boot.dtb with the microcode removed
1136 the microcode
1137 """
Simon Glass511f6582018-10-01 12:22:30 -06001138 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001139 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001140 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1141 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001142
Simon Glassbac25c82017-05-27 07:38:26 -06001143 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001144 """Test that x86 microcode can be handled correctly
1145
1146 We expect to see the following in the image, in order:
1147 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1148 place
1149 u-boot.dtb with the microcode
1150 an empty microcode region
1151 """
1152 # We need the libfdt library to run this test since only that allows
1153 # finding the offset of a property. This is required by
1154 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001155 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001156
1157 second = data[len(U_BOOT_NODTB_DATA):]
1158
1159 fdt_len = self.GetFdtLen(second)
1160 third = second[fdt_len:]
1161 second = second[:fdt_len]
1162
Simon Glassbac25c82017-05-27 07:38:26 -06001163 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1164 self.assertIn(ucode_data, second)
1165 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001166
Simon Glassbac25c82017-05-27 07:38:26 -06001167 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001168 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001169 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1170 len(ucode_data))
1171 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001172 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1173 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001174
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001175 def testPackUbootSingleMicrocode(self):
1176 """Test that x86 microcode can be handled correctly with fdt_normal.
1177 """
Simon Glassbac25c82017-05-27 07:38:26 -06001178 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001179
Simon Glass996021e2016-11-25 20:15:54 -07001180 def testUBootImg(self):
1181 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001182 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001183 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001184
1185 def testNoMicrocode(self):
1186 """Test that a missing microcode region is detected"""
1187 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001188 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001189 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1190 "node found in ", str(e.exception))
1191
1192 def testMicrocodeWithoutNode(self):
1193 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1194 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001195 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001196 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1197 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1198
1199 def testMicrocodeWithoutNode2(self):
1200 """Test that a missing u-boot-ucode node is detected"""
1201 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001202 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001203 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1204 "microcode region u-boot-ucode", str(e.exception))
1205
1206 def testMicrocodeWithoutPtrInElf(self):
1207 """Test that a U-Boot binary without the microcode symbol is detected"""
1208 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001209 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001210 TestFunctional._MakeInputFile('u-boot',
1211 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001212
1213 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001214 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001215 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1216 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1217
1218 finally:
1219 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001220 TestFunctional._MakeInputFile('u-boot',
1221 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001222
1223 def testMicrocodeNotInImage(self):
1224 """Test that microcode must be placed within the image"""
1225 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001226 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001227 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1228 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001229 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001230
1231 def testWithoutMicrocode(self):
1232 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001233 TestFunctional._MakeInputFile('u-boot',
1234 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001235 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001236
1237 # Now check the device tree has no microcode
1238 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1239 second = data[len(U_BOOT_NODTB_DATA):]
1240
1241 fdt_len = self.GetFdtLen(second)
1242 self.assertEqual(dtb, second[:fdt_len])
1243
1244 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1245 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001246 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001247
1248 def testUnknownPosSize(self):
1249 """Test that microcode must be placed within the image"""
1250 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001251 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001252 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001253 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001254
1255 def testPackFsp(self):
1256 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001257 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001258 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1259
1260 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001261 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001262 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001263 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001264
1265 def testPackVbt(self):
1266 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001267 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001268 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001269
Simon Glass7f94e832017-11-12 21:52:25 -07001270 def testSplBssPad(self):
1271 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001272 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001273 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001274 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001275 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1276 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001277
Simon Glass04cda032018-10-01 21:12:42 -06001278 def testSplBssPadMissing(self):
1279 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001280 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001281 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001282 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001283 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1284 str(e.exception))
1285
Simon Glasse83679d2017-11-12 21:52:26 -07001286 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001287 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001288 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001289 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1290
Simon Glass6ba679c2018-07-06 10:27:17 -06001291 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1292 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001293
1294 We expect to see the following in the image, in order:
1295 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1296 correct place
1297 u-boot.dtb with the microcode removed
1298 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001299
1300 Args:
1301 dts: Device tree file to use for test
1302 ucode_second: True if the microsecond entry is second instead of
1303 third
Simon Glass3d274232017-11-12 21:52:27 -07001304 """
Simon Glass7057d022018-10-01 21:12:47 -06001305 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001306 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1307 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001308 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1309 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001310
Simon Glass6ba679c2018-07-06 10:27:17 -06001311 def testPackUbootSplMicrocode(self):
1312 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001313 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001314
1315 def testPackUbootSplMicrocodeReorder(self):
1316 """Test that order doesn't matter for microcode entries
1317
1318 This is the same as testPackUbootSplMicrocode but when we process the
1319 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1320 entry, so we reply on binman to try later.
1321 """
Simon Glass511f6582018-10-01 12:22:30 -06001322 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001323 ucode_second=True)
1324
Simon Glassa409c932017-11-12 21:52:28 -07001325 def testPackMrc(self):
1326 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001327 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001328 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1329
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001330 def testSplDtb(self):
1331 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001332 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001333 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1334
Simon Glass0a6da312017-11-13 18:54:56 -07001335 def testSplNoDtb(self):
1336 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001337 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001338 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1339
Simon Glass4ca8e042017-11-13 18:55:01 -07001340 def testSymbols(self):
1341 """Test binman can assign symbols embedded in U-Boot"""
Simon Glass5d0c0262019-08-24 07:22:56 -06001342 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001343 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1344 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glasse8561af2018-08-01 15:22:37 -06001345 self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001346
Simon Glass7057d022018-10-01 21:12:47 -06001347 self._SetupSplElf('u_boot_binman_syms')
Simon Glass511f6582018-10-01 12:22:30 -06001348 data = self._DoReadFile('053_symbols.dts')
Simon Glass72555fa2019-11-06 17:22:44 -07001349 sym_values = struct.pack('<LQLL', 0x00, 0x1c, 0x28, 0x04)
Simon Glass3f8ff012019-08-24 07:23:05 -06001350 expected = (sym_values + U_BOOT_SPL_DATA[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001351 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass3f8ff012019-08-24 07:23:05 -06001352 U_BOOT_SPL_DATA[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001353 self.assertEqual(expected, data)
1354
Simon Glasse76a3e62018-06-01 09:38:11 -06001355 def testPackUnitAddress(self):
1356 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001357 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001358 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1359
Simon Glassa91e1152018-06-01 09:38:16 -06001360 def testSections(self):
1361 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001362 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001363 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1364 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1365 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001366 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001367
Simon Glass30732662018-06-01 09:38:20 -06001368 def testMap(self):
1369 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001370 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001371 self.assertEqual('''ImagePos Offset Size Name
137200000000 00000000 00000028 main-section
137300000000 00000000 00000010 section@0
137400000000 00000000 00000004 u-boot
137500000010 00000010 00000010 section@1
137600000010 00000000 00000004 u-boot
137700000020 00000020 00000004 section@2
137800000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001379''', map_data)
1380
Simon Glass3b78d532018-06-01 09:38:21 -06001381 def testNamePrefix(self):
1382 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001383 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001384 self.assertEqual('''ImagePos Offset Size Name
138500000000 00000000 00000028 main-section
138600000000 00000000 00000010 section@0
138700000000 00000000 00000004 ro-u-boot
138800000010 00000010 00000010 section@1
138900000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001390''', map_data)
1391
Simon Glass6ba679c2018-07-06 10:27:17 -06001392 def testUnknownContents(self):
1393 """Test that obtaining the contents works as expected"""
1394 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001395 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001396 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001397 "processing of contents: remaining ["
1398 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001399
Simon Glass2e1169f2018-07-06 10:27:19 -06001400 def testBadChangeSize(self):
1401 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001402 try:
1403 state.SetAllowEntryExpansion(False)
1404 with self.assertRaises(ValueError) as e:
1405 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001406 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001407 str(e.exception))
1408 finally:
1409 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001410
Simon Glassa87014e2018-07-06 10:27:42 -06001411 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001412 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001413 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001414 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001415 dtb = fdt.Fdt(out_dtb_fname)
1416 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001417 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001418 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001419 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001420 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001421 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001422 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001423 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001424 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001425 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001426 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001427 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001428 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001429 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001430
Simon Glasse8561af2018-08-01 15:22:37 -06001431 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001432 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001433 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001434 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001435 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001436 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001437 'size': 40
1438 }, props)
1439
1440 def testUpdateFdtBad(self):
1441 """Test that we detect when ProcessFdt never completes"""
1442 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001443 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001444 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001445 '[<binman.etype._testing.Entry__testing',
1446 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001447
Simon Glass91710b32018-07-17 13:25:32 -06001448 def testEntryArgs(self):
1449 """Test passing arguments to entries from the command line"""
1450 entry_args = {
1451 'test-str-arg': 'test1',
1452 'test-int-arg': '456',
1453 }
Simon Glass511f6582018-10-01 12:22:30 -06001454 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001455 self.assertIn('image', control.images)
1456 entry = control.images['image'].GetEntries()['_testing']
1457 self.assertEqual('test0', entry.test_str_fdt)
1458 self.assertEqual('test1', entry.test_str_arg)
1459 self.assertEqual(123, entry.test_int_fdt)
1460 self.assertEqual(456, entry.test_int_arg)
1461
1462 def testEntryArgsMissing(self):
1463 """Test missing arguments and properties"""
1464 entry_args = {
1465 'test-int-arg': '456',
1466 }
Simon Glass511f6582018-10-01 12:22:30 -06001467 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001468 entry = control.images['image'].GetEntries()['_testing']
1469 self.assertEqual('test0', entry.test_str_fdt)
1470 self.assertEqual(None, entry.test_str_arg)
1471 self.assertEqual(None, entry.test_int_fdt)
1472 self.assertEqual(456, entry.test_int_arg)
1473
1474 def testEntryArgsRequired(self):
1475 """Test missing arguments and properties"""
1476 entry_args = {
1477 'test-int-arg': '456',
1478 }
1479 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001480 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001481 self.assertIn("Node '/binman/_testing': "
1482 'Missing required properties/entry args: test-str-arg, '
1483 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001484 str(e.exception))
1485
1486 def testEntryArgsInvalidFormat(self):
1487 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001488 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1489 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001490 with self.assertRaises(ValueError) as e:
1491 self._DoBinman(*args)
1492 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1493
1494 def testEntryArgsInvalidInteger(self):
1495 """Test that an invalid entry-argument integer is detected"""
1496 entry_args = {
1497 'test-int-arg': 'abc',
1498 }
1499 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001500 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001501 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1502 "'test-int-arg' (value 'abc') to integer",
1503 str(e.exception))
1504
1505 def testEntryArgsInvalidDatatype(self):
1506 """Test that an invalid entry-argument datatype is detected
1507
1508 This test could be written in entry_test.py except that it needs
1509 access to control.entry_args, which seems more than that module should
1510 be able to see.
1511 """
1512 entry_args = {
1513 'test-bad-datatype-arg': '12',
1514 }
1515 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001516 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001517 entry_args=entry_args)
1518 self.assertIn('GetArg() internal error: Unknown data type ',
1519 str(e.exception))
1520
Simon Glass2ca52032018-07-17 13:25:33 -06001521 def testText(self):
1522 """Test for a text entry type"""
1523 entry_args = {
1524 'test-id': TEXT_DATA,
1525 'test-id2': TEXT_DATA2,
1526 'test-id3': TEXT_DATA3,
1527 }
Simon Glass511f6582018-10-01 12:22:30 -06001528 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001529 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001530 expected = (tools.ToBytes(TEXT_DATA) +
1531 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1532 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001533 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001534 self.assertEqual(expected, data)
1535
Simon Glass969616c2018-07-17 13:25:36 -06001536 def testEntryDocs(self):
1537 """Test for creation of entry documentation"""
1538 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001539 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001540 self.assertTrue(len(stdout.getvalue()) > 0)
1541
1542 def testEntryDocsMissing(self):
1543 """Test handling of missing entry documentation"""
1544 with self.assertRaises(ValueError) as e:
1545 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001546 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001547 self.assertIn('Documentation is missing for modules: u_boot',
1548 str(e.exception))
1549
Simon Glass704784b2018-07-17 13:25:38 -06001550 def testFmap(self):
1551 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001552 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001553 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001554 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1555 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001556 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001557 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001558 self.assertEqual(1, fhdr.ver_major)
1559 self.assertEqual(0, fhdr.ver_minor)
1560 self.assertEqual(0, fhdr.base)
1561 self.assertEqual(16 + 16 +
1562 fmap_util.FMAP_HEADER_LEN +
1563 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001564 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass704784b2018-07-17 13:25:38 -06001565 self.assertEqual(3, fhdr.nareas)
1566 for fentry in fentries:
1567 self.assertEqual(0, fentry.flags)
1568
1569 self.assertEqual(0, fentries[0].offset)
1570 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001571 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass704784b2018-07-17 13:25:38 -06001572
1573 self.assertEqual(16, fentries[1].offset)
1574 self.assertEqual(4, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001575 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass704784b2018-07-17 13:25:38 -06001576
1577 self.assertEqual(32, fentries[2].offset)
1578 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1579 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001580 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass704784b2018-07-17 13:25:38 -06001581
Simon Glassdb168d42018-07-17 13:25:39 -06001582 def testBlobNamedByArg(self):
1583 """Test we can add a blob with the filename coming from an entry arg"""
1584 entry_args = {
1585 'cros-ec-rw-path': 'ecrw.bin',
1586 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001587 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001588
Simon Glass53f53992018-07-17 13:25:40 -06001589 def testFill(self):
1590 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001591 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001592 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001593 self.assertEqual(expected, data)
1594
1595 def testFillNoSize(self):
1596 """Test for an fill entry type with no size"""
1597 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001598 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001599 self.assertIn("'fill' entry must have a size property",
1600 str(e.exception))
1601
Simon Glassc1ae83c2018-07-17 13:25:44 -06001602 def _HandleGbbCommand(self, pipe_list):
1603 """Fake calls to the futility utility"""
1604 if pipe_list[0][0] == 'futility':
1605 fname = pipe_list[0][-1]
1606 # Append our GBB data to the file, which will happen every time the
1607 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001608 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001609 fd.write(GBB_DATA)
1610 return command.CommandResult()
1611
1612 def testGbb(self):
1613 """Test for the Chromium OS Google Binary Block"""
1614 command.test_result = self._HandleGbbCommand
1615 entry_args = {
1616 'keydir': 'devkeys',
1617 'bmpblk': 'bmpblk.bin',
1618 }
Simon Glass511f6582018-10-01 12:22:30 -06001619 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001620
1621 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001622 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1623 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001624 self.assertEqual(expected, data)
1625
1626 def testGbbTooSmall(self):
1627 """Test for the Chromium OS Google Binary Block being large enough"""
1628 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001629 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001630 self.assertIn("Node '/binman/gbb': GBB is too small",
1631 str(e.exception))
1632
1633 def testGbbNoSize(self):
1634 """Test for the Chromium OS Google Binary Block having a size"""
1635 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001636 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001637 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1638 str(e.exception))
1639
Simon Glass5c350162018-07-17 13:25:47 -06001640 def _HandleVblockCommand(self, pipe_list):
1641 """Fake calls to the futility utility"""
1642 if pipe_list[0][0] == 'futility':
1643 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001644 with open(fname, 'wb') as fd:
Simon Glass5c350162018-07-17 13:25:47 -06001645 fd.write(VBLOCK_DATA)
1646 return command.CommandResult()
1647
1648 def testVblock(self):
1649 """Test for the Chromium OS Verified Boot Block"""
1650 command.test_result = self._HandleVblockCommand
1651 entry_args = {
1652 'keydir': 'devkeys',
1653 }
Simon Glass511f6582018-10-01 12:22:30 -06001654 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001655 entry_args=entry_args)
1656 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1657 self.assertEqual(expected, data)
1658
1659 def testVblockNoContent(self):
1660 """Test we detect a vblock which has no content to sign"""
1661 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001662 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001663 self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
1664 'property', str(e.exception))
1665
1666 def testVblockBadPhandle(self):
1667 """Test that we detect a vblock with an invalid phandle in contents"""
1668 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001669 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001670 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1671 '1000', str(e.exception))
1672
1673 def testVblockBadEntry(self):
1674 """Test that we detect an entry that points to a non-entry"""
1675 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001676 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001677 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1678 "'other'", str(e.exception))
1679
Simon Glass8425a1f2018-07-17 13:25:48 -06001680 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001681 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001682 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001683 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001684 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001685 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1686
Simon Glass24b97442018-07-17 13:25:51 -06001687 def testUsesPos(self):
1688 """Test that the 'pos' property cannot be used anymore"""
1689 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001690 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001691 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1692 "'pos'", str(e.exception))
1693
Simon Glass274bf092018-09-14 04:57:08 -06001694 def testFillZero(self):
1695 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001696 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001697 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001698
Simon Glass267de432018-09-14 04:57:09 -06001699 def testTextMissing(self):
1700 """Test for a text entry type where there is no text"""
1701 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001702 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001703 self.assertIn("Node '/binman/text': No value provided for text label "
1704 "'test-id'", str(e.exception))
1705
Simon Glassed40e962018-09-14 04:57:10 -06001706 def testPackStart16Tpl(self):
1707 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001708 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001709 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1710
Simon Glass3b376c32018-09-14 04:57:12 -06001711 def testSelectImage(self):
1712 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001713 expected = 'Skipping images: image1'
1714
1715 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001716 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001717 with test_util.capture_sys_output() as (stdout, stderr):
1718 retcode = self._DoTestFile('006_dual_image.dts',
1719 verbosity=verbosity,
1720 images=['image2'])
1721 self.assertEqual(0, retcode)
1722 if verbosity:
1723 self.assertIn(expected, stdout.getvalue())
1724 else:
1725 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001726
Simon Glassb4595d82019-04-25 21:58:34 -06001727 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1728 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001729 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001730
Simon Glasse219aa42018-09-14 04:57:24 -06001731 def testUpdateFdtAll(self):
1732 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001733 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001734
1735 base_expected = {
1736 'section:image-pos': 0,
1737 'u-boot-tpl-dtb:size': 513,
1738 'u-boot-spl-dtb:size': 513,
1739 'u-boot-spl-dtb:offset': 493,
1740 'image-pos': 0,
1741 'section/u-boot-dtb:image-pos': 0,
1742 'u-boot-spl-dtb:image-pos': 493,
1743 'section/u-boot-dtb:size': 493,
1744 'u-boot-tpl-dtb:image-pos': 1006,
1745 'section/u-boot-dtb:offset': 0,
1746 'section:size': 493,
1747 'offset': 0,
1748 'section:offset': 0,
1749 'u-boot-tpl-dtb:offset': 1006,
1750 'size': 1519
1751 }
1752
1753 # We expect three device-tree files in the output, one after the other.
1754 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1755 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1756 # main U-Boot tree. All three should have the same postions and offset.
1757 start = 0
1758 for item in ['', 'spl', 'tpl']:
1759 dtb = fdt.Fdt.FromData(data[start:])
1760 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001761 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1762 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001763 expected = dict(base_expected)
1764 if item:
1765 expected[item] = 0
1766 self.assertEqual(expected, props)
1767 start += dtb._fdt_obj.totalsize()
1768
1769 def testUpdateFdtOutput(self):
1770 """Test that output DTB files are updated"""
1771 try:
Simon Glass511f6582018-10-01 12:22:30 -06001772 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001773 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1774
1775 # Unfortunately, compiling a source file always results in a file
1776 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001777 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001778 # binman as a file called u-boot.dtb. To fix this, copy the file
1779 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001780 start = 0
1781 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1782 'tpl/u-boot-tpl.dtb.out']:
1783 dtb = fdt.Fdt.FromData(data[start:])
1784 size = dtb._fdt_obj.totalsize()
1785 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1786 outdata = tools.ReadFile(pathname)
1787 name = os.path.split(fname)[0]
1788
1789 if name:
1790 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1791 else:
1792 orig_indata = dtb_data
1793 self.assertNotEqual(outdata, orig_indata,
1794 "Expected output file '%s' be updated" % pathname)
1795 self.assertEqual(outdata, data[start:start + size],
1796 "Expected output file '%s' to match output image" %
1797 pathname)
1798 start += size
1799 finally:
1800 self._ResetDtbs()
1801
Simon Glass7ba33592018-09-14 04:57:26 -06001802 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001803 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001804
1805 def testCompress(self):
1806 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001807 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001808 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001809 use_real_dtb=True, update_dtb=True)
1810 dtb = fdt.Fdt(out_dtb_fname)
1811 dtb.Scan()
1812 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1813 orig = self._decompress(data)
1814 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001815
1816 # Do a sanity check on various fields
1817 image = control.images['image']
1818 entries = image.GetEntries()
1819 self.assertEqual(1, len(entries))
1820
1821 entry = entries['blob']
1822 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1823 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1824 orig = self._decompress(entry.data)
1825 self.assertEqual(orig, entry.uncomp_data)
1826
Simon Glass72eeff12020-10-26 17:40:16 -06001827 self.assertEqual(image.data, entry.data)
1828
Simon Glass7ba33592018-09-14 04:57:26 -06001829 expected = {
1830 'blob:uncomp-size': len(COMPRESS_DATA),
1831 'blob:size': len(data),
1832 'size': len(data),
1833 }
1834 self.assertEqual(expected, props)
1835
Simon Glassac6328c2018-09-14 04:57:28 -06001836 def testFiles(self):
1837 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001838 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001839 self.assertEqual(FILES_DATA, data)
1840
1841 def testFilesCompress(self):
1842 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001843 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001844 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001845
1846 image = control.images['image']
1847 entries = image.GetEntries()
1848 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001849 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001850
Simon Glass303f62f2019-05-17 22:00:46 -06001851 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001852 for i in range(1, 3):
1853 key = '%d.dat' % i
1854 start = entries[key].image_pos
1855 len = entries[key].size
1856 chunk = data[start:start + len]
1857 orig += self._decompress(chunk)
1858
1859 self.assertEqual(FILES_DATA, orig)
1860
1861 def testFilesMissing(self):
1862 """Test missing files"""
1863 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001864 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001865 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1866 'no files', str(e.exception))
1867
1868 def testFilesNoPattern(self):
1869 """Test missing files"""
1870 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001871 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001872 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1873 str(e.exception))
1874
Simon Glassfa79a812018-09-14 04:57:29 -06001875 def testExpandSize(self):
1876 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001877 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001878 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001879 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1880 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1881 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1882 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001883 self.assertEqual(expect, data)
1884 self.assertEqual('''ImagePos Offset Size Name
188500000000 00000000 00000028 main-section
188600000000 00000000 00000008 fill
188700000008 00000008 00000004 u-boot
18880000000c 0000000c 00000004 section
18890000000c 00000000 00000003 intel-mrc
189000000010 00000010 00000004 u-boot2
189100000014 00000014 0000000c section2
189200000014 00000000 00000008 fill
18930000001c 00000008 00000004 u-boot
189400000020 00000020 00000008 fill2
1895''', map_data)
1896
1897 def testExpandSizeBad(self):
1898 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001899 with test_util.capture_sys_output() as (stdout, stderr):
1900 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001901 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001902 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1903 'expanding entry', str(e.exception))
1904
Simon Glassae7cf032018-09-14 04:57:31 -06001905 def testHash(self):
1906 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001907 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001908 use_real_dtb=True, update_dtb=True)
1909 dtb = fdt.Fdt(out_dtb_fname)
1910 dtb.Scan()
1911 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1912 m = hashlib.sha256()
1913 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001914 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001915
1916 def testHashNoAlgo(self):
1917 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001918 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001919 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
1920 'hash node', str(e.exception))
1921
1922 def testHashBadAlgo(self):
1923 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001924 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06001925 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
1926 str(e.exception))
1927
1928 def testHashSection(self):
1929 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001930 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001931 use_real_dtb=True, update_dtb=True)
1932 dtb = fdt.Fdt(out_dtb_fname)
1933 dtb.Scan()
1934 hash_node = dtb.GetNode('/binman/section/hash').props['value']
1935 m = hashlib.sha256()
1936 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001937 m.update(tools.GetBytes(ord('a'), 16))
1938 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001939
Simon Glass3fb4f422018-09-14 04:57:32 -06001940 def testPackUBootTplMicrocode(self):
1941 """Test that x86 microcode can be handled correctly in TPL
1942
1943 We expect to see the following in the image, in order:
1944 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
1945 place
1946 u-boot-tpl.dtb with the microcode removed
1947 the microcode
1948 """
Simon Glass3eb5b202019-08-24 07:23:00 -06001949 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06001950 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06001951 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001952 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
1953 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06001954
Simon Glassc64aea52018-09-14 04:57:34 -06001955 def testFmapX86(self):
1956 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001957 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06001958 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001959 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001960 self.assertEqual(expected, data[:32])
1961 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
1962
1963 self.assertEqual(0x100, fhdr.image_size)
1964
1965 self.assertEqual(0, fentries[0].offset)
1966 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001967 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001968
1969 self.assertEqual(4, fentries[1].offset)
1970 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001971 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001972
1973 self.assertEqual(32, fentries[2].offset)
1974 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1975 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001976 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001977
1978 def testFmapX86Section(self):
1979 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001980 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001981 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06001982 self.assertEqual(expected, data[:32])
1983 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
1984
1985 self.assertEqual(0x100, fhdr.image_size)
1986
1987 self.assertEqual(0, fentries[0].offset)
1988 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001989 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001990
1991 self.assertEqual(4, fentries[1].offset)
1992 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001993 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001994
1995 self.assertEqual(36, fentries[2].offset)
1996 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1997 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001998 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06001999
Simon Glassb1714232018-09-14 04:57:35 -06002000 def testElf(self):
2001 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002002 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002003 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002004 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002005 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002006 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002007
Simon Glass0d673792019-07-08 13:18:25 -06002008 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002009 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002010 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002011 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002012 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002013 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002014
Simon Glasscd817d52018-09-14 04:57:36 -06002015 def testPackOverlapMap(self):
2016 """Test that overlapping regions are detected"""
2017 with test_util.capture_sys_output() as (stdout, stderr):
2018 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002019 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06002020 map_fname = tools.GetOutputFilename('image.map')
2021 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2022 stdout.getvalue())
2023
2024 # We should not get an inmage, but there should be a map file
2025 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2026 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06002027 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002028 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002029<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002030<none> 00000000 00000004 u-boot
2031<none> 00000003 00000004 u-boot-align
2032''', map_data)
2033
Simon Glass0d673792019-07-08 13:18:25 -06002034 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002035 """Test that an image with an Intel Reference code binary works"""
2036 data = self._DoReadFile('100_intel_refcode.dts')
2037 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2038
Simon Glasseb023b32019-04-25 21:58:39 -06002039 def testSectionOffset(self):
2040 """Tests use of a section with an offset"""
2041 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2042 map=True)
2043 self.assertEqual('''ImagePos Offset Size Name
204400000000 00000000 00000038 main-section
204500000004 00000004 00000010 section@0
204600000004 00000000 00000004 u-boot
204700000018 00000018 00000010 section@1
204800000018 00000000 00000004 u-boot
20490000002c 0000002c 00000004 section@2
20500000002c 00000000 00000004 u-boot
2051''', map_data)
2052 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06002053 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2054 tools.GetBytes(0x21, 12) +
2055 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2056 tools.GetBytes(0x61, 12) +
2057 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2058 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002059
Simon Glass1de34482019-07-08 13:18:53 -06002060 def testCbfsRaw(self):
2061 """Test base handling of a Coreboot Filesystem (CBFS)
2062
2063 The exact contents of the CBFS is verified by similar tests in
2064 cbfs_util_test.py. The tests here merely check that the files added to
2065 the CBFS can be found in the final image.
2066 """
2067 data = self._DoReadFile('102_cbfs_raw.dts')
2068 size = 0xb0
2069
2070 cbfs = cbfs_util.CbfsReader(data)
2071 self.assertEqual(size, cbfs.rom_size)
2072
2073 self.assertIn('u-boot-dtb', cbfs.files)
2074 cfile = cbfs.files['u-boot-dtb']
2075 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2076
2077 def testCbfsArch(self):
2078 """Test on non-x86 architecture"""
2079 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2080 size = 0x100
2081
2082 cbfs = cbfs_util.CbfsReader(data)
2083 self.assertEqual(size, cbfs.rom_size)
2084
2085 self.assertIn('u-boot-dtb', cbfs.files)
2086 cfile = cbfs.files['u-boot-dtb']
2087 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2088
2089 def testCbfsStage(self):
2090 """Tests handling of a Coreboot Filesystem (CBFS)"""
2091 if not elf.ELF_TOOLS:
2092 self.skipTest('Python elftools not available')
2093 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2094 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2095 size = 0xb0
2096
2097 data = self._DoReadFile('104_cbfs_stage.dts')
2098 cbfs = cbfs_util.CbfsReader(data)
2099 self.assertEqual(size, cbfs.rom_size)
2100
2101 self.assertIn('u-boot', cbfs.files)
2102 cfile = cbfs.files['u-boot']
2103 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2104
2105 def testCbfsRawCompress(self):
2106 """Test handling of compressing raw files"""
2107 self._CheckLz4()
2108 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2109 size = 0x140
2110
2111 cbfs = cbfs_util.CbfsReader(data)
2112 self.assertIn('u-boot', cbfs.files)
2113 cfile = cbfs.files['u-boot']
2114 self.assertEqual(COMPRESS_DATA, cfile.data)
2115
2116 def testCbfsBadArch(self):
2117 """Test handling of a bad architecture"""
2118 with self.assertRaises(ValueError) as e:
2119 self._DoReadFile('106_cbfs_bad_arch.dts')
2120 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2121
2122 def testCbfsNoSize(self):
2123 """Test handling of a missing size property"""
2124 with self.assertRaises(ValueError) as e:
2125 self._DoReadFile('107_cbfs_no_size.dts')
2126 self.assertIn('entry must have a size property', str(e.exception))
2127
2128 def testCbfsNoCOntents(self):
2129 """Test handling of a CBFS entry which does not provide contentsy"""
2130 with self.assertRaises(ValueError) as e:
2131 self._DoReadFile('108_cbfs_no_contents.dts')
2132 self.assertIn('Could not complete processing of contents',
2133 str(e.exception))
2134
2135 def testCbfsBadCompress(self):
2136 """Test handling of a bad architecture"""
2137 with self.assertRaises(ValueError) as e:
2138 self._DoReadFile('109_cbfs_bad_compress.dts')
2139 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2140 str(e.exception))
2141
2142 def testCbfsNamedEntries(self):
2143 """Test handling of named entries"""
2144 data = self._DoReadFile('110_cbfs_name.dts')
2145
2146 cbfs = cbfs_util.CbfsReader(data)
2147 self.assertIn('FRED', cbfs.files)
2148 cfile1 = cbfs.files['FRED']
2149 self.assertEqual(U_BOOT_DATA, cfile1.data)
2150
2151 self.assertIn('hello', cbfs.files)
2152 cfile2 = cbfs.files['hello']
2153 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2154
Simon Glass759af872019-07-08 13:18:54 -06002155 def _SetupIfwi(self, fname):
2156 """Set up to run an IFWI test
2157
2158 Args:
2159 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2160 """
2161 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002162 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002163
2164 # Intel Integrated Firmware Image (IFWI) file
2165 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2166 data = fd.read()
2167 TestFunctional._MakeInputFile(fname,data)
2168
2169 def _CheckIfwi(self, data):
2170 """Check that an image with an IFWI contains the correct output
2171
2172 Args:
2173 data: Conents of output file
2174 """
2175 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2176 if data[:0x1000] != expected_desc:
2177 self.fail('Expected descriptor binary at start of image')
2178
2179 # We expect to find the TPL wil in subpart IBBP entry IBBL
2180 image_fname = tools.GetOutputFilename('image.bin')
2181 tpl_fname = tools.GetOutputFilename('tpl.out')
2182 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2183 subpart='IBBP', entry_name='IBBL')
2184
2185 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002186 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002187
2188 def testPackX86RomIfwi(self):
2189 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2190 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002191 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002192 self._CheckIfwi(data)
2193
2194 def testPackX86RomIfwiNoDesc(self):
2195 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2196 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002197 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002198 self._CheckIfwi(data)
2199
2200 def testPackX86RomIfwiNoData(self):
2201 """Test that an x86 ROM with IFWI handles missing data"""
2202 self._SetupIfwi('ifwi.bin')
2203 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002204 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002205 self.assertIn('Could not complete processing of contents',
2206 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002207
Simon Glassc2f1aed2019-07-08 13:18:56 -06002208 def testCbfsOffset(self):
2209 """Test a CBFS with files at particular offsets
2210
2211 Like all CFBS tests, this is just checking the logic that calls
2212 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2213 """
2214 data = self._DoReadFile('114_cbfs_offset.dts')
2215 size = 0x200
2216
2217 cbfs = cbfs_util.CbfsReader(data)
2218 self.assertEqual(size, cbfs.rom_size)
2219
2220 self.assertIn('u-boot', cbfs.files)
2221 cfile = cbfs.files['u-boot']
2222 self.assertEqual(U_BOOT_DATA, cfile.data)
2223 self.assertEqual(0x40, cfile.cbfs_offset)
2224
2225 self.assertIn('u-boot-dtb', cbfs.files)
2226 cfile2 = cbfs.files['u-boot-dtb']
2227 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2228 self.assertEqual(0x140, cfile2.cbfs_offset)
2229
Simon Glass0f621332019-07-08 14:25:27 -06002230 def testFdtmap(self):
2231 """Test an FDT map can be inserted in the image"""
2232 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2233 fdtmap_data = data[len(U_BOOT_DATA):]
2234 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002235 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002236 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2237
2238 fdt_data = fdtmap_data[16:]
2239 dtb = fdt.Fdt.FromData(fdt_data)
2240 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002241 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002242 self.assertEqual({
2243 'image-pos': 0,
2244 'offset': 0,
2245 'u-boot:offset': 0,
2246 'u-boot:size': len(U_BOOT_DATA),
2247 'u-boot:image-pos': 0,
2248 'fdtmap:image-pos': 4,
2249 'fdtmap:offset': 4,
2250 'fdtmap:size': len(fdtmap_data),
2251 'size': len(data),
2252 }, props)
2253
2254 def testFdtmapNoMatch(self):
2255 """Check handling of an FDT map when the section cannot be found"""
2256 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2257
2258 # Mangle the section name, which should cause a mismatch between the
2259 # correct FDT path and the one expected by the section
2260 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002261 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002262 entries = image.GetEntries()
2263 fdtmap = entries['fdtmap']
2264 with self.assertRaises(ValueError) as e:
2265 fdtmap._GetFdtmap()
2266 self.assertIn("Cannot locate node for path '/binman-suffix'",
2267 str(e.exception))
2268
Simon Glasscec34ba2019-07-08 14:25:28 -06002269 def testFdtmapHeader(self):
2270 """Test an FDT map and image header can be inserted in the image"""
2271 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2272 fdtmap_pos = len(U_BOOT_DATA)
2273 fdtmap_data = data[fdtmap_pos:]
2274 fdt_data = fdtmap_data[16:]
2275 dtb = fdt.Fdt.FromData(fdt_data)
2276 fdt_size = dtb.GetFdtObj().totalsize()
2277 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002278 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002279 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2280 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2281
2282 def testFdtmapHeaderStart(self):
2283 """Test an image header can be inserted at the image start"""
2284 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2285 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2286 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002287 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002288 offset = struct.unpack('<I', hdr_data[4:])[0]
2289 self.assertEqual(fdtmap_pos, offset)
2290
2291 def testFdtmapHeaderPos(self):
2292 """Test an image header can be inserted at a chosen position"""
2293 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2294 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2295 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002296 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002297 offset = struct.unpack('<I', hdr_data[4:])[0]
2298 self.assertEqual(fdtmap_pos, offset)
2299
2300 def testHeaderMissingFdtmap(self):
2301 """Test an image header requires an fdtmap"""
2302 with self.assertRaises(ValueError) as e:
2303 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2304 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2305 str(e.exception))
2306
2307 def testHeaderNoLocation(self):
2308 """Test an image header with a no specified location is detected"""
2309 with self.assertRaises(ValueError) as e:
2310 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2311 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2312 str(e.exception))
2313
Simon Glasse61b6f62019-07-08 14:25:37 -06002314 def testEntryExpand(self):
2315 """Test expanding an entry after it is packed"""
2316 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002317 self.assertEqual(b'aaa', data[:3])
2318 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2319 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002320
2321 def testEntryExpandBad(self):
2322 """Test expanding an entry after it is packed, twice"""
2323 with self.assertRaises(ValueError) as e:
2324 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002325 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002326 str(e.exception))
2327
2328 def testEntryExpandSection(self):
2329 """Test expanding an entry within a section after it is packed"""
2330 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002331 self.assertEqual(b'aaa', data[:3])
2332 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2333 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002334
Simon Glass90d29682019-07-08 14:25:38 -06002335 def testCompressDtb(self):
2336 """Test that compress of device-tree files is supported"""
2337 self._CheckLz4()
2338 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2339 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2340 comp_data = data[len(U_BOOT_DATA):]
2341 orig = self._decompress(comp_data)
2342 dtb = fdt.Fdt.FromData(orig)
2343 dtb.Scan()
2344 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2345 expected = {
2346 'u-boot:size': len(U_BOOT_DATA),
2347 'u-boot-dtb:uncomp-size': len(orig),
2348 'u-boot-dtb:size': len(comp_data),
2349 'size': len(data),
2350 }
2351 self.assertEqual(expected, props)
2352
Simon Glass151bbbf2019-07-08 14:25:41 -06002353 def testCbfsUpdateFdt(self):
2354 """Test that we can update the device tree with CBFS offset/size info"""
2355 self._CheckLz4()
2356 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2357 update_dtb=True)
2358 dtb = fdt.Fdt(out_dtb_fname)
2359 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002360 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002361 del props['cbfs/u-boot:size']
2362 self.assertEqual({
2363 'offset': 0,
2364 'size': len(data),
2365 'image-pos': 0,
2366 'cbfs:offset': 0,
2367 'cbfs:size': len(data),
2368 'cbfs:image-pos': 0,
2369 'cbfs/u-boot:offset': 0x38,
2370 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2371 'cbfs/u-boot:image-pos': 0x38,
2372 'cbfs/u-boot-dtb:offset': 0xb8,
2373 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2374 'cbfs/u-boot-dtb:image-pos': 0xb8,
2375 }, props)
2376
Simon Glass3c9b4f22019-07-08 14:25:42 -06002377 def testCbfsBadType(self):
2378 """Test an image header with a no specified location is detected"""
2379 with self.assertRaises(ValueError) as e:
2380 self._DoReadFile('126_cbfs_bad_type.dts')
2381 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2382
Simon Glass6b156f82019-07-08 14:25:43 -06002383 def testList(self):
2384 """Test listing the files in an image"""
2385 self._CheckLz4()
2386 data = self._DoReadFile('127_list.dts')
2387 image = control.images['image']
2388 entries = image.BuildEntryList()
2389 self.assertEqual(7, len(entries))
2390
2391 ent = entries[0]
2392 self.assertEqual(0, ent.indent)
2393 self.assertEqual('main-section', ent.name)
2394 self.assertEqual('section', ent.etype)
2395 self.assertEqual(len(data), ent.size)
2396 self.assertEqual(0, ent.image_pos)
2397 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002398 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002399
2400 ent = entries[1]
2401 self.assertEqual(1, ent.indent)
2402 self.assertEqual('u-boot', ent.name)
2403 self.assertEqual('u-boot', ent.etype)
2404 self.assertEqual(len(U_BOOT_DATA), ent.size)
2405 self.assertEqual(0, ent.image_pos)
2406 self.assertEqual(None, ent.uncomp_size)
2407 self.assertEqual(0, ent.offset)
2408
2409 ent = entries[2]
2410 self.assertEqual(1, ent.indent)
2411 self.assertEqual('section', ent.name)
2412 self.assertEqual('section', ent.etype)
2413 section_size = ent.size
2414 self.assertEqual(0x100, ent.image_pos)
2415 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002416 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002417
2418 ent = entries[3]
2419 self.assertEqual(2, ent.indent)
2420 self.assertEqual('cbfs', ent.name)
2421 self.assertEqual('cbfs', ent.etype)
2422 self.assertEqual(0x400, ent.size)
2423 self.assertEqual(0x100, ent.image_pos)
2424 self.assertEqual(None, ent.uncomp_size)
2425 self.assertEqual(0, ent.offset)
2426
2427 ent = entries[4]
2428 self.assertEqual(3, ent.indent)
2429 self.assertEqual('u-boot', ent.name)
2430 self.assertEqual('u-boot', ent.etype)
2431 self.assertEqual(len(U_BOOT_DATA), ent.size)
2432 self.assertEqual(0x138, ent.image_pos)
2433 self.assertEqual(None, ent.uncomp_size)
2434 self.assertEqual(0x38, ent.offset)
2435
2436 ent = entries[5]
2437 self.assertEqual(3, ent.indent)
2438 self.assertEqual('u-boot-dtb', ent.name)
2439 self.assertEqual('text', ent.etype)
2440 self.assertGreater(len(COMPRESS_DATA), ent.size)
2441 self.assertEqual(0x178, ent.image_pos)
2442 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2443 self.assertEqual(0x78, ent.offset)
2444
2445 ent = entries[6]
2446 self.assertEqual(2, ent.indent)
2447 self.assertEqual('u-boot-dtb', ent.name)
2448 self.assertEqual('u-boot-dtb', ent.etype)
2449 self.assertEqual(0x500, ent.image_pos)
2450 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2451 dtb_size = ent.size
2452 # Compressing this data expands it since headers are added
2453 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2454 self.assertEqual(0x400, ent.offset)
2455
2456 self.assertEqual(len(data), 0x100 + section_size)
2457 self.assertEqual(section_size, 0x400 + dtb_size)
2458
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002459 def testFindFdtmap(self):
2460 """Test locating an FDT map in an image"""
2461 self._CheckLz4()
2462 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2463 image = control.images['image']
2464 entries = image.GetEntries()
2465 entry = entries['fdtmap']
2466 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2467
2468 def testFindFdtmapMissing(self):
2469 """Test failing to locate an FDP map"""
2470 data = self._DoReadFile('005_simple.dts')
2471 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2472
Simon Glassed39a3c2019-07-08 14:25:45 -06002473 def testFindImageHeader(self):
2474 """Test locating a image header"""
2475 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002476 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002477 image = control.images['image']
2478 entries = image.GetEntries()
2479 entry = entries['fdtmap']
2480 # The header should point to the FDT map
2481 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2482
2483 def testFindImageHeaderStart(self):
2484 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002485 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002486 image = control.images['image']
2487 entries = image.GetEntries()
2488 entry = entries['fdtmap']
2489 # The header should point to the FDT map
2490 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2491
2492 def testFindImageHeaderMissing(self):
2493 """Test failing to locate an image header"""
2494 data = self._DoReadFile('005_simple.dts')
2495 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2496
Simon Glassb8424fa2019-07-08 14:25:46 -06002497 def testReadImage(self):
2498 """Test reading an image and accessing its FDT map"""
2499 self._CheckLz4()
2500 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2501 image_fname = tools.GetOutputFilename('image.bin')
2502 orig_image = control.images['image']
2503 image = Image.FromFile(image_fname)
2504 self.assertEqual(orig_image.GetEntries().keys(),
2505 image.GetEntries().keys())
2506
2507 orig_entry = orig_image.GetEntries()['fdtmap']
2508 entry = image.GetEntries()['fdtmap']
2509 self.assertEquals(orig_entry.offset, entry.offset)
2510 self.assertEquals(orig_entry.size, entry.size)
2511 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2512
2513 def testReadImageNoHeader(self):
2514 """Test accessing an image's FDT map without an image header"""
2515 self._CheckLz4()
2516 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2517 image_fname = tools.GetOutputFilename('image.bin')
2518 image = Image.FromFile(image_fname)
2519 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002520 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002521
2522 def testReadImageFail(self):
2523 """Test failing to read an image image's FDT map"""
2524 self._DoReadFile('005_simple.dts')
2525 image_fname = tools.GetOutputFilename('image.bin')
2526 with self.assertRaises(ValueError) as e:
2527 image = Image.FromFile(image_fname)
2528 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002529
Simon Glassb2fd11d2019-07-08 14:25:48 -06002530 def testListCmd(self):
2531 """Test listing the files in an image using an Fdtmap"""
2532 self._CheckLz4()
2533 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2534
2535 # lz4 compression size differs depending on the version
2536 image = control.images['image']
2537 entries = image.GetEntries()
2538 section_size = entries['section'].size
2539 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2540 fdtmap_offset = entries['fdtmap'].offset
2541
Simon Glassb3d6fc72019-07-20 12:24:10 -06002542 try:
2543 tmpdir, updated_fname = self._SetupImageInTmpdir()
2544 with test_util.capture_sys_output() as (stdout, stderr):
2545 self._DoBinman('ls', '-i', updated_fname)
2546 finally:
2547 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002548 lines = stdout.getvalue().splitlines()
2549 expected = [
2550'Name Image-pos Size Entry-type Offset Uncomp-size',
2551'----------------------------------------------------------------------',
2552'main-section 0 c00 section 0',
2553' u-boot 0 4 u-boot 0',
2554' section 100 %x section 100' % section_size,
2555' cbfs 100 400 cbfs 0',
2556' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002557' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002558' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002559' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002560 (fdtmap_offset, fdtmap_offset),
2561' image-header bf8 8 image-header bf8',
2562 ]
2563 self.assertEqual(expected, lines)
2564
2565 def testListCmdFail(self):
2566 """Test failing to list an image"""
2567 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002568 try:
2569 tmpdir, updated_fname = self._SetupImageInTmpdir()
2570 with self.assertRaises(ValueError) as e:
2571 self._DoBinman('ls', '-i', updated_fname)
2572 finally:
2573 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002574 self.assertIn("Cannot find FDT map in image", str(e.exception))
2575
2576 def _RunListCmd(self, paths, expected):
2577 """List out entries and check the result
2578
2579 Args:
2580 paths: List of paths to pass to the list command
2581 expected: Expected list of filenames to be returned, in order
2582 """
2583 self._CheckLz4()
2584 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2585 image_fname = tools.GetOutputFilename('image.bin')
2586 image = Image.FromFile(image_fname)
2587 lines = image.GetListEntries(paths)[1]
2588 files = [line[0].strip() for line in lines[1:]]
2589 self.assertEqual(expected, files)
2590
2591 def testListCmdSection(self):
2592 """Test listing the files in a section"""
2593 self._RunListCmd(['section'],
2594 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2595
2596 def testListCmdFile(self):
2597 """Test listing a particular file"""
2598 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2599
2600 def testListCmdWildcard(self):
2601 """Test listing a wildcarded file"""
2602 self._RunListCmd(['*boot*'],
2603 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2604
2605 def testListCmdWildcardMulti(self):
2606 """Test listing a wildcarded file"""
2607 self._RunListCmd(['*cb*', '*head*'],
2608 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2609
2610 def testListCmdEmpty(self):
2611 """Test listing a wildcarded file"""
2612 self._RunListCmd(['nothing'], [])
2613
2614 def testListCmdPath(self):
2615 """Test listing the files in a sub-entry of a section"""
2616 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2617
Simon Glass4c613bf2019-07-08 14:25:50 -06002618 def _RunExtractCmd(self, entry_name, decomp=True):
2619 """Extract an entry from an image
2620
2621 Args:
2622 entry_name: Entry name to extract
2623 decomp: True to decompress the data if compressed, False to leave
2624 it in its raw uncompressed format
2625
2626 Returns:
2627 data from entry
2628 """
2629 self._CheckLz4()
2630 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2631 image_fname = tools.GetOutputFilename('image.bin')
2632 return control.ReadEntry(image_fname, entry_name, decomp)
2633
2634 def testExtractSimple(self):
2635 """Test extracting a single file"""
2636 data = self._RunExtractCmd('u-boot')
2637 self.assertEqual(U_BOOT_DATA, data)
2638
Simon Glass980a2842019-07-08 14:25:52 -06002639 def testExtractSection(self):
2640 """Test extracting the files in a section"""
2641 data = self._RunExtractCmd('section')
2642 cbfs_data = data[:0x400]
2643 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002644 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002645 dtb_data = data[0x400:]
2646 dtb = self._decompress(dtb_data)
2647 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2648
2649 def testExtractCompressed(self):
2650 """Test extracting compressed data"""
2651 data = self._RunExtractCmd('section/u-boot-dtb')
2652 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2653
2654 def testExtractRaw(self):
2655 """Test extracting compressed data without decompressing it"""
2656 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2657 dtb = self._decompress(data)
2658 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2659
2660 def testExtractCbfs(self):
2661 """Test extracting CBFS data"""
2662 data = self._RunExtractCmd('section/cbfs/u-boot')
2663 self.assertEqual(U_BOOT_DATA, data)
2664
2665 def testExtractCbfsCompressed(self):
2666 """Test extracting CBFS compressed data"""
2667 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2668 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2669
2670 def testExtractCbfsRaw(self):
2671 """Test extracting CBFS compressed data without decompressing it"""
2672 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002673 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002674 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2675
Simon Glass4c613bf2019-07-08 14:25:50 -06002676 def testExtractBadEntry(self):
2677 """Test extracting a bad section path"""
2678 with self.assertRaises(ValueError) as e:
2679 self._RunExtractCmd('section/does-not-exist')
2680 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2681 str(e.exception))
2682
2683 def testExtractMissingFile(self):
2684 """Test extracting file that does not exist"""
2685 with self.assertRaises(IOError) as e:
2686 control.ReadEntry('missing-file', 'name')
2687
2688 def testExtractBadFile(self):
2689 """Test extracting an invalid file"""
2690 fname = os.path.join(self._indir, 'badfile')
2691 tools.WriteFile(fname, b'')
2692 with self.assertRaises(ValueError) as e:
2693 control.ReadEntry(fname, 'name')
2694
Simon Glass980a2842019-07-08 14:25:52 -06002695 def testExtractCmd(self):
2696 """Test extracting a file fron an image on the command line"""
2697 self._CheckLz4()
2698 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002699 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002700 try:
2701 tmpdir, updated_fname = self._SetupImageInTmpdir()
2702 with test_util.capture_sys_output() as (stdout, stderr):
2703 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2704 '-f', fname)
2705 finally:
2706 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002707 data = tools.ReadFile(fname)
2708 self.assertEqual(U_BOOT_DATA, data)
2709
2710 def testExtractOneEntry(self):
2711 """Test extracting a single entry fron an image """
2712 self._CheckLz4()
2713 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2714 image_fname = tools.GetOutputFilename('image.bin')
2715 fname = os.path.join(self._indir, 'output.extact')
2716 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2717 data = tools.ReadFile(fname)
2718 self.assertEqual(U_BOOT_DATA, data)
2719
2720 def _CheckExtractOutput(self, decomp):
2721 """Helper to test file output with and without decompression
2722
2723 Args:
2724 decomp: True to decompress entry data, False to output it raw
2725 """
2726 def _CheckPresent(entry_path, expect_data, expect_size=None):
2727 """Check and remove expected file
2728
2729 This checks the data/size of a file and removes the file both from
2730 the outfiles set and from the output directory. Once all files are
2731 processed, both the set and directory should be empty.
2732
2733 Args:
2734 entry_path: Entry path
2735 expect_data: Data to expect in file, or None to skip check
2736 expect_size: Size of data to expect in file, or None to skip
2737 """
2738 path = os.path.join(outdir, entry_path)
2739 data = tools.ReadFile(path)
2740 os.remove(path)
2741 if expect_data:
2742 self.assertEqual(expect_data, data)
2743 elif expect_size:
2744 self.assertEqual(expect_size, len(data))
2745 outfiles.remove(path)
2746
2747 def _CheckDirPresent(name):
2748 """Remove expected directory
2749
2750 This gives an error if the directory does not exist as expected
2751
2752 Args:
2753 name: Name of directory to remove
2754 """
2755 path = os.path.join(outdir, name)
2756 os.rmdir(path)
2757
2758 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2759 image_fname = tools.GetOutputFilename('image.bin')
2760 outdir = os.path.join(self._indir, 'extract')
2761 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2762
2763 # Create a set of all file that were output (should be 9)
2764 outfiles = set()
2765 for root, dirs, files in os.walk(outdir):
2766 outfiles |= set([os.path.join(root, fname) for fname in files])
2767 self.assertEqual(9, len(outfiles))
2768 self.assertEqual(9, len(einfos))
2769
2770 image = control.images['image']
2771 entries = image.GetEntries()
2772
2773 # Check the 9 files in various ways
2774 section = entries['section']
2775 section_entries = section.GetEntries()
2776 cbfs_entries = section_entries['cbfs'].GetEntries()
2777 _CheckPresent('u-boot', U_BOOT_DATA)
2778 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2779 dtb_len = EXTRACT_DTB_SIZE
2780 if not decomp:
2781 dtb_len = cbfs_entries['u-boot-dtb'].size
2782 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2783 if not decomp:
2784 dtb_len = section_entries['u-boot-dtb'].size
2785 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2786
2787 fdtmap = entries['fdtmap']
2788 _CheckPresent('fdtmap', fdtmap.data)
2789 hdr = entries['image-header']
2790 _CheckPresent('image-header', hdr.data)
2791
2792 _CheckPresent('section/root', section.data)
2793 cbfs = section_entries['cbfs']
2794 _CheckPresent('section/cbfs/root', cbfs.data)
2795 data = tools.ReadFile(image_fname)
2796 _CheckPresent('root', data)
2797
2798 # There should be no files left. Remove all the directories to check.
2799 # If there are any files/dirs remaining, one of these checks will fail.
2800 self.assertEqual(0, len(outfiles))
2801 _CheckDirPresent('section/cbfs')
2802 _CheckDirPresent('section')
2803 _CheckDirPresent('')
2804 self.assertFalse(os.path.exists(outdir))
2805
2806 def testExtractAllEntries(self):
2807 """Test extracting all entries"""
2808 self._CheckLz4()
2809 self._CheckExtractOutput(decomp=True)
2810
2811 def testExtractAllEntriesRaw(self):
2812 """Test extracting all entries without decompressing them"""
2813 self._CheckLz4()
2814 self._CheckExtractOutput(decomp=False)
2815
2816 def testExtractSelectedEntries(self):
2817 """Test extracting some entries"""
2818 self._CheckLz4()
2819 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2820 image_fname = tools.GetOutputFilename('image.bin')
2821 outdir = os.path.join(self._indir, 'extract')
2822 einfos = control.ExtractEntries(image_fname, None, outdir,
2823 ['*cb*', '*head*'])
2824
2825 # File output is tested by testExtractAllEntries(), so just check that
2826 # the expected entries are selected
2827 names = [einfo.name for einfo in einfos]
2828 self.assertEqual(names,
2829 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2830
2831 def testExtractNoEntryPaths(self):
2832 """Test extracting some entries"""
2833 self._CheckLz4()
2834 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2835 image_fname = tools.GetOutputFilename('image.bin')
2836 with self.assertRaises(ValueError) as e:
2837 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002838 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002839 str(e.exception))
2840
2841 def testExtractTooManyEntryPaths(self):
2842 """Test extracting some entries"""
2843 self._CheckLz4()
2844 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2845 image_fname = tools.GetOutputFilename('image.bin')
2846 with self.assertRaises(ValueError) as e:
2847 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002848 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002849 str(e.exception))
2850
Simon Glass52d06212019-07-08 14:25:53 -06002851 def testPackAlignSection(self):
2852 """Test that sections can have alignment"""
2853 self._DoReadFile('131_pack_align_section.dts')
2854
2855 self.assertIn('image', control.images)
2856 image = control.images['image']
2857 entries = image.GetEntries()
2858 self.assertEqual(3, len(entries))
2859
2860 # First u-boot
2861 self.assertIn('u-boot', entries)
2862 entry = entries['u-boot']
2863 self.assertEqual(0, entry.offset)
2864 self.assertEqual(0, entry.image_pos)
2865 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2866 self.assertEqual(len(U_BOOT_DATA), entry.size)
2867
2868 # Section0
2869 self.assertIn('section0', entries)
2870 section0 = entries['section0']
2871 self.assertEqual(0x10, section0.offset)
2872 self.assertEqual(0x10, section0.image_pos)
2873 self.assertEqual(len(U_BOOT_DATA), section0.size)
2874
2875 # Second u-boot
2876 section_entries = section0.GetEntries()
2877 self.assertIn('u-boot', section_entries)
2878 entry = section_entries['u-boot']
2879 self.assertEqual(0, entry.offset)
2880 self.assertEqual(0x10, entry.image_pos)
2881 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2882 self.assertEqual(len(U_BOOT_DATA), entry.size)
2883
2884 # Section1
2885 self.assertIn('section1', entries)
2886 section1 = entries['section1']
2887 self.assertEqual(0x14, section1.offset)
2888 self.assertEqual(0x14, section1.image_pos)
2889 self.assertEqual(0x20, section1.size)
2890
2891 # Second u-boot
2892 section_entries = section1.GetEntries()
2893 self.assertIn('u-boot', section_entries)
2894 entry = section_entries['u-boot']
2895 self.assertEqual(0, entry.offset)
2896 self.assertEqual(0x14, entry.image_pos)
2897 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2898 self.assertEqual(len(U_BOOT_DATA), entry.size)
2899
2900 # Section2
2901 self.assertIn('section2', section_entries)
2902 section2 = section_entries['section2']
2903 self.assertEqual(0x4, section2.offset)
2904 self.assertEqual(0x18, section2.image_pos)
2905 self.assertEqual(4, section2.size)
2906
2907 # Third u-boot
2908 section_entries = section2.GetEntries()
2909 self.assertIn('u-boot', section_entries)
2910 entry = section_entries['u-boot']
2911 self.assertEqual(0, entry.offset)
2912 self.assertEqual(0x18, entry.image_pos)
2913 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2914 self.assertEqual(len(U_BOOT_DATA), entry.size)
2915
Simon Glassf8a54bc2019-07-20 12:23:56 -06002916 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2917 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06002918 """Replace an entry in an image
2919
2920 This writes the entry data to update it, then opens the updated file and
2921 returns the value that it now finds there.
2922
2923 Args:
2924 entry_name: Entry name to replace
2925 data: Data to replace it with
2926 decomp: True to compress the data if needed, False if data is
2927 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06002928 allow_resize: True to allow entries to change size, False to raise
2929 an exception
Simon Glass072959a2019-07-20 12:23:50 -06002930
2931 Returns:
2932 Tuple:
2933 data from entry
2934 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06002935 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06002936 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06002937 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06002938 update_dtb=True)[1]
2939
2940 self.assertIn('image', control.images)
2941 image = control.images['image']
2942 entries = image.GetEntries()
2943 orig_dtb_data = entries['u-boot-dtb'].data
2944 orig_fdtmap_data = entries['fdtmap'].data
2945
2946 image_fname = tools.GetOutputFilename('image.bin')
2947 updated_fname = tools.GetOutputFilename('image-updated.bin')
2948 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06002949 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
2950 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06002951 data = control.ReadEntry(updated_fname, entry_name, decomp)
2952
Simon Glassf8a54bc2019-07-20 12:23:56 -06002953 # The DT data should not change unless resized:
2954 if not allow_resize:
2955 new_dtb_data = entries['u-boot-dtb'].data
2956 self.assertEqual(new_dtb_data, orig_dtb_data)
2957 new_fdtmap_data = entries['fdtmap'].data
2958 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06002959
Simon Glassf8a54bc2019-07-20 12:23:56 -06002960 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06002961
2962 def testReplaceSimple(self):
2963 """Test replacing a single file"""
2964 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06002965 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
2966 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06002967 self.assertEqual(expected, data)
2968
2969 # Test that the state looks right. There should be an FDT for the fdtmap
2970 # that we jsut read back in, and it should match what we find in the
2971 # 'control' tables. Checking for an FDT that does not exist should
2972 # return None.
2973 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06002974 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06002975 self.assertEqual(expected_fdtmap, fdtmap)
2976
2977 dtb = state.GetFdtForEtype('fdtmap')
2978 self.assertEqual(dtb.GetContents(), fdtmap)
2979
2980 missing_path, missing_fdtmap = state.GetFdtContents('missing')
2981 self.assertIsNone(missing_path)
2982 self.assertIsNone(missing_fdtmap)
2983
2984 missing_dtb = state.GetFdtForEtype('missing')
2985 self.assertIsNone(missing_dtb)
2986
2987 self.assertEqual('/binman', state.fdt_path_prefix)
2988
2989 def testReplaceResizeFail(self):
2990 """Test replacing a file by something larger"""
2991 expected = U_BOOT_DATA + b'x'
2992 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06002993 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
2994 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06002995 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
2996 str(e.exception))
2997
2998 def testReplaceMulti(self):
2999 """Test replacing entry data where multiple images are generated"""
3000 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3001 update_dtb=True)[0]
3002 expected = b'x' * len(U_BOOT_DATA)
3003 updated_fname = tools.GetOutputFilename('image-updated.bin')
3004 tools.WriteFile(updated_fname, data)
3005 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003006 control.WriteEntry(updated_fname, entry_name, expected,
3007 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003008 data = control.ReadEntry(updated_fname, entry_name)
3009 self.assertEqual(expected, data)
3010
3011 # Check the state looks right.
3012 self.assertEqual('/binman/image', state.fdt_path_prefix)
3013
3014 # Now check we can write the first image
3015 image_fname = tools.GetOutputFilename('first-image.bin')
3016 updated_fname = tools.GetOutputFilename('first-updated.bin')
3017 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3018 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003019 control.WriteEntry(updated_fname, entry_name, expected,
3020 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003021 data = control.ReadEntry(updated_fname, entry_name)
3022 self.assertEqual(expected, data)
3023
3024 # Check the state looks right.
3025 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003026
Simon Glassfb30e292019-07-20 12:23:51 -06003027 def testUpdateFdtAllRepack(self):
3028 """Test that all device trees are updated with offset/size info"""
3029 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3030 SECTION_SIZE = 0x300
3031 DTB_SIZE = 602
3032 FDTMAP_SIZE = 608
3033 base_expected = {
3034 'offset': 0,
3035 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3036 'image-pos': 0,
3037 'section:offset': 0,
3038 'section:size': SECTION_SIZE,
3039 'section:image-pos': 0,
3040 'section/u-boot-dtb:offset': 4,
3041 'section/u-boot-dtb:size': 636,
3042 'section/u-boot-dtb:image-pos': 4,
3043 'u-boot-spl-dtb:offset': SECTION_SIZE,
3044 'u-boot-spl-dtb:size': DTB_SIZE,
3045 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3046 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3047 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3048 'u-boot-tpl-dtb:size': DTB_SIZE,
3049 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3050 'fdtmap:size': FDTMAP_SIZE,
3051 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3052 }
3053 main_expected = {
3054 'section:orig-size': SECTION_SIZE,
3055 'section/u-boot-dtb:orig-offset': 4,
3056 }
3057
3058 # We expect three device-tree files in the output, with the first one
3059 # within a fixed-size section.
3060 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3061 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3062 # main U-Boot tree. All three should have the same positions and offset
3063 # except that the main tree should include the main_expected properties
3064 start = 4
3065 for item in ['', 'spl', 'tpl', None]:
3066 if item is None:
3067 start += 16 # Move past fdtmap header
3068 dtb = fdt.Fdt.FromData(data[start:])
3069 dtb.Scan()
3070 props = self._GetPropTree(dtb,
3071 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3072 prefix='/' if item is None else '/binman/')
3073 expected = dict(base_expected)
3074 if item:
3075 expected[item] = 0
3076 else:
3077 # Main DTB and fdtdec should include the 'orig-' properties
3078 expected.update(main_expected)
3079 # Helpful for debugging:
3080 #for prop in sorted(props):
3081 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3082 self.assertEqual(expected, props)
3083 if item == '':
3084 start = SECTION_SIZE
3085 else:
3086 start += dtb._fdt_obj.totalsize()
3087
Simon Glass11453762019-07-20 12:23:55 -06003088 def testFdtmapHeaderMiddle(self):
3089 """Test an FDT map in the middle of an image when it should be at end"""
3090 with self.assertRaises(ValueError) as e:
3091 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3092 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3093 str(e.exception))
3094
3095 def testFdtmapHeaderStartBad(self):
3096 """Test an FDT map in middle of an image when it should be at start"""
3097 with self.assertRaises(ValueError) as e:
3098 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3099 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3100 str(e.exception))
3101
3102 def testFdtmapHeaderEndBad(self):
3103 """Test an FDT map at the start of an image when it should be at end"""
3104 with self.assertRaises(ValueError) as e:
3105 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3106 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3107 str(e.exception))
3108
3109 def testFdtmapHeaderNoSize(self):
3110 """Test an image header at the end of an image with undefined size"""
3111 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3112
Simon Glassf8a54bc2019-07-20 12:23:56 -06003113 def testReplaceResize(self):
3114 """Test replacing a single file in an entry with a larger file"""
3115 expected = U_BOOT_DATA + b'x'
3116 data, _, image = self._RunReplaceCmd('u-boot', expected,
3117 dts='139_replace_repack.dts')
3118 self.assertEqual(expected, data)
3119
3120 entries = image.GetEntries()
3121 dtb_data = entries['u-boot-dtb'].data
3122 dtb = fdt.Fdt.FromData(dtb_data)
3123 dtb.Scan()
3124
3125 # The u-boot section should now be larger in the dtb
3126 node = dtb.GetNode('/binman/u-boot')
3127 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3128
3129 # Same for the fdtmap
3130 fdata = entries['fdtmap'].data
3131 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3132 fdtb.Scan()
3133 fnode = fdtb.GetNode('/u-boot')
3134 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3135
3136 def testReplaceResizeNoRepack(self):
3137 """Test replacing an entry with a larger file when not allowed"""
3138 expected = U_BOOT_DATA + b'x'
3139 with self.assertRaises(ValueError) as e:
3140 self._RunReplaceCmd('u-boot', expected)
3141 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3142 str(e.exception))
3143
Simon Glass9d8ee322019-07-20 12:23:58 -06003144 def testEntryShrink(self):
3145 """Test contracting an entry after it is packed"""
3146 try:
3147 state.SetAllowEntryContraction(True)
3148 data = self._DoReadFileDtb('140_entry_shrink.dts',
3149 update_dtb=True)[0]
3150 finally:
3151 state.SetAllowEntryContraction(False)
3152 self.assertEqual(b'a', data[:1])
3153 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3154 self.assertEqual(b'a', data[-1:])
3155
3156 def testEntryShrinkFail(self):
3157 """Test not being allowed to contract an entry after it is packed"""
3158 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3159
3160 # In this case there is a spare byte at the end of the data. The size of
3161 # the contents is only 1 byte but we still have the size before it
3162 # shrunk.
3163 self.assertEqual(b'a\0', data[:2])
3164 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3165 self.assertEqual(b'a\0', data[-2:])
3166
Simon Glass70e32982019-07-20 12:24:01 -06003167 def testDescriptorOffset(self):
3168 """Test that the Intel descriptor is always placed at at the start"""
3169 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3170 image = control.images['image']
3171 entries = image.GetEntries()
3172 desc = entries['intel-descriptor']
3173 self.assertEqual(0xff800000, desc.offset);
3174 self.assertEqual(0xff800000, desc.image_pos);
3175
Simon Glass37fdd142019-07-20 12:24:06 -06003176 def testReplaceCbfs(self):
3177 """Test replacing a single file in CBFS without changing the size"""
3178 self._CheckLz4()
3179 expected = b'x' * len(U_BOOT_DATA)
3180 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3181 updated_fname = tools.GetOutputFilename('image-updated.bin')
3182 tools.WriteFile(updated_fname, data)
3183 entry_name = 'section/cbfs/u-boot'
3184 control.WriteEntry(updated_fname, entry_name, expected,
3185 allow_resize=True)
3186 data = control.ReadEntry(updated_fname, entry_name)
3187 self.assertEqual(expected, data)
3188
3189 def testReplaceResizeCbfs(self):
3190 """Test replacing a single file in CBFS with one of a different size"""
3191 self._CheckLz4()
3192 expected = U_BOOT_DATA + b'x'
3193 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3194 updated_fname = tools.GetOutputFilename('image-updated.bin')
3195 tools.WriteFile(updated_fname, data)
3196 entry_name = 'section/cbfs/u-boot'
3197 control.WriteEntry(updated_fname, entry_name, expected,
3198 allow_resize=True)
3199 data = control.ReadEntry(updated_fname, entry_name)
3200 self.assertEqual(expected, data)
3201
Simon Glass30033c22019-07-20 12:24:15 -06003202 def _SetupForReplace(self):
3203 """Set up some files to use to replace entries
3204
3205 This generates an image, copies it to a new file, extracts all the files
3206 in it and updates some of them
3207
3208 Returns:
3209 List
3210 Image filename
3211 Output directory
3212 Expected values for updated entries, each a string
3213 """
3214 data = self._DoReadFileRealDtb('143_replace_all.dts')
3215
3216 updated_fname = tools.GetOutputFilename('image-updated.bin')
3217 tools.WriteFile(updated_fname, data)
3218
3219 outdir = os.path.join(self._indir, 'extract')
3220 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3221
3222 expected1 = b'x' + U_BOOT_DATA + b'y'
3223 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3224 tools.WriteFile(u_boot_fname1, expected1)
3225
3226 expected2 = b'a' + U_BOOT_DATA + b'b'
3227 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3228 tools.WriteFile(u_boot_fname2, expected2)
3229
3230 expected_text = b'not the same text'
3231 text_fname = os.path.join(outdir, 'text')
3232 tools.WriteFile(text_fname, expected_text)
3233
3234 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3235 dtb = fdt.FdtScan(dtb_fname)
3236 node = dtb.GetNode('/binman/text')
3237 node.AddString('my-property', 'the value')
3238 dtb.Sync(auto_resize=True)
3239 dtb.Flush()
3240
3241 return updated_fname, outdir, expected1, expected2, expected_text
3242
3243 def _CheckReplaceMultiple(self, entry_paths):
3244 """Handle replacing the contents of multiple entries
3245
3246 Args:
3247 entry_paths: List of entry paths to replace
3248
3249 Returns:
3250 List
3251 Dict of entries in the image:
3252 key: Entry name
3253 Value: Entry object
3254 Expected values for updated entries, each a string
3255 """
3256 updated_fname, outdir, expected1, expected2, expected_text = (
3257 self._SetupForReplace())
3258 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3259
3260 image = Image.FromFile(updated_fname)
3261 image.LoadData()
3262 return image.GetEntries(), expected1, expected2, expected_text
3263
3264 def testReplaceAll(self):
3265 """Test replacing the contents of all entries"""
3266 entries, expected1, expected2, expected_text = (
3267 self._CheckReplaceMultiple([]))
3268 data = entries['u-boot'].data
3269 self.assertEqual(expected1, data)
3270
3271 data = entries['u-boot2'].data
3272 self.assertEqual(expected2, data)
3273
3274 data = entries['text'].data
3275 self.assertEqual(expected_text, data)
3276
3277 # Check that the device tree is updated
3278 data = entries['u-boot-dtb'].data
3279 dtb = fdt.Fdt.FromData(data)
3280 dtb.Scan()
3281 node = dtb.GetNode('/binman/text')
3282 self.assertEqual('the value', node.props['my-property'].value)
3283
3284 def testReplaceSome(self):
3285 """Test replacing the contents of a few entries"""
3286 entries, expected1, expected2, expected_text = (
3287 self._CheckReplaceMultiple(['u-boot2', 'text']))
3288
3289 # This one should not change
3290 data = entries['u-boot'].data
3291 self.assertEqual(U_BOOT_DATA, data)
3292
3293 data = entries['u-boot2'].data
3294 self.assertEqual(expected2, data)
3295
3296 data = entries['text'].data
3297 self.assertEqual(expected_text, data)
3298
3299 def testReplaceCmd(self):
3300 """Test replacing a file fron an image on the command line"""
3301 self._DoReadFileRealDtb('143_replace_all.dts')
3302
3303 try:
3304 tmpdir, updated_fname = self._SetupImageInTmpdir()
3305
3306 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3307 expected = b'x' * len(U_BOOT_DATA)
3308 tools.WriteFile(fname, expected)
3309
3310 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3311 data = tools.ReadFile(updated_fname)
3312 self.assertEqual(expected, data[:len(expected)])
3313 map_fname = os.path.join(tmpdir, 'image-updated.map')
3314 self.assertFalse(os.path.exists(map_fname))
3315 finally:
3316 shutil.rmtree(tmpdir)
3317
3318 def testReplaceCmdSome(self):
3319 """Test replacing some files fron an image on the command line"""
3320 updated_fname, outdir, expected1, expected2, expected_text = (
3321 self._SetupForReplace())
3322
3323 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3324 'u-boot2', 'text')
3325
3326 tools.PrepareOutputDir(None)
3327 image = Image.FromFile(updated_fname)
3328 image.LoadData()
3329 entries = image.GetEntries()
3330
3331 # This one should not change
3332 data = entries['u-boot'].data
3333 self.assertEqual(U_BOOT_DATA, data)
3334
3335 data = entries['u-boot2'].data
3336 self.assertEqual(expected2, data)
3337
3338 data = entries['text'].data
3339 self.assertEqual(expected_text, data)
3340
3341 def testReplaceMissing(self):
3342 """Test replacing entries where the file is missing"""
3343 updated_fname, outdir, expected1, expected2, expected_text = (
3344 self._SetupForReplace())
3345
3346 # Remove one of the files, to generate a warning
3347 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3348 os.remove(u_boot_fname1)
3349
3350 with test_util.capture_sys_output() as (stdout, stderr):
3351 control.ReplaceEntries(updated_fname, None, outdir, [])
3352 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003353 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003354
3355 def testReplaceCmdMap(self):
3356 """Test replacing a file fron an image on the command line"""
3357 self._DoReadFileRealDtb('143_replace_all.dts')
3358
3359 try:
3360 tmpdir, updated_fname = self._SetupImageInTmpdir()
3361
3362 fname = os.path.join(self._indir, 'update-u-boot.bin')
3363 expected = b'x' * len(U_BOOT_DATA)
3364 tools.WriteFile(fname, expected)
3365
3366 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3367 '-f', fname, '-m')
3368 map_fname = os.path.join(tmpdir, 'image-updated.map')
3369 self.assertTrue(os.path.exists(map_fname))
3370 finally:
3371 shutil.rmtree(tmpdir)
3372
3373 def testReplaceNoEntryPaths(self):
3374 """Test replacing an entry without an entry path"""
3375 self._DoReadFileRealDtb('143_replace_all.dts')
3376 image_fname = tools.GetOutputFilename('image.bin')
3377 with self.assertRaises(ValueError) as e:
3378 control.ReplaceEntries(image_fname, 'fname', None, [])
3379 self.assertIn('Must specify an entry path to read with -f',
3380 str(e.exception))
3381
3382 def testReplaceTooManyEntryPaths(self):
3383 """Test extracting some entries"""
3384 self._DoReadFileRealDtb('143_replace_all.dts')
3385 image_fname = tools.GetOutputFilename('image.bin')
3386 with self.assertRaises(ValueError) as e:
3387 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3388 self.assertIn('Must specify exactly one entry path to write with -f',
3389 str(e.exception))
3390
Simon Glass0b074d62019-08-24 07:22:48 -06003391 def testPackReset16(self):
3392 """Test that an image with an x86 reset16 region can be created"""
3393 data = self._DoReadFile('144_x86_reset16.dts')
3394 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3395
3396 def testPackReset16Spl(self):
3397 """Test that an image with an x86 reset16-spl region can be created"""
3398 data = self._DoReadFile('145_x86_reset16_spl.dts')
3399 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3400
3401 def testPackReset16Tpl(self):
3402 """Test that an image with an x86 reset16-tpl region can be created"""
3403 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3404 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3405
Simon Glass232f90c2019-08-24 07:22:50 -06003406 def testPackIntelFit(self):
3407 """Test that an image with an Intel FIT and pointer can be created"""
3408 data = self._DoReadFile('147_intel_fit.dts')
3409 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3410 fit = data[16:32];
3411 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3412 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3413
3414 image = control.images['image']
3415 entries = image.GetEntries()
3416 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3417 self.assertEqual(expected_ptr, ptr)
3418
3419 def testPackIntelFitMissing(self):
3420 """Test detection of a FIT pointer with not FIT region"""
3421 with self.assertRaises(ValueError) as e:
3422 self._DoReadFile('148_intel_fit_missing.dts')
3423 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3424 str(e.exception))
3425
Simon Glass72555fa2019-11-06 17:22:44 -07003426 def _CheckSymbolsTplSection(self, dts, expected_vals):
3427 data = self._DoReadFile(dts)
3428 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003429 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003430 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003431 self.assertEqual(expected1, data[:upto1])
3432
3433 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003434 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003435 self.assertEqual(expected2, data[upto1:upto2])
3436
Simon Glass4e353e22019-08-24 07:23:04 -06003437 upto3 = 0x34 + len(U_BOOT_DATA)
3438 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003439 self.assertEqual(expected3, data[upto2:upto3])
3440
Simon Glass3f8ff012019-08-24 07:23:05 -06003441 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003442 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3443
3444 def testSymbolsTplSection(self):
3445 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3446 self._SetupSplElf('u_boot_binman_syms')
3447 self._SetupTplElf('u_boot_binman_syms')
3448 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3449 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3450
3451 def testSymbolsTplSectionX86(self):
3452 """Test binman can assign symbols in a section with end-at-4gb"""
3453 self._SetupSplElf('u_boot_binman_syms_x86')
3454 self._SetupTplElf('u_boot_binman_syms_x86')
3455 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3456 [0xffffff04, 0xffffff1c, 0xffffff34,
3457 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003458
Simon Glass98c59572019-08-24 07:23:03 -06003459 def testPackX86RomIfwiSectiom(self):
3460 """Test that a section can be placed in an IFWI region"""
3461 self._SetupIfwi('fitimage.bin')
3462 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3463 self._CheckIfwi(data)
3464
Simon Glassba7985d2019-08-24 07:23:07 -06003465 def testPackFspM(self):
3466 """Test that an image with a FSP memory-init binary can be created"""
3467 data = self._DoReadFile('152_intel_fsp_m.dts')
3468 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3469
Simon Glass4d9086d2019-10-20 21:31:35 -06003470 def testPackFspS(self):
3471 """Test that an image with a FSP silicon-init binary can be created"""
3472 data = self._DoReadFile('153_intel_fsp_s.dts')
3473 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003474
Simon Glass9ea87b22019-10-20 21:31:36 -06003475 def testPackFspT(self):
3476 """Test that an image with a FSP temp-ram-init binary can be created"""
3477 data = self._DoReadFile('154_intel_fsp_t.dts')
3478 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3479
Simon Glass48f3aad2020-07-09 18:39:31 -06003480 def testMkimage(self):
3481 """Test using mkimage to build an image"""
3482 data = self._DoReadFile('156_mkimage.dts')
3483
3484 # Just check that the data appears in the file somewhere
3485 self.assertIn(U_BOOT_SPL_DATA, data)
3486
Simon Glass5e560182020-07-09 18:39:36 -06003487 def testExtblob(self):
3488 """Test an image with an external blob"""
3489 data = self._DoReadFile('157_blob_ext.dts')
3490 self.assertEqual(REFCODE_DATA, data)
3491
3492 def testExtblobMissing(self):
3493 """Test an image with a missing external blob"""
3494 with self.assertRaises(ValueError) as e:
3495 self._DoReadFile('158_blob_ext_missing.dts')
3496 self.assertIn("Filename 'missing-file' not found in input path",
3497 str(e.exception))
3498
Simon Glass5d94cc62020-07-09 18:39:38 -06003499 def testExtblobMissingOk(self):
3500 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003501 with test_util.capture_sys_output() as (stdout, stderr):
3502 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3503 err = stderr.getvalue()
3504 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3505
3506 def testExtblobMissingOkSect(self):
3507 """Test an image with an missing external blob that is allowed"""
3508 with test_util.capture_sys_output() as (stdout, stderr):
3509 self._DoTestFile('159_blob_ext_missing_sect.dts',
3510 allow_missing=True)
3511 err = stderr.getvalue()
3512 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3513 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003514
Simon Glasse88cef92020-07-09 18:39:41 -06003515 def testPackX86RomMeMissingDesc(self):
3516 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003517 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003518 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003519 err = stderr.getvalue()
3520 self.assertRegex(err,
3521 "Image 'main-section'.*missing.*: intel-descriptor")
3522
3523 def testPackX86RomMissingIfwi(self):
3524 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3525 self._SetupIfwi('fitimage.bin')
3526 pathname = os.path.join(self._indir, 'fitimage.bin')
3527 os.remove(pathname)
3528 with test_util.capture_sys_output() as (stdout, stderr):
3529 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3530 err = stderr.getvalue()
3531 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3532
Simon Glassd70829a2020-07-09 18:39:42 -06003533 def testPackOverlap(self):
3534 """Test that zero-size overlapping regions are ignored"""
3535 self._DoTestFile('160_pack_overlap_zero.dts')
3536
Simon Glass45d556d2020-07-09 18:39:45 -06003537 def testSimpleFit(self):
3538 """Test an image with a FIT inside"""
3539 data = self._DoReadFile('161_fit.dts')
3540 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3541 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3542 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3543
3544 # The data should be inside the FIT
3545 dtb = fdt.Fdt.FromData(fit_data)
3546 dtb.Scan()
3547 fnode = dtb.GetNode('/images/kernel')
3548 self.assertIn('data', fnode.props)
3549
3550 fname = os.path.join(self._indir, 'fit_data.fit')
3551 tools.WriteFile(fname, fit_data)
3552 out = tools.Run('dumpimage', '-l', fname)
3553
3554 # Check a few features to make sure the plumbing works. We don't need
3555 # to test the operation of mkimage or dumpimage here. First convert the
3556 # output into a dict where the keys are the fields printed by dumpimage
3557 # and the values are a list of values for each field
3558 lines = out.splitlines()
3559
3560 # Converts "Compression: gzip compressed" into two groups:
3561 # 'Compression' and 'gzip compressed'
3562 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3563 vals = collections.defaultdict(list)
3564 for line in lines:
3565 mat = re_line.match(line)
3566 vals[mat.group(1)].append(mat.group(2))
3567
3568 self.assertEquals('FIT description: test-desc', lines[0])
3569 self.assertIn('Created:', lines[1])
3570 self.assertIn('Image 0 (kernel)', vals)
3571 self.assertIn('Hash value', vals)
3572 data_sizes = vals.get('Data Size')
3573 self.assertIsNotNone(data_sizes)
3574 self.assertEqual(2, len(data_sizes))
3575 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3576 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3577 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3578
3579 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003580 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003581 data = self._DoReadFile('162_fit_external.dts')
3582 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3583
3584 # The data should be outside the FIT
3585 dtb = fdt.Fdt.FromData(fit_data)
3586 dtb.Scan()
3587 fnode = dtb.GetNode('/images/kernel')
3588 self.assertNotIn('data', fnode.props)
Simon Glassfb30e292019-07-20 12:23:51 -06003589
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003590 def testSectionIgnoreHashSignature(self):
3591 """Test that sections ignore hash, signature nodes for its data"""
3592 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3593 expected = (U_BOOT_DATA + U_BOOT_DATA)
3594 self.assertEqual(expected, data)
3595
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003596 def testPadInSections(self):
3597 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003598 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3599 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003600 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3601 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3602 U_BOOT_DATA)
3603 self.assertEqual(expected, data)
3604
Simon Glassd12599d2020-10-26 17:40:09 -06003605 dtb = fdt.Fdt(out_dtb_fname)
3606 dtb.Scan()
3607 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3608 expected = {
3609 'image-pos': 0,
3610 'offset': 0,
3611 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3612
3613 'section:image-pos': 0,
3614 'section:offset': 0,
3615 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3616
3617 'section/before:image-pos': 0,
3618 'section/before:offset': 0,
3619 'section/before:size': len(U_BOOT_DATA),
3620
3621 'section/u-boot:image-pos': 4,
3622 'section/u-boot:offset': 4,
3623 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3624
3625 'section/after:image-pos': 26,
3626 'section/after:offset': 26,
3627 'section/after:size': len(U_BOOT_DATA),
3628 }
3629 self.assertEqual(expected, props)
3630
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003631 def testFitImageSubentryAlignment(self):
3632 """Test relative alignability of FIT image subentries"""
3633 entry_args = {
3634 'test-id': TEXT_DATA,
3635 }
3636 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3637 entry_args=entry_args)
3638 dtb = fdt.Fdt.FromData(data)
3639 dtb.Scan()
3640
3641 node = dtb.GetNode('/images/kernel')
3642 data = dtb.GetProps(node)["data"].bytes
3643 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3644 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3645 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3646 self.assertEqual(expected, data)
3647
3648 node = dtb.GetNode('/images/fdt-1')
3649 data = dtb.GetProps(node)["data"].bytes
3650 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3651 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3652 U_BOOT_DTB_DATA)
3653 self.assertEqual(expected, data)
3654
3655 def testFitExtblobMissingOk(self):
3656 """Test a FIT with a missing external blob that is allowed"""
3657 with test_util.capture_sys_output() as (stdout, stderr):
3658 self._DoTestFile('168_fit_missing_blob.dts',
3659 allow_missing=True)
3660 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003661 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003662
Simon Glass21db0ff2020-09-01 05:13:54 -06003663 def testBlobNamedByArgMissing(self):
3664 """Test handling of a missing entry arg"""
3665 with self.assertRaises(ValueError) as e:
3666 self._DoReadFile('068_blob_named_by_arg.dts')
3667 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3668 str(e.exception))
3669
Simon Glass559c4de2020-09-01 05:13:58 -06003670 def testPackBl31(self):
3671 """Test that an image with an ATF BL31 binary can be created"""
3672 data = self._DoReadFile('169_atf_bl31.dts')
3673 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3674
Samuel Holland9d8cc632020-10-21 21:12:15 -05003675 def testPackScp(self):
3676 """Test that an image with an SCP binary can be created"""
3677 data = self._DoReadFile('172_scp.dts')
3678 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3679
Simon Glassa435cd12020-09-01 05:13:59 -06003680 def testFitFdt(self):
3681 """Test an image with an FIT with multiple FDT images"""
3682 def _CheckFdt(seq, expected_data):
3683 """Check the FDT nodes
3684
3685 Args:
3686 seq: Sequence number to check (0 or 1)
3687 expected_data: Expected contents of 'data' property
3688 """
3689 name = 'fdt-%d' % seq
3690 fnode = dtb.GetNode('/images/%s' % name)
3691 self.assertIsNotNone(fnode)
3692 self.assertEqual({'description','type', 'compression', 'data'},
3693 set(fnode.props.keys()))
3694 self.assertEqual(expected_data, fnode.props['data'].bytes)
3695 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3696 fnode.props['description'].value)
3697
3698 def _CheckConfig(seq, expected_data):
3699 """Check the configuration nodes
3700
3701 Args:
3702 seq: Sequence number to check (0 or 1)
3703 expected_data: Expected contents of 'data' property
3704 """
3705 cnode = dtb.GetNode('/configurations')
3706 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003707 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003708
3709 name = 'config-%d' % seq
3710 fnode = dtb.GetNode('/configurations/%s' % name)
3711 self.assertIsNotNone(fnode)
3712 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3713 set(fnode.props.keys()))
3714 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3715 fnode.props['description'].value)
3716 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3717
3718 entry_args = {
3719 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003720 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003721 }
3722 data = self._DoReadFileDtb(
Simon Glass1032acc2020-09-06 10:39:08 -06003723 '172_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003724 entry_args=entry_args,
3725 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3726 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3727 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3728
3729 dtb = fdt.Fdt.FromData(fit_data)
3730 dtb.Scan()
3731 fnode = dtb.GetNode('/images/kernel')
3732 self.assertIn('data', fnode.props)
3733
3734 # Check all the properties in fdt-1 and fdt-2
3735 _CheckFdt(1, TEST_FDT1_DATA)
3736 _CheckFdt(2, TEST_FDT2_DATA)
3737
3738 # Check configurations
3739 _CheckConfig(1, TEST_FDT1_DATA)
3740 _CheckConfig(2, TEST_FDT2_DATA)
3741
3742 def testFitFdtMissingList(self):
3743 """Test handling of a missing 'of-list' entry arg"""
3744 with self.assertRaises(ValueError) as e:
Simon Glass1032acc2020-09-06 10:39:08 -06003745 self._DoReadFile('172_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003746 self.assertIn("Generator node requires 'of-list' entry argument",
3747 str(e.exception))
3748
3749 def testFitFdtEmptyList(self):
3750 """Test handling of an empty 'of-list' entry arg"""
3751 entry_args = {
3752 'of-list': '',
3753 }
3754 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3755
3756 def testFitFdtMissingProp(self):
3757 """Test handling of a missing 'fit,fdt-list' property"""
3758 with self.assertRaises(ValueError) as e:
3759 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3760 self.assertIn("Generator node requires 'fit,fdt-list' property",
3761 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003762
Simon Glass1032acc2020-09-06 10:39:08 -06003763 def testFitFdtEmptyList(self):
3764 """Test handling of an empty 'of-list' entry arg"""
3765 entry_args = {
3766 'of-list': '',
3767 }
3768 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3769
3770 def testFitFdtMissing(self):
3771 """Test handling of a missing 'default-dt' entry arg"""
3772 entry_args = {
3773 'of-list': 'test-fdt1 test-fdt2',
3774 }
3775 with self.assertRaises(ValueError) as e:
3776 self._DoReadFileDtb(
3777 '172_fit_fdt.dts',
3778 entry_args=entry_args,
3779 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3780 self.assertIn("Generated 'default' node requires default-dt entry argument",
3781 str(e.exception))
3782
3783 def testFitFdtNotInList(self):
3784 """Test handling of a default-dt that is not in the of-list"""
3785 entry_args = {
3786 'of-list': 'test-fdt1 test-fdt2',
3787 'default-dt': 'test-fdt3',
3788 }
3789 with self.assertRaises(ValueError) as e:
3790 self._DoReadFileDtb(
3791 '172_fit_fdt.dts',
3792 entry_args=entry_args,
3793 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3794 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3795 str(e.exception))
3796
Simon Glassa820af72020-09-06 10:39:09 -06003797 def testFitExtblobMissingHelp(self):
3798 """Test display of help messages when an external blob is missing"""
3799 control.missing_blob_help = control._ReadMissingBlobHelp()
3800 control.missing_blob_help['wibble'] = 'Wibble test'
3801 control.missing_blob_help['another'] = 'Another test'
3802 with test_util.capture_sys_output() as (stdout, stderr):
3803 self._DoTestFile('168_fit_missing_blob.dts',
3804 allow_missing=True)
3805 err = stderr.getvalue()
3806
3807 # We can get the tag from the name, the type or the missing-msg
3808 # property. Check all three.
3809 self.assertIn('You may need to build ARM Trusted', err)
3810 self.assertIn('Wibble test', err)
3811 self.assertIn('Another test', err)
3812
Simon Glass6f1f4d42020-09-06 10:35:32 -06003813 def testMissingBlob(self):
3814 """Test handling of a blob containing a missing file"""
3815 with self.assertRaises(ValueError) as e:
3816 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3817 self.assertIn("Filename 'missing' not found in input path",
3818 str(e.exception))
3819
Simon Glassa0729502020-09-06 10:35:33 -06003820 def testEnvironment(self):
3821 """Test adding a U-Boot environment"""
3822 data = self._DoReadFile('174_env.dts')
3823 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3824 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3825 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3826 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3827 env)
3828
3829 def testEnvironmentNoSize(self):
3830 """Test that a missing 'size' property is detected"""
3831 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003832 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003833 self.assertIn("'u-boot-env' entry must have a size property",
3834 str(e.exception))
3835
3836 def testEnvironmentTooSmall(self):
3837 """Test handling of an environment that does not fit"""
3838 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003839 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003840
3841 # checksum, start byte, environment with \0 terminator, final \0
3842 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3843 short = need - 0x8
3844 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3845 str(e.exception))
3846
Simon Glassd1fdf752020-10-26 17:40:01 -06003847 def testSkipAtStart(self):
3848 """Test handling of skip-at-start section"""
3849 data = self._DoReadFile('177_skip_at_start.dts')
3850 self.assertEqual(U_BOOT_DATA, data)
3851
3852 image = control.images['image']
3853 entries = image.GetEntries()
3854 section = entries['section']
3855 self.assertEqual(0, section.offset)
3856 self.assertEqual(len(U_BOOT_DATA), section.size)
3857 self.assertEqual(U_BOOT_DATA, section.GetData())
3858
3859 entry = section.GetEntries()['u-boot']
3860 self.assertEqual(16, entry.offset)
3861 self.assertEqual(len(U_BOOT_DATA), entry.size)
3862 self.assertEqual(U_BOOT_DATA, entry.data)
3863
3864 def testSkipAtStartPad(self):
3865 """Test handling of skip-at-start section with padded entry"""
3866 data = self._DoReadFile('178_skip_at_start_pad.dts')
3867 before = tools.GetBytes(0, 8)
3868 after = tools.GetBytes(0, 4)
3869 all = before + U_BOOT_DATA + after
3870 self.assertEqual(all, data)
3871
3872 image = control.images['image']
3873 entries = image.GetEntries()
3874 section = entries['section']
3875 self.assertEqual(0, section.offset)
3876 self.assertEqual(len(all), section.size)
3877 self.assertEqual(all, section.GetData())
3878
3879 entry = section.GetEntries()['u-boot']
3880 self.assertEqual(16, entry.offset)
3881 self.assertEqual(len(all), entry.size)
3882 self.assertEqual(U_BOOT_DATA, entry.data)
3883
3884 def testSkipAtStartSectionPad(self):
3885 """Test handling of skip-at-start section with padding"""
3886 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3887 before = tools.GetBytes(0, 8)
3888 after = tools.GetBytes(0, 4)
3889 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06003890 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06003891
3892 image = control.images['image']
3893 entries = image.GetEntries()
3894 section = entries['section']
3895 self.assertEqual(0, section.offset)
3896 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06003897 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06003898 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06003899
3900 entry = section.GetEntries()['u-boot']
3901 self.assertEqual(16, entry.offset)
3902 self.assertEqual(len(U_BOOT_DATA), entry.size)
3903 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06003904
Simon Glassbb395742020-10-26 17:40:14 -06003905 def testSectionPad(self):
3906 """Testing padding with sections"""
3907 data = self._DoReadFile('180_section_pad.dts')
3908 expected = (tools.GetBytes(ord('&'), 3) +
3909 tools.GetBytes(ord('!'), 5) +
3910 U_BOOT_DATA +
3911 tools.GetBytes(ord('!'), 1) +
3912 tools.GetBytes(ord('&'), 2))
3913 self.assertEqual(expected, data)
3914
3915 def testSectionAlign(self):
3916 """Testing alignment with sections"""
3917 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
3918 expected = (b'\0' + # fill section
3919 tools.GetBytes(ord('&'), 1) + # padding to section align
3920 b'\0' + # fill section
3921 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
3922 U_BOOT_DATA +
3923 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
3924 tools.GetBytes(ord('!'), 4)) # padding to section size
3925 self.assertEqual(expected, data)
3926
Simon Glassd92c8362020-10-26 17:40:25 -06003927 def testCompressImage(self):
3928 """Test compression of the entire image"""
3929 self._CheckLz4()
3930 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3931 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
3932 dtb = fdt.Fdt(out_dtb_fname)
3933 dtb.Scan()
3934 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
3935 'uncomp-size'])
3936 orig = self._decompress(data)
3937 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
3938
3939 # Do a sanity check on various fields
3940 image = control.images['image']
3941 entries = image.GetEntries()
3942 self.assertEqual(2, len(entries))
3943
3944 entry = entries['blob']
3945 self.assertEqual(COMPRESS_DATA, entry.data)
3946 self.assertEqual(len(COMPRESS_DATA), entry.size)
3947
3948 entry = entries['u-boot']
3949 self.assertEqual(U_BOOT_DATA, entry.data)
3950 self.assertEqual(len(U_BOOT_DATA), entry.size)
3951
3952 self.assertEqual(len(data), image.size)
3953 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
3954 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
3955 orig = self._decompress(image.data)
3956 self.assertEqual(orig, image.uncomp_data)
3957
3958 expected = {
3959 'blob:offset': 0,
3960 'blob:size': len(COMPRESS_DATA),
3961 'u-boot:offset': len(COMPRESS_DATA),
3962 'u-boot:size': len(U_BOOT_DATA),
3963 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
3964 'offset': 0,
3965 'image-pos': 0,
3966 'size': len(data),
3967 }
3968 self.assertEqual(expected, props)
3969
3970 def testCompressImageLess(self):
3971 """Test compression where compression reduces the image size"""
3972 self._CheckLz4()
3973 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3974 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
3975 dtb = fdt.Fdt(out_dtb_fname)
3976 dtb.Scan()
3977 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
3978 'uncomp-size'])
3979 orig = self._decompress(data)
3980
3981 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
3982
3983 # Do a sanity check on various fields
3984 image = control.images['image']
3985 entries = image.GetEntries()
3986 self.assertEqual(2, len(entries))
3987
3988 entry = entries['blob']
3989 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
3990 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
3991
3992 entry = entries['u-boot']
3993 self.assertEqual(U_BOOT_DATA, entry.data)
3994 self.assertEqual(len(U_BOOT_DATA), entry.size)
3995
3996 self.assertEqual(len(data), image.size)
3997 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
3998 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
3999 image.uncomp_size)
4000 orig = self._decompress(image.data)
4001 self.assertEqual(orig, image.uncomp_data)
4002
4003 expected = {
4004 'blob:offset': 0,
4005 'blob:size': len(COMPRESS_DATA_BIG),
4006 'u-boot:offset': len(COMPRESS_DATA_BIG),
4007 'u-boot:size': len(U_BOOT_DATA),
4008 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4009 'offset': 0,
4010 'image-pos': 0,
4011 'size': len(data),
4012 }
4013 self.assertEqual(expected, props)
4014
4015 def testCompressSectionSize(self):
4016 """Test compression of a section with a fixed size"""
4017 self._CheckLz4()
4018 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4019 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4020 dtb = fdt.Fdt(out_dtb_fname)
4021 dtb.Scan()
4022 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4023 'uncomp-size'])
4024 orig = self._decompress(data)
4025 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4026 expected = {
4027 'section/blob:offset': 0,
4028 'section/blob:size': len(COMPRESS_DATA),
4029 'section/u-boot:offset': len(COMPRESS_DATA),
4030 'section/u-boot:size': len(U_BOOT_DATA),
4031 'section:offset': 0,
4032 'section:image-pos': 0,
4033 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4034 'section:size': 0x30,
4035 'offset': 0,
4036 'image-pos': 0,
4037 'size': 0x30,
4038 }
4039 self.assertEqual(expected, props)
4040
4041 def testCompressSection(self):
4042 """Test compression of a section with no fixed size"""
4043 self._CheckLz4()
4044 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4045 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4046 dtb = fdt.Fdt(out_dtb_fname)
4047 dtb.Scan()
4048 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4049 'uncomp-size'])
4050 orig = self._decompress(data)
4051 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4052 expected = {
4053 'section/blob:offset': 0,
4054 'section/blob:size': len(COMPRESS_DATA),
4055 'section/u-boot:offset': len(COMPRESS_DATA),
4056 'section/u-boot:size': len(U_BOOT_DATA),
4057 'section:offset': 0,
4058 'section:image-pos': 0,
4059 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4060 'section:size': len(data),
4061 'offset': 0,
4062 'image-pos': 0,
4063 'size': len(data),
4064 }
4065 self.assertEqual(expected, props)
4066
4067 def testCompressExtra(self):
4068 """Test compression of a section with no fixed size"""
4069 self._CheckLz4()
4070 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4071 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4072 dtb = fdt.Fdt(out_dtb_fname)
4073 dtb.Scan()
4074 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4075 'uncomp-size'])
4076
4077 base = data[len(U_BOOT_DATA):]
4078 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4079 rest = base[len(U_BOOT_DATA):]
4080
4081 # Check compressed data
4082 section1 = self._decompress(rest)
4083 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4084 self.assertEquals(expect1, rest[:len(expect1)])
4085 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4086 rest1 = rest[len(expect1):]
4087
4088 section2 = self._decompress(rest1)
4089 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4090 self.assertEquals(expect2, rest1[:len(expect2)])
4091 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4092 rest2 = rest1[len(expect2):]
4093
4094 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4095 len(expect2) + len(U_BOOT_DATA))
4096 #self.assertEquals(expect_size, len(data))
4097
4098 #self.assertEquals(U_BOOT_DATA, rest2)
4099
4100 self.maxDiff = None
4101 expected = {
4102 'u-boot:offset': 0,
4103 'u-boot:image-pos': 0,
4104 'u-boot:size': len(U_BOOT_DATA),
4105
4106 'base:offset': len(U_BOOT_DATA),
4107 'base:image-pos': len(U_BOOT_DATA),
4108 'base:size': len(data) - len(U_BOOT_DATA),
4109 'base/u-boot:offset': 0,
4110 'base/u-boot:image-pos': len(U_BOOT_DATA),
4111 'base/u-boot:size': len(U_BOOT_DATA),
4112 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4113 len(expect2),
4114 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4115 len(expect2),
4116 'base/u-boot2:size': len(U_BOOT_DATA),
4117
4118 'base/section:offset': len(U_BOOT_DATA),
4119 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4120 'base/section:size': len(expect1),
4121 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4122 'base/section/blob:offset': 0,
4123 'base/section/blob:size': len(COMPRESS_DATA),
4124 'base/section/u-boot:offset': len(COMPRESS_DATA),
4125 'base/section/u-boot:size': len(U_BOOT_DATA),
4126
4127 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4128 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4129 'base/section2:size': len(expect2),
4130 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4131 'base/section2/blob:offset': 0,
4132 'base/section2/blob:size': len(COMPRESS_DATA),
4133 'base/section2/blob2:offset': len(COMPRESS_DATA),
4134 'base/section2/blob2:size': len(COMPRESS_DATA),
4135
4136 'offset': 0,
4137 'image-pos': 0,
4138 'size': len(data),
4139 }
4140 self.assertEqual(expected, props)
4141
Simon Glassbb395742020-10-26 17:40:14 -06004142
Simon Glassac599912017-11-12 21:52:22 -07004143if __name__ == "__main__":
4144 unittest.main()