blob: 89fe6612e1b6ee0f823892433a97956ea0d4bc88 [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 Glassed930672021-03-18 20:25:05 +1300308 use_expanded=False, verbosity=None, allow_missing=False,
309 extra_indirs=None):
Simon Glass57454f42016-11-25 20:15:52 -0700310 """Run binman with a given test file
311
312 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600313 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600314 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600315 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600316 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600317 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600318 entry_args: Dict of entry args to supply to binman
319 key: arg name
320 value: value of that arg
321 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600322 use_real_dtb: True to use the test file as the contents of
323 the u-boot-dtb entry. Normally this is not needed and the
324 test contents (the U_BOOT_DTB_DATA string) can be used.
325 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300326 use_expanded: True to use expanded entries where available, e.g.
327 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600328 verbosity: Verbosity level to use (0-3, None=don't set it)
329 allow_missing: Set the '--allow-missing' flag so that missing
330 external binaries just produce a warning instead of an error
Simon Glassa435cd12020-09-01 05:13:59 -0600331 extra_indirs: Extra input directories to add using -I
Simon Glass57454f42016-11-25 20:15:52 -0700332 """
Simon Glassf46732a2019-07-08 14:25:29 -0600333 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700334 if debug:
335 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600336 if verbosity is not None:
337 args.append('-v%d' % verbosity)
338 elif self.verbosity:
339 args.append('-v%d' % self.verbosity)
340 if self.toolpath:
341 for path in self.toolpath:
342 args += ['--toolpath', path]
343 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600344 if map:
345 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600346 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600347 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600348 if not use_real_dtb:
349 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300350 if not use_expanded:
351 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600352 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600353 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600354 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600355 if allow_missing:
356 args.append('-M')
Simon Glass3b376c32018-09-14 04:57:12 -0600357 if images:
358 for image in images:
359 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600360 if extra_indirs:
361 for indir in extra_indirs:
362 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700363 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700364
365 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700366 """Set up a new test device-tree file
367
368 The given file is compiled and set up as the device tree to be used
369 for ths test.
370
371 Args:
372 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600373 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700374
375 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600376 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700377 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600378 tmpdir = tempfile.mkdtemp(prefix='binmant.')
379 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600380 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700381 data = fd.read()
382 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600383 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600384 return data
Simon Glass57454f42016-11-25 20:15:52 -0700385
Simon Glasse219aa42018-09-14 04:57:24 -0600386 def _GetDtbContentsForSplTpl(self, dtb_data, name):
387 """Create a version of the main DTB for SPL or SPL
388
389 For testing we don't actually have different versions of the DTB. With
390 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
391 we don't normally have any unwanted nodes.
392
393 We still want the DTBs for SPL and TPL to be different though, since
394 otherwise it is confusing to know which one we are looking at. So add
395 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600396
397 Args:
398 dtb_data: dtb data to modify (this should be a value devicetree)
399 name: Name of a new property to add
400
401 Returns:
402 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600403 """
404 dtb = fdt.Fdt.FromData(dtb_data)
405 dtb.Scan()
406 dtb.GetNode('/binman').AddZeroProp(name)
407 dtb.Sync(auto_resize=True)
408 dtb.Pack()
409 return dtb.GetContents()
410
Simon Glassed930672021-03-18 20:25:05 +1300411 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
412 map=False, update_dtb=False, entry_args=None,
413 reset_dtbs=True, extra_indirs=None):
Simon Glass57454f42016-11-25 20:15:52 -0700414 """Run binman and return the resulting image
415
416 This runs binman with a given test file and then reads the resulting
417 output file. It is a shortcut function since most tests need to do
418 these steps.
419
420 Raises an assertion failure if binman returns a non-zero exit code.
421
422 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600423 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700424 use_real_dtb: True to use the test file as the contents of
425 the u-boot-dtb entry. Normally this is not needed and the
426 test contents (the U_BOOT_DTB_DATA string) can be used.
427 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300428 use_expanded: True to use expanded entries where available, e.g.
429 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600430 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600431 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600432 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600433 entry_args: Dict of entry args to supply to binman
434 key: arg name
435 value: value of that arg
436 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
437 function. If reset_dtbs is True, then the original test dtb
438 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600439 extra_indirs: Extra input directories to add using -I
Simon Glass72232452016-11-25 20:15:53 -0700440
441 Returns:
442 Tuple:
443 Resulting image contents
444 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600445 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600446 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700447 """
Simon Glass72232452016-11-25 20:15:53 -0700448 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700449 # Use the compiled test file as the u-boot-dtb input
450 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700451 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600452
453 # For testing purposes, make a copy of the DT for SPL and TPL. Add
454 # a node indicating which it is, so aid verification.
455 for name in ['spl', 'tpl']:
456 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
457 outfile = os.path.join(self._indir, dtb_fname)
458 TestFunctional._MakeInputFile(dtb_fname,
459 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700460
461 try:
Simon Glass91710b32018-07-17 13:25:32 -0600462 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600463 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassed930672021-03-18 20:25:05 +1300464 use_expanded=use_expanded, extra_indirs=extra_indirs)
Simon Glass57454f42016-11-25 20:15:52 -0700465 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600466 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700467
468 # Find the (only) image, read it and return its contents
469 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600470 image_fname = tools.GetOutputFilename('image.bin')
471 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600472 if map:
473 map_fname = tools.GetOutputFilename('image.map')
474 with open(map_fname) as fd:
475 map_data = fd.read()
476 else:
477 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600478 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600479 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700480 finally:
481 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600482 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600483 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700484
Simon Glass5b4bce32019-07-08 14:25:26 -0600485 def _DoReadFileRealDtb(self, fname):
486 """Run binman with a real .dtb file and return the resulting data
487
488 Args:
489 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
490
491 Returns:
492 Resulting image contents
493 """
494 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
495
Simon Glass72232452016-11-25 20:15:53 -0700496 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600497 """Helper function which discards the device-tree binary
498
499 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600500 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600501 use_real_dtb: True to use the test file as the contents of
502 the u-boot-dtb entry. Normally this is not needed and the
503 test contents (the U_BOOT_DTB_DATA string) can be used.
504 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600505
506 Returns:
507 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600508 """
Simon Glass72232452016-11-25 20:15:53 -0700509 return self._DoReadFileDtb(fname, use_real_dtb)[0]
510
Simon Glass57454f42016-11-25 20:15:52 -0700511 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600512 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700513 """Create a new test input file, creating directories as needed
514
515 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600516 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700517 contents: File contents to write in to the file
518 Returns:
519 Full pathname of file created
520 """
Simon Glass862f8e22019-08-24 07:22:43 -0600521 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700522 dirname = os.path.dirname(pathname)
523 if dirname and not os.path.exists(dirname):
524 os.makedirs(dirname)
525 with open(pathname, 'wb') as fd:
526 fd.write(contents)
527 return pathname
528
529 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600530 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600531 """Create a new test input directory, creating directories as needed
532
533 Args:
534 dirname: Directory name to create
535
536 Returns:
537 Full pathname of directory created
538 """
Simon Glass862f8e22019-08-24 07:22:43 -0600539 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600540 if not os.path.exists(pathname):
541 os.makedirs(pathname)
542 return pathname
543
544 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600545 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600546 """Set up an ELF file with a '_dt_ucode_base_size' symbol
547
548 Args:
549 Filename of ELF file to use as SPL
550 """
Simon Glass93a806f2019-08-24 07:22:59 -0600551 TestFunctional._MakeInputFile('spl/u-boot-spl',
552 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600553
554 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600555 def _SetupTplElf(cls, src_fname='bss_data'):
556 """Set up an ELF file with a '_dt_ucode_base_size' symbol
557
558 Args:
559 Filename of ELF file to use as TPL
560 """
561 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
562 tools.ReadFile(cls.ElfTestFile(src_fname)))
563
564 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600565 def _SetupDescriptor(cls):
566 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
567 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
568
569 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600570 def TestFile(cls, fname):
571 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700572
Simon Glassf6290892019-08-24 07:22:53 -0600573 @classmethod
574 def ElfTestFile(cls, fname):
575 return os.path.join(cls._elf_testdir, fname)
576
Simon Glass57454f42016-11-25 20:15:52 -0700577 def AssertInList(self, grep_list, target):
578 """Assert that at least one of a list of things is in a target
579
580 Args:
581 grep_list: List of strings to check
582 target: Target string
583 """
584 for grep in grep_list:
585 if grep in target:
586 return
Simon Glass848cdb52019-05-17 22:00:50 -0600587 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700588
589 def CheckNoGaps(self, entries):
590 """Check that all entries fit together without gaps
591
592 Args:
593 entries: List of entries to check
594 """
Simon Glasse8561af2018-08-01 15:22:37 -0600595 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700596 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600597 self.assertEqual(offset, entry.offset)
598 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700599
Simon Glass72232452016-11-25 20:15:53 -0700600 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600601 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700602
603 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600604 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700605
606 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600607 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700608 """
609 return struct.unpack('>L', dtb[4:8])[0]
610
Simon Glass0f621332019-07-08 14:25:27 -0600611 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600612 def AddNode(node, path):
613 if node.name != '/':
614 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600615 for prop in node.props.values():
616 if prop.name in prop_names:
617 prop_path = path + ':' + prop.name
618 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
619 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600620 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600621 AddNode(subnode, path)
622
623 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600624 AddNode(dtb.GetRoot(), '')
625 return tree
626
Simon Glass57454f42016-11-25 20:15:52 -0700627 def testRun(self):
628 """Test a basic run with valid args"""
629 result = self._RunBinman('-h')
630
631 def testFullHelp(self):
632 """Test that the full help is displayed with -H"""
633 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300634 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500635 # Remove possible extraneous strings
636 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
637 gothelp = result.stdout.replace(extra, '')
638 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700639 self.assertEqual(0, len(result.stderr))
640 self.assertEqual(0, result.return_code)
641
642 def testFullHelpInternal(self):
643 """Test that the full help is displayed with -H"""
644 try:
645 command.test_result = command.CommandResult()
646 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300647 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700648 finally:
649 command.test_result = None
650
651 def testHelp(self):
652 """Test that the basic help is displayed with -h"""
653 result = self._RunBinman('-h')
654 self.assertTrue(len(result.stdout) > 200)
655 self.assertEqual(0, len(result.stderr))
656 self.assertEqual(0, result.return_code)
657
Simon Glass57454f42016-11-25 20:15:52 -0700658 def testBoard(self):
659 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600660 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700661 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300662 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700663 self.assertEqual(0, result)
664
665 def testNeedBoard(self):
666 """Test that we get an error when no board ius supplied"""
667 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600668 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700669 self.assertIn("Must provide a board to process (use -b <board>)",
670 str(e.exception))
671
672 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600673 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700674 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600675 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700676 # We get one error from libfdt, and a different one from fdtget.
677 self.AssertInList(["Couldn't open blob from 'missing_file'",
678 'No such file or directory'], str(e.exception))
679
680 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600681 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700682
683 Since this is a source file it should be compiled and the error
684 will come from the device-tree compiler (dtc).
685 """
686 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600687 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700688 self.assertIn("FATAL ERROR: Unable to parse input tree",
689 str(e.exception))
690
691 def testMissingNode(self):
692 """Test that a device tree without a 'binman' node generates an error"""
693 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600694 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700695 self.assertIn("does not have a 'binman' node", str(e.exception))
696
697 def testEmpty(self):
698 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600699 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700700 self.assertEqual(0, len(result.stderr))
701 self.assertEqual(0, result.return_code)
702
703 def testInvalidEntry(self):
704 """Test that an invalid entry is flagged"""
705 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600706 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600707 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700708 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
709 "'/binman/not-a-valid-type'", str(e.exception))
710
711 def testSimple(self):
712 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600713 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700714 self.assertEqual(U_BOOT_DATA, data)
715
Simon Glass075a45c2017-11-13 18:55:00 -0700716 def testSimpleDebug(self):
717 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600718 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700719
Simon Glass57454f42016-11-25 20:15:52 -0700720 def testDual(self):
721 """Test that we can handle creating two images
722
723 This also tests image padding.
724 """
Simon Glass511f6582018-10-01 12:22:30 -0600725 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700726 self.assertEqual(0, retcode)
727
728 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600729 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700730 fname = tools.GetOutputFilename('image1.bin')
731 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600732 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700733 data = fd.read()
734 self.assertEqual(U_BOOT_DATA, data)
735
736 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600737 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700738 fname = tools.GetOutputFilename('image2.bin')
739 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600740 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700741 data = fd.read()
742 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600743 self.assertEqual(tools.GetBytes(0, 3), data[:3])
744 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700745
746 def testBadAlign(self):
747 """Test that an invalid alignment value is detected"""
748 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600749 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700750 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
751 "of two", str(e.exception))
752
753 def testPackSimple(self):
754 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600755 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700756 self.assertEqual(0, retcode)
757 self.assertIn('image', control.images)
758 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600759 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700760 self.assertEqual(5, len(entries))
761
762 # First u-boot
763 self.assertIn('u-boot', entries)
764 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600765 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700766 self.assertEqual(len(U_BOOT_DATA), entry.size)
767
768 # Second u-boot, aligned to 16-byte boundary
769 self.assertIn('u-boot-align', entries)
770 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600771 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700772 self.assertEqual(len(U_BOOT_DATA), entry.size)
773
774 # Third u-boot, size 23 bytes
775 self.assertIn('u-boot-size', entries)
776 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600777 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700778 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
779 self.assertEqual(23, entry.size)
780
781 # Fourth u-boot, placed immediate after the above
782 self.assertIn('u-boot-next', entries)
783 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600784 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700785 self.assertEqual(len(U_BOOT_DATA), entry.size)
786
Simon Glasse8561af2018-08-01 15:22:37 -0600787 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700788 self.assertIn('u-boot-fixed', entries)
789 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600790 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700791 self.assertEqual(len(U_BOOT_DATA), entry.size)
792
Simon Glass39dd2152019-07-08 14:25:47 -0600793 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700794
795 def testPackExtra(self):
796 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600797 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
798 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700799
Simon Glass57454f42016-11-25 20:15:52 -0700800 self.assertIn('image', control.images)
801 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600802 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700803 self.assertEqual(5, len(entries))
804
805 # First u-boot with padding before and after
806 self.assertIn('u-boot', entries)
807 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600808 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700809 self.assertEqual(3, entry.pad_before)
810 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600811 self.assertEqual(U_BOOT_DATA, entry.data)
812 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
813 tools.GetBytes(0, 5), data[:entry.size])
814 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700815
816 # Second u-boot has an aligned size, but it has no effect
817 self.assertIn('u-boot-align-size-nop', entries)
818 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600819 self.assertEqual(pos, entry.offset)
820 self.assertEqual(len(U_BOOT_DATA), entry.size)
821 self.assertEqual(U_BOOT_DATA, entry.data)
822 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
823 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700824
825 # Third u-boot has an aligned size too
826 self.assertIn('u-boot-align-size', entries)
827 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600828 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700829 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600830 self.assertEqual(U_BOOT_DATA, entry.data)
831 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
832 data[pos:pos + entry.size])
833 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700834
835 # Fourth u-boot has an aligned end
836 self.assertIn('u-boot-align-end', entries)
837 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600838 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700839 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600840 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
841 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
842 data[pos:pos + entry.size])
843 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700844
845 # Fifth u-boot immediately afterwards
846 self.assertIn('u-boot-align-both', entries)
847 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600848 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600850 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
851 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
852 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700853
854 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600855 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700856
Simon Glassafb9caa2020-10-26 17:40:10 -0600857 dtb = fdt.Fdt(out_dtb_fname)
858 dtb.Scan()
859 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
860 expected = {
861 'image-pos': 0,
862 'offset': 0,
863 'size': 128,
864
865 'u-boot:image-pos': 0,
866 'u-boot:offset': 0,
867 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
868
869 'u-boot-align-size-nop:image-pos': 12,
870 'u-boot-align-size-nop:offset': 12,
871 'u-boot-align-size-nop:size': 4,
872
873 'u-boot-align-size:image-pos': 16,
874 'u-boot-align-size:offset': 16,
875 'u-boot-align-size:size': 32,
876
877 'u-boot-align-end:image-pos': 48,
878 'u-boot-align-end:offset': 48,
879 'u-boot-align-end:size': 16,
880
881 'u-boot-align-both:image-pos': 64,
882 'u-boot-align-both:offset': 64,
883 'u-boot-align-both:size': 64,
884 }
885 self.assertEqual(expected, props)
886
Simon Glass57454f42016-11-25 20:15:52 -0700887 def testPackAlignPowerOf2(self):
888 """Test that invalid entry alignment is detected"""
889 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600890 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700891 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
892 "of two", str(e.exception))
893
894 def testPackAlignSizePowerOf2(self):
895 """Test that invalid entry size alignment is detected"""
896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600897 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700898 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
899 "power of two", str(e.exception))
900
901 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600902 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700903 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600904 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600905 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700906 "align 0x4 (4)", str(e.exception))
907
908 def testPackInvalidSizeAlign(self):
909 """Test that invalid entry size alignment is detected"""
910 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600911 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700912 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
913 "align-size 0x4 (4)", str(e.exception))
914
915 def testPackOverlap(self):
916 """Test that overlapping regions are detected"""
917 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600918 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600919 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700920 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
921 str(e.exception))
922
923 def testPackEntryOverflow(self):
924 """Test that entries that overflow their size are detected"""
925 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600926 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
928 "but entry size is 0x3 (3)", str(e.exception))
929
930 def testPackImageOverflow(self):
931 """Test that entries which overflow the image size are detected"""
932 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600933 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600934 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700935 "size 0x3 (3)", str(e.exception))
936
937 def testPackImageSize(self):
938 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600939 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700940 self.assertEqual(0, retcode)
941 self.assertIn('image', control.images)
942 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600943 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700944
945 def testPackImageSizeAlign(self):
946 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600947 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700948 self.assertEqual(0, retcode)
949 self.assertIn('image', control.images)
950 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600951 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700952
953 def testPackInvalidImageAlign(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('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600957 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700958 "align-size 0x8 (8)", str(e.exception))
959
960 def testPackAlignPowerOf2(self):
961 """Test that invalid image alignment is detected"""
962 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600963 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600964 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700965 "two", str(e.exception))
966
967 def testImagePadByte(self):
968 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600969 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600970 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600971 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
972 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700973
974 def testImageName(self):
975 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600976 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700977 self.assertEqual(0, retcode)
978 image = control.images['image1']
979 fname = tools.GetOutputFilename('test-name')
980 self.assertTrue(os.path.exists(fname))
981
982 image = control.images['image2']
983 fname = tools.GetOutputFilename('test-name.xx')
984 self.assertTrue(os.path.exists(fname))
985
986 def testBlobFilename(self):
987 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -0600988 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700989 self.assertEqual(BLOB_DATA, data)
990
991 def testPackSorted(self):
992 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -0600993 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600994 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600995 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
996 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700997
Simon Glasse8561af2018-08-01 15:22:37 -0600998 def testPackZeroOffset(self):
999 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001000 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001001 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001002 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001003 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1004 str(e.exception))
1005
1006 def testPackUbootDtb(self):
1007 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001008 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001009 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001010
1011 def testPackX86RomNoSize(self):
1012 """Test that the end-at-4gb property requires a size property"""
1013 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001014 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001015 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001016 "using end-at-4gb", str(e.exception))
1017
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301018 def test4gbAndSkipAtStartTogether(self):
1019 """Test that the end-at-4gb and skip-at-size property can't be used
1020 together"""
1021 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001022 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001023 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301024 "'skip-at-start'", str(e.exception))
1025
Simon Glass72232452016-11-25 20:15:53 -07001026 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001027 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001028 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001029 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001030 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1031 "is outside the section '/binman' starting at "
1032 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001033 str(e.exception))
1034
1035 def testPackX86Rom(self):
1036 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001037 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001038 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -06001039 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -06001040 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001041
1042 def testPackX86RomMeNoDesc(self):
1043 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001044 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001045 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001046 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001047 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001048 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1049 str(e.exception))
1050 finally:
1051 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001052
1053 def testPackX86RomBadDesc(self):
1054 """Test that the Intel requires a descriptor entry"""
1055 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001056 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001057 self.assertIn("Node '/binman/intel-me': No offset set with "
1058 "offset-unset: should another entry provide this correct "
1059 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001060
1061 def testPackX86RomMe(self):
1062 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001063 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -06001064 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1065 if data[:0x1000] != expected_desc:
1066 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001067 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1068
1069 def testPackVga(self):
1070 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001071 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001072 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1073
1074 def testPackStart16(self):
1075 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001076 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001077 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1078
Jagdish Gediya311d4842018-09-03 21:35:08 +05301079 def testPackPowerpcMpc85xxBootpgResetvec(self):
1080 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1081 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001082 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301083 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1084
Simon Glass6ba679c2018-07-06 10:27:17 -06001085 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001086 """Handle running a test for insertion of microcode
1087
1088 Args:
1089 dts_fname: Name of test .dts file
1090 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001091 ucode_second: True if the microsecond entry is second instead of
1092 third
Simon Glass820af1d2018-07-06 10:27:16 -06001093
1094 Returns:
1095 Tuple:
1096 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001097 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001098 in the above (two 4-byte words)
1099 """
Simon Glass3d274232017-11-12 21:52:27 -07001100 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001101
1102 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001103 if ucode_second:
1104 ucode_content = data[len(nodtb_data):]
1105 ucode_pos = len(nodtb_data)
1106 dtb_with_ucode = ucode_content[16:]
1107 fdt_len = self.GetFdtLen(dtb_with_ucode)
1108 else:
1109 dtb_with_ucode = data[len(nodtb_data):]
1110 fdt_len = self.GetFdtLen(dtb_with_ucode)
1111 ucode_content = dtb_with_ucode[fdt_len:]
1112 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001113 fname = tools.GetOutputFilename('test.dtb')
1114 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001115 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001116 dtb = fdt.FdtScan(fname)
1117 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001118 self.assertTrue(ucode)
1119 for node in ucode.subnodes:
1120 self.assertFalse(node.props.get('data'))
1121
Simon Glass72232452016-11-25 20:15:53 -07001122 # Check that the microcode appears immediately after the Fdt
1123 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001124 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001125 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1126 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001127 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001128
1129 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001130 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001131 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1132 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001133 u_boot = data[:len(nodtb_data)]
1134 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001135
1136 def testPackUbootMicrocode(self):
1137 """Test that x86 microcode can be handled correctly
1138
1139 We expect to see the following in the image, in order:
1140 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1141 place
1142 u-boot.dtb with the microcode removed
1143 the microcode
1144 """
Simon Glass511f6582018-10-01 12:22:30 -06001145 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001146 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001147 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1148 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001149
Simon Glassbac25c82017-05-27 07:38:26 -06001150 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001151 """Test that x86 microcode can be handled correctly
1152
1153 We expect to see the following in the image, in order:
1154 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1155 place
1156 u-boot.dtb with the microcode
1157 an empty microcode region
1158 """
1159 # We need the libfdt library to run this test since only that allows
1160 # finding the offset of a property. This is required by
1161 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001162 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001163
1164 second = data[len(U_BOOT_NODTB_DATA):]
1165
1166 fdt_len = self.GetFdtLen(second)
1167 third = second[fdt_len:]
1168 second = second[:fdt_len]
1169
Simon Glassbac25c82017-05-27 07:38:26 -06001170 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1171 self.assertIn(ucode_data, second)
1172 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001173
Simon Glassbac25c82017-05-27 07:38:26 -06001174 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001175 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001176 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1177 len(ucode_data))
1178 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001179 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1180 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001181
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001182 def testPackUbootSingleMicrocode(self):
1183 """Test that x86 microcode can be handled correctly with fdt_normal.
1184 """
Simon Glassbac25c82017-05-27 07:38:26 -06001185 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001186
Simon Glass996021e2016-11-25 20:15:54 -07001187 def testUBootImg(self):
1188 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001189 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001190 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001191
1192 def testNoMicrocode(self):
1193 """Test that a missing microcode region is detected"""
1194 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001195 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001196 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1197 "node found in ", str(e.exception))
1198
1199 def testMicrocodeWithoutNode(self):
1200 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1201 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001202 self._DoReadFile('038_x86_ucode_missing_node.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-dtb-with-ucode", str(e.exception))
1205
1206 def testMicrocodeWithoutNode2(self):
1207 """Test that a missing u-boot-ucode node is detected"""
1208 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001209 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001210 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1211 "microcode region u-boot-ucode", str(e.exception))
1212
1213 def testMicrocodeWithoutPtrInElf(self):
1214 """Test that a U-Boot binary without the microcode symbol is detected"""
1215 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001216 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001217 TestFunctional._MakeInputFile('u-boot',
1218 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001219
1220 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001221 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001222 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1223 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1224
1225 finally:
1226 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001227 TestFunctional._MakeInputFile('u-boot',
1228 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001229
1230 def testMicrocodeNotInImage(self):
1231 """Test that microcode must be placed within the image"""
1232 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001233 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001234 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1235 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001236 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001237
1238 def testWithoutMicrocode(self):
1239 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001240 TestFunctional._MakeInputFile('u-boot',
1241 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001242 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001243
1244 # Now check the device tree has no microcode
1245 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1246 second = data[len(U_BOOT_NODTB_DATA):]
1247
1248 fdt_len = self.GetFdtLen(second)
1249 self.assertEqual(dtb, second[:fdt_len])
1250
1251 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1252 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001253 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001254
1255 def testUnknownPosSize(self):
1256 """Test that microcode must be placed within the image"""
1257 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001258 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001259 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001260 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001261
1262 def testPackFsp(self):
1263 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001264 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001265 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1266
1267 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001268 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001269 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001270 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001271
1272 def testPackVbt(self):
1273 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001274 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001275 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001276
Simon Glass7f94e832017-11-12 21:52:25 -07001277 def testSplBssPad(self):
1278 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001279 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001280 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001281 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001282 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1283 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001284
Simon Glass04cda032018-10-01 21:12:42 -06001285 def testSplBssPadMissing(self):
1286 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001287 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001288 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001289 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001290 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1291 str(e.exception))
1292
Simon Glasse83679d2017-11-12 21:52:26 -07001293 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001294 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001295 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001296 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1297
Simon Glass6ba679c2018-07-06 10:27:17 -06001298 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1299 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001300
1301 We expect to see the following in the image, in order:
1302 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1303 correct place
1304 u-boot.dtb with the microcode removed
1305 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001306
1307 Args:
1308 dts: Device tree file to use for test
1309 ucode_second: True if the microsecond entry is second instead of
1310 third
Simon Glass3d274232017-11-12 21:52:27 -07001311 """
Simon Glass7057d022018-10-01 21:12:47 -06001312 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001313 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1314 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001315 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1316 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001317
Simon Glass6ba679c2018-07-06 10:27:17 -06001318 def testPackUbootSplMicrocode(self):
1319 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001320 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001321
1322 def testPackUbootSplMicrocodeReorder(self):
1323 """Test that order doesn't matter for microcode entries
1324
1325 This is the same as testPackUbootSplMicrocode but when we process the
1326 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1327 entry, so we reply on binman to try later.
1328 """
Simon Glass511f6582018-10-01 12:22:30 -06001329 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001330 ucode_second=True)
1331
Simon Glassa409c932017-11-12 21:52:28 -07001332 def testPackMrc(self):
1333 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001334 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001335 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1336
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001337 def testSplDtb(self):
1338 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001339 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001340 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1341
Simon Glass0a6da312017-11-13 18:54:56 -07001342 def testSplNoDtb(self):
1343 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001344 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001345 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1346
Simon Glass7098b7f2021-03-21 18:24:30 +13001347 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1348 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001349 """Check the image contains the expected symbol values
1350
1351 Args:
1352 dts: Device tree file to use for test
1353 base_data: Data before and after 'u-boot' section
1354 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001355 entry_args: Dict of entry args to supply to binman
1356 key: arg name
1357 value: value of that arg
1358 use_expanded: True to use expanded entries where available, e.g.
1359 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001360 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001361 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001362 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1363 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001364 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1365 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001366
Simon Glass7057d022018-10-01 21:12:47 -06001367 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001368 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1369 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001370 # The image should contain the symbols from u_boot_binman_syms.c
1371 # Note that image_pos is adjusted by the base address of the image,
1372 # which is 0x10 in our test image
1373 sym_values = struct.pack('<LQLL', 0x00,
1374 u_boot_offset + len(U_BOOT_DATA),
1375 0x10 + u_boot_offset, 0x04)
1376 expected = (sym_values + base_data[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001377 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001378 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001379 self.assertEqual(expected, data)
1380
Simon Glass31e04cb2021-03-18 20:24:56 +13001381 def testSymbols(self):
1382 """Test binman can assign symbols embedded in U-Boot"""
1383 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1384
1385 def testSymbolsNoDtb(self):
1386 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001387 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001388 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1389 0x38)
1390
Simon Glasse76a3e62018-06-01 09:38:11 -06001391 def testPackUnitAddress(self):
1392 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001393 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001394 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1395
Simon Glassa91e1152018-06-01 09:38:16 -06001396 def testSections(self):
1397 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001398 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001399 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1400 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1401 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001402 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001403
Simon Glass30732662018-06-01 09:38:20 -06001404 def testMap(self):
1405 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001406 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001407 self.assertEqual('''ImagePos Offset Size Name
140800000000 00000000 00000028 main-section
140900000000 00000000 00000010 section@0
141000000000 00000000 00000004 u-boot
141100000010 00000010 00000010 section@1
141200000010 00000000 00000004 u-boot
141300000020 00000020 00000004 section@2
141400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001415''', map_data)
1416
Simon Glass3b78d532018-06-01 09:38:21 -06001417 def testNamePrefix(self):
1418 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001419 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001420 self.assertEqual('''ImagePos Offset Size Name
142100000000 00000000 00000028 main-section
142200000000 00000000 00000010 section@0
142300000000 00000000 00000004 ro-u-boot
142400000010 00000010 00000010 section@1
142500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001426''', map_data)
1427
Simon Glass6ba679c2018-07-06 10:27:17 -06001428 def testUnknownContents(self):
1429 """Test that obtaining the contents works as expected"""
1430 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001431 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001432 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001433 "processing of contents: remaining ["
1434 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001435
Simon Glass2e1169f2018-07-06 10:27:19 -06001436 def testBadChangeSize(self):
1437 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001438 try:
1439 state.SetAllowEntryExpansion(False)
1440 with self.assertRaises(ValueError) as e:
1441 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001442 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001443 str(e.exception))
1444 finally:
1445 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001446
Simon Glassa87014e2018-07-06 10:27:42 -06001447 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001448 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001449 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001450 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001451 dtb = fdt.Fdt(out_dtb_fname)
1452 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001453 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001454 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001455 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001456 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001457 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001458 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001459 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001460 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001461 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001462 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001463 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001464 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001465 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001466
Simon Glasse8561af2018-08-01 15:22:37 -06001467 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001468 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001469 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001470 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001471 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001472 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001473 'size': 40
1474 }, props)
1475
1476 def testUpdateFdtBad(self):
1477 """Test that we detect when ProcessFdt never completes"""
1478 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001479 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001480 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001481 '[<binman.etype._testing.Entry__testing',
1482 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001483
Simon Glass91710b32018-07-17 13:25:32 -06001484 def testEntryArgs(self):
1485 """Test passing arguments to entries from the command line"""
1486 entry_args = {
1487 'test-str-arg': 'test1',
1488 'test-int-arg': '456',
1489 }
Simon Glass511f6582018-10-01 12:22:30 -06001490 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001491 self.assertIn('image', control.images)
1492 entry = control.images['image'].GetEntries()['_testing']
1493 self.assertEqual('test0', entry.test_str_fdt)
1494 self.assertEqual('test1', entry.test_str_arg)
1495 self.assertEqual(123, entry.test_int_fdt)
1496 self.assertEqual(456, entry.test_int_arg)
1497
1498 def testEntryArgsMissing(self):
1499 """Test missing arguments and properties"""
1500 entry_args = {
1501 'test-int-arg': '456',
1502 }
Simon Glass511f6582018-10-01 12:22:30 -06001503 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001504 entry = control.images['image'].GetEntries()['_testing']
1505 self.assertEqual('test0', entry.test_str_fdt)
1506 self.assertEqual(None, entry.test_str_arg)
1507 self.assertEqual(None, entry.test_int_fdt)
1508 self.assertEqual(456, entry.test_int_arg)
1509
1510 def testEntryArgsRequired(self):
1511 """Test missing arguments and properties"""
1512 entry_args = {
1513 'test-int-arg': '456',
1514 }
1515 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001516 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001517 self.assertIn("Node '/binman/_testing': "
1518 'Missing required properties/entry args: test-str-arg, '
1519 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001520 str(e.exception))
1521
1522 def testEntryArgsInvalidFormat(self):
1523 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001524 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1525 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001526 with self.assertRaises(ValueError) as e:
1527 self._DoBinman(*args)
1528 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1529
1530 def testEntryArgsInvalidInteger(self):
1531 """Test that an invalid entry-argument integer is detected"""
1532 entry_args = {
1533 'test-int-arg': 'abc',
1534 }
1535 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001536 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001537 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1538 "'test-int-arg' (value 'abc') to integer",
1539 str(e.exception))
1540
1541 def testEntryArgsInvalidDatatype(self):
1542 """Test that an invalid entry-argument datatype is detected
1543
1544 This test could be written in entry_test.py except that it needs
1545 access to control.entry_args, which seems more than that module should
1546 be able to see.
1547 """
1548 entry_args = {
1549 'test-bad-datatype-arg': '12',
1550 }
1551 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001552 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001553 entry_args=entry_args)
1554 self.assertIn('GetArg() internal error: Unknown data type ',
1555 str(e.exception))
1556
Simon Glass2ca52032018-07-17 13:25:33 -06001557 def testText(self):
1558 """Test for a text entry type"""
1559 entry_args = {
1560 'test-id': TEXT_DATA,
1561 'test-id2': TEXT_DATA2,
1562 'test-id3': TEXT_DATA3,
1563 }
Simon Glass511f6582018-10-01 12:22:30 -06001564 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001565 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001566 expected = (tools.ToBytes(TEXT_DATA) +
1567 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1568 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001569 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001570 self.assertEqual(expected, data)
1571
Simon Glass969616c2018-07-17 13:25:36 -06001572 def testEntryDocs(self):
1573 """Test for creation of entry documentation"""
1574 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001575 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001576 self.assertTrue(len(stdout.getvalue()) > 0)
1577
1578 def testEntryDocsMissing(self):
1579 """Test handling of missing entry documentation"""
1580 with self.assertRaises(ValueError) as e:
1581 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001582 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001583 self.assertIn('Documentation is missing for modules: u_boot',
1584 str(e.exception))
1585
Simon Glass704784b2018-07-17 13:25:38 -06001586 def testFmap(self):
1587 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001588 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001589 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001590 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1591 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001592 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001593 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001594 self.assertEqual(1, fhdr.ver_major)
1595 self.assertEqual(0, fhdr.ver_minor)
1596 self.assertEqual(0, fhdr.base)
1597 self.assertEqual(16 + 16 +
1598 fmap_util.FMAP_HEADER_LEN +
1599 fmap_util.FMAP_AREA_LEN * 3, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001600 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass704784b2018-07-17 13:25:38 -06001601 self.assertEqual(3, fhdr.nareas)
1602 for fentry in fentries:
1603 self.assertEqual(0, fentry.flags)
1604
1605 self.assertEqual(0, fentries[0].offset)
1606 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001607 self.assertEqual(b'RO_U_BOOT', fentries[0].name)
Simon Glass704784b2018-07-17 13:25:38 -06001608
1609 self.assertEqual(16, fentries[1].offset)
1610 self.assertEqual(4, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001611 self.assertEqual(b'RW_U_BOOT', fentries[1].name)
Simon Glass704784b2018-07-17 13:25:38 -06001612
1613 self.assertEqual(32, fentries[2].offset)
1614 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
1615 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06001616 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glass704784b2018-07-17 13:25:38 -06001617
Simon Glassdb168d42018-07-17 13:25:39 -06001618 def testBlobNamedByArg(self):
1619 """Test we can add a blob with the filename coming from an entry arg"""
1620 entry_args = {
1621 'cros-ec-rw-path': 'ecrw.bin',
1622 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001623 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001624
Simon Glass53f53992018-07-17 13:25:40 -06001625 def testFill(self):
1626 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001627 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001628 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001629 self.assertEqual(expected, data)
1630
1631 def testFillNoSize(self):
1632 """Test for an fill entry type with no size"""
1633 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001634 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001635 self.assertIn("'fill' entry must have a size property",
1636 str(e.exception))
1637
Simon Glassc1ae83c2018-07-17 13:25:44 -06001638 def _HandleGbbCommand(self, pipe_list):
1639 """Fake calls to the futility utility"""
1640 if pipe_list[0][0] == 'futility':
1641 fname = pipe_list[0][-1]
1642 # Append our GBB data to the file, which will happen every time the
1643 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001644 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001645 fd.write(GBB_DATA)
1646 return command.CommandResult()
1647
1648 def testGbb(self):
1649 """Test for the Chromium OS Google Binary Block"""
1650 command.test_result = self._HandleGbbCommand
1651 entry_args = {
1652 'keydir': 'devkeys',
1653 'bmpblk': 'bmpblk.bin',
1654 }
Simon Glass511f6582018-10-01 12:22:30 -06001655 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001656
1657 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001658 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1659 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001660 self.assertEqual(expected, data)
1661
1662 def testGbbTooSmall(self):
1663 """Test for the Chromium OS Google Binary Block being large enough"""
1664 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001665 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001666 self.assertIn("Node '/binman/gbb': GBB is too small",
1667 str(e.exception))
1668
1669 def testGbbNoSize(self):
1670 """Test for the Chromium OS Google Binary Block having a size"""
1671 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001672 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001673 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1674 str(e.exception))
1675
Simon Glass5c350162018-07-17 13:25:47 -06001676 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001677 """Fake calls to the futility utility
1678
1679 The expected pipe is:
1680
1681 [('futility', 'vbutil_firmware', '--vblock',
1682 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1683 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1684 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1685 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1686
1687 This writes to the output file (here, 'vblock.vblock'). If
1688 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1689 of the input data (here, 'input.vblock').
1690 """
Simon Glass5c350162018-07-17 13:25:47 -06001691 if pipe_list[0][0] == 'futility':
1692 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001693 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001694 if self._hash_data:
1695 infile = pipe_list[0][11]
1696 m = hashlib.sha256()
1697 data = tools.ReadFile(infile)
1698 m.update(data)
1699 fd.write(m.digest())
1700 else:
1701 fd.write(VBLOCK_DATA)
1702
Simon Glass5c350162018-07-17 13:25:47 -06001703 return command.CommandResult()
1704
1705 def testVblock(self):
1706 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001707 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001708 command.test_result = self._HandleVblockCommand
1709 entry_args = {
1710 'keydir': 'devkeys',
1711 }
Simon Glass511f6582018-10-01 12:22:30 -06001712 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001713 entry_args=entry_args)
1714 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1715 self.assertEqual(expected, data)
1716
1717 def testVblockNoContent(self):
1718 """Test we detect a vblock which has no content to sign"""
1719 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001720 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001721 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001722 'property', str(e.exception))
1723
1724 def testVblockBadPhandle(self):
1725 """Test that we detect a vblock with an invalid phandle in contents"""
1726 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001727 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001728 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1729 '1000', str(e.exception))
1730
1731 def testVblockBadEntry(self):
1732 """Test that we detect an entry that points to a non-entry"""
1733 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001734 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001735 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1736 "'other'", str(e.exception))
1737
Simon Glass220c6222021-01-06 21:35:17 -07001738 def testVblockContent(self):
1739 """Test that the vblock signs the right data"""
1740 self._hash_data = True
1741 command.test_result = self._HandleVblockCommand
1742 entry_args = {
1743 'keydir': 'devkeys',
1744 }
1745 data = self._DoReadFileDtb(
1746 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1747 entry_args=entry_args)[0]
1748 hashlen = 32 # SHA256 hash is 32 bytes
1749 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1750 hashval = data[-hashlen:]
1751 dtb = data[len(U_BOOT_DATA):-hashlen]
1752
1753 expected_data = U_BOOT_DATA + dtb
1754
1755 # The hashval should be a hash of the dtb
1756 m = hashlib.sha256()
1757 m.update(expected_data)
1758 expected_hashval = m.digest()
1759 self.assertEqual(expected_hashval, hashval)
1760
Simon Glass8425a1f2018-07-17 13:25:48 -06001761 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001762 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001763 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001764 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001765 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001766 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1767
Simon Glass24b97442018-07-17 13:25:51 -06001768 def testUsesPos(self):
1769 """Test that the 'pos' property cannot be used anymore"""
1770 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001771 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001772 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1773 "'pos'", str(e.exception))
1774
Simon Glass274bf092018-09-14 04:57:08 -06001775 def testFillZero(self):
1776 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001777 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001778 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001779
Simon Glass267de432018-09-14 04:57:09 -06001780 def testTextMissing(self):
1781 """Test for a text entry type where there is no text"""
1782 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001783 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001784 self.assertIn("Node '/binman/text': No value provided for text label "
1785 "'test-id'", str(e.exception))
1786
Simon Glassed40e962018-09-14 04:57:10 -06001787 def testPackStart16Tpl(self):
1788 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001789 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001790 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1791
Simon Glass3b376c32018-09-14 04:57:12 -06001792 def testSelectImage(self):
1793 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001794 expected = 'Skipping images: image1'
1795
1796 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001797 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001798 with test_util.capture_sys_output() as (stdout, stderr):
1799 retcode = self._DoTestFile('006_dual_image.dts',
1800 verbosity=verbosity,
1801 images=['image2'])
1802 self.assertEqual(0, retcode)
1803 if verbosity:
1804 self.assertIn(expected, stdout.getvalue())
1805 else:
1806 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001807
Simon Glassb4595d82019-04-25 21:58:34 -06001808 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1809 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001810 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001811
Simon Glasse219aa42018-09-14 04:57:24 -06001812 def testUpdateFdtAll(self):
1813 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001814 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001815
1816 base_expected = {
1817 'section:image-pos': 0,
1818 'u-boot-tpl-dtb:size': 513,
1819 'u-boot-spl-dtb:size': 513,
1820 'u-boot-spl-dtb:offset': 493,
1821 'image-pos': 0,
1822 'section/u-boot-dtb:image-pos': 0,
1823 'u-boot-spl-dtb:image-pos': 493,
1824 'section/u-boot-dtb:size': 493,
1825 'u-boot-tpl-dtb:image-pos': 1006,
1826 'section/u-boot-dtb:offset': 0,
1827 'section:size': 493,
1828 'offset': 0,
1829 'section:offset': 0,
1830 'u-boot-tpl-dtb:offset': 1006,
1831 'size': 1519
1832 }
1833
1834 # We expect three device-tree files in the output, one after the other.
1835 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1836 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1837 # main U-Boot tree. All three should have the same postions and offset.
1838 start = 0
1839 for item in ['', 'spl', 'tpl']:
1840 dtb = fdt.Fdt.FromData(data[start:])
1841 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001842 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1843 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001844 expected = dict(base_expected)
1845 if item:
1846 expected[item] = 0
1847 self.assertEqual(expected, props)
1848 start += dtb._fdt_obj.totalsize()
1849
1850 def testUpdateFdtOutput(self):
1851 """Test that output DTB files are updated"""
1852 try:
Simon Glass511f6582018-10-01 12:22:30 -06001853 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001854 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1855
1856 # Unfortunately, compiling a source file always results in a file
1857 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001858 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001859 # binman as a file called u-boot.dtb. To fix this, copy the file
1860 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001861 start = 0
1862 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1863 'tpl/u-boot-tpl.dtb.out']:
1864 dtb = fdt.Fdt.FromData(data[start:])
1865 size = dtb._fdt_obj.totalsize()
1866 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1867 outdata = tools.ReadFile(pathname)
1868 name = os.path.split(fname)[0]
1869
1870 if name:
1871 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1872 else:
1873 orig_indata = dtb_data
1874 self.assertNotEqual(outdata, orig_indata,
1875 "Expected output file '%s' be updated" % pathname)
1876 self.assertEqual(outdata, data[start:start + size],
1877 "Expected output file '%s' to match output image" %
1878 pathname)
1879 start += size
1880 finally:
1881 self._ResetDtbs()
1882
Simon Glass7ba33592018-09-14 04:57:26 -06001883 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001884 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001885
1886 def testCompress(self):
1887 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001888 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001889 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001890 use_real_dtb=True, update_dtb=True)
1891 dtb = fdt.Fdt(out_dtb_fname)
1892 dtb.Scan()
1893 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1894 orig = self._decompress(data)
1895 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001896
1897 # Do a sanity check on various fields
1898 image = control.images['image']
1899 entries = image.GetEntries()
1900 self.assertEqual(1, len(entries))
1901
1902 entry = entries['blob']
1903 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1904 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1905 orig = self._decompress(entry.data)
1906 self.assertEqual(orig, entry.uncomp_data)
1907
Simon Glass72eeff12020-10-26 17:40:16 -06001908 self.assertEqual(image.data, entry.data)
1909
Simon Glass7ba33592018-09-14 04:57:26 -06001910 expected = {
1911 'blob:uncomp-size': len(COMPRESS_DATA),
1912 'blob:size': len(data),
1913 'size': len(data),
1914 }
1915 self.assertEqual(expected, props)
1916
Simon Glassac6328c2018-09-14 04:57:28 -06001917 def testFiles(self):
1918 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001919 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001920 self.assertEqual(FILES_DATA, data)
1921
1922 def testFilesCompress(self):
1923 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001924 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001925 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001926
1927 image = control.images['image']
1928 entries = image.GetEntries()
1929 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001930 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001931
Simon Glass303f62f2019-05-17 22:00:46 -06001932 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001933 for i in range(1, 3):
1934 key = '%d.dat' % i
1935 start = entries[key].image_pos
1936 len = entries[key].size
1937 chunk = data[start:start + len]
1938 orig += self._decompress(chunk)
1939
1940 self.assertEqual(FILES_DATA, orig)
1941
1942 def testFilesMissing(self):
1943 """Test missing files"""
1944 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001945 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001946 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1947 'no files', str(e.exception))
1948
1949 def testFilesNoPattern(self):
1950 """Test missing files"""
1951 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001952 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001953 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1954 str(e.exception))
1955
Simon Glassfa79a812018-09-14 04:57:29 -06001956 def testExpandSize(self):
1957 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001958 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001959 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001960 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1961 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1962 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1963 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001964 self.assertEqual(expect, data)
1965 self.assertEqual('''ImagePos Offset Size Name
196600000000 00000000 00000028 main-section
196700000000 00000000 00000008 fill
196800000008 00000008 00000004 u-boot
19690000000c 0000000c 00000004 section
19700000000c 00000000 00000003 intel-mrc
197100000010 00000010 00000004 u-boot2
197200000014 00000014 0000000c section2
197300000014 00000000 00000008 fill
19740000001c 00000008 00000004 u-boot
197500000020 00000020 00000008 fill2
1976''', map_data)
1977
1978 def testExpandSizeBad(self):
1979 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001980 with test_util.capture_sys_output() as (stdout, stderr):
1981 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001982 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001983 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1984 'expanding entry', str(e.exception))
1985
Simon Glassae7cf032018-09-14 04:57:31 -06001986 def testHash(self):
1987 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001988 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001989 use_real_dtb=True, update_dtb=True)
1990 dtb = fdt.Fdt(out_dtb_fname)
1991 dtb.Scan()
1992 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1993 m = hashlib.sha256()
1994 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001995 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06001996
1997 def testHashNoAlgo(self):
1998 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001999 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002000 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2001 'hash node', str(e.exception))
2002
2003 def testHashBadAlgo(self):
2004 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002005 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002006 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2007 str(e.exception))
2008
2009 def testHashSection(self):
2010 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002011 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002012 use_real_dtb=True, update_dtb=True)
2013 dtb = fdt.Fdt(out_dtb_fname)
2014 dtb.Scan()
2015 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2016 m = hashlib.sha256()
2017 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002018 m.update(tools.GetBytes(ord('a'), 16))
2019 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002020
Simon Glass3fb4f422018-09-14 04:57:32 -06002021 def testPackUBootTplMicrocode(self):
2022 """Test that x86 microcode can be handled correctly in TPL
2023
2024 We expect to see the following in the image, in order:
2025 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2026 place
2027 u-boot-tpl.dtb with the microcode removed
2028 the microcode
2029 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002030 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002031 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002032 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002033 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2034 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002035
Simon Glassc64aea52018-09-14 04:57:34 -06002036 def testFmapX86(self):
2037 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002038 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002039 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06002040 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002041 self.assertEqual(expected, data[:32])
2042 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2043
2044 self.assertEqual(0x100, fhdr.image_size)
2045
2046 self.assertEqual(0, fentries[0].offset)
2047 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002048 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002049
2050 self.assertEqual(4, fentries[1].offset)
2051 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002052 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002053
2054 self.assertEqual(32, fentries[2].offset)
2055 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2056 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002057 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002058
2059 def testFmapX86Section(self):
2060 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002061 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06002062 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002063 self.assertEqual(expected, data[:32])
2064 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2065
2066 self.assertEqual(0x100, fhdr.image_size)
2067
2068 self.assertEqual(0, fentries[0].offset)
2069 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002070 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002071
2072 self.assertEqual(4, fentries[1].offset)
2073 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002074 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002075
2076 self.assertEqual(36, fentries[2].offset)
2077 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2078 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002079 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002080
Simon Glassb1714232018-09-14 04:57:35 -06002081 def testElf(self):
2082 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002083 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002084 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002085 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002086 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002087 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002088
Simon Glass0d673792019-07-08 13:18:25 -06002089 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002090 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002091 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002092 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002093 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002094 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002095
Simon Glasscd817d52018-09-14 04:57:36 -06002096 def testPackOverlapMap(self):
2097 """Test that overlapping regions are detected"""
2098 with test_util.capture_sys_output() as (stdout, stderr):
2099 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002100 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06002101 map_fname = tools.GetOutputFilename('image.map')
2102 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2103 stdout.getvalue())
2104
2105 # We should not get an inmage, but there should be a map file
2106 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2107 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06002108 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002109 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002110<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002111<none> 00000000 00000004 u-boot
2112<none> 00000003 00000004 u-boot-align
2113''', map_data)
2114
Simon Glass0d673792019-07-08 13:18:25 -06002115 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002116 """Test that an image with an Intel Reference code binary works"""
2117 data = self._DoReadFile('100_intel_refcode.dts')
2118 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2119
Simon Glasseb023b32019-04-25 21:58:39 -06002120 def testSectionOffset(self):
2121 """Tests use of a section with an offset"""
2122 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2123 map=True)
2124 self.assertEqual('''ImagePos Offset Size Name
212500000000 00000000 00000038 main-section
212600000004 00000004 00000010 section@0
212700000004 00000000 00000004 u-boot
212800000018 00000018 00000010 section@1
212900000018 00000000 00000004 u-boot
21300000002c 0000002c 00000004 section@2
21310000002c 00000000 00000004 u-boot
2132''', map_data)
2133 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06002134 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2135 tools.GetBytes(0x21, 12) +
2136 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2137 tools.GetBytes(0x61, 12) +
2138 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2139 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002140
Simon Glass1de34482019-07-08 13:18:53 -06002141 def testCbfsRaw(self):
2142 """Test base handling of a Coreboot Filesystem (CBFS)
2143
2144 The exact contents of the CBFS is verified by similar tests in
2145 cbfs_util_test.py. The tests here merely check that the files added to
2146 the CBFS can be found in the final image.
2147 """
2148 data = self._DoReadFile('102_cbfs_raw.dts')
2149 size = 0xb0
2150
2151 cbfs = cbfs_util.CbfsReader(data)
2152 self.assertEqual(size, cbfs.rom_size)
2153
2154 self.assertIn('u-boot-dtb', cbfs.files)
2155 cfile = cbfs.files['u-boot-dtb']
2156 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2157
2158 def testCbfsArch(self):
2159 """Test on non-x86 architecture"""
2160 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2161 size = 0x100
2162
2163 cbfs = cbfs_util.CbfsReader(data)
2164 self.assertEqual(size, cbfs.rom_size)
2165
2166 self.assertIn('u-boot-dtb', cbfs.files)
2167 cfile = cbfs.files['u-boot-dtb']
2168 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2169
2170 def testCbfsStage(self):
2171 """Tests handling of a Coreboot Filesystem (CBFS)"""
2172 if not elf.ELF_TOOLS:
2173 self.skipTest('Python elftools not available')
2174 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2175 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2176 size = 0xb0
2177
2178 data = self._DoReadFile('104_cbfs_stage.dts')
2179 cbfs = cbfs_util.CbfsReader(data)
2180 self.assertEqual(size, cbfs.rom_size)
2181
2182 self.assertIn('u-boot', cbfs.files)
2183 cfile = cbfs.files['u-boot']
2184 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2185
2186 def testCbfsRawCompress(self):
2187 """Test handling of compressing raw files"""
2188 self._CheckLz4()
2189 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2190 size = 0x140
2191
2192 cbfs = cbfs_util.CbfsReader(data)
2193 self.assertIn('u-boot', cbfs.files)
2194 cfile = cbfs.files['u-boot']
2195 self.assertEqual(COMPRESS_DATA, cfile.data)
2196
2197 def testCbfsBadArch(self):
2198 """Test handling of a bad architecture"""
2199 with self.assertRaises(ValueError) as e:
2200 self._DoReadFile('106_cbfs_bad_arch.dts')
2201 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2202
2203 def testCbfsNoSize(self):
2204 """Test handling of a missing size property"""
2205 with self.assertRaises(ValueError) as e:
2206 self._DoReadFile('107_cbfs_no_size.dts')
2207 self.assertIn('entry must have a size property', str(e.exception))
2208
2209 def testCbfsNoCOntents(self):
2210 """Test handling of a CBFS entry which does not provide contentsy"""
2211 with self.assertRaises(ValueError) as e:
2212 self._DoReadFile('108_cbfs_no_contents.dts')
2213 self.assertIn('Could not complete processing of contents',
2214 str(e.exception))
2215
2216 def testCbfsBadCompress(self):
2217 """Test handling of a bad architecture"""
2218 with self.assertRaises(ValueError) as e:
2219 self._DoReadFile('109_cbfs_bad_compress.dts')
2220 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2221 str(e.exception))
2222
2223 def testCbfsNamedEntries(self):
2224 """Test handling of named entries"""
2225 data = self._DoReadFile('110_cbfs_name.dts')
2226
2227 cbfs = cbfs_util.CbfsReader(data)
2228 self.assertIn('FRED', cbfs.files)
2229 cfile1 = cbfs.files['FRED']
2230 self.assertEqual(U_BOOT_DATA, cfile1.data)
2231
2232 self.assertIn('hello', cbfs.files)
2233 cfile2 = cbfs.files['hello']
2234 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2235
Simon Glass759af872019-07-08 13:18:54 -06002236 def _SetupIfwi(self, fname):
2237 """Set up to run an IFWI test
2238
2239 Args:
2240 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2241 """
2242 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002243 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002244
2245 # Intel Integrated Firmware Image (IFWI) file
2246 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2247 data = fd.read()
2248 TestFunctional._MakeInputFile(fname,data)
2249
2250 def _CheckIfwi(self, data):
2251 """Check that an image with an IFWI contains the correct output
2252
2253 Args:
2254 data: Conents of output file
2255 """
2256 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2257 if data[:0x1000] != expected_desc:
2258 self.fail('Expected descriptor binary at start of image')
2259
2260 # We expect to find the TPL wil in subpart IBBP entry IBBL
2261 image_fname = tools.GetOutputFilename('image.bin')
2262 tpl_fname = tools.GetOutputFilename('tpl.out')
2263 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2264 subpart='IBBP', entry_name='IBBL')
2265
2266 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002267 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002268
2269 def testPackX86RomIfwi(self):
2270 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2271 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002272 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002273 self._CheckIfwi(data)
2274
2275 def testPackX86RomIfwiNoDesc(self):
2276 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2277 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002278 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002279 self._CheckIfwi(data)
2280
2281 def testPackX86RomIfwiNoData(self):
2282 """Test that an x86 ROM with IFWI handles missing data"""
2283 self._SetupIfwi('ifwi.bin')
2284 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002285 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002286 self.assertIn('Could not complete processing of contents',
2287 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002288
Simon Glassc2f1aed2019-07-08 13:18:56 -06002289 def testCbfsOffset(self):
2290 """Test a CBFS with files at particular offsets
2291
2292 Like all CFBS tests, this is just checking the logic that calls
2293 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2294 """
2295 data = self._DoReadFile('114_cbfs_offset.dts')
2296 size = 0x200
2297
2298 cbfs = cbfs_util.CbfsReader(data)
2299 self.assertEqual(size, cbfs.rom_size)
2300
2301 self.assertIn('u-boot', cbfs.files)
2302 cfile = cbfs.files['u-boot']
2303 self.assertEqual(U_BOOT_DATA, cfile.data)
2304 self.assertEqual(0x40, cfile.cbfs_offset)
2305
2306 self.assertIn('u-boot-dtb', cbfs.files)
2307 cfile2 = cbfs.files['u-boot-dtb']
2308 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2309 self.assertEqual(0x140, cfile2.cbfs_offset)
2310
Simon Glass0f621332019-07-08 14:25:27 -06002311 def testFdtmap(self):
2312 """Test an FDT map can be inserted in the image"""
2313 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2314 fdtmap_data = data[len(U_BOOT_DATA):]
2315 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002316 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002317 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2318
2319 fdt_data = fdtmap_data[16:]
2320 dtb = fdt.Fdt.FromData(fdt_data)
2321 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002322 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002323 self.assertEqual({
2324 'image-pos': 0,
2325 'offset': 0,
2326 'u-boot:offset': 0,
2327 'u-boot:size': len(U_BOOT_DATA),
2328 'u-boot:image-pos': 0,
2329 'fdtmap:image-pos': 4,
2330 'fdtmap:offset': 4,
2331 'fdtmap:size': len(fdtmap_data),
2332 'size': len(data),
2333 }, props)
2334
2335 def testFdtmapNoMatch(self):
2336 """Check handling of an FDT map when the section cannot be found"""
2337 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2338
2339 # Mangle the section name, which should cause a mismatch between the
2340 # correct FDT path and the one expected by the section
2341 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002342 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002343 entries = image.GetEntries()
2344 fdtmap = entries['fdtmap']
2345 with self.assertRaises(ValueError) as e:
2346 fdtmap._GetFdtmap()
2347 self.assertIn("Cannot locate node for path '/binman-suffix'",
2348 str(e.exception))
2349
Simon Glasscec34ba2019-07-08 14:25:28 -06002350 def testFdtmapHeader(self):
2351 """Test an FDT map and image header can be inserted in the image"""
2352 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2353 fdtmap_pos = len(U_BOOT_DATA)
2354 fdtmap_data = data[fdtmap_pos:]
2355 fdt_data = fdtmap_data[16:]
2356 dtb = fdt.Fdt.FromData(fdt_data)
2357 fdt_size = dtb.GetFdtObj().totalsize()
2358 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002359 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002360 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2361 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2362
2363 def testFdtmapHeaderStart(self):
2364 """Test an image header can be inserted at the image start"""
2365 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2366 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2367 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002368 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002369 offset = struct.unpack('<I', hdr_data[4:])[0]
2370 self.assertEqual(fdtmap_pos, offset)
2371
2372 def testFdtmapHeaderPos(self):
2373 """Test an image header can be inserted at a chosen position"""
2374 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2375 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2376 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002377 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002378 offset = struct.unpack('<I', hdr_data[4:])[0]
2379 self.assertEqual(fdtmap_pos, offset)
2380
2381 def testHeaderMissingFdtmap(self):
2382 """Test an image header requires an fdtmap"""
2383 with self.assertRaises(ValueError) as e:
2384 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2385 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2386 str(e.exception))
2387
2388 def testHeaderNoLocation(self):
2389 """Test an image header with a no specified location is detected"""
2390 with self.assertRaises(ValueError) as e:
2391 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2392 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2393 str(e.exception))
2394
Simon Glasse61b6f62019-07-08 14:25:37 -06002395 def testEntryExpand(self):
2396 """Test expanding an entry after it is packed"""
2397 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002398 self.assertEqual(b'aaa', data[:3])
2399 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2400 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002401
2402 def testEntryExpandBad(self):
2403 """Test expanding an entry after it is packed, twice"""
2404 with self.assertRaises(ValueError) as e:
2405 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002406 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002407 str(e.exception))
2408
2409 def testEntryExpandSection(self):
2410 """Test expanding an entry within a section after it is packed"""
2411 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002412 self.assertEqual(b'aaa', data[:3])
2413 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2414 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002415
Simon Glass90d29682019-07-08 14:25:38 -06002416 def testCompressDtb(self):
2417 """Test that compress of device-tree files is supported"""
2418 self._CheckLz4()
2419 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2420 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2421 comp_data = data[len(U_BOOT_DATA):]
2422 orig = self._decompress(comp_data)
2423 dtb = fdt.Fdt.FromData(orig)
2424 dtb.Scan()
2425 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2426 expected = {
2427 'u-boot:size': len(U_BOOT_DATA),
2428 'u-boot-dtb:uncomp-size': len(orig),
2429 'u-boot-dtb:size': len(comp_data),
2430 'size': len(data),
2431 }
2432 self.assertEqual(expected, props)
2433
Simon Glass151bbbf2019-07-08 14:25:41 -06002434 def testCbfsUpdateFdt(self):
2435 """Test that we can update the device tree with CBFS offset/size info"""
2436 self._CheckLz4()
2437 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2438 update_dtb=True)
2439 dtb = fdt.Fdt(out_dtb_fname)
2440 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002441 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002442 del props['cbfs/u-boot:size']
2443 self.assertEqual({
2444 'offset': 0,
2445 'size': len(data),
2446 'image-pos': 0,
2447 'cbfs:offset': 0,
2448 'cbfs:size': len(data),
2449 'cbfs:image-pos': 0,
2450 'cbfs/u-boot:offset': 0x38,
2451 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2452 'cbfs/u-boot:image-pos': 0x38,
2453 'cbfs/u-boot-dtb:offset': 0xb8,
2454 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2455 'cbfs/u-boot-dtb:image-pos': 0xb8,
2456 }, props)
2457
Simon Glass3c9b4f22019-07-08 14:25:42 -06002458 def testCbfsBadType(self):
2459 """Test an image header with a no specified location is detected"""
2460 with self.assertRaises(ValueError) as e:
2461 self._DoReadFile('126_cbfs_bad_type.dts')
2462 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2463
Simon Glass6b156f82019-07-08 14:25:43 -06002464 def testList(self):
2465 """Test listing the files in an image"""
2466 self._CheckLz4()
2467 data = self._DoReadFile('127_list.dts')
2468 image = control.images['image']
2469 entries = image.BuildEntryList()
2470 self.assertEqual(7, len(entries))
2471
2472 ent = entries[0]
2473 self.assertEqual(0, ent.indent)
2474 self.assertEqual('main-section', ent.name)
2475 self.assertEqual('section', ent.etype)
2476 self.assertEqual(len(data), ent.size)
2477 self.assertEqual(0, ent.image_pos)
2478 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002479 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002480
2481 ent = entries[1]
2482 self.assertEqual(1, ent.indent)
2483 self.assertEqual('u-boot', ent.name)
2484 self.assertEqual('u-boot', ent.etype)
2485 self.assertEqual(len(U_BOOT_DATA), ent.size)
2486 self.assertEqual(0, ent.image_pos)
2487 self.assertEqual(None, ent.uncomp_size)
2488 self.assertEqual(0, ent.offset)
2489
2490 ent = entries[2]
2491 self.assertEqual(1, ent.indent)
2492 self.assertEqual('section', ent.name)
2493 self.assertEqual('section', ent.etype)
2494 section_size = ent.size
2495 self.assertEqual(0x100, ent.image_pos)
2496 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002497 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002498
2499 ent = entries[3]
2500 self.assertEqual(2, ent.indent)
2501 self.assertEqual('cbfs', ent.name)
2502 self.assertEqual('cbfs', ent.etype)
2503 self.assertEqual(0x400, ent.size)
2504 self.assertEqual(0x100, ent.image_pos)
2505 self.assertEqual(None, ent.uncomp_size)
2506 self.assertEqual(0, ent.offset)
2507
2508 ent = entries[4]
2509 self.assertEqual(3, ent.indent)
2510 self.assertEqual('u-boot', ent.name)
2511 self.assertEqual('u-boot', ent.etype)
2512 self.assertEqual(len(U_BOOT_DATA), ent.size)
2513 self.assertEqual(0x138, ent.image_pos)
2514 self.assertEqual(None, ent.uncomp_size)
2515 self.assertEqual(0x38, ent.offset)
2516
2517 ent = entries[5]
2518 self.assertEqual(3, ent.indent)
2519 self.assertEqual('u-boot-dtb', ent.name)
2520 self.assertEqual('text', ent.etype)
2521 self.assertGreater(len(COMPRESS_DATA), ent.size)
2522 self.assertEqual(0x178, ent.image_pos)
2523 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2524 self.assertEqual(0x78, ent.offset)
2525
2526 ent = entries[6]
2527 self.assertEqual(2, ent.indent)
2528 self.assertEqual('u-boot-dtb', ent.name)
2529 self.assertEqual('u-boot-dtb', ent.etype)
2530 self.assertEqual(0x500, ent.image_pos)
2531 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2532 dtb_size = ent.size
2533 # Compressing this data expands it since headers are added
2534 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2535 self.assertEqual(0x400, ent.offset)
2536
2537 self.assertEqual(len(data), 0x100 + section_size)
2538 self.assertEqual(section_size, 0x400 + dtb_size)
2539
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002540 def testFindFdtmap(self):
2541 """Test locating an FDT map in an image"""
2542 self._CheckLz4()
2543 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2544 image = control.images['image']
2545 entries = image.GetEntries()
2546 entry = entries['fdtmap']
2547 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2548
2549 def testFindFdtmapMissing(self):
2550 """Test failing to locate an FDP map"""
2551 data = self._DoReadFile('005_simple.dts')
2552 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2553
Simon Glassed39a3c2019-07-08 14:25:45 -06002554 def testFindImageHeader(self):
2555 """Test locating a image header"""
2556 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002557 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002558 image = control.images['image']
2559 entries = image.GetEntries()
2560 entry = entries['fdtmap']
2561 # The header should point to the FDT map
2562 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2563
2564 def testFindImageHeaderStart(self):
2565 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002566 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002567 image = control.images['image']
2568 entries = image.GetEntries()
2569 entry = entries['fdtmap']
2570 # The header should point to the FDT map
2571 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2572
2573 def testFindImageHeaderMissing(self):
2574 """Test failing to locate an image header"""
2575 data = self._DoReadFile('005_simple.dts')
2576 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2577
Simon Glassb8424fa2019-07-08 14:25:46 -06002578 def testReadImage(self):
2579 """Test reading an image and accessing its FDT map"""
2580 self._CheckLz4()
2581 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2582 image_fname = tools.GetOutputFilename('image.bin')
2583 orig_image = control.images['image']
2584 image = Image.FromFile(image_fname)
2585 self.assertEqual(orig_image.GetEntries().keys(),
2586 image.GetEntries().keys())
2587
2588 orig_entry = orig_image.GetEntries()['fdtmap']
2589 entry = image.GetEntries()['fdtmap']
2590 self.assertEquals(orig_entry.offset, entry.offset)
2591 self.assertEquals(orig_entry.size, entry.size)
2592 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2593
2594 def testReadImageNoHeader(self):
2595 """Test accessing an image's FDT map without an image header"""
2596 self._CheckLz4()
2597 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2598 image_fname = tools.GetOutputFilename('image.bin')
2599 image = Image.FromFile(image_fname)
2600 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002601 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002602
2603 def testReadImageFail(self):
2604 """Test failing to read an image image's FDT map"""
2605 self._DoReadFile('005_simple.dts')
2606 image_fname = tools.GetOutputFilename('image.bin')
2607 with self.assertRaises(ValueError) as e:
2608 image = Image.FromFile(image_fname)
2609 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002610
Simon Glassb2fd11d2019-07-08 14:25:48 -06002611 def testListCmd(self):
2612 """Test listing the files in an image using an Fdtmap"""
2613 self._CheckLz4()
2614 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2615
2616 # lz4 compression size differs depending on the version
2617 image = control.images['image']
2618 entries = image.GetEntries()
2619 section_size = entries['section'].size
2620 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2621 fdtmap_offset = entries['fdtmap'].offset
2622
Simon Glassb3d6fc72019-07-20 12:24:10 -06002623 try:
2624 tmpdir, updated_fname = self._SetupImageInTmpdir()
2625 with test_util.capture_sys_output() as (stdout, stderr):
2626 self._DoBinman('ls', '-i', updated_fname)
2627 finally:
2628 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002629 lines = stdout.getvalue().splitlines()
2630 expected = [
2631'Name Image-pos Size Entry-type Offset Uncomp-size',
2632'----------------------------------------------------------------------',
2633'main-section 0 c00 section 0',
2634' u-boot 0 4 u-boot 0',
2635' section 100 %x section 100' % section_size,
2636' cbfs 100 400 cbfs 0',
2637' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002638' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002639' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002640' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002641 (fdtmap_offset, fdtmap_offset),
2642' image-header bf8 8 image-header bf8',
2643 ]
2644 self.assertEqual(expected, lines)
2645
2646 def testListCmdFail(self):
2647 """Test failing to list an image"""
2648 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002649 try:
2650 tmpdir, updated_fname = self._SetupImageInTmpdir()
2651 with self.assertRaises(ValueError) as e:
2652 self._DoBinman('ls', '-i', updated_fname)
2653 finally:
2654 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002655 self.assertIn("Cannot find FDT map in image", str(e.exception))
2656
2657 def _RunListCmd(self, paths, expected):
2658 """List out entries and check the result
2659
2660 Args:
2661 paths: List of paths to pass to the list command
2662 expected: Expected list of filenames to be returned, in order
2663 """
2664 self._CheckLz4()
2665 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2666 image_fname = tools.GetOutputFilename('image.bin')
2667 image = Image.FromFile(image_fname)
2668 lines = image.GetListEntries(paths)[1]
2669 files = [line[0].strip() for line in lines[1:]]
2670 self.assertEqual(expected, files)
2671
2672 def testListCmdSection(self):
2673 """Test listing the files in a section"""
2674 self._RunListCmd(['section'],
2675 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2676
2677 def testListCmdFile(self):
2678 """Test listing a particular file"""
2679 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2680
2681 def testListCmdWildcard(self):
2682 """Test listing a wildcarded file"""
2683 self._RunListCmd(['*boot*'],
2684 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2685
2686 def testListCmdWildcardMulti(self):
2687 """Test listing a wildcarded file"""
2688 self._RunListCmd(['*cb*', '*head*'],
2689 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2690
2691 def testListCmdEmpty(self):
2692 """Test listing a wildcarded file"""
2693 self._RunListCmd(['nothing'], [])
2694
2695 def testListCmdPath(self):
2696 """Test listing the files in a sub-entry of a section"""
2697 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2698
Simon Glass4c613bf2019-07-08 14:25:50 -06002699 def _RunExtractCmd(self, entry_name, decomp=True):
2700 """Extract an entry from an image
2701
2702 Args:
2703 entry_name: Entry name to extract
2704 decomp: True to decompress the data if compressed, False to leave
2705 it in its raw uncompressed format
2706
2707 Returns:
2708 data from entry
2709 """
2710 self._CheckLz4()
2711 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2712 image_fname = tools.GetOutputFilename('image.bin')
2713 return control.ReadEntry(image_fname, entry_name, decomp)
2714
2715 def testExtractSimple(self):
2716 """Test extracting a single file"""
2717 data = self._RunExtractCmd('u-boot')
2718 self.assertEqual(U_BOOT_DATA, data)
2719
Simon Glass980a2842019-07-08 14:25:52 -06002720 def testExtractSection(self):
2721 """Test extracting the files in a section"""
2722 data = self._RunExtractCmd('section')
2723 cbfs_data = data[:0x400]
2724 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002725 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002726 dtb_data = data[0x400:]
2727 dtb = self._decompress(dtb_data)
2728 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2729
2730 def testExtractCompressed(self):
2731 """Test extracting compressed data"""
2732 data = self._RunExtractCmd('section/u-boot-dtb')
2733 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2734
2735 def testExtractRaw(self):
2736 """Test extracting compressed data without decompressing it"""
2737 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2738 dtb = self._decompress(data)
2739 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2740
2741 def testExtractCbfs(self):
2742 """Test extracting CBFS data"""
2743 data = self._RunExtractCmd('section/cbfs/u-boot')
2744 self.assertEqual(U_BOOT_DATA, data)
2745
2746 def testExtractCbfsCompressed(self):
2747 """Test extracting CBFS compressed data"""
2748 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2749 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2750
2751 def testExtractCbfsRaw(self):
2752 """Test extracting CBFS compressed data without decompressing it"""
2753 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002754 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002755 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2756
Simon Glass4c613bf2019-07-08 14:25:50 -06002757 def testExtractBadEntry(self):
2758 """Test extracting a bad section path"""
2759 with self.assertRaises(ValueError) as e:
2760 self._RunExtractCmd('section/does-not-exist')
2761 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2762 str(e.exception))
2763
2764 def testExtractMissingFile(self):
2765 """Test extracting file that does not exist"""
2766 with self.assertRaises(IOError) as e:
2767 control.ReadEntry('missing-file', 'name')
2768
2769 def testExtractBadFile(self):
2770 """Test extracting an invalid file"""
2771 fname = os.path.join(self._indir, 'badfile')
2772 tools.WriteFile(fname, b'')
2773 with self.assertRaises(ValueError) as e:
2774 control.ReadEntry(fname, 'name')
2775
Simon Glass980a2842019-07-08 14:25:52 -06002776 def testExtractCmd(self):
2777 """Test extracting a file fron an image on the command line"""
2778 self._CheckLz4()
2779 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002780 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002781 try:
2782 tmpdir, updated_fname = self._SetupImageInTmpdir()
2783 with test_util.capture_sys_output() as (stdout, stderr):
2784 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2785 '-f', fname)
2786 finally:
2787 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002788 data = tools.ReadFile(fname)
2789 self.assertEqual(U_BOOT_DATA, data)
2790
2791 def testExtractOneEntry(self):
2792 """Test extracting a single entry fron an image """
2793 self._CheckLz4()
2794 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2795 image_fname = tools.GetOutputFilename('image.bin')
2796 fname = os.path.join(self._indir, 'output.extact')
2797 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2798 data = tools.ReadFile(fname)
2799 self.assertEqual(U_BOOT_DATA, data)
2800
2801 def _CheckExtractOutput(self, decomp):
2802 """Helper to test file output with and without decompression
2803
2804 Args:
2805 decomp: True to decompress entry data, False to output it raw
2806 """
2807 def _CheckPresent(entry_path, expect_data, expect_size=None):
2808 """Check and remove expected file
2809
2810 This checks the data/size of a file and removes the file both from
2811 the outfiles set and from the output directory. Once all files are
2812 processed, both the set and directory should be empty.
2813
2814 Args:
2815 entry_path: Entry path
2816 expect_data: Data to expect in file, or None to skip check
2817 expect_size: Size of data to expect in file, or None to skip
2818 """
2819 path = os.path.join(outdir, entry_path)
2820 data = tools.ReadFile(path)
2821 os.remove(path)
2822 if expect_data:
2823 self.assertEqual(expect_data, data)
2824 elif expect_size:
2825 self.assertEqual(expect_size, len(data))
2826 outfiles.remove(path)
2827
2828 def _CheckDirPresent(name):
2829 """Remove expected directory
2830
2831 This gives an error if the directory does not exist as expected
2832
2833 Args:
2834 name: Name of directory to remove
2835 """
2836 path = os.path.join(outdir, name)
2837 os.rmdir(path)
2838
2839 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2840 image_fname = tools.GetOutputFilename('image.bin')
2841 outdir = os.path.join(self._indir, 'extract')
2842 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2843
2844 # Create a set of all file that were output (should be 9)
2845 outfiles = set()
2846 for root, dirs, files in os.walk(outdir):
2847 outfiles |= set([os.path.join(root, fname) for fname in files])
2848 self.assertEqual(9, len(outfiles))
2849 self.assertEqual(9, len(einfos))
2850
2851 image = control.images['image']
2852 entries = image.GetEntries()
2853
2854 # Check the 9 files in various ways
2855 section = entries['section']
2856 section_entries = section.GetEntries()
2857 cbfs_entries = section_entries['cbfs'].GetEntries()
2858 _CheckPresent('u-boot', U_BOOT_DATA)
2859 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2860 dtb_len = EXTRACT_DTB_SIZE
2861 if not decomp:
2862 dtb_len = cbfs_entries['u-boot-dtb'].size
2863 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2864 if not decomp:
2865 dtb_len = section_entries['u-boot-dtb'].size
2866 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2867
2868 fdtmap = entries['fdtmap']
2869 _CheckPresent('fdtmap', fdtmap.data)
2870 hdr = entries['image-header']
2871 _CheckPresent('image-header', hdr.data)
2872
2873 _CheckPresent('section/root', section.data)
2874 cbfs = section_entries['cbfs']
2875 _CheckPresent('section/cbfs/root', cbfs.data)
2876 data = tools.ReadFile(image_fname)
2877 _CheckPresent('root', data)
2878
2879 # There should be no files left. Remove all the directories to check.
2880 # If there are any files/dirs remaining, one of these checks will fail.
2881 self.assertEqual(0, len(outfiles))
2882 _CheckDirPresent('section/cbfs')
2883 _CheckDirPresent('section')
2884 _CheckDirPresent('')
2885 self.assertFalse(os.path.exists(outdir))
2886
2887 def testExtractAllEntries(self):
2888 """Test extracting all entries"""
2889 self._CheckLz4()
2890 self._CheckExtractOutput(decomp=True)
2891
2892 def testExtractAllEntriesRaw(self):
2893 """Test extracting all entries without decompressing them"""
2894 self._CheckLz4()
2895 self._CheckExtractOutput(decomp=False)
2896
2897 def testExtractSelectedEntries(self):
2898 """Test extracting some entries"""
2899 self._CheckLz4()
2900 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2901 image_fname = tools.GetOutputFilename('image.bin')
2902 outdir = os.path.join(self._indir, 'extract')
2903 einfos = control.ExtractEntries(image_fname, None, outdir,
2904 ['*cb*', '*head*'])
2905
2906 # File output is tested by testExtractAllEntries(), so just check that
2907 # the expected entries are selected
2908 names = [einfo.name for einfo in einfos]
2909 self.assertEqual(names,
2910 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2911
2912 def testExtractNoEntryPaths(self):
2913 """Test extracting some entries"""
2914 self._CheckLz4()
2915 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2916 image_fname = tools.GetOutputFilename('image.bin')
2917 with self.assertRaises(ValueError) as e:
2918 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002919 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002920 str(e.exception))
2921
2922 def testExtractTooManyEntryPaths(self):
2923 """Test extracting some entries"""
2924 self._CheckLz4()
2925 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2926 image_fname = tools.GetOutputFilename('image.bin')
2927 with self.assertRaises(ValueError) as e:
2928 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002929 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002930 str(e.exception))
2931
Simon Glass52d06212019-07-08 14:25:53 -06002932 def testPackAlignSection(self):
2933 """Test that sections can have alignment"""
2934 self._DoReadFile('131_pack_align_section.dts')
2935
2936 self.assertIn('image', control.images)
2937 image = control.images['image']
2938 entries = image.GetEntries()
2939 self.assertEqual(3, len(entries))
2940
2941 # First u-boot
2942 self.assertIn('u-boot', entries)
2943 entry = entries['u-boot']
2944 self.assertEqual(0, entry.offset)
2945 self.assertEqual(0, entry.image_pos)
2946 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2947 self.assertEqual(len(U_BOOT_DATA), entry.size)
2948
2949 # Section0
2950 self.assertIn('section0', entries)
2951 section0 = entries['section0']
2952 self.assertEqual(0x10, section0.offset)
2953 self.assertEqual(0x10, section0.image_pos)
2954 self.assertEqual(len(U_BOOT_DATA), section0.size)
2955
2956 # Second u-boot
2957 section_entries = section0.GetEntries()
2958 self.assertIn('u-boot', section_entries)
2959 entry = section_entries['u-boot']
2960 self.assertEqual(0, entry.offset)
2961 self.assertEqual(0x10, entry.image_pos)
2962 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2963 self.assertEqual(len(U_BOOT_DATA), entry.size)
2964
2965 # Section1
2966 self.assertIn('section1', entries)
2967 section1 = entries['section1']
2968 self.assertEqual(0x14, section1.offset)
2969 self.assertEqual(0x14, section1.image_pos)
2970 self.assertEqual(0x20, section1.size)
2971
2972 # Second u-boot
2973 section_entries = section1.GetEntries()
2974 self.assertIn('u-boot', section_entries)
2975 entry = section_entries['u-boot']
2976 self.assertEqual(0, entry.offset)
2977 self.assertEqual(0x14, entry.image_pos)
2978 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2979 self.assertEqual(len(U_BOOT_DATA), entry.size)
2980
2981 # Section2
2982 self.assertIn('section2', section_entries)
2983 section2 = section_entries['section2']
2984 self.assertEqual(0x4, section2.offset)
2985 self.assertEqual(0x18, section2.image_pos)
2986 self.assertEqual(4, section2.size)
2987
2988 # Third u-boot
2989 section_entries = section2.GetEntries()
2990 self.assertIn('u-boot', section_entries)
2991 entry = section_entries['u-boot']
2992 self.assertEqual(0, entry.offset)
2993 self.assertEqual(0x18, entry.image_pos)
2994 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2995 self.assertEqual(len(U_BOOT_DATA), entry.size)
2996
Simon Glassf8a54bc2019-07-20 12:23:56 -06002997 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
2998 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06002999 """Replace an entry in an image
3000
3001 This writes the entry data to update it, then opens the updated file and
3002 returns the value that it now finds there.
3003
3004 Args:
3005 entry_name: Entry name to replace
3006 data: Data to replace it with
3007 decomp: True to compress the data if needed, False if data is
3008 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003009 allow_resize: True to allow entries to change size, False to raise
3010 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003011
3012 Returns:
3013 Tuple:
3014 data from entry
3015 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003016 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003017 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003018 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003019 update_dtb=True)[1]
3020
3021 self.assertIn('image', control.images)
3022 image = control.images['image']
3023 entries = image.GetEntries()
3024 orig_dtb_data = entries['u-boot-dtb'].data
3025 orig_fdtmap_data = entries['fdtmap'].data
3026
3027 image_fname = tools.GetOutputFilename('image.bin')
3028 updated_fname = tools.GetOutputFilename('image-updated.bin')
3029 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003030 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3031 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003032 data = control.ReadEntry(updated_fname, entry_name, decomp)
3033
Simon Glassf8a54bc2019-07-20 12:23:56 -06003034 # The DT data should not change unless resized:
3035 if not allow_resize:
3036 new_dtb_data = entries['u-boot-dtb'].data
3037 self.assertEqual(new_dtb_data, orig_dtb_data)
3038 new_fdtmap_data = entries['fdtmap'].data
3039 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003040
Simon Glassf8a54bc2019-07-20 12:23:56 -06003041 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003042
3043 def testReplaceSimple(self):
3044 """Test replacing a single file"""
3045 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003046 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3047 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003048 self.assertEqual(expected, data)
3049
3050 # Test that the state looks right. There should be an FDT for the fdtmap
3051 # that we jsut read back in, and it should match what we find in the
3052 # 'control' tables. Checking for an FDT that does not exist should
3053 # return None.
3054 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003055 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003056 self.assertEqual(expected_fdtmap, fdtmap)
3057
3058 dtb = state.GetFdtForEtype('fdtmap')
3059 self.assertEqual(dtb.GetContents(), fdtmap)
3060
3061 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3062 self.assertIsNone(missing_path)
3063 self.assertIsNone(missing_fdtmap)
3064
3065 missing_dtb = state.GetFdtForEtype('missing')
3066 self.assertIsNone(missing_dtb)
3067
3068 self.assertEqual('/binman', state.fdt_path_prefix)
3069
3070 def testReplaceResizeFail(self):
3071 """Test replacing a file by something larger"""
3072 expected = U_BOOT_DATA + b'x'
3073 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003074 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3075 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003076 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3077 str(e.exception))
3078
3079 def testReplaceMulti(self):
3080 """Test replacing entry data where multiple images are generated"""
3081 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3082 update_dtb=True)[0]
3083 expected = b'x' * len(U_BOOT_DATA)
3084 updated_fname = tools.GetOutputFilename('image-updated.bin')
3085 tools.WriteFile(updated_fname, data)
3086 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003087 control.WriteEntry(updated_fname, entry_name, expected,
3088 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003089 data = control.ReadEntry(updated_fname, entry_name)
3090 self.assertEqual(expected, data)
3091
3092 # Check the state looks right.
3093 self.assertEqual('/binman/image', state.fdt_path_prefix)
3094
3095 # Now check we can write the first image
3096 image_fname = tools.GetOutputFilename('first-image.bin')
3097 updated_fname = tools.GetOutputFilename('first-updated.bin')
3098 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3099 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003100 control.WriteEntry(updated_fname, entry_name, expected,
3101 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003102 data = control.ReadEntry(updated_fname, entry_name)
3103 self.assertEqual(expected, data)
3104
3105 # Check the state looks right.
3106 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003107
Simon Glassfb30e292019-07-20 12:23:51 -06003108 def testUpdateFdtAllRepack(self):
3109 """Test that all device trees are updated with offset/size info"""
3110 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3111 SECTION_SIZE = 0x300
3112 DTB_SIZE = 602
3113 FDTMAP_SIZE = 608
3114 base_expected = {
3115 'offset': 0,
3116 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3117 'image-pos': 0,
3118 'section:offset': 0,
3119 'section:size': SECTION_SIZE,
3120 'section:image-pos': 0,
3121 'section/u-boot-dtb:offset': 4,
3122 'section/u-boot-dtb:size': 636,
3123 'section/u-boot-dtb:image-pos': 4,
3124 'u-boot-spl-dtb:offset': SECTION_SIZE,
3125 'u-boot-spl-dtb:size': DTB_SIZE,
3126 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3127 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3128 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3129 'u-boot-tpl-dtb:size': DTB_SIZE,
3130 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3131 'fdtmap:size': FDTMAP_SIZE,
3132 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3133 }
3134 main_expected = {
3135 'section:orig-size': SECTION_SIZE,
3136 'section/u-boot-dtb:orig-offset': 4,
3137 }
3138
3139 # We expect three device-tree files in the output, with the first one
3140 # within a fixed-size section.
3141 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3142 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3143 # main U-Boot tree. All three should have the same positions and offset
3144 # except that the main tree should include the main_expected properties
3145 start = 4
3146 for item in ['', 'spl', 'tpl', None]:
3147 if item is None:
3148 start += 16 # Move past fdtmap header
3149 dtb = fdt.Fdt.FromData(data[start:])
3150 dtb.Scan()
3151 props = self._GetPropTree(dtb,
3152 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3153 prefix='/' if item is None else '/binman/')
3154 expected = dict(base_expected)
3155 if item:
3156 expected[item] = 0
3157 else:
3158 # Main DTB and fdtdec should include the 'orig-' properties
3159 expected.update(main_expected)
3160 # Helpful for debugging:
3161 #for prop in sorted(props):
3162 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3163 self.assertEqual(expected, props)
3164 if item == '':
3165 start = SECTION_SIZE
3166 else:
3167 start += dtb._fdt_obj.totalsize()
3168
Simon Glass11453762019-07-20 12:23:55 -06003169 def testFdtmapHeaderMiddle(self):
3170 """Test an FDT map in the middle of an image when it should be at end"""
3171 with self.assertRaises(ValueError) as e:
3172 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3173 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3174 str(e.exception))
3175
3176 def testFdtmapHeaderStartBad(self):
3177 """Test an FDT map in middle of an image when it should be at start"""
3178 with self.assertRaises(ValueError) as e:
3179 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3180 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3181 str(e.exception))
3182
3183 def testFdtmapHeaderEndBad(self):
3184 """Test an FDT map at the start of an image when it should be at end"""
3185 with self.assertRaises(ValueError) as e:
3186 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3187 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3188 str(e.exception))
3189
3190 def testFdtmapHeaderNoSize(self):
3191 """Test an image header at the end of an image with undefined size"""
3192 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3193
Simon Glassf8a54bc2019-07-20 12:23:56 -06003194 def testReplaceResize(self):
3195 """Test replacing a single file in an entry with a larger file"""
3196 expected = U_BOOT_DATA + b'x'
3197 data, _, image = self._RunReplaceCmd('u-boot', expected,
3198 dts='139_replace_repack.dts')
3199 self.assertEqual(expected, data)
3200
3201 entries = image.GetEntries()
3202 dtb_data = entries['u-boot-dtb'].data
3203 dtb = fdt.Fdt.FromData(dtb_data)
3204 dtb.Scan()
3205
3206 # The u-boot section should now be larger in the dtb
3207 node = dtb.GetNode('/binman/u-boot')
3208 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3209
3210 # Same for the fdtmap
3211 fdata = entries['fdtmap'].data
3212 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3213 fdtb.Scan()
3214 fnode = fdtb.GetNode('/u-boot')
3215 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3216
3217 def testReplaceResizeNoRepack(self):
3218 """Test replacing an entry with a larger file when not allowed"""
3219 expected = U_BOOT_DATA + b'x'
3220 with self.assertRaises(ValueError) as e:
3221 self._RunReplaceCmd('u-boot', expected)
3222 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3223 str(e.exception))
3224
Simon Glass9d8ee322019-07-20 12:23:58 -06003225 def testEntryShrink(self):
3226 """Test contracting an entry after it is packed"""
3227 try:
3228 state.SetAllowEntryContraction(True)
3229 data = self._DoReadFileDtb('140_entry_shrink.dts',
3230 update_dtb=True)[0]
3231 finally:
3232 state.SetAllowEntryContraction(False)
3233 self.assertEqual(b'a', data[:1])
3234 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3235 self.assertEqual(b'a', data[-1:])
3236
3237 def testEntryShrinkFail(self):
3238 """Test not being allowed to contract an entry after it is packed"""
3239 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3240
3241 # In this case there is a spare byte at the end of the data. The size of
3242 # the contents is only 1 byte but we still have the size before it
3243 # shrunk.
3244 self.assertEqual(b'a\0', data[:2])
3245 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3246 self.assertEqual(b'a\0', data[-2:])
3247
Simon Glass70e32982019-07-20 12:24:01 -06003248 def testDescriptorOffset(self):
3249 """Test that the Intel descriptor is always placed at at the start"""
3250 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3251 image = control.images['image']
3252 entries = image.GetEntries()
3253 desc = entries['intel-descriptor']
3254 self.assertEqual(0xff800000, desc.offset);
3255 self.assertEqual(0xff800000, desc.image_pos);
3256
Simon Glass37fdd142019-07-20 12:24:06 -06003257 def testReplaceCbfs(self):
3258 """Test replacing a single file in CBFS without changing the size"""
3259 self._CheckLz4()
3260 expected = b'x' * len(U_BOOT_DATA)
3261 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3262 updated_fname = tools.GetOutputFilename('image-updated.bin')
3263 tools.WriteFile(updated_fname, data)
3264 entry_name = 'section/cbfs/u-boot'
3265 control.WriteEntry(updated_fname, entry_name, expected,
3266 allow_resize=True)
3267 data = control.ReadEntry(updated_fname, entry_name)
3268 self.assertEqual(expected, data)
3269
3270 def testReplaceResizeCbfs(self):
3271 """Test replacing a single file in CBFS with one of a different size"""
3272 self._CheckLz4()
3273 expected = U_BOOT_DATA + b'x'
3274 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3275 updated_fname = tools.GetOutputFilename('image-updated.bin')
3276 tools.WriteFile(updated_fname, data)
3277 entry_name = 'section/cbfs/u-boot'
3278 control.WriteEntry(updated_fname, entry_name, expected,
3279 allow_resize=True)
3280 data = control.ReadEntry(updated_fname, entry_name)
3281 self.assertEqual(expected, data)
3282
Simon Glass30033c22019-07-20 12:24:15 -06003283 def _SetupForReplace(self):
3284 """Set up some files to use to replace entries
3285
3286 This generates an image, copies it to a new file, extracts all the files
3287 in it and updates some of them
3288
3289 Returns:
3290 List
3291 Image filename
3292 Output directory
3293 Expected values for updated entries, each a string
3294 """
3295 data = self._DoReadFileRealDtb('143_replace_all.dts')
3296
3297 updated_fname = tools.GetOutputFilename('image-updated.bin')
3298 tools.WriteFile(updated_fname, data)
3299
3300 outdir = os.path.join(self._indir, 'extract')
3301 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3302
3303 expected1 = b'x' + U_BOOT_DATA + b'y'
3304 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3305 tools.WriteFile(u_boot_fname1, expected1)
3306
3307 expected2 = b'a' + U_BOOT_DATA + b'b'
3308 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3309 tools.WriteFile(u_boot_fname2, expected2)
3310
3311 expected_text = b'not the same text'
3312 text_fname = os.path.join(outdir, 'text')
3313 tools.WriteFile(text_fname, expected_text)
3314
3315 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3316 dtb = fdt.FdtScan(dtb_fname)
3317 node = dtb.GetNode('/binman/text')
3318 node.AddString('my-property', 'the value')
3319 dtb.Sync(auto_resize=True)
3320 dtb.Flush()
3321
3322 return updated_fname, outdir, expected1, expected2, expected_text
3323
3324 def _CheckReplaceMultiple(self, entry_paths):
3325 """Handle replacing the contents of multiple entries
3326
3327 Args:
3328 entry_paths: List of entry paths to replace
3329
3330 Returns:
3331 List
3332 Dict of entries in the image:
3333 key: Entry name
3334 Value: Entry object
3335 Expected values for updated entries, each a string
3336 """
3337 updated_fname, outdir, expected1, expected2, expected_text = (
3338 self._SetupForReplace())
3339 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3340
3341 image = Image.FromFile(updated_fname)
3342 image.LoadData()
3343 return image.GetEntries(), expected1, expected2, expected_text
3344
3345 def testReplaceAll(self):
3346 """Test replacing the contents of all entries"""
3347 entries, expected1, expected2, expected_text = (
3348 self._CheckReplaceMultiple([]))
3349 data = entries['u-boot'].data
3350 self.assertEqual(expected1, data)
3351
3352 data = entries['u-boot2'].data
3353 self.assertEqual(expected2, data)
3354
3355 data = entries['text'].data
3356 self.assertEqual(expected_text, data)
3357
3358 # Check that the device tree is updated
3359 data = entries['u-boot-dtb'].data
3360 dtb = fdt.Fdt.FromData(data)
3361 dtb.Scan()
3362 node = dtb.GetNode('/binman/text')
3363 self.assertEqual('the value', node.props['my-property'].value)
3364
3365 def testReplaceSome(self):
3366 """Test replacing the contents of a few entries"""
3367 entries, expected1, expected2, expected_text = (
3368 self._CheckReplaceMultiple(['u-boot2', 'text']))
3369
3370 # This one should not change
3371 data = entries['u-boot'].data
3372 self.assertEqual(U_BOOT_DATA, data)
3373
3374 data = entries['u-boot2'].data
3375 self.assertEqual(expected2, data)
3376
3377 data = entries['text'].data
3378 self.assertEqual(expected_text, data)
3379
3380 def testReplaceCmd(self):
3381 """Test replacing a file fron an image on the command line"""
3382 self._DoReadFileRealDtb('143_replace_all.dts')
3383
3384 try:
3385 tmpdir, updated_fname = self._SetupImageInTmpdir()
3386
3387 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3388 expected = b'x' * len(U_BOOT_DATA)
3389 tools.WriteFile(fname, expected)
3390
3391 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3392 data = tools.ReadFile(updated_fname)
3393 self.assertEqual(expected, data[:len(expected)])
3394 map_fname = os.path.join(tmpdir, 'image-updated.map')
3395 self.assertFalse(os.path.exists(map_fname))
3396 finally:
3397 shutil.rmtree(tmpdir)
3398
3399 def testReplaceCmdSome(self):
3400 """Test replacing some files fron an image on the command line"""
3401 updated_fname, outdir, expected1, expected2, expected_text = (
3402 self._SetupForReplace())
3403
3404 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3405 'u-boot2', 'text')
3406
3407 tools.PrepareOutputDir(None)
3408 image = Image.FromFile(updated_fname)
3409 image.LoadData()
3410 entries = image.GetEntries()
3411
3412 # This one should not change
3413 data = entries['u-boot'].data
3414 self.assertEqual(U_BOOT_DATA, data)
3415
3416 data = entries['u-boot2'].data
3417 self.assertEqual(expected2, data)
3418
3419 data = entries['text'].data
3420 self.assertEqual(expected_text, data)
3421
3422 def testReplaceMissing(self):
3423 """Test replacing entries where the file is missing"""
3424 updated_fname, outdir, expected1, expected2, expected_text = (
3425 self._SetupForReplace())
3426
3427 # Remove one of the files, to generate a warning
3428 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3429 os.remove(u_boot_fname1)
3430
3431 with test_util.capture_sys_output() as (stdout, stderr):
3432 control.ReplaceEntries(updated_fname, None, outdir, [])
3433 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003434 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003435
3436 def testReplaceCmdMap(self):
3437 """Test replacing a file fron an image on the command line"""
3438 self._DoReadFileRealDtb('143_replace_all.dts')
3439
3440 try:
3441 tmpdir, updated_fname = self._SetupImageInTmpdir()
3442
3443 fname = os.path.join(self._indir, 'update-u-boot.bin')
3444 expected = b'x' * len(U_BOOT_DATA)
3445 tools.WriteFile(fname, expected)
3446
3447 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3448 '-f', fname, '-m')
3449 map_fname = os.path.join(tmpdir, 'image-updated.map')
3450 self.assertTrue(os.path.exists(map_fname))
3451 finally:
3452 shutil.rmtree(tmpdir)
3453
3454 def testReplaceNoEntryPaths(self):
3455 """Test replacing an entry without an entry path"""
3456 self._DoReadFileRealDtb('143_replace_all.dts')
3457 image_fname = tools.GetOutputFilename('image.bin')
3458 with self.assertRaises(ValueError) as e:
3459 control.ReplaceEntries(image_fname, 'fname', None, [])
3460 self.assertIn('Must specify an entry path to read with -f',
3461 str(e.exception))
3462
3463 def testReplaceTooManyEntryPaths(self):
3464 """Test extracting some entries"""
3465 self._DoReadFileRealDtb('143_replace_all.dts')
3466 image_fname = tools.GetOutputFilename('image.bin')
3467 with self.assertRaises(ValueError) as e:
3468 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3469 self.assertIn('Must specify exactly one entry path to write with -f',
3470 str(e.exception))
3471
Simon Glass0b074d62019-08-24 07:22:48 -06003472 def testPackReset16(self):
3473 """Test that an image with an x86 reset16 region can be created"""
3474 data = self._DoReadFile('144_x86_reset16.dts')
3475 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3476
3477 def testPackReset16Spl(self):
3478 """Test that an image with an x86 reset16-spl region can be created"""
3479 data = self._DoReadFile('145_x86_reset16_spl.dts')
3480 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3481
3482 def testPackReset16Tpl(self):
3483 """Test that an image with an x86 reset16-tpl region can be created"""
3484 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3485 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3486
Simon Glass232f90c2019-08-24 07:22:50 -06003487 def testPackIntelFit(self):
3488 """Test that an image with an Intel FIT and pointer can be created"""
3489 data = self._DoReadFile('147_intel_fit.dts')
3490 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3491 fit = data[16:32];
3492 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3493 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3494
3495 image = control.images['image']
3496 entries = image.GetEntries()
3497 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3498 self.assertEqual(expected_ptr, ptr)
3499
3500 def testPackIntelFitMissing(self):
3501 """Test detection of a FIT pointer with not FIT region"""
3502 with self.assertRaises(ValueError) as e:
3503 self._DoReadFile('148_intel_fit_missing.dts')
3504 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3505 str(e.exception))
3506
Simon Glass72555fa2019-11-06 17:22:44 -07003507 def _CheckSymbolsTplSection(self, dts, expected_vals):
3508 data = self._DoReadFile(dts)
3509 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003510 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003511 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003512 self.assertEqual(expected1, data[:upto1])
3513
3514 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003515 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003516 self.assertEqual(expected2, data[upto1:upto2])
3517
Simon Glass4e353e22019-08-24 07:23:04 -06003518 upto3 = 0x34 + len(U_BOOT_DATA)
3519 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003520 self.assertEqual(expected3, data[upto2:upto3])
3521
Simon Glass3f8ff012019-08-24 07:23:05 -06003522 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003523 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3524
3525 def testSymbolsTplSection(self):
3526 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3527 self._SetupSplElf('u_boot_binman_syms')
3528 self._SetupTplElf('u_boot_binman_syms')
3529 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3530 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3531
3532 def testSymbolsTplSectionX86(self):
3533 """Test binman can assign symbols in a section with end-at-4gb"""
3534 self._SetupSplElf('u_boot_binman_syms_x86')
3535 self._SetupTplElf('u_boot_binman_syms_x86')
3536 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3537 [0xffffff04, 0xffffff1c, 0xffffff34,
3538 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003539
Simon Glass98c59572019-08-24 07:23:03 -06003540 def testPackX86RomIfwiSectiom(self):
3541 """Test that a section can be placed in an IFWI region"""
3542 self._SetupIfwi('fitimage.bin')
3543 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3544 self._CheckIfwi(data)
3545
Simon Glassba7985d2019-08-24 07:23:07 -06003546 def testPackFspM(self):
3547 """Test that an image with a FSP memory-init binary can be created"""
3548 data = self._DoReadFile('152_intel_fsp_m.dts')
3549 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3550
Simon Glass4d9086d2019-10-20 21:31:35 -06003551 def testPackFspS(self):
3552 """Test that an image with a FSP silicon-init binary can be created"""
3553 data = self._DoReadFile('153_intel_fsp_s.dts')
3554 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003555
Simon Glass9ea87b22019-10-20 21:31:36 -06003556 def testPackFspT(self):
3557 """Test that an image with a FSP temp-ram-init binary can be created"""
3558 data = self._DoReadFile('154_intel_fsp_t.dts')
3559 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3560
Simon Glass48f3aad2020-07-09 18:39:31 -06003561 def testMkimage(self):
3562 """Test using mkimage to build an image"""
3563 data = self._DoReadFile('156_mkimage.dts')
3564
3565 # Just check that the data appears in the file somewhere
3566 self.assertIn(U_BOOT_SPL_DATA, data)
3567
Simon Glass5e560182020-07-09 18:39:36 -06003568 def testExtblob(self):
3569 """Test an image with an external blob"""
3570 data = self._DoReadFile('157_blob_ext.dts')
3571 self.assertEqual(REFCODE_DATA, data)
3572
3573 def testExtblobMissing(self):
3574 """Test an image with a missing external blob"""
3575 with self.assertRaises(ValueError) as e:
3576 self._DoReadFile('158_blob_ext_missing.dts')
3577 self.assertIn("Filename 'missing-file' not found in input path",
3578 str(e.exception))
3579
Simon Glass5d94cc62020-07-09 18:39:38 -06003580 def testExtblobMissingOk(self):
3581 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003582 with test_util.capture_sys_output() as (stdout, stderr):
3583 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3584 err = stderr.getvalue()
3585 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3586
3587 def testExtblobMissingOkSect(self):
3588 """Test an image with an missing external blob that is allowed"""
3589 with test_util.capture_sys_output() as (stdout, stderr):
3590 self._DoTestFile('159_blob_ext_missing_sect.dts',
3591 allow_missing=True)
3592 err = stderr.getvalue()
3593 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3594 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003595
Simon Glasse88cef92020-07-09 18:39:41 -06003596 def testPackX86RomMeMissingDesc(self):
3597 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003598 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003599 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003600 err = stderr.getvalue()
3601 self.assertRegex(err,
3602 "Image 'main-section'.*missing.*: intel-descriptor")
3603
3604 def testPackX86RomMissingIfwi(self):
3605 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3606 self._SetupIfwi('fitimage.bin')
3607 pathname = os.path.join(self._indir, 'fitimage.bin')
3608 os.remove(pathname)
3609 with test_util.capture_sys_output() as (stdout, stderr):
3610 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3611 err = stderr.getvalue()
3612 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3613
Simon Glassd70829a2020-07-09 18:39:42 -06003614 def testPackOverlap(self):
3615 """Test that zero-size overlapping regions are ignored"""
3616 self._DoTestFile('160_pack_overlap_zero.dts')
3617
Simon Glass45d556d2020-07-09 18:39:45 -06003618 def testSimpleFit(self):
3619 """Test an image with a FIT inside"""
3620 data = self._DoReadFile('161_fit.dts')
3621 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3622 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3623 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3624
3625 # The data should be inside the FIT
3626 dtb = fdt.Fdt.FromData(fit_data)
3627 dtb.Scan()
3628 fnode = dtb.GetNode('/images/kernel')
3629 self.assertIn('data', fnode.props)
3630
3631 fname = os.path.join(self._indir, 'fit_data.fit')
3632 tools.WriteFile(fname, fit_data)
3633 out = tools.Run('dumpimage', '-l', fname)
3634
3635 # Check a few features to make sure the plumbing works. We don't need
3636 # to test the operation of mkimage or dumpimage here. First convert the
3637 # output into a dict where the keys are the fields printed by dumpimage
3638 # and the values are a list of values for each field
3639 lines = out.splitlines()
3640
3641 # Converts "Compression: gzip compressed" into two groups:
3642 # 'Compression' and 'gzip compressed'
3643 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3644 vals = collections.defaultdict(list)
3645 for line in lines:
3646 mat = re_line.match(line)
3647 vals[mat.group(1)].append(mat.group(2))
3648
3649 self.assertEquals('FIT description: test-desc', lines[0])
3650 self.assertIn('Created:', lines[1])
3651 self.assertIn('Image 0 (kernel)', vals)
3652 self.assertIn('Hash value', vals)
3653 data_sizes = vals.get('Data Size')
3654 self.assertIsNotNone(data_sizes)
3655 self.assertEqual(2, len(data_sizes))
3656 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3657 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3658 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3659
3660 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003661 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003662 data = self._DoReadFile('162_fit_external.dts')
3663 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3664
3665 # The data should be outside the FIT
3666 dtb = fdt.Fdt.FromData(fit_data)
3667 dtb.Scan()
3668 fnode = dtb.GetNode('/images/kernel')
3669 self.assertNotIn('data', fnode.props)
Simon Glassfb30e292019-07-20 12:23:51 -06003670
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003671 def testSectionIgnoreHashSignature(self):
3672 """Test that sections ignore hash, signature nodes for its data"""
3673 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3674 expected = (U_BOOT_DATA + U_BOOT_DATA)
3675 self.assertEqual(expected, data)
3676
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003677 def testPadInSections(self):
3678 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003679 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3680 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003681 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3682 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3683 U_BOOT_DATA)
3684 self.assertEqual(expected, data)
3685
Simon Glassd12599d2020-10-26 17:40:09 -06003686 dtb = fdt.Fdt(out_dtb_fname)
3687 dtb.Scan()
3688 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3689 expected = {
3690 'image-pos': 0,
3691 'offset': 0,
3692 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3693
3694 'section:image-pos': 0,
3695 'section:offset': 0,
3696 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3697
3698 'section/before:image-pos': 0,
3699 'section/before:offset': 0,
3700 'section/before:size': len(U_BOOT_DATA),
3701
3702 'section/u-boot:image-pos': 4,
3703 'section/u-boot:offset': 4,
3704 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3705
3706 'section/after:image-pos': 26,
3707 'section/after:offset': 26,
3708 'section/after:size': len(U_BOOT_DATA),
3709 }
3710 self.assertEqual(expected, props)
3711
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003712 def testFitImageSubentryAlignment(self):
3713 """Test relative alignability of FIT image subentries"""
3714 entry_args = {
3715 'test-id': TEXT_DATA,
3716 }
3717 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3718 entry_args=entry_args)
3719 dtb = fdt.Fdt.FromData(data)
3720 dtb.Scan()
3721
3722 node = dtb.GetNode('/images/kernel')
3723 data = dtb.GetProps(node)["data"].bytes
3724 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3725 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3726 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3727 self.assertEqual(expected, data)
3728
3729 node = dtb.GetNode('/images/fdt-1')
3730 data = dtb.GetProps(node)["data"].bytes
3731 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3732 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3733 U_BOOT_DTB_DATA)
3734 self.assertEqual(expected, data)
3735
3736 def testFitExtblobMissingOk(self):
3737 """Test a FIT with a missing external blob that is allowed"""
3738 with test_util.capture_sys_output() as (stdout, stderr):
3739 self._DoTestFile('168_fit_missing_blob.dts',
3740 allow_missing=True)
3741 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003742 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003743
Simon Glass21db0ff2020-09-01 05:13:54 -06003744 def testBlobNamedByArgMissing(self):
3745 """Test handling of a missing entry arg"""
3746 with self.assertRaises(ValueError) as e:
3747 self._DoReadFile('068_blob_named_by_arg.dts')
3748 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3749 str(e.exception))
3750
Simon Glass559c4de2020-09-01 05:13:58 -06003751 def testPackBl31(self):
3752 """Test that an image with an ATF BL31 binary can be created"""
3753 data = self._DoReadFile('169_atf_bl31.dts')
3754 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3755
Samuel Holland9d8cc632020-10-21 21:12:15 -05003756 def testPackScp(self):
3757 """Test that an image with an SCP binary can be created"""
3758 data = self._DoReadFile('172_scp.dts')
3759 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3760
Simon Glassa435cd12020-09-01 05:13:59 -06003761 def testFitFdt(self):
3762 """Test an image with an FIT with multiple FDT images"""
3763 def _CheckFdt(seq, expected_data):
3764 """Check the FDT nodes
3765
3766 Args:
3767 seq: Sequence number to check (0 or 1)
3768 expected_data: Expected contents of 'data' property
3769 """
3770 name = 'fdt-%d' % seq
3771 fnode = dtb.GetNode('/images/%s' % name)
3772 self.assertIsNotNone(fnode)
3773 self.assertEqual({'description','type', 'compression', 'data'},
3774 set(fnode.props.keys()))
3775 self.assertEqual(expected_data, fnode.props['data'].bytes)
3776 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3777 fnode.props['description'].value)
3778
3779 def _CheckConfig(seq, expected_data):
3780 """Check the configuration nodes
3781
3782 Args:
3783 seq: Sequence number to check (0 or 1)
3784 expected_data: Expected contents of 'data' property
3785 """
3786 cnode = dtb.GetNode('/configurations')
3787 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003788 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003789
3790 name = 'config-%d' % seq
3791 fnode = dtb.GetNode('/configurations/%s' % name)
3792 self.assertIsNotNone(fnode)
3793 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3794 set(fnode.props.keys()))
3795 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3796 fnode.props['description'].value)
3797 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3798
3799 entry_args = {
3800 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003801 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003802 }
3803 data = self._DoReadFileDtb(
Simon Glass1032acc2020-09-06 10:39:08 -06003804 '172_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003805 entry_args=entry_args,
3806 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3807 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3808 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3809
3810 dtb = fdt.Fdt.FromData(fit_data)
3811 dtb.Scan()
3812 fnode = dtb.GetNode('/images/kernel')
3813 self.assertIn('data', fnode.props)
3814
3815 # Check all the properties in fdt-1 and fdt-2
3816 _CheckFdt(1, TEST_FDT1_DATA)
3817 _CheckFdt(2, TEST_FDT2_DATA)
3818
3819 # Check configurations
3820 _CheckConfig(1, TEST_FDT1_DATA)
3821 _CheckConfig(2, TEST_FDT2_DATA)
3822
3823 def testFitFdtMissingList(self):
3824 """Test handling of a missing 'of-list' entry arg"""
3825 with self.assertRaises(ValueError) as e:
Simon Glass1032acc2020-09-06 10:39:08 -06003826 self._DoReadFile('172_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003827 self.assertIn("Generator node requires 'of-list' entry argument",
3828 str(e.exception))
3829
3830 def testFitFdtEmptyList(self):
3831 """Test handling of an empty 'of-list' entry arg"""
3832 entry_args = {
3833 'of-list': '',
3834 }
3835 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3836
3837 def testFitFdtMissingProp(self):
3838 """Test handling of a missing 'fit,fdt-list' property"""
3839 with self.assertRaises(ValueError) as e:
3840 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3841 self.assertIn("Generator node requires 'fit,fdt-list' property",
3842 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003843
Simon Glass1032acc2020-09-06 10:39:08 -06003844 def testFitFdtEmptyList(self):
3845 """Test handling of an empty 'of-list' entry arg"""
3846 entry_args = {
3847 'of-list': '',
3848 }
3849 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3850
3851 def testFitFdtMissing(self):
3852 """Test handling of a missing 'default-dt' entry arg"""
3853 entry_args = {
3854 'of-list': 'test-fdt1 test-fdt2',
3855 }
3856 with self.assertRaises(ValueError) as e:
3857 self._DoReadFileDtb(
3858 '172_fit_fdt.dts',
3859 entry_args=entry_args,
3860 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3861 self.assertIn("Generated 'default' node requires default-dt entry argument",
3862 str(e.exception))
3863
3864 def testFitFdtNotInList(self):
3865 """Test handling of a default-dt that is not in the of-list"""
3866 entry_args = {
3867 'of-list': 'test-fdt1 test-fdt2',
3868 'default-dt': 'test-fdt3',
3869 }
3870 with self.assertRaises(ValueError) as e:
3871 self._DoReadFileDtb(
3872 '172_fit_fdt.dts',
3873 entry_args=entry_args,
3874 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3875 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3876 str(e.exception))
3877
Simon Glassa820af72020-09-06 10:39:09 -06003878 def testFitExtblobMissingHelp(self):
3879 """Test display of help messages when an external blob is missing"""
3880 control.missing_blob_help = control._ReadMissingBlobHelp()
3881 control.missing_blob_help['wibble'] = 'Wibble test'
3882 control.missing_blob_help['another'] = 'Another test'
3883 with test_util.capture_sys_output() as (stdout, stderr):
3884 self._DoTestFile('168_fit_missing_blob.dts',
3885 allow_missing=True)
3886 err = stderr.getvalue()
3887
3888 # We can get the tag from the name, the type or the missing-msg
3889 # property. Check all three.
3890 self.assertIn('You may need to build ARM Trusted', err)
3891 self.assertIn('Wibble test', err)
3892 self.assertIn('Another test', err)
3893
Simon Glass6f1f4d42020-09-06 10:35:32 -06003894 def testMissingBlob(self):
3895 """Test handling of a blob containing a missing file"""
3896 with self.assertRaises(ValueError) as e:
3897 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3898 self.assertIn("Filename 'missing' not found in input path",
3899 str(e.exception))
3900
Simon Glassa0729502020-09-06 10:35:33 -06003901 def testEnvironment(self):
3902 """Test adding a U-Boot environment"""
3903 data = self._DoReadFile('174_env.dts')
3904 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3905 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3906 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3907 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3908 env)
3909
3910 def testEnvironmentNoSize(self):
3911 """Test that a missing 'size' property is detected"""
3912 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003913 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003914 self.assertIn("'u-boot-env' entry must have a size property",
3915 str(e.exception))
3916
3917 def testEnvironmentTooSmall(self):
3918 """Test handling of an environment that does not fit"""
3919 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003920 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003921
3922 # checksum, start byte, environment with \0 terminator, final \0
3923 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3924 short = need - 0x8
3925 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3926 str(e.exception))
3927
Simon Glassd1fdf752020-10-26 17:40:01 -06003928 def testSkipAtStart(self):
3929 """Test handling of skip-at-start section"""
3930 data = self._DoReadFile('177_skip_at_start.dts')
3931 self.assertEqual(U_BOOT_DATA, data)
3932
3933 image = control.images['image']
3934 entries = image.GetEntries()
3935 section = entries['section']
3936 self.assertEqual(0, section.offset)
3937 self.assertEqual(len(U_BOOT_DATA), section.size)
3938 self.assertEqual(U_BOOT_DATA, section.GetData())
3939
3940 entry = section.GetEntries()['u-boot']
3941 self.assertEqual(16, entry.offset)
3942 self.assertEqual(len(U_BOOT_DATA), entry.size)
3943 self.assertEqual(U_BOOT_DATA, entry.data)
3944
3945 def testSkipAtStartPad(self):
3946 """Test handling of skip-at-start section with padded entry"""
3947 data = self._DoReadFile('178_skip_at_start_pad.dts')
3948 before = tools.GetBytes(0, 8)
3949 after = tools.GetBytes(0, 4)
3950 all = before + U_BOOT_DATA + after
3951 self.assertEqual(all, data)
3952
3953 image = control.images['image']
3954 entries = image.GetEntries()
3955 section = entries['section']
3956 self.assertEqual(0, section.offset)
3957 self.assertEqual(len(all), section.size)
3958 self.assertEqual(all, section.GetData())
3959
3960 entry = section.GetEntries()['u-boot']
3961 self.assertEqual(16, entry.offset)
3962 self.assertEqual(len(all), entry.size)
3963 self.assertEqual(U_BOOT_DATA, entry.data)
3964
3965 def testSkipAtStartSectionPad(self):
3966 """Test handling of skip-at-start section with padding"""
3967 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3968 before = tools.GetBytes(0, 8)
3969 after = tools.GetBytes(0, 4)
3970 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06003971 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06003972
3973 image = control.images['image']
3974 entries = image.GetEntries()
3975 section = entries['section']
3976 self.assertEqual(0, section.offset)
3977 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06003978 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06003979 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06003980
3981 entry = section.GetEntries()['u-boot']
3982 self.assertEqual(16, entry.offset)
3983 self.assertEqual(len(U_BOOT_DATA), entry.size)
3984 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06003985
Simon Glassbb395742020-10-26 17:40:14 -06003986 def testSectionPad(self):
3987 """Testing padding with sections"""
3988 data = self._DoReadFile('180_section_pad.dts')
3989 expected = (tools.GetBytes(ord('&'), 3) +
3990 tools.GetBytes(ord('!'), 5) +
3991 U_BOOT_DATA +
3992 tools.GetBytes(ord('!'), 1) +
3993 tools.GetBytes(ord('&'), 2))
3994 self.assertEqual(expected, data)
3995
3996 def testSectionAlign(self):
3997 """Testing alignment with sections"""
3998 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
3999 expected = (b'\0' + # fill section
4000 tools.GetBytes(ord('&'), 1) + # padding to section align
4001 b'\0' + # fill section
4002 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4003 U_BOOT_DATA +
4004 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4005 tools.GetBytes(ord('!'), 4)) # padding to section size
4006 self.assertEqual(expected, data)
4007
Simon Glassd92c8362020-10-26 17:40:25 -06004008 def testCompressImage(self):
4009 """Test compression of the entire image"""
4010 self._CheckLz4()
4011 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4012 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4013 dtb = fdt.Fdt(out_dtb_fname)
4014 dtb.Scan()
4015 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4016 'uncomp-size'])
4017 orig = self._decompress(data)
4018 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4019
4020 # Do a sanity check on various fields
4021 image = control.images['image']
4022 entries = image.GetEntries()
4023 self.assertEqual(2, len(entries))
4024
4025 entry = entries['blob']
4026 self.assertEqual(COMPRESS_DATA, entry.data)
4027 self.assertEqual(len(COMPRESS_DATA), entry.size)
4028
4029 entry = entries['u-boot']
4030 self.assertEqual(U_BOOT_DATA, entry.data)
4031 self.assertEqual(len(U_BOOT_DATA), entry.size)
4032
4033 self.assertEqual(len(data), image.size)
4034 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4035 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4036 orig = self._decompress(image.data)
4037 self.assertEqual(orig, image.uncomp_data)
4038
4039 expected = {
4040 'blob:offset': 0,
4041 'blob:size': len(COMPRESS_DATA),
4042 'u-boot:offset': len(COMPRESS_DATA),
4043 'u-boot:size': len(U_BOOT_DATA),
4044 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4045 'offset': 0,
4046 'image-pos': 0,
4047 'size': len(data),
4048 }
4049 self.assertEqual(expected, props)
4050
4051 def testCompressImageLess(self):
4052 """Test compression where compression reduces the image size"""
4053 self._CheckLz4()
4054 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4055 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4056 dtb = fdt.Fdt(out_dtb_fname)
4057 dtb.Scan()
4058 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4059 'uncomp-size'])
4060 orig = self._decompress(data)
4061
4062 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4063
4064 # Do a sanity check on various fields
4065 image = control.images['image']
4066 entries = image.GetEntries()
4067 self.assertEqual(2, len(entries))
4068
4069 entry = entries['blob']
4070 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4071 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4072
4073 entry = entries['u-boot']
4074 self.assertEqual(U_BOOT_DATA, entry.data)
4075 self.assertEqual(len(U_BOOT_DATA), entry.size)
4076
4077 self.assertEqual(len(data), image.size)
4078 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4079 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4080 image.uncomp_size)
4081 orig = self._decompress(image.data)
4082 self.assertEqual(orig, image.uncomp_data)
4083
4084 expected = {
4085 'blob:offset': 0,
4086 'blob:size': len(COMPRESS_DATA_BIG),
4087 'u-boot:offset': len(COMPRESS_DATA_BIG),
4088 'u-boot:size': len(U_BOOT_DATA),
4089 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4090 'offset': 0,
4091 'image-pos': 0,
4092 'size': len(data),
4093 }
4094 self.assertEqual(expected, props)
4095
4096 def testCompressSectionSize(self):
4097 """Test compression of a section with a fixed size"""
4098 self._CheckLz4()
4099 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4100 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4101 dtb = fdt.Fdt(out_dtb_fname)
4102 dtb.Scan()
4103 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4104 'uncomp-size'])
4105 orig = self._decompress(data)
4106 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4107 expected = {
4108 'section/blob:offset': 0,
4109 'section/blob:size': len(COMPRESS_DATA),
4110 'section/u-boot:offset': len(COMPRESS_DATA),
4111 'section/u-boot:size': len(U_BOOT_DATA),
4112 'section:offset': 0,
4113 'section:image-pos': 0,
4114 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4115 'section:size': 0x30,
4116 'offset': 0,
4117 'image-pos': 0,
4118 'size': 0x30,
4119 }
4120 self.assertEqual(expected, props)
4121
4122 def testCompressSection(self):
4123 """Test compression of a section with no fixed size"""
4124 self._CheckLz4()
4125 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4126 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4127 dtb = fdt.Fdt(out_dtb_fname)
4128 dtb.Scan()
4129 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4130 'uncomp-size'])
4131 orig = self._decompress(data)
4132 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4133 expected = {
4134 'section/blob:offset': 0,
4135 'section/blob:size': len(COMPRESS_DATA),
4136 'section/u-boot:offset': len(COMPRESS_DATA),
4137 'section/u-boot:size': len(U_BOOT_DATA),
4138 'section:offset': 0,
4139 'section:image-pos': 0,
4140 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4141 'section:size': len(data),
4142 'offset': 0,
4143 'image-pos': 0,
4144 'size': len(data),
4145 }
4146 self.assertEqual(expected, props)
4147
4148 def testCompressExtra(self):
4149 """Test compression of a section with no fixed size"""
4150 self._CheckLz4()
4151 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4152 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4153 dtb = fdt.Fdt(out_dtb_fname)
4154 dtb.Scan()
4155 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4156 'uncomp-size'])
4157
4158 base = data[len(U_BOOT_DATA):]
4159 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4160 rest = base[len(U_BOOT_DATA):]
4161
4162 # Check compressed data
4163 section1 = self._decompress(rest)
4164 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4165 self.assertEquals(expect1, rest[:len(expect1)])
4166 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4167 rest1 = rest[len(expect1):]
4168
4169 section2 = self._decompress(rest1)
4170 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4171 self.assertEquals(expect2, rest1[:len(expect2)])
4172 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4173 rest2 = rest1[len(expect2):]
4174
4175 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4176 len(expect2) + len(U_BOOT_DATA))
4177 #self.assertEquals(expect_size, len(data))
4178
4179 #self.assertEquals(U_BOOT_DATA, rest2)
4180
4181 self.maxDiff = None
4182 expected = {
4183 'u-boot:offset': 0,
4184 'u-boot:image-pos': 0,
4185 'u-boot:size': len(U_BOOT_DATA),
4186
4187 'base:offset': len(U_BOOT_DATA),
4188 'base:image-pos': len(U_BOOT_DATA),
4189 'base:size': len(data) - len(U_BOOT_DATA),
4190 'base/u-boot:offset': 0,
4191 'base/u-boot:image-pos': len(U_BOOT_DATA),
4192 'base/u-boot:size': len(U_BOOT_DATA),
4193 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4194 len(expect2),
4195 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4196 len(expect2),
4197 'base/u-boot2:size': len(U_BOOT_DATA),
4198
4199 'base/section:offset': len(U_BOOT_DATA),
4200 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4201 'base/section:size': len(expect1),
4202 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4203 'base/section/blob:offset': 0,
4204 'base/section/blob:size': len(COMPRESS_DATA),
4205 'base/section/u-boot:offset': len(COMPRESS_DATA),
4206 'base/section/u-boot:size': len(U_BOOT_DATA),
4207
4208 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4209 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4210 'base/section2:size': len(expect2),
4211 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4212 'base/section2/blob:offset': 0,
4213 'base/section2/blob:size': len(COMPRESS_DATA),
4214 'base/section2/blob2:offset': len(COMPRESS_DATA),
4215 'base/section2/blob2:size': len(COMPRESS_DATA),
4216
4217 'offset': 0,
4218 'image-pos': 0,
4219 'size': len(data),
4220 }
4221 self.assertEqual(expected, props)
4222
Simon Glassecbe4732021-01-06 21:35:15 -07004223 def testSymbolsSubsection(self):
4224 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004225 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004226
Simon Glass3fb25402021-01-06 21:35:16 -07004227 def testReadImageEntryArg(self):
4228 """Test reading an image that would need an entry arg to generate"""
4229 entry_args = {
4230 'cros-ec-rw-path': 'ecrw.bin',
4231 }
4232 data = self.data = self._DoReadFileDtb(
4233 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4234 entry_args=entry_args)
4235
4236 image_fname = tools.GetOutputFilename('image.bin')
4237 orig_image = control.images['image']
4238
4239 # This should not generate an error about the missing 'cros-ec-rw-path'
4240 # since we are reading the image from a file. Compare with
4241 # testEntryArgsRequired()
4242 image = Image.FromFile(image_fname)
4243 self.assertEqual(orig_image.GetEntries().keys(),
4244 image.GetEntries().keys())
4245
Simon Glassa2af7302021-01-06 21:35:18 -07004246 def testFilesAlign(self):
4247 """Test alignment with files"""
4248 data = self._DoReadFile('190_files_align.dts')
4249
4250 # The first string is 15 bytes so will align to 16
4251 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4252 self.assertEqual(expect, data)
4253
Simon Glassdb84b562021-01-06 21:35:19 -07004254 def testReadImageSkip(self):
4255 """Test reading an image and accessing its FDT map"""
4256 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4257 image_fname = tools.GetOutputFilename('image.bin')
4258 orig_image = control.images['image']
4259 image = Image.FromFile(image_fname)
4260 self.assertEqual(orig_image.GetEntries().keys(),
4261 image.GetEntries().keys())
4262
4263 orig_entry = orig_image.GetEntries()['fdtmap']
4264 entry = image.GetEntries()['fdtmap']
4265 self.assertEqual(orig_entry.offset, entry.offset)
4266 self.assertEqual(orig_entry.size, entry.size)
4267 self.assertEqual(16, entry.image_pos)
4268
4269 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4270
4271 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4272
Simon Glassc98de972021-03-18 20:24:57 +13004273 def testTplNoDtb(self):
4274 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
4275 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4276 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4277 data[:len(U_BOOT_TPL_NODTB_DATA)])
4278
Simon Glass63f41d42021-03-18 20:24:58 +13004279 def testTplBssPad(self):
4280 """Test that we can pad TPL's BSS with zeros"""
4281 # ELF file with a '__bss_size' symbol
4282 self._SetupTplElf()
4283 data = self._DoReadFile('193_tpl_bss_pad.dts')
4284 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4285 data)
4286
4287 def testTplBssPadMissing(self):
4288 """Test that a missing symbol is detected"""
4289 self._SetupTplElf('u_boot_ucode_ptr')
4290 with self.assertRaises(ValueError) as e:
4291 self._DoReadFile('193_tpl_bss_pad.dts')
4292 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4293 str(e.exception))
4294
Simon Glass718b5292021-03-18 20:25:07 +13004295 def checkDtbSizes(self, data, pad_len, start):
4296 """Check the size arguments in a dtb embedded in an image
4297
4298 Args:
4299 data: The image data
4300 pad_len: Length of the pad section in the image, in bytes
4301 start: Start offset of the devicetree to examine, within the image
4302
4303 Returns:
4304 Size of the devicetree in bytes
4305 """
4306 dtb_data = data[start:]
4307 dtb = fdt.Fdt.FromData(dtb_data)
4308 fdt_size = dtb.GetFdtObj().totalsize()
4309 dtb.Scan()
4310 props = self._GetPropTree(dtb, 'size')
4311 self.assertEqual({
4312 'size': len(data),
4313 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4314 'u-boot-spl/u-boot-spl-dtb:size': 801,
4315 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4316 'u-boot-spl:size': 860,
4317 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4318 'u-boot/u-boot-dtb:size': 781,
4319 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4320 'u-boot:size': 827,
4321 }, props)
4322 return fdt_size
4323
4324 def testExpanded(self):
4325 """Test that an expanded entry type is selected when needed"""
4326 self._SetupSplElf()
4327 self._SetupTplElf()
4328
4329 # SPL has a devicetree, TPL does not
4330 entry_args = {
4331 'spl-dtb': '1',
4332 'spl-bss-pad': 'y',
4333 'tpl-dtb': '',
4334 }
4335 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4336 entry_args=entry_args)
4337 image = control.images['image']
4338 entries = image.GetEntries()
4339 self.assertEqual(3, len(entries))
4340
4341 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4342 self.assertIn('u-boot', entries)
4343 entry = entries['u-boot']
4344 self.assertEqual('u-boot-expanded', entry.etype)
4345 subent = entry.GetEntries()
4346 self.assertEqual(2, len(subent))
4347 self.assertIn('u-boot-nodtb', subent)
4348 self.assertIn('u-boot-dtb', subent)
4349
4350 # Second, u-boot-spl, which should be expanded into three parts
4351 self.assertIn('u-boot-spl', entries)
4352 entry = entries['u-boot-spl']
4353 self.assertEqual('u-boot-spl-expanded', entry.etype)
4354 subent = entry.GetEntries()
4355 self.assertEqual(3, len(subent))
4356 self.assertIn('u-boot-spl-nodtb', subent)
4357 self.assertIn('u-boot-spl-bss-pad', subent)
4358 self.assertIn('u-boot-spl-dtb', subent)
4359
4360 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4361 # devicetree
4362 self.assertIn('u-boot-tpl', entries)
4363 entry = entries['u-boot-tpl']
4364 self.assertEqual('u-boot-tpl', entry.etype)
4365 self.assertEqual(None, entry.GetEntries())
4366
4367 def testExpandedTpl(self):
4368 """Test that an expanded entry type is selected for TPL when needed"""
4369 self._SetupTplElf()
4370
4371 entry_args = {
4372 'tpl-bss-pad': 'y',
4373 'tpl-dtb': 'y',
4374 }
4375 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4376 entry_args=entry_args)
4377 image = control.images['image']
4378 entries = image.GetEntries()
4379 self.assertEqual(1, len(entries))
4380
4381 # We only have u-boot-tpl, which be expanded
4382 self.assertIn('u-boot-tpl', entries)
4383 entry = entries['u-boot-tpl']
4384 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4385 subent = entry.GetEntries()
4386 self.assertEqual(3, len(subent))
4387 self.assertIn('u-boot-tpl-nodtb', subent)
4388 self.assertIn('u-boot-tpl-bss-pad', subent)
4389 self.assertIn('u-boot-tpl-dtb', subent)
4390
4391 def testExpandedNoPad(self):
4392 """Test an expanded entry without BSS pad enabled"""
4393 self._SetupSplElf()
4394 self._SetupTplElf()
4395
4396 # SPL has a devicetree, TPL does not
4397 entry_args = {
4398 'spl-dtb': 'something',
4399 'spl-bss-pad': 'n',
4400 'tpl-dtb': '',
4401 }
4402 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4403 entry_args=entry_args)
4404 image = control.images['image']
4405 entries = image.GetEntries()
4406
4407 # Just check u-boot-spl, which should be expanded into two parts
4408 self.assertIn('u-boot-spl', entries)
4409 entry = entries['u-boot-spl']
4410 self.assertEqual('u-boot-spl-expanded', entry.etype)
4411 subent = entry.GetEntries()
4412 self.assertEqual(2, len(subent))
4413 self.assertIn('u-boot-spl-nodtb', subent)
4414 self.assertIn('u-boot-spl-dtb', subent)
4415
4416 def testExpandedTplNoPad(self):
4417 """Test that an expanded entry type with padding disabled in TPL"""
4418 self._SetupTplElf()
4419
4420 entry_args = {
4421 'tpl-bss-pad': '',
4422 'tpl-dtb': 'y',
4423 }
4424 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4425 entry_args=entry_args)
4426 image = control.images['image']
4427 entries = image.GetEntries()
4428 self.assertEqual(1, len(entries))
4429
4430 # We only have u-boot-tpl, which be expanded
4431 self.assertIn('u-boot-tpl', entries)
4432 entry = entries['u-boot-tpl']
4433 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4434 subent = entry.GetEntries()
4435 self.assertEqual(2, len(subent))
4436 self.assertIn('u-boot-tpl-nodtb', subent)
4437 self.assertIn('u-boot-tpl-dtb', subent)
4438
4439 def testFdtInclude(self):
4440 """Test that an Fdt is update within all binaries"""
4441 self._SetupSplElf()
4442 self._SetupTplElf()
4443
4444 # SPL has a devicetree, TPL does not
4445 self.maxDiff = None
4446 entry_args = {
4447 'spl-dtb': '1',
4448 'spl-bss-pad': 'y',
4449 'tpl-dtb': '',
4450 }
4451 # Build the image. It includes two separate devicetree binaries, each
4452 # with their own contents, but all contain the binman definition.
4453 data = self._DoReadFileDtb(
4454 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4455 update_dtb=True, entry_args=entry_args)[0]
4456 pad_len = 10
4457
4458 # Check the U-Boot dtb
4459 start = len(U_BOOT_NODTB_DATA)
4460 fdt_size = self.checkDtbSizes(data, pad_len, start)
4461
4462 # Now check SPL
4463 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4464 fdt_size = self.checkDtbSizes(data, pad_len, start)
4465
4466 # TPL has no devicetree
4467 start += fdt_size + len(U_BOOT_TPL_DATA)
4468 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004469
Simon Glass7098b7f2021-03-21 18:24:30 +13004470 def testSymbolsExpanded(self):
4471 """Test binman can assign symbols in expanded entries"""
4472 entry_args = {
4473 'spl-dtb': '1',
4474 }
4475 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4476 U_BOOT_SPL_DTB_DATA, 0x38,
4477 entry_args=entry_args, use_expanded=True)
4478
Simon Glasse1915782021-03-21 18:24:31 +13004479 def testCollection(self):
4480 """Test a collection"""
4481 data = self._DoReadFile('198_collection.dts')
4482 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4483 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4484 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4485 data)
4486
Simon Glass27a7f772021-03-21 18:24:32 +13004487 def testCollectionSection(self):
4488 """Test a collection where a section must be built first"""
4489 # Sections never have their contents when GetData() is called, but when
4490 # _BuildSectionData() is called with required=True, a section will force
4491 # building the contents, producing an error is anything is still
4492 # missing.
4493 data = self._DoReadFile('199_collection_section.dts')
4494 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4495 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4496 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4497 data)
4498
Simon Glassf427c5f2021-03-21 18:24:33 +13004499 def testAlignDefault(self):
4500 """Test that default alignment works on sections"""
4501 data = self._DoReadFile('200_align_default.dts')
4502 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4503 U_BOOT_DATA)
4504 # Special alignment for section
4505 expected += tools.GetBytes(0, 32 - len(expected))
4506 # No alignment within the nested section
4507 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4508 # Now the final piece, which should be default-aligned
4509 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4510 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004511
Simon Glassac599912017-11-12 21:52:22 -07004512if __name__ == "__main__":
4513 unittest.main()