blob: d0a1d99c0d031cd60b2550eaae6fdf4a624378a1 [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 Glass13089cc2021-04-25 08:39:32 +12001344 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001345 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001346 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1347
Simon Glass7098b7f2021-03-21 18:24:30 +13001348 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1349 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001350 """Check the image contains the expected symbol values
1351
1352 Args:
1353 dts: Device tree file to use for test
1354 base_data: Data before and after 'u-boot' section
1355 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001356 entry_args: Dict of entry args to supply to binman
1357 key: arg name
1358 value: value of that arg
1359 use_expanded: True to use expanded entries where available, e.g.
1360 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001361 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001362 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001363 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1364 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001365 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1366 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001367
Simon Glass7057d022018-10-01 21:12:47 -06001368 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001369 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1370 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001371 # The image should contain the symbols from u_boot_binman_syms.c
1372 # Note that image_pos is adjusted by the base address of the image,
1373 # which is 0x10 in our test image
1374 sym_values = struct.pack('<LQLL', 0x00,
1375 u_boot_offset + len(U_BOOT_DATA),
1376 0x10 + u_boot_offset, 0x04)
1377 expected = (sym_values + base_data[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001378 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001379 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001380 self.assertEqual(expected, data)
1381
Simon Glass31e04cb2021-03-18 20:24:56 +13001382 def testSymbols(self):
1383 """Test binman can assign symbols embedded in U-Boot"""
1384 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1385
1386 def testSymbolsNoDtb(self):
1387 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001388 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001389 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1390 0x38)
1391
Simon Glasse76a3e62018-06-01 09:38:11 -06001392 def testPackUnitAddress(self):
1393 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001394 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001395 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1396
Simon Glassa91e1152018-06-01 09:38:16 -06001397 def testSections(self):
1398 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001399 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001400 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1401 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1402 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001403 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001404
Simon Glass30732662018-06-01 09:38:20 -06001405 def testMap(self):
1406 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001407 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001408 self.assertEqual('''ImagePos Offset Size Name
140900000000 00000000 00000028 main-section
141000000000 00000000 00000010 section@0
141100000000 00000000 00000004 u-boot
141200000010 00000010 00000010 section@1
141300000010 00000000 00000004 u-boot
141400000020 00000020 00000004 section@2
141500000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001416''', map_data)
1417
Simon Glass3b78d532018-06-01 09:38:21 -06001418 def testNamePrefix(self):
1419 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001420 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001421 self.assertEqual('''ImagePos Offset Size Name
142200000000 00000000 00000028 main-section
142300000000 00000000 00000010 section@0
142400000000 00000000 00000004 ro-u-boot
142500000010 00000010 00000010 section@1
142600000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001427''', map_data)
1428
Simon Glass6ba679c2018-07-06 10:27:17 -06001429 def testUnknownContents(self):
1430 """Test that obtaining the contents works as expected"""
1431 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001432 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001433 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001434 "processing of contents: remaining ["
1435 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001436
Simon Glass2e1169f2018-07-06 10:27:19 -06001437 def testBadChangeSize(self):
1438 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001439 try:
1440 state.SetAllowEntryExpansion(False)
1441 with self.assertRaises(ValueError) as e:
1442 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001443 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001444 str(e.exception))
1445 finally:
1446 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001447
Simon Glassa87014e2018-07-06 10:27:42 -06001448 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001449 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001450 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001451 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001452 dtb = fdt.Fdt(out_dtb_fname)
1453 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001454 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001455 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001456 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001457 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001458 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001459 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001460 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001461 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001462 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001463 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001464 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001465 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001466 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001467
Simon Glasse8561af2018-08-01 15:22:37 -06001468 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001469 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001470 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001471 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001472 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001473 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001474 'size': 40
1475 }, props)
1476
1477 def testUpdateFdtBad(self):
1478 """Test that we detect when ProcessFdt never completes"""
1479 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001480 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001481 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001482 '[<binman.etype._testing.Entry__testing',
1483 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001484
Simon Glass91710b32018-07-17 13:25:32 -06001485 def testEntryArgs(self):
1486 """Test passing arguments to entries from the command line"""
1487 entry_args = {
1488 'test-str-arg': 'test1',
1489 'test-int-arg': '456',
1490 }
Simon Glass511f6582018-10-01 12:22:30 -06001491 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001492 self.assertIn('image', control.images)
1493 entry = control.images['image'].GetEntries()['_testing']
1494 self.assertEqual('test0', entry.test_str_fdt)
1495 self.assertEqual('test1', entry.test_str_arg)
1496 self.assertEqual(123, entry.test_int_fdt)
1497 self.assertEqual(456, entry.test_int_arg)
1498
1499 def testEntryArgsMissing(self):
1500 """Test missing arguments and properties"""
1501 entry_args = {
1502 'test-int-arg': '456',
1503 }
Simon Glass511f6582018-10-01 12:22:30 -06001504 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001505 entry = control.images['image'].GetEntries()['_testing']
1506 self.assertEqual('test0', entry.test_str_fdt)
1507 self.assertEqual(None, entry.test_str_arg)
1508 self.assertEqual(None, entry.test_int_fdt)
1509 self.assertEqual(456, entry.test_int_arg)
1510
1511 def testEntryArgsRequired(self):
1512 """Test missing arguments and properties"""
1513 entry_args = {
1514 'test-int-arg': '456',
1515 }
1516 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001517 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001518 self.assertIn("Node '/binman/_testing': "
1519 'Missing required properties/entry args: test-str-arg, '
1520 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001521 str(e.exception))
1522
1523 def testEntryArgsInvalidFormat(self):
1524 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001525 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1526 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001527 with self.assertRaises(ValueError) as e:
1528 self._DoBinman(*args)
1529 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1530
1531 def testEntryArgsInvalidInteger(self):
1532 """Test that an invalid entry-argument integer is detected"""
1533 entry_args = {
1534 'test-int-arg': 'abc',
1535 }
1536 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001537 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001538 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1539 "'test-int-arg' (value 'abc') to integer",
1540 str(e.exception))
1541
1542 def testEntryArgsInvalidDatatype(self):
1543 """Test that an invalid entry-argument datatype is detected
1544
1545 This test could be written in entry_test.py except that it needs
1546 access to control.entry_args, which seems more than that module should
1547 be able to see.
1548 """
1549 entry_args = {
1550 'test-bad-datatype-arg': '12',
1551 }
1552 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001553 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001554 entry_args=entry_args)
1555 self.assertIn('GetArg() internal error: Unknown data type ',
1556 str(e.exception))
1557
Simon Glass2ca52032018-07-17 13:25:33 -06001558 def testText(self):
1559 """Test for a text entry type"""
1560 entry_args = {
1561 'test-id': TEXT_DATA,
1562 'test-id2': TEXT_DATA2,
1563 'test-id3': TEXT_DATA3,
1564 }
Simon Glass511f6582018-10-01 12:22:30 -06001565 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001566 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001567 expected = (tools.ToBytes(TEXT_DATA) +
1568 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1569 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001570 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001571 self.assertEqual(expected, data)
1572
Simon Glass969616c2018-07-17 13:25:36 -06001573 def testEntryDocs(self):
1574 """Test for creation of entry documentation"""
1575 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001576 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001577 self.assertTrue(len(stdout.getvalue()) > 0)
1578
1579 def testEntryDocsMissing(self):
1580 """Test handling of missing entry documentation"""
1581 with self.assertRaises(ValueError) as e:
1582 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001583 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001584 self.assertIn('Documentation is missing for modules: u_boot',
1585 str(e.exception))
1586
Simon Glass704784b2018-07-17 13:25:38 -06001587 def testFmap(self):
1588 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001589 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001590 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001591 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1592 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001593 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001594 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001595 self.assertEqual(1, fhdr.ver_major)
1596 self.assertEqual(0, fhdr.ver_minor)
1597 self.assertEqual(0, fhdr.base)
Simon Glass82059c22021-04-03 11:05:09 +13001598 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 3
1599 self.assertEqual(16 + 16 + expect_size, 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)
Simon Glass82059c22021-04-03 11:05:09 +13001602 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001603
Simon Glass82059c22021-04-03 11:05:09 +13001604 fentry = next(fiter)
1605 self.assertEqual(b'RO_U_BOOT', fentry.name)
1606 self.assertEqual(0, fentry.offset)
1607 self.assertEqual(4, fentry.size)
1608 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001609
Simon Glass82059c22021-04-03 11:05:09 +13001610 fentry = next(fiter)
1611 self.assertEqual(b'RW_U_BOOT', fentry.name)
1612 self.assertEqual(16, fentry.offset)
1613 self.assertEqual(4, fentry.size)
1614 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001615
Simon Glass82059c22021-04-03 11:05:09 +13001616 fentry = next(fiter)
1617 self.assertEqual(b'FMAP', fentry.name)
1618 self.assertEqual(32, fentry.offset)
1619 self.assertEqual(expect_size, fentry.size)
1620 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001621
Simon Glassdb168d42018-07-17 13:25:39 -06001622 def testBlobNamedByArg(self):
1623 """Test we can add a blob with the filename coming from an entry arg"""
1624 entry_args = {
1625 'cros-ec-rw-path': 'ecrw.bin',
1626 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001627 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001628
Simon Glass53f53992018-07-17 13:25:40 -06001629 def testFill(self):
1630 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001631 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001632 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001633 self.assertEqual(expected, data)
1634
1635 def testFillNoSize(self):
1636 """Test for an fill entry type with no size"""
1637 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001638 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001639 self.assertIn("'fill' entry must have a size property",
1640 str(e.exception))
1641
Simon Glassc1ae83c2018-07-17 13:25:44 -06001642 def _HandleGbbCommand(self, pipe_list):
1643 """Fake calls to the futility utility"""
1644 if pipe_list[0][0] == 'futility':
1645 fname = pipe_list[0][-1]
1646 # Append our GBB data to the file, which will happen every time the
1647 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001648 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001649 fd.write(GBB_DATA)
1650 return command.CommandResult()
1651
1652 def testGbb(self):
1653 """Test for the Chromium OS Google Binary Block"""
1654 command.test_result = self._HandleGbbCommand
1655 entry_args = {
1656 'keydir': 'devkeys',
1657 'bmpblk': 'bmpblk.bin',
1658 }
Simon Glass511f6582018-10-01 12:22:30 -06001659 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001660
1661 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001662 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1663 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001664 self.assertEqual(expected, data)
1665
1666 def testGbbTooSmall(self):
1667 """Test for the Chromium OS Google Binary Block being large enough"""
1668 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001669 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001670 self.assertIn("Node '/binman/gbb': GBB is too small",
1671 str(e.exception))
1672
1673 def testGbbNoSize(self):
1674 """Test for the Chromium OS Google Binary Block having a size"""
1675 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001676 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001677 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1678 str(e.exception))
1679
Simon Glass5c350162018-07-17 13:25:47 -06001680 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001681 """Fake calls to the futility utility
1682
1683 The expected pipe is:
1684
1685 [('futility', 'vbutil_firmware', '--vblock',
1686 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1687 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1688 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1689 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1690
1691 This writes to the output file (here, 'vblock.vblock'). If
1692 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1693 of the input data (here, 'input.vblock').
1694 """
Simon Glass5c350162018-07-17 13:25:47 -06001695 if pipe_list[0][0] == 'futility':
1696 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001697 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001698 if self._hash_data:
1699 infile = pipe_list[0][11]
1700 m = hashlib.sha256()
1701 data = tools.ReadFile(infile)
1702 m.update(data)
1703 fd.write(m.digest())
1704 else:
1705 fd.write(VBLOCK_DATA)
1706
Simon Glass5c350162018-07-17 13:25:47 -06001707 return command.CommandResult()
1708
1709 def testVblock(self):
1710 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001711 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001712 command.test_result = self._HandleVblockCommand
1713 entry_args = {
1714 'keydir': 'devkeys',
1715 }
Simon Glass511f6582018-10-01 12:22:30 -06001716 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001717 entry_args=entry_args)
1718 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1719 self.assertEqual(expected, data)
1720
1721 def testVblockNoContent(self):
1722 """Test we detect a vblock which has no content to sign"""
1723 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001724 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001725 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001726 'property', str(e.exception))
1727
1728 def testVblockBadPhandle(self):
1729 """Test that we detect a vblock with an invalid phandle in contents"""
1730 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001731 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001732 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1733 '1000', str(e.exception))
1734
1735 def testVblockBadEntry(self):
1736 """Test that we detect an entry that points to a non-entry"""
1737 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001738 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001739 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1740 "'other'", str(e.exception))
1741
Simon Glass220c6222021-01-06 21:35:17 -07001742 def testVblockContent(self):
1743 """Test that the vblock signs the right data"""
1744 self._hash_data = True
1745 command.test_result = self._HandleVblockCommand
1746 entry_args = {
1747 'keydir': 'devkeys',
1748 }
1749 data = self._DoReadFileDtb(
1750 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1751 entry_args=entry_args)[0]
1752 hashlen = 32 # SHA256 hash is 32 bytes
1753 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1754 hashval = data[-hashlen:]
1755 dtb = data[len(U_BOOT_DATA):-hashlen]
1756
1757 expected_data = U_BOOT_DATA + dtb
1758
1759 # The hashval should be a hash of the dtb
1760 m = hashlib.sha256()
1761 m.update(expected_data)
1762 expected_hashval = m.digest()
1763 self.assertEqual(expected_hashval, hashval)
1764
Simon Glass8425a1f2018-07-17 13:25:48 -06001765 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001766 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001767 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001768 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001769 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001770 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1771
Simon Glass24b97442018-07-17 13:25:51 -06001772 def testUsesPos(self):
1773 """Test that the 'pos' property cannot be used anymore"""
1774 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001775 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001776 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1777 "'pos'", str(e.exception))
1778
Simon Glass274bf092018-09-14 04:57:08 -06001779 def testFillZero(self):
1780 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001781 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001782 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001783
Simon Glass267de432018-09-14 04:57:09 -06001784 def testTextMissing(self):
1785 """Test for a text entry type where there is no text"""
1786 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001787 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001788 self.assertIn("Node '/binman/text': No value provided for text label "
1789 "'test-id'", str(e.exception))
1790
Simon Glassed40e962018-09-14 04:57:10 -06001791 def testPackStart16Tpl(self):
1792 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001793 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001794 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1795
Simon Glass3b376c32018-09-14 04:57:12 -06001796 def testSelectImage(self):
1797 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001798 expected = 'Skipping images: image1'
1799
1800 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001801 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001802 with test_util.capture_sys_output() as (stdout, stderr):
1803 retcode = self._DoTestFile('006_dual_image.dts',
1804 verbosity=verbosity,
1805 images=['image2'])
1806 self.assertEqual(0, retcode)
1807 if verbosity:
1808 self.assertIn(expected, stdout.getvalue())
1809 else:
1810 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001811
Simon Glassb4595d82019-04-25 21:58:34 -06001812 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1813 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001814 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001815
Simon Glasse219aa42018-09-14 04:57:24 -06001816 def testUpdateFdtAll(self):
1817 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001818 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001819
1820 base_expected = {
1821 'section:image-pos': 0,
1822 'u-boot-tpl-dtb:size': 513,
1823 'u-boot-spl-dtb:size': 513,
1824 'u-boot-spl-dtb:offset': 493,
1825 'image-pos': 0,
1826 'section/u-boot-dtb:image-pos': 0,
1827 'u-boot-spl-dtb:image-pos': 493,
1828 'section/u-boot-dtb:size': 493,
1829 'u-boot-tpl-dtb:image-pos': 1006,
1830 'section/u-boot-dtb:offset': 0,
1831 'section:size': 493,
1832 'offset': 0,
1833 'section:offset': 0,
1834 'u-boot-tpl-dtb:offset': 1006,
1835 'size': 1519
1836 }
1837
1838 # We expect three device-tree files in the output, one after the other.
1839 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1840 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1841 # main U-Boot tree. All three should have the same postions and offset.
1842 start = 0
1843 for item in ['', 'spl', 'tpl']:
1844 dtb = fdt.Fdt.FromData(data[start:])
1845 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001846 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1847 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001848 expected = dict(base_expected)
1849 if item:
1850 expected[item] = 0
1851 self.assertEqual(expected, props)
1852 start += dtb._fdt_obj.totalsize()
1853
1854 def testUpdateFdtOutput(self):
1855 """Test that output DTB files are updated"""
1856 try:
Simon Glass511f6582018-10-01 12:22:30 -06001857 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001858 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1859
1860 # Unfortunately, compiling a source file always results in a file
1861 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001862 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001863 # binman as a file called u-boot.dtb. To fix this, copy the file
1864 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001865 start = 0
1866 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1867 'tpl/u-boot-tpl.dtb.out']:
1868 dtb = fdt.Fdt.FromData(data[start:])
1869 size = dtb._fdt_obj.totalsize()
1870 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1871 outdata = tools.ReadFile(pathname)
1872 name = os.path.split(fname)[0]
1873
1874 if name:
1875 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1876 else:
1877 orig_indata = dtb_data
1878 self.assertNotEqual(outdata, orig_indata,
1879 "Expected output file '%s' be updated" % pathname)
1880 self.assertEqual(outdata, data[start:start + size],
1881 "Expected output file '%s' to match output image" %
1882 pathname)
1883 start += size
1884 finally:
1885 self._ResetDtbs()
1886
Simon Glass7ba33592018-09-14 04:57:26 -06001887 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001888 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001889
1890 def testCompress(self):
1891 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001892 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001893 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001894 use_real_dtb=True, update_dtb=True)
1895 dtb = fdt.Fdt(out_dtb_fname)
1896 dtb.Scan()
1897 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1898 orig = self._decompress(data)
1899 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001900
1901 # Do a sanity check on various fields
1902 image = control.images['image']
1903 entries = image.GetEntries()
1904 self.assertEqual(1, len(entries))
1905
1906 entry = entries['blob']
1907 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1908 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1909 orig = self._decompress(entry.data)
1910 self.assertEqual(orig, entry.uncomp_data)
1911
Simon Glass72eeff12020-10-26 17:40:16 -06001912 self.assertEqual(image.data, entry.data)
1913
Simon Glass7ba33592018-09-14 04:57:26 -06001914 expected = {
1915 'blob:uncomp-size': len(COMPRESS_DATA),
1916 'blob:size': len(data),
1917 'size': len(data),
1918 }
1919 self.assertEqual(expected, props)
1920
Simon Glassac6328c2018-09-14 04:57:28 -06001921 def testFiles(self):
1922 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001923 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001924 self.assertEqual(FILES_DATA, data)
1925
1926 def testFilesCompress(self):
1927 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001928 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001929 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001930
1931 image = control.images['image']
1932 entries = image.GetEntries()
1933 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001934 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001935
Simon Glass303f62f2019-05-17 22:00:46 -06001936 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001937 for i in range(1, 3):
1938 key = '%d.dat' % i
1939 start = entries[key].image_pos
1940 len = entries[key].size
1941 chunk = data[start:start + len]
1942 orig += self._decompress(chunk)
1943
1944 self.assertEqual(FILES_DATA, orig)
1945
1946 def testFilesMissing(self):
1947 """Test missing files"""
1948 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001949 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001950 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1951 'no files', str(e.exception))
1952
1953 def testFilesNoPattern(self):
1954 """Test missing files"""
1955 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001956 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001957 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1958 str(e.exception))
1959
Simon Glassfa79a812018-09-14 04:57:29 -06001960 def testExpandSize(self):
1961 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001962 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001963 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001964 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
1965 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
1966 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
1967 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06001968 self.assertEqual(expect, data)
1969 self.assertEqual('''ImagePos Offset Size Name
197000000000 00000000 00000028 main-section
197100000000 00000000 00000008 fill
197200000008 00000008 00000004 u-boot
19730000000c 0000000c 00000004 section
19740000000c 00000000 00000003 intel-mrc
197500000010 00000010 00000004 u-boot2
197600000014 00000014 0000000c section2
197700000014 00000000 00000008 fill
19780000001c 00000008 00000004 u-boot
197900000020 00000020 00000008 fill2
1980''', map_data)
1981
1982 def testExpandSizeBad(self):
1983 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06001984 with test_util.capture_sys_output() as (stdout, stderr):
1985 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001986 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06001987 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
1988 'expanding entry', str(e.exception))
1989
Simon Glassae7cf032018-09-14 04:57:31 -06001990 def testHash(self):
1991 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001992 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06001993 use_real_dtb=True, update_dtb=True)
1994 dtb = fdt.Fdt(out_dtb_fname)
1995 dtb.Scan()
1996 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
1997 m = hashlib.sha256()
1998 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001999 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002000
2001 def testHashNoAlgo(self):
2002 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002003 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002004 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2005 'hash node', str(e.exception))
2006
2007 def testHashBadAlgo(self):
2008 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002009 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002010 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2011 str(e.exception))
2012
2013 def testHashSection(self):
2014 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002015 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002016 use_real_dtb=True, update_dtb=True)
2017 dtb = fdt.Fdt(out_dtb_fname)
2018 dtb.Scan()
2019 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2020 m = hashlib.sha256()
2021 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002022 m.update(tools.GetBytes(ord('a'), 16))
2023 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002024
Simon Glass3fb4f422018-09-14 04:57:32 -06002025 def testPackUBootTplMicrocode(self):
2026 """Test that x86 microcode can be handled correctly in TPL
2027
2028 We expect to see the following in the image, in order:
2029 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2030 place
2031 u-boot-tpl.dtb with the microcode removed
2032 the microcode
2033 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002034 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002035 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002036 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002037 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2038 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002039
Simon Glassc64aea52018-09-14 04:57:34 -06002040 def testFmapX86(self):
2041 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002042 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002043 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06002044 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002045 self.assertEqual(expected, data[:32])
2046 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2047
2048 self.assertEqual(0x100, fhdr.image_size)
2049
2050 self.assertEqual(0, fentries[0].offset)
2051 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002052 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002053
2054 self.assertEqual(4, fentries[1].offset)
2055 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002056 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002057
2058 self.assertEqual(32, fentries[2].offset)
2059 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2060 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002061 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002062
2063 def testFmapX86Section(self):
2064 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002065 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06002066 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002067 self.assertEqual(expected, data[:32])
2068 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2069
2070 self.assertEqual(0x100, fhdr.image_size)
Simon Glass82059c22021-04-03 11:05:09 +13002071 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 3
2072 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002073
Simon Glass82059c22021-04-03 11:05:09 +13002074 fentry = next(fiter)
2075 self.assertEqual(b'U_BOOT', fentry.name)
2076 self.assertEqual(0, fentry.offset)
2077 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002078
Simon Glass82059c22021-04-03 11:05:09 +13002079 fentry = next(fiter)
2080 self.assertEqual(b'INTEL_MRC', fentry.name)
2081 self.assertEqual(4, fentry.offset)
2082 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002083
Simon Glass82059c22021-04-03 11:05:09 +13002084 fentry = next(fiter)
2085 self.assertEqual(b'FMAP', fentry.name)
2086 self.assertEqual(36, fentry.offset)
2087 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002088
Simon Glassb1714232018-09-14 04:57:35 -06002089 def testElf(self):
2090 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002091 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002092 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002093 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002094 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002095 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002096
Simon Glass0d673792019-07-08 13:18:25 -06002097 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002098 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002099 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002100 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002101 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002102 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002103
Simon Glasscd817d52018-09-14 04:57:36 -06002104 def testPackOverlapMap(self):
2105 """Test that overlapping regions are detected"""
2106 with test_util.capture_sys_output() as (stdout, stderr):
2107 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002108 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06002109 map_fname = tools.GetOutputFilename('image.map')
2110 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2111 stdout.getvalue())
2112
2113 # We should not get an inmage, but there should be a map file
2114 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2115 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06002116 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002117 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002118<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002119<none> 00000000 00000004 u-boot
2120<none> 00000003 00000004 u-boot-align
2121''', map_data)
2122
Simon Glass0d673792019-07-08 13:18:25 -06002123 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002124 """Test that an image with an Intel Reference code binary works"""
2125 data = self._DoReadFile('100_intel_refcode.dts')
2126 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2127
Simon Glasseb023b32019-04-25 21:58:39 -06002128 def testSectionOffset(self):
2129 """Tests use of a section with an offset"""
2130 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2131 map=True)
2132 self.assertEqual('''ImagePos Offset Size Name
213300000000 00000000 00000038 main-section
213400000004 00000004 00000010 section@0
213500000004 00000000 00000004 u-boot
213600000018 00000018 00000010 section@1
213700000018 00000000 00000004 u-boot
21380000002c 0000002c 00000004 section@2
21390000002c 00000000 00000004 u-boot
2140''', map_data)
2141 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06002142 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2143 tools.GetBytes(0x21, 12) +
2144 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2145 tools.GetBytes(0x61, 12) +
2146 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2147 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002148
Simon Glass1de34482019-07-08 13:18:53 -06002149 def testCbfsRaw(self):
2150 """Test base handling of a Coreboot Filesystem (CBFS)
2151
2152 The exact contents of the CBFS is verified by similar tests in
2153 cbfs_util_test.py. The tests here merely check that the files added to
2154 the CBFS can be found in the final image.
2155 """
2156 data = self._DoReadFile('102_cbfs_raw.dts')
2157 size = 0xb0
2158
2159 cbfs = cbfs_util.CbfsReader(data)
2160 self.assertEqual(size, cbfs.rom_size)
2161
2162 self.assertIn('u-boot-dtb', cbfs.files)
2163 cfile = cbfs.files['u-boot-dtb']
2164 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2165
2166 def testCbfsArch(self):
2167 """Test on non-x86 architecture"""
2168 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2169 size = 0x100
2170
2171 cbfs = cbfs_util.CbfsReader(data)
2172 self.assertEqual(size, cbfs.rom_size)
2173
2174 self.assertIn('u-boot-dtb', cbfs.files)
2175 cfile = cbfs.files['u-boot-dtb']
2176 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2177
2178 def testCbfsStage(self):
2179 """Tests handling of a Coreboot Filesystem (CBFS)"""
2180 if not elf.ELF_TOOLS:
2181 self.skipTest('Python elftools not available')
2182 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2183 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2184 size = 0xb0
2185
2186 data = self._DoReadFile('104_cbfs_stage.dts')
2187 cbfs = cbfs_util.CbfsReader(data)
2188 self.assertEqual(size, cbfs.rom_size)
2189
2190 self.assertIn('u-boot', cbfs.files)
2191 cfile = cbfs.files['u-boot']
2192 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2193
2194 def testCbfsRawCompress(self):
2195 """Test handling of compressing raw files"""
2196 self._CheckLz4()
2197 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2198 size = 0x140
2199
2200 cbfs = cbfs_util.CbfsReader(data)
2201 self.assertIn('u-boot', cbfs.files)
2202 cfile = cbfs.files['u-boot']
2203 self.assertEqual(COMPRESS_DATA, cfile.data)
2204
2205 def testCbfsBadArch(self):
2206 """Test handling of a bad architecture"""
2207 with self.assertRaises(ValueError) as e:
2208 self._DoReadFile('106_cbfs_bad_arch.dts')
2209 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2210
2211 def testCbfsNoSize(self):
2212 """Test handling of a missing size property"""
2213 with self.assertRaises(ValueError) as e:
2214 self._DoReadFile('107_cbfs_no_size.dts')
2215 self.assertIn('entry must have a size property', str(e.exception))
2216
2217 def testCbfsNoCOntents(self):
2218 """Test handling of a CBFS entry which does not provide contentsy"""
2219 with self.assertRaises(ValueError) as e:
2220 self._DoReadFile('108_cbfs_no_contents.dts')
2221 self.assertIn('Could not complete processing of contents',
2222 str(e.exception))
2223
2224 def testCbfsBadCompress(self):
2225 """Test handling of a bad architecture"""
2226 with self.assertRaises(ValueError) as e:
2227 self._DoReadFile('109_cbfs_bad_compress.dts')
2228 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2229 str(e.exception))
2230
2231 def testCbfsNamedEntries(self):
2232 """Test handling of named entries"""
2233 data = self._DoReadFile('110_cbfs_name.dts')
2234
2235 cbfs = cbfs_util.CbfsReader(data)
2236 self.assertIn('FRED', cbfs.files)
2237 cfile1 = cbfs.files['FRED']
2238 self.assertEqual(U_BOOT_DATA, cfile1.data)
2239
2240 self.assertIn('hello', cbfs.files)
2241 cfile2 = cbfs.files['hello']
2242 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2243
Simon Glass759af872019-07-08 13:18:54 -06002244 def _SetupIfwi(self, fname):
2245 """Set up to run an IFWI test
2246
2247 Args:
2248 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2249 """
2250 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002251 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002252
2253 # Intel Integrated Firmware Image (IFWI) file
2254 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2255 data = fd.read()
2256 TestFunctional._MakeInputFile(fname,data)
2257
2258 def _CheckIfwi(self, data):
2259 """Check that an image with an IFWI contains the correct output
2260
2261 Args:
2262 data: Conents of output file
2263 """
2264 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2265 if data[:0x1000] != expected_desc:
2266 self.fail('Expected descriptor binary at start of image')
2267
2268 # We expect to find the TPL wil in subpart IBBP entry IBBL
2269 image_fname = tools.GetOutputFilename('image.bin')
2270 tpl_fname = tools.GetOutputFilename('tpl.out')
2271 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2272 subpart='IBBP', entry_name='IBBL')
2273
2274 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002275 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002276
2277 def testPackX86RomIfwi(self):
2278 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2279 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002280 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002281 self._CheckIfwi(data)
2282
2283 def testPackX86RomIfwiNoDesc(self):
2284 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2285 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002286 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002287 self._CheckIfwi(data)
2288
2289 def testPackX86RomIfwiNoData(self):
2290 """Test that an x86 ROM with IFWI handles missing data"""
2291 self._SetupIfwi('ifwi.bin')
2292 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002293 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002294 self.assertIn('Could not complete processing of contents',
2295 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002296
Simon Glassc2f1aed2019-07-08 13:18:56 -06002297 def testCbfsOffset(self):
2298 """Test a CBFS with files at particular offsets
2299
2300 Like all CFBS tests, this is just checking the logic that calls
2301 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2302 """
2303 data = self._DoReadFile('114_cbfs_offset.dts')
2304 size = 0x200
2305
2306 cbfs = cbfs_util.CbfsReader(data)
2307 self.assertEqual(size, cbfs.rom_size)
2308
2309 self.assertIn('u-boot', cbfs.files)
2310 cfile = cbfs.files['u-boot']
2311 self.assertEqual(U_BOOT_DATA, cfile.data)
2312 self.assertEqual(0x40, cfile.cbfs_offset)
2313
2314 self.assertIn('u-boot-dtb', cbfs.files)
2315 cfile2 = cbfs.files['u-boot-dtb']
2316 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2317 self.assertEqual(0x140, cfile2.cbfs_offset)
2318
Simon Glass0f621332019-07-08 14:25:27 -06002319 def testFdtmap(self):
2320 """Test an FDT map can be inserted in the image"""
2321 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2322 fdtmap_data = data[len(U_BOOT_DATA):]
2323 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002324 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002325 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2326
2327 fdt_data = fdtmap_data[16:]
2328 dtb = fdt.Fdt.FromData(fdt_data)
2329 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002330 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002331 self.assertEqual({
2332 'image-pos': 0,
2333 'offset': 0,
2334 'u-boot:offset': 0,
2335 'u-boot:size': len(U_BOOT_DATA),
2336 'u-boot:image-pos': 0,
2337 'fdtmap:image-pos': 4,
2338 'fdtmap:offset': 4,
2339 'fdtmap:size': len(fdtmap_data),
2340 'size': len(data),
2341 }, props)
2342
2343 def testFdtmapNoMatch(self):
2344 """Check handling of an FDT map when the section cannot be found"""
2345 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2346
2347 # Mangle the section name, which should cause a mismatch between the
2348 # correct FDT path and the one expected by the section
2349 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002350 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002351 entries = image.GetEntries()
2352 fdtmap = entries['fdtmap']
2353 with self.assertRaises(ValueError) as e:
2354 fdtmap._GetFdtmap()
2355 self.assertIn("Cannot locate node for path '/binman-suffix'",
2356 str(e.exception))
2357
Simon Glasscec34ba2019-07-08 14:25:28 -06002358 def testFdtmapHeader(self):
2359 """Test an FDT map and image header can be inserted in the image"""
2360 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2361 fdtmap_pos = len(U_BOOT_DATA)
2362 fdtmap_data = data[fdtmap_pos:]
2363 fdt_data = fdtmap_data[16:]
2364 dtb = fdt.Fdt.FromData(fdt_data)
2365 fdt_size = dtb.GetFdtObj().totalsize()
2366 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002367 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002368 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2369 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2370
2371 def testFdtmapHeaderStart(self):
2372 """Test an image header can be inserted at the image start"""
2373 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2374 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2375 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002376 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002377 offset = struct.unpack('<I', hdr_data[4:])[0]
2378 self.assertEqual(fdtmap_pos, offset)
2379
2380 def testFdtmapHeaderPos(self):
2381 """Test an image header can be inserted at a chosen position"""
2382 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2383 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2384 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002385 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002386 offset = struct.unpack('<I', hdr_data[4:])[0]
2387 self.assertEqual(fdtmap_pos, offset)
2388
2389 def testHeaderMissingFdtmap(self):
2390 """Test an image header requires an fdtmap"""
2391 with self.assertRaises(ValueError) as e:
2392 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2393 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2394 str(e.exception))
2395
2396 def testHeaderNoLocation(self):
2397 """Test an image header with a no specified location is detected"""
2398 with self.assertRaises(ValueError) as e:
2399 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2400 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2401 str(e.exception))
2402
Simon Glasse61b6f62019-07-08 14:25:37 -06002403 def testEntryExpand(self):
2404 """Test expanding an entry after it is packed"""
2405 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002406 self.assertEqual(b'aaa', data[:3])
2407 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2408 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002409
2410 def testEntryExpandBad(self):
2411 """Test expanding an entry after it is packed, twice"""
2412 with self.assertRaises(ValueError) as e:
2413 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002414 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002415 str(e.exception))
2416
2417 def testEntryExpandSection(self):
2418 """Test expanding an entry within a section after it is packed"""
2419 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002420 self.assertEqual(b'aaa', data[:3])
2421 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2422 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002423
Simon Glass90d29682019-07-08 14:25:38 -06002424 def testCompressDtb(self):
2425 """Test that compress of device-tree files is supported"""
2426 self._CheckLz4()
2427 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2428 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2429 comp_data = data[len(U_BOOT_DATA):]
2430 orig = self._decompress(comp_data)
2431 dtb = fdt.Fdt.FromData(orig)
2432 dtb.Scan()
2433 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2434 expected = {
2435 'u-boot:size': len(U_BOOT_DATA),
2436 'u-boot-dtb:uncomp-size': len(orig),
2437 'u-boot-dtb:size': len(comp_data),
2438 'size': len(data),
2439 }
2440 self.assertEqual(expected, props)
2441
Simon Glass151bbbf2019-07-08 14:25:41 -06002442 def testCbfsUpdateFdt(self):
2443 """Test that we can update the device tree with CBFS offset/size info"""
2444 self._CheckLz4()
2445 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2446 update_dtb=True)
2447 dtb = fdt.Fdt(out_dtb_fname)
2448 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002449 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002450 del props['cbfs/u-boot:size']
2451 self.assertEqual({
2452 'offset': 0,
2453 'size': len(data),
2454 'image-pos': 0,
2455 'cbfs:offset': 0,
2456 'cbfs:size': len(data),
2457 'cbfs:image-pos': 0,
2458 'cbfs/u-boot:offset': 0x38,
2459 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2460 'cbfs/u-boot:image-pos': 0x38,
2461 'cbfs/u-boot-dtb:offset': 0xb8,
2462 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2463 'cbfs/u-boot-dtb:image-pos': 0xb8,
2464 }, props)
2465
Simon Glass3c9b4f22019-07-08 14:25:42 -06002466 def testCbfsBadType(self):
2467 """Test an image header with a no specified location is detected"""
2468 with self.assertRaises(ValueError) as e:
2469 self._DoReadFile('126_cbfs_bad_type.dts')
2470 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2471
Simon Glass6b156f82019-07-08 14:25:43 -06002472 def testList(self):
2473 """Test listing the files in an image"""
2474 self._CheckLz4()
2475 data = self._DoReadFile('127_list.dts')
2476 image = control.images['image']
2477 entries = image.BuildEntryList()
2478 self.assertEqual(7, len(entries))
2479
2480 ent = entries[0]
2481 self.assertEqual(0, ent.indent)
2482 self.assertEqual('main-section', ent.name)
2483 self.assertEqual('section', ent.etype)
2484 self.assertEqual(len(data), ent.size)
2485 self.assertEqual(0, ent.image_pos)
2486 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002487 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002488
2489 ent = entries[1]
2490 self.assertEqual(1, ent.indent)
2491 self.assertEqual('u-boot', ent.name)
2492 self.assertEqual('u-boot', ent.etype)
2493 self.assertEqual(len(U_BOOT_DATA), ent.size)
2494 self.assertEqual(0, ent.image_pos)
2495 self.assertEqual(None, ent.uncomp_size)
2496 self.assertEqual(0, ent.offset)
2497
2498 ent = entries[2]
2499 self.assertEqual(1, ent.indent)
2500 self.assertEqual('section', ent.name)
2501 self.assertEqual('section', ent.etype)
2502 section_size = ent.size
2503 self.assertEqual(0x100, ent.image_pos)
2504 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002505 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002506
2507 ent = entries[3]
2508 self.assertEqual(2, ent.indent)
2509 self.assertEqual('cbfs', ent.name)
2510 self.assertEqual('cbfs', ent.etype)
2511 self.assertEqual(0x400, ent.size)
2512 self.assertEqual(0x100, ent.image_pos)
2513 self.assertEqual(None, ent.uncomp_size)
2514 self.assertEqual(0, ent.offset)
2515
2516 ent = entries[4]
2517 self.assertEqual(3, ent.indent)
2518 self.assertEqual('u-boot', ent.name)
2519 self.assertEqual('u-boot', ent.etype)
2520 self.assertEqual(len(U_BOOT_DATA), ent.size)
2521 self.assertEqual(0x138, ent.image_pos)
2522 self.assertEqual(None, ent.uncomp_size)
2523 self.assertEqual(0x38, ent.offset)
2524
2525 ent = entries[5]
2526 self.assertEqual(3, ent.indent)
2527 self.assertEqual('u-boot-dtb', ent.name)
2528 self.assertEqual('text', ent.etype)
2529 self.assertGreater(len(COMPRESS_DATA), ent.size)
2530 self.assertEqual(0x178, ent.image_pos)
2531 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2532 self.assertEqual(0x78, ent.offset)
2533
2534 ent = entries[6]
2535 self.assertEqual(2, ent.indent)
2536 self.assertEqual('u-boot-dtb', ent.name)
2537 self.assertEqual('u-boot-dtb', ent.etype)
2538 self.assertEqual(0x500, ent.image_pos)
2539 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2540 dtb_size = ent.size
2541 # Compressing this data expands it since headers are added
2542 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2543 self.assertEqual(0x400, ent.offset)
2544
2545 self.assertEqual(len(data), 0x100 + section_size)
2546 self.assertEqual(section_size, 0x400 + dtb_size)
2547
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002548 def testFindFdtmap(self):
2549 """Test locating an FDT map in an image"""
2550 self._CheckLz4()
2551 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2552 image = control.images['image']
2553 entries = image.GetEntries()
2554 entry = entries['fdtmap']
2555 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2556
2557 def testFindFdtmapMissing(self):
2558 """Test failing to locate an FDP map"""
2559 data = self._DoReadFile('005_simple.dts')
2560 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2561
Simon Glassed39a3c2019-07-08 14:25:45 -06002562 def testFindImageHeader(self):
2563 """Test locating a image header"""
2564 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002565 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002566 image = control.images['image']
2567 entries = image.GetEntries()
2568 entry = entries['fdtmap']
2569 # The header should point to the FDT map
2570 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2571
2572 def testFindImageHeaderStart(self):
2573 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002574 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002575 image = control.images['image']
2576 entries = image.GetEntries()
2577 entry = entries['fdtmap']
2578 # The header should point to the FDT map
2579 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2580
2581 def testFindImageHeaderMissing(self):
2582 """Test failing to locate an image header"""
2583 data = self._DoReadFile('005_simple.dts')
2584 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2585
Simon Glassb8424fa2019-07-08 14:25:46 -06002586 def testReadImage(self):
2587 """Test reading an image and accessing its FDT map"""
2588 self._CheckLz4()
2589 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2590 image_fname = tools.GetOutputFilename('image.bin')
2591 orig_image = control.images['image']
2592 image = Image.FromFile(image_fname)
2593 self.assertEqual(orig_image.GetEntries().keys(),
2594 image.GetEntries().keys())
2595
2596 orig_entry = orig_image.GetEntries()['fdtmap']
2597 entry = image.GetEntries()['fdtmap']
2598 self.assertEquals(orig_entry.offset, entry.offset)
2599 self.assertEquals(orig_entry.size, entry.size)
2600 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2601
2602 def testReadImageNoHeader(self):
2603 """Test accessing an image's FDT map without an image header"""
2604 self._CheckLz4()
2605 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2606 image_fname = tools.GetOutputFilename('image.bin')
2607 image = Image.FromFile(image_fname)
2608 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002609 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002610
2611 def testReadImageFail(self):
2612 """Test failing to read an image image's FDT map"""
2613 self._DoReadFile('005_simple.dts')
2614 image_fname = tools.GetOutputFilename('image.bin')
2615 with self.assertRaises(ValueError) as e:
2616 image = Image.FromFile(image_fname)
2617 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002618
Simon Glassb2fd11d2019-07-08 14:25:48 -06002619 def testListCmd(self):
2620 """Test listing the files in an image using an Fdtmap"""
2621 self._CheckLz4()
2622 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2623
2624 # lz4 compression size differs depending on the version
2625 image = control.images['image']
2626 entries = image.GetEntries()
2627 section_size = entries['section'].size
2628 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2629 fdtmap_offset = entries['fdtmap'].offset
2630
Simon Glassb3d6fc72019-07-20 12:24:10 -06002631 try:
2632 tmpdir, updated_fname = self._SetupImageInTmpdir()
2633 with test_util.capture_sys_output() as (stdout, stderr):
2634 self._DoBinman('ls', '-i', updated_fname)
2635 finally:
2636 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002637 lines = stdout.getvalue().splitlines()
2638 expected = [
2639'Name Image-pos Size Entry-type Offset Uncomp-size',
2640'----------------------------------------------------------------------',
2641'main-section 0 c00 section 0',
2642' u-boot 0 4 u-boot 0',
2643' section 100 %x section 100' % section_size,
2644' cbfs 100 400 cbfs 0',
2645' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002646' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002647' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002648' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002649 (fdtmap_offset, fdtmap_offset),
2650' image-header bf8 8 image-header bf8',
2651 ]
2652 self.assertEqual(expected, lines)
2653
2654 def testListCmdFail(self):
2655 """Test failing to list an image"""
2656 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002657 try:
2658 tmpdir, updated_fname = self._SetupImageInTmpdir()
2659 with self.assertRaises(ValueError) as e:
2660 self._DoBinman('ls', '-i', updated_fname)
2661 finally:
2662 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002663 self.assertIn("Cannot find FDT map in image", str(e.exception))
2664
2665 def _RunListCmd(self, paths, expected):
2666 """List out entries and check the result
2667
2668 Args:
2669 paths: List of paths to pass to the list command
2670 expected: Expected list of filenames to be returned, in order
2671 """
2672 self._CheckLz4()
2673 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2674 image_fname = tools.GetOutputFilename('image.bin')
2675 image = Image.FromFile(image_fname)
2676 lines = image.GetListEntries(paths)[1]
2677 files = [line[0].strip() for line in lines[1:]]
2678 self.assertEqual(expected, files)
2679
2680 def testListCmdSection(self):
2681 """Test listing the files in a section"""
2682 self._RunListCmd(['section'],
2683 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2684
2685 def testListCmdFile(self):
2686 """Test listing a particular file"""
2687 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2688
2689 def testListCmdWildcard(self):
2690 """Test listing a wildcarded file"""
2691 self._RunListCmd(['*boot*'],
2692 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2693
2694 def testListCmdWildcardMulti(self):
2695 """Test listing a wildcarded file"""
2696 self._RunListCmd(['*cb*', '*head*'],
2697 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2698
2699 def testListCmdEmpty(self):
2700 """Test listing a wildcarded file"""
2701 self._RunListCmd(['nothing'], [])
2702
2703 def testListCmdPath(self):
2704 """Test listing the files in a sub-entry of a section"""
2705 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2706
Simon Glass4c613bf2019-07-08 14:25:50 -06002707 def _RunExtractCmd(self, entry_name, decomp=True):
2708 """Extract an entry from an image
2709
2710 Args:
2711 entry_name: Entry name to extract
2712 decomp: True to decompress the data if compressed, False to leave
2713 it in its raw uncompressed format
2714
2715 Returns:
2716 data from entry
2717 """
2718 self._CheckLz4()
2719 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2720 image_fname = tools.GetOutputFilename('image.bin')
2721 return control.ReadEntry(image_fname, entry_name, decomp)
2722
2723 def testExtractSimple(self):
2724 """Test extracting a single file"""
2725 data = self._RunExtractCmd('u-boot')
2726 self.assertEqual(U_BOOT_DATA, data)
2727
Simon Glass980a2842019-07-08 14:25:52 -06002728 def testExtractSection(self):
2729 """Test extracting the files in a section"""
2730 data = self._RunExtractCmd('section')
2731 cbfs_data = data[:0x400]
2732 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002733 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002734 dtb_data = data[0x400:]
2735 dtb = self._decompress(dtb_data)
2736 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2737
2738 def testExtractCompressed(self):
2739 """Test extracting compressed data"""
2740 data = self._RunExtractCmd('section/u-boot-dtb')
2741 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2742
2743 def testExtractRaw(self):
2744 """Test extracting compressed data without decompressing it"""
2745 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2746 dtb = self._decompress(data)
2747 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2748
2749 def testExtractCbfs(self):
2750 """Test extracting CBFS data"""
2751 data = self._RunExtractCmd('section/cbfs/u-boot')
2752 self.assertEqual(U_BOOT_DATA, data)
2753
2754 def testExtractCbfsCompressed(self):
2755 """Test extracting CBFS compressed data"""
2756 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2757 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2758
2759 def testExtractCbfsRaw(self):
2760 """Test extracting CBFS compressed data without decompressing it"""
2761 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002762 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002763 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2764
Simon Glass4c613bf2019-07-08 14:25:50 -06002765 def testExtractBadEntry(self):
2766 """Test extracting a bad section path"""
2767 with self.assertRaises(ValueError) as e:
2768 self._RunExtractCmd('section/does-not-exist')
2769 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2770 str(e.exception))
2771
2772 def testExtractMissingFile(self):
2773 """Test extracting file that does not exist"""
2774 with self.assertRaises(IOError) as e:
2775 control.ReadEntry('missing-file', 'name')
2776
2777 def testExtractBadFile(self):
2778 """Test extracting an invalid file"""
2779 fname = os.path.join(self._indir, 'badfile')
2780 tools.WriteFile(fname, b'')
2781 with self.assertRaises(ValueError) as e:
2782 control.ReadEntry(fname, 'name')
2783
Simon Glass980a2842019-07-08 14:25:52 -06002784 def testExtractCmd(self):
2785 """Test extracting a file fron an image on the command line"""
2786 self._CheckLz4()
2787 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002788 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002789 try:
2790 tmpdir, updated_fname = self._SetupImageInTmpdir()
2791 with test_util.capture_sys_output() as (stdout, stderr):
2792 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2793 '-f', fname)
2794 finally:
2795 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002796 data = tools.ReadFile(fname)
2797 self.assertEqual(U_BOOT_DATA, data)
2798
2799 def testExtractOneEntry(self):
2800 """Test extracting a single entry fron an image """
2801 self._CheckLz4()
2802 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2803 image_fname = tools.GetOutputFilename('image.bin')
2804 fname = os.path.join(self._indir, 'output.extact')
2805 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2806 data = tools.ReadFile(fname)
2807 self.assertEqual(U_BOOT_DATA, data)
2808
2809 def _CheckExtractOutput(self, decomp):
2810 """Helper to test file output with and without decompression
2811
2812 Args:
2813 decomp: True to decompress entry data, False to output it raw
2814 """
2815 def _CheckPresent(entry_path, expect_data, expect_size=None):
2816 """Check and remove expected file
2817
2818 This checks the data/size of a file and removes the file both from
2819 the outfiles set and from the output directory. Once all files are
2820 processed, both the set and directory should be empty.
2821
2822 Args:
2823 entry_path: Entry path
2824 expect_data: Data to expect in file, or None to skip check
2825 expect_size: Size of data to expect in file, or None to skip
2826 """
2827 path = os.path.join(outdir, entry_path)
2828 data = tools.ReadFile(path)
2829 os.remove(path)
2830 if expect_data:
2831 self.assertEqual(expect_data, data)
2832 elif expect_size:
2833 self.assertEqual(expect_size, len(data))
2834 outfiles.remove(path)
2835
2836 def _CheckDirPresent(name):
2837 """Remove expected directory
2838
2839 This gives an error if the directory does not exist as expected
2840
2841 Args:
2842 name: Name of directory to remove
2843 """
2844 path = os.path.join(outdir, name)
2845 os.rmdir(path)
2846
2847 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2848 image_fname = tools.GetOutputFilename('image.bin')
2849 outdir = os.path.join(self._indir, 'extract')
2850 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2851
2852 # Create a set of all file that were output (should be 9)
2853 outfiles = set()
2854 for root, dirs, files in os.walk(outdir):
2855 outfiles |= set([os.path.join(root, fname) for fname in files])
2856 self.assertEqual(9, len(outfiles))
2857 self.assertEqual(9, len(einfos))
2858
2859 image = control.images['image']
2860 entries = image.GetEntries()
2861
2862 # Check the 9 files in various ways
2863 section = entries['section']
2864 section_entries = section.GetEntries()
2865 cbfs_entries = section_entries['cbfs'].GetEntries()
2866 _CheckPresent('u-boot', U_BOOT_DATA)
2867 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2868 dtb_len = EXTRACT_DTB_SIZE
2869 if not decomp:
2870 dtb_len = cbfs_entries['u-boot-dtb'].size
2871 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2872 if not decomp:
2873 dtb_len = section_entries['u-boot-dtb'].size
2874 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2875
2876 fdtmap = entries['fdtmap']
2877 _CheckPresent('fdtmap', fdtmap.data)
2878 hdr = entries['image-header']
2879 _CheckPresent('image-header', hdr.data)
2880
2881 _CheckPresent('section/root', section.data)
2882 cbfs = section_entries['cbfs']
2883 _CheckPresent('section/cbfs/root', cbfs.data)
2884 data = tools.ReadFile(image_fname)
2885 _CheckPresent('root', data)
2886
2887 # There should be no files left. Remove all the directories to check.
2888 # If there are any files/dirs remaining, one of these checks will fail.
2889 self.assertEqual(0, len(outfiles))
2890 _CheckDirPresent('section/cbfs')
2891 _CheckDirPresent('section')
2892 _CheckDirPresent('')
2893 self.assertFalse(os.path.exists(outdir))
2894
2895 def testExtractAllEntries(self):
2896 """Test extracting all entries"""
2897 self._CheckLz4()
2898 self._CheckExtractOutput(decomp=True)
2899
2900 def testExtractAllEntriesRaw(self):
2901 """Test extracting all entries without decompressing them"""
2902 self._CheckLz4()
2903 self._CheckExtractOutput(decomp=False)
2904
2905 def testExtractSelectedEntries(self):
2906 """Test extracting some entries"""
2907 self._CheckLz4()
2908 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2909 image_fname = tools.GetOutputFilename('image.bin')
2910 outdir = os.path.join(self._indir, 'extract')
2911 einfos = control.ExtractEntries(image_fname, None, outdir,
2912 ['*cb*', '*head*'])
2913
2914 # File output is tested by testExtractAllEntries(), so just check that
2915 # the expected entries are selected
2916 names = [einfo.name for einfo in einfos]
2917 self.assertEqual(names,
2918 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2919
2920 def testExtractNoEntryPaths(self):
2921 """Test extracting some entries"""
2922 self._CheckLz4()
2923 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2924 image_fname = tools.GetOutputFilename('image.bin')
2925 with self.assertRaises(ValueError) as e:
2926 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002927 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002928 str(e.exception))
2929
2930 def testExtractTooManyEntryPaths(self):
2931 """Test extracting some entries"""
2932 self._CheckLz4()
2933 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2934 image_fname = tools.GetOutputFilename('image.bin')
2935 with self.assertRaises(ValueError) as e:
2936 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002937 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002938 str(e.exception))
2939
Simon Glass52d06212019-07-08 14:25:53 -06002940 def testPackAlignSection(self):
2941 """Test that sections can have alignment"""
2942 self._DoReadFile('131_pack_align_section.dts')
2943
2944 self.assertIn('image', control.images)
2945 image = control.images['image']
2946 entries = image.GetEntries()
2947 self.assertEqual(3, len(entries))
2948
2949 # First u-boot
2950 self.assertIn('u-boot', entries)
2951 entry = entries['u-boot']
2952 self.assertEqual(0, entry.offset)
2953 self.assertEqual(0, entry.image_pos)
2954 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2955 self.assertEqual(len(U_BOOT_DATA), entry.size)
2956
2957 # Section0
2958 self.assertIn('section0', entries)
2959 section0 = entries['section0']
2960 self.assertEqual(0x10, section0.offset)
2961 self.assertEqual(0x10, section0.image_pos)
2962 self.assertEqual(len(U_BOOT_DATA), section0.size)
2963
2964 # Second u-boot
2965 section_entries = section0.GetEntries()
2966 self.assertIn('u-boot', section_entries)
2967 entry = section_entries['u-boot']
2968 self.assertEqual(0, entry.offset)
2969 self.assertEqual(0x10, entry.image_pos)
2970 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2971 self.assertEqual(len(U_BOOT_DATA), entry.size)
2972
2973 # Section1
2974 self.assertIn('section1', entries)
2975 section1 = entries['section1']
2976 self.assertEqual(0x14, section1.offset)
2977 self.assertEqual(0x14, section1.image_pos)
2978 self.assertEqual(0x20, section1.size)
2979
2980 # Second u-boot
2981 section_entries = section1.GetEntries()
2982 self.assertIn('u-boot', section_entries)
2983 entry = section_entries['u-boot']
2984 self.assertEqual(0, entry.offset)
2985 self.assertEqual(0x14, entry.image_pos)
2986 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2987 self.assertEqual(len(U_BOOT_DATA), entry.size)
2988
2989 # Section2
2990 self.assertIn('section2', section_entries)
2991 section2 = section_entries['section2']
2992 self.assertEqual(0x4, section2.offset)
2993 self.assertEqual(0x18, section2.image_pos)
2994 self.assertEqual(4, section2.size)
2995
2996 # Third u-boot
2997 section_entries = section2.GetEntries()
2998 self.assertIn('u-boot', section_entries)
2999 entry = section_entries['u-boot']
3000 self.assertEqual(0, entry.offset)
3001 self.assertEqual(0x18, entry.image_pos)
3002 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3003 self.assertEqual(len(U_BOOT_DATA), entry.size)
3004
Simon Glassf8a54bc2019-07-20 12:23:56 -06003005 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3006 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003007 """Replace an entry in an image
3008
3009 This writes the entry data to update it, then opens the updated file and
3010 returns the value that it now finds there.
3011
3012 Args:
3013 entry_name: Entry name to replace
3014 data: Data to replace it with
3015 decomp: True to compress the data if needed, False if data is
3016 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003017 allow_resize: True to allow entries to change size, False to raise
3018 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003019
3020 Returns:
3021 Tuple:
3022 data from entry
3023 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003024 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003025 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003026 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003027 update_dtb=True)[1]
3028
3029 self.assertIn('image', control.images)
3030 image = control.images['image']
3031 entries = image.GetEntries()
3032 orig_dtb_data = entries['u-boot-dtb'].data
3033 orig_fdtmap_data = entries['fdtmap'].data
3034
3035 image_fname = tools.GetOutputFilename('image.bin')
3036 updated_fname = tools.GetOutputFilename('image-updated.bin')
3037 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003038 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3039 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003040 data = control.ReadEntry(updated_fname, entry_name, decomp)
3041
Simon Glassf8a54bc2019-07-20 12:23:56 -06003042 # The DT data should not change unless resized:
3043 if not allow_resize:
3044 new_dtb_data = entries['u-boot-dtb'].data
3045 self.assertEqual(new_dtb_data, orig_dtb_data)
3046 new_fdtmap_data = entries['fdtmap'].data
3047 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003048
Simon Glassf8a54bc2019-07-20 12:23:56 -06003049 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003050
3051 def testReplaceSimple(self):
3052 """Test replacing a single file"""
3053 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003054 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3055 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003056 self.assertEqual(expected, data)
3057
3058 # Test that the state looks right. There should be an FDT for the fdtmap
3059 # that we jsut read back in, and it should match what we find in the
3060 # 'control' tables. Checking for an FDT that does not exist should
3061 # return None.
3062 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003063 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003064 self.assertEqual(expected_fdtmap, fdtmap)
3065
3066 dtb = state.GetFdtForEtype('fdtmap')
3067 self.assertEqual(dtb.GetContents(), fdtmap)
3068
3069 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3070 self.assertIsNone(missing_path)
3071 self.assertIsNone(missing_fdtmap)
3072
3073 missing_dtb = state.GetFdtForEtype('missing')
3074 self.assertIsNone(missing_dtb)
3075
3076 self.assertEqual('/binman', state.fdt_path_prefix)
3077
3078 def testReplaceResizeFail(self):
3079 """Test replacing a file by something larger"""
3080 expected = U_BOOT_DATA + b'x'
3081 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003082 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3083 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003084 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3085 str(e.exception))
3086
3087 def testReplaceMulti(self):
3088 """Test replacing entry data where multiple images are generated"""
3089 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3090 update_dtb=True)[0]
3091 expected = b'x' * len(U_BOOT_DATA)
3092 updated_fname = tools.GetOutputFilename('image-updated.bin')
3093 tools.WriteFile(updated_fname, data)
3094 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003095 control.WriteEntry(updated_fname, entry_name, expected,
3096 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003097 data = control.ReadEntry(updated_fname, entry_name)
3098 self.assertEqual(expected, data)
3099
3100 # Check the state looks right.
3101 self.assertEqual('/binman/image', state.fdt_path_prefix)
3102
3103 # Now check we can write the first image
3104 image_fname = tools.GetOutputFilename('first-image.bin')
3105 updated_fname = tools.GetOutputFilename('first-updated.bin')
3106 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3107 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003108 control.WriteEntry(updated_fname, entry_name, expected,
3109 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003110 data = control.ReadEntry(updated_fname, entry_name)
3111 self.assertEqual(expected, data)
3112
3113 # Check the state looks right.
3114 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003115
Simon Glassfb30e292019-07-20 12:23:51 -06003116 def testUpdateFdtAllRepack(self):
3117 """Test that all device trees are updated with offset/size info"""
3118 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3119 SECTION_SIZE = 0x300
3120 DTB_SIZE = 602
3121 FDTMAP_SIZE = 608
3122 base_expected = {
3123 'offset': 0,
3124 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3125 'image-pos': 0,
3126 'section:offset': 0,
3127 'section:size': SECTION_SIZE,
3128 'section:image-pos': 0,
3129 'section/u-boot-dtb:offset': 4,
3130 'section/u-boot-dtb:size': 636,
3131 'section/u-boot-dtb:image-pos': 4,
3132 'u-boot-spl-dtb:offset': SECTION_SIZE,
3133 'u-boot-spl-dtb:size': DTB_SIZE,
3134 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3135 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3136 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3137 'u-boot-tpl-dtb:size': DTB_SIZE,
3138 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3139 'fdtmap:size': FDTMAP_SIZE,
3140 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3141 }
3142 main_expected = {
3143 'section:orig-size': SECTION_SIZE,
3144 'section/u-boot-dtb:orig-offset': 4,
3145 }
3146
3147 # We expect three device-tree files in the output, with the first one
3148 # within a fixed-size section.
3149 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3150 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3151 # main U-Boot tree. All three should have the same positions and offset
3152 # except that the main tree should include the main_expected properties
3153 start = 4
3154 for item in ['', 'spl', 'tpl', None]:
3155 if item is None:
3156 start += 16 # Move past fdtmap header
3157 dtb = fdt.Fdt.FromData(data[start:])
3158 dtb.Scan()
3159 props = self._GetPropTree(dtb,
3160 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3161 prefix='/' if item is None else '/binman/')
3162 expected = dict(base_expected)
3163 if item:
3164 expected[item] = 0
3165 else:
3166 # Main DTB and fdtdec should include the 'orig-' properties
3167 expected.update(main_expected)
3168 # Helpful for debugging:
3169 #for prop in sorted(props):
3170 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3171 self.assertEqual(expected, props)
3172 if item == '':
3173 start = SECTION_SIZE
3174 else:
3175 start += dtb._fdt_obj.totalsize()
3176
Simon Glass11453762019-07-20 12:23:55 -06003177 def testFdtmapHeaderMiddle(self):
3178 """Test an FDT map in the middle of an image when it should be at end"""
3179 with self.assertRaises(ValueError) as e:
3180 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3181 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3182 str(e.exception))
3183
3184 def testFdtmapHeaderStartBad(self):
3185 """Test an FDT map in middle of an image when it should be at start"""
3186 with self.assertRaises(ValueError) as e:
3187 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3188 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3189 str(e.exception))
3190
3191 def testFdtmapHeaderEndBad(self):
3192 """Test an FDT map at the start of an image when it should be at end"""
3193 with self.assertRaises(ValueError) as e:
3194 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3195 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3196 str(e.exception))
3197
3198 def testFdtmapHeaderNoSize(self):
3199 """Test an image header at the end of an image with undefined size"""
3200 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3201
Simon Glassf8a54bc2019-07-20 12:23:56 -06003202 def testReplaceResize(self):
3203 """Test replacing a single file in an entry with a larger file"""
3204 expected = U_BOOT_DATA + b'x'
3205 data, _, image = self._RunReplaceCmd('u-boot', expected,
3206 dts='139_replace_repack.dts')
3207 self.assertEqual(expected, data)
3208
3209 entries = image.GetEntries()
3210 dtb_data = entries['u-boot-dtb'].data
3211 dtb = fdt.Fdt.FromData(dtb_data)
3212 dtb.Scan()
3213
3214 # The u-boot section should now be larger in the dtb
3215 node = dtb.GetNode('/binman/u-boot')
3216 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3217
3218 # Same for the fdtmap
3219 fdata = entries['fdtmap'].data
3220 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3221 fdtb.Scan()
3222 fnode = fdtb.GetNode('/u-boot')
3223 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3224
3225 def testReplaceResizeNoRepack(self):
3226 """Test replacing an entry with a larger file when not allowed"""
3227 expected = U_BOOT_DATA + b'x'
3228 with self.assertRaises(ValueError) as e:
3229 self._RunReplaceCmd('u-boot', expected)
3230 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3231 str(e.exception))
3232
Simon Glass9d8ee322019-07-20 12:23:58 -06003233 def testEntryShrink(self):
3234 """Test contracting an entry after it is packed"""
3235 try:
3236 state.SetAllowEntryContraction(True)
3237 data = self._DoReadFileDtb('140_entry_shrink.dts',
3238 update_dtb=True)[0]
3239 finally:
3240 state.SetAllowEntryContraction(False)
3241 self.assertEqual(b'a', data[:1])
3242 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3243 self.assertEqual(b'a', data[-1:])
3244
3245 def testEntryShrinkFail(self):
3246 """Test not being allowed to contract an entry after it is packed"""
3247 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3248
3249 # In this case there is a spare byte at the end of the data. The size of
3250 # the contents is only 1 byte but we still have the size before it
3251 # shrunk.
3252 self.assertEqual(b'a\0', data[:2])
3253 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3254 self.assertEqual(b'a\0', data[-2:])
3255
Simon Glass70e32982019-07-20 12:24:01 -06003256 def testDescriptorOffset(self):
3257 """Test that the Intel descriptor is always placed at at the start"""
3258 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3259 image = control.images['image']
3260 entries = image.GetEntries()
3261 desc = entries['intel-descriptor']
3262 self.assertEqual(0xff800000, desc.offset);
3263 self.assertEqual(0xff800000, desc.image_pos);
3264
Simon Glass37fdd142019-07-20 12:24:06 -06003265 def testReplaceCbfs(self):
3266 """Test replacing a single file in CBFS without changing the size"""
3267 self._CheckLz4()
3268 expected = b'x' * len(U_BOOT_DATA)
3269 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3270 updated_fname = tools.GetOutputFilename('image-updated.bin')
3271 tools.WriteFile(updated_fname, data)
3272 entry_name = 'section/cbfs/u-boot'
3273 control.WriteEntry(updated_fname, entry_name, expected,
3274 allow_resize=True)
3275 data = control.ReadEntry(updated_fname, entry_name)
3276 self.assertEqual(expected, data)
3277
3278 def testReplaceResizeCbfs(self):
3279 """Test replacing a single file in CBFS with one of a different size"""
3280 self._CheckLz4()
3281 expected = U_BOOT_DATA + b'x'
3282 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3283 updated_fname = tools.GetOutputFilename('image-updated.bin')
3284 tools.WriteFile(updated_fname, data)
3285 entry_name = 'section/cbfs/u-boot'
3286 control.WriteEntry(updated_fname, entry_name, expected,
3287 allow_resize=True)
3288 data = control.ReadEntry(updated_fname, entry_name)
3289 self.assertEqual(expected, data)
3290
Simon Glass30033c22019-07-20 12:24:15 -06003291 def _SetupForReplace(self):
3292 """Set up some files to use to replace entries
3293
3294 This generates an image, copies it to a new file, extracts all the files
3295 in it and updates some of them
3296
3297 Returns:
3298 List
3299 Image filename
3300 Output directory
3301 Expected values for updated entries, each a string
3302 """
3303 data = self._DoReadFileRealDtb('143_replace_all.dts')
3304
3305 updated_fname = tools.GetOutputFilename('image-updated.bin')
3306 tools.WriteFile(updated_fname, data)
3307
3308 outdir = os.path.join(self._indir, 'extract')
3309 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3310
3311 expected1 = b'x' + U_BOOT_DATA + b'y'
3312 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3313 tools.WriteFile(u_boot_fname1, expected1)
3314
3315 expected2 = b'a' + U_BOOT_DATA + b'b'
3316 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3317 tools.WriteFile(u_boot_fname2, expected2)
3318
3319 expected_text = b'not the same text'
3320 text_fname = os.path.join(outdir, 'text')
3321 tools.WriteFile(text_fname, expected_text)
3322
3323 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3324 dtb = fdt.FdtScan(dtb_fname)
3325 node = dtb.GetNode('/binman/text')
3326 node.AddString('my-property', 'the value')
3327 dtb.Sync(auto_resize=True)
3328 dtb.Flush()
3329
3330 return updated_fname, outdir, expected1, expected2, expected_text
3331
3332 def _CheckReplaceMultiple(self, entry_paths):
3333 """Handle replacing the contents of multiple entries
3334
3335 Args:
3336 entry_paths: List of entry paths to replace
3337
3338 Returns:
3339 List
3340 Dict of entries in the image:
3341 key: Entry name
3342 Value: Entry object
3343 Expected values for updated entries, each a string
3344 """
3345 updated_fname, outdir, expected1, expected2, expected_text = (
3346 self._SetupForReplace())
3347 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3348
3349 image = Image.FromFile(updated_fname)
3350 image.LoadData()
3351 return image.GetEntries(), expected1, expected2, expected_text
3352
3353 def testReplaceAll(self):
3354 """Test replacing the contents of all entries"""
3355 entries, expected1, expected2, expected_text = (
3356 self._CheckReplaceMultiple([]))
3357 data = entries['u-boot'].data
3358 self.assertEqual(expected1, data)
3359
3360 data = entries['u-boot2'].data
3361 self.assertEqual(expected2, data)
3362
3363 data = entries['text'].data
3364 self.assertEqual(expected_text, data)
3365
3366 # Check that the device tree is updated
3367 data = entries['u-boot-dtb'].data
3368 dtb = fdt.Fdt.FromData(data)
3369 dtb.Scan()
3370 node = dtb.GetNode('/binman/text')
3371 self.assertEqual('the value', node.props['my-property'].value)
3372
3373 def testReplaceSome(self):
3374 """Test replacing the contents of a few entries"""
3375 entries, expected1, expected2, expected_text = (
3376 self._CheckReplaceMultiple(['u-boot2', 'text']))
3377
3378 # This one should not change
3379 data = entries['u-boot'].data
3380 self.assertEqual(U_BOOT_DATA, data)
3381
3382 data = entries['u-boot2'].data
3383 self.assertEqual(expected2, data)
3384
3385 data = entries['text'].data
3386 self.assertEqual(expected_text, data)
3387
3388 def testReplaceCmd(self):
3389 """Test replacing a file fron an image on the command line"""
3390 self._DoReadFileRealDtb('143_replace_all.dts')
3391
3392 try:
3393 tmpdir, updated_fname = self._SetupImageInTmpdir()
3394
3395 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3396 expected = b'x' * len(U_BOOT_DATA)
3397 tools.WriteFile(fname, expected)
3398
3399 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3400 data = tools.ReadFile(updated_fname)
3401 self.assertEqual(expected, data[:len(expected)])
3402 map_fname = os.path.join(tmpdir, 'image-updated.map')
3403 self.assertFalse(os.path.exists(map_fname))
3404 finally:
3405 shutil.rmtree(tmpdir)
3406
3407 def testReplaceCmdSome(self):
3408 """Test replacing some files fron an image on the command line"""
3409 updated_fname, outdir, expected1, expected2, expected_text = (
3410 self._SetupForReplace())
3411
3412 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3413 'u-boot2', 'text')
3414
3415 tools.PrepareOutputDir(None)
3416 image = Image.FromFile(updated_fname)
3417 image.LoadData()
3418 entries = image.GetEntries()
3419
3420 # This one should not change
3421 data = entries['u-boot'].data
3422 self.assertEqual(U_BOOT_DATA, data)
3423
3424 data = entries['u-boot2'].data
3425 self.assertEqual(expected2, data)
3426
3427 data = entries['text'].data
3428 self.assertEqual(expected_text, data)
3429
3430 def testReplaceMissing(self):
3431 """Test replacing entries where the file is missing"""
3432 updated_fname, outdir, expected1, expected2, expected_text = (
3433 self._SetupForReplace())
3434
3435 # Remove one of the files, to generate a warning
3436 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3437 os.remove(u_boot_fname1)
3438
3439 with test_util.capture_sys_output() as (stdout, stderr):
3440 control.ReplaceEntries(updated_fname, None, outdir, [])
3441 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003442 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003443
3444 def testReplaceCmdMap(self):
3445 """Test replacing a file fron an image on the command line"""
3446 self._DoReadFileRealDtb('143_replace_all.dts')
3447
3448 try:
3449 tmpdir, updated_fname = self._SetupImageInTmpdir()
3450
3451 fname = os.path.join(self._indir, 'update-u-boot.bin')
3452 expected = b'x' * len(U_BOOT_DATA)
3453 tools.WriteFile(fname, expected)
3454
3455 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3456 '-f', fname, '-m')
3457 map_fname = os.path.join(tmpdir, 'image-updated.map')
3458 self.assertTrue(os.path.exists(map_fname))
3459 finally:
3460 shutil.rmtree(tmpdir)
3461
3462 def testReplaceNoEntryPaths(self):
3463 """Test replacing an entry without an entry path"""
3464 self._DoReadFileRealDtb('143_replace_all.dts')
3465 image_fname = tools.GetOutputFilename('image.bin')
3466 with self.assertRaises(ValueError) as e:
3467 control.ReplaceEntries(image_fname, 'fname', None, [])
3468 self.assertIn('Must specify an entry path to read with -f',
3469 str(e.exception))
3470
3471 def testReplaceTooManyEntryPaths(self):
3472 """Test extracting some entries"""
3473 self._DoReadFileRealDtb('143_replace_all.dts')
3474 image_fname = tools.GetOutputFilename('image.bin')
3475 with self.assertRaises(ValueError) as e:
3476 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3477 self.assertIn('Must specify exactly one entry path to write with -f',
3478 str(e.exception))
3479
Simon Glass0b074d62019-08-24 07:22:48 -06003480 def testPackReset16(self):
3481 """Test that an image with an x86 reset16 region can be created"""
3482 data = self._DoReadFile('144_x86_reset16.dts')
3483 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3484
3485 def testPackReset16Spl(self):
3486 """Test that an image with an x86 reset16-spl region can be created"""
3487 data = self._DoReadFile('145_x86_reset16_spl.dts')
3488 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3489
3490 def testPackReset16Tpl(self):
3491 """Test that an image with an x86 reset16-tpl region can be created"""
3492 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3493 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3494
Simon Glass232f90c2019-08-24 07:22:50 -06003495 def testPackIntelFit(self):
3496 """Test that an image with an Intel FIT and pointer can be created"""
3497 data = self._DoReadFile('147_intel_fit.dts')
3498 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3499 fit = data[16:32];
3500 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3501 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3502
3503 image = control.images['image']
3504 entries = image.GetEntries()
3505 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3506 self.assertEqual(expected_ptr, ptr)
3507
3508 def testPackIntelFitMissing(self):
3509 """Test detection of a FIT pointer with not FIT region"""
3510 with self.assertRaises(ValueError) as e:
3511 self._DoReadFile('148_intel_fit_missing.dts')
3512 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3513 str(e.exception))
3514
Simon Glass72555fa2019-11-06 17:22:44 -07003515 def _CheckSymbolsTplSection(self, dts, expected_vals):
3516 data = self._DoReadFile(dts)
3517 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003518 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003519 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003520 self.assertEqual(expected1, data[:upto1])
3521
3522 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003523 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003524 self.assertEqual(expected2, data[upto1:upto2])
3525
Simon Glass4e353e22019-08-24 07:23:04 -06003526 upto3 = 0x34 + len(U_BOOT_DATA)
3527 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003528 self.assertEqual(expected3, data[upto2:upto3])
3529
Simon Glass3f8ff012019-08-24 07:23:05 -06003530 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003531 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3532
3533 def testSymbolsTplSection(self):
3534 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3535 self._SetupSplElf('u_boot_binman_syms')
3536 self._SetupTplElf('u_boot_binman_syms')
3537 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3538 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3539
3540 def testSymbolsTplSectionX86(self):
3541 """Test binman can assign symbols in a section with end-at-4gb"""
3542 self._SetupSplElf('u_boot_binman_syms_x86')
3543 self._SetupTplElf('u_boot_binman_syms_x86')
3544 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3545 [0xffffff04, 0xffffff1c, 0xffffff34,
3546 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003547
Simon Glass98c59572019-08-24 07:23:03 -06003548 def testPackX86RomIfwiSectiom(self):
3549 """Test that a section can be placed in an IFWI region"""
3550 self._SetupIfwi('fitimage.bin')
3551 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3552 self._CheckIfwi(data)
3553
Simon Glassba7985d2019-08-24 07:23:07 -06003554 def testPackFspM(self):
3555 """Test that an image with a FSP memory-init binary can be created"""
3556 data = self._DoReadFile('152_intel_fsp_m.dts')
3557 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3558
Simon Glass4d9086d2019-10-20 21:31:35 -06003559 def testPackFspS(self):
3560 """Test that an image with a FSP silicon-init binary can be created"""
3561 data = self._DoReadFile('153_intel_fsp_s.dts')
3562 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003563
Simon Glass9ea87b22019-10-20 21:31:36 -06003564 def testPackFspT(self):
3565 """Test that an image with a FSP temp-ram-init binary can be created"""
3566 data = self._DoReadFile('154_intel_fsp_t.dts')
3567 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3568
Simon Glass48f3aad2020-07-09 18:39:31 -06003569 def testMkimage(self):
3570 """Test using mkimage to build an image"""
3571 data = self._DoReadFile('156_mkimage.dts')
3572
3573 # Just check that the data appears in the file somewhere
3574 self.assertIn(U_BOOT_SPL_DATA, data)
3575
Simon Glass5e560182020-07-09 18:39:36 -06003576 def testExtblob(self):
3577 """Test an image with an external blob"""
3578 data = self._DoReadFile('157_blob_ext.dts')
3579 self.assertEqual(REFCODE_DATA, data)
3580
3581 def testExtblobMissing(self):
3582 """Test an image with a missing external blob"""
3583 with self.assertRaises(ValueError) as e:
3584 self._DoReadFile('158_blob_ext_missing.dts')
3585 self.assertIn("Filename 'missing-file' not found in input path",
3586 str(e.exception))
3587
Simon Glass5d94cc62020-07-09 18:39:38 -06003588 def testExtblobMissingOk(self):
3589 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003590 with test_util.capture_sys_output() as (stdout, stderr):
3591 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3592 err = stderr.getvalue()
3593 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3594
3595 def testExtblobMissingOkSect(self):
3596 """Test an image with an missing external blob that is allowed"""
3597 with test_util.capture_sys_output() as (stdout, stderr):
3598 self._DoTestFile('159_blob_ext_missing_sect.dts',
3599 allow_missing=True)
3600 err = stderr.getvalue()
3601 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3602 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003603
Simon Glasse88cef92020-07-09 18:39:41 -06003604 def testPackX86RomMeMissingDesc(self):
3605 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003606 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003607 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003608 err = stderr.getvalue()
3609 self.assertRegex(err,
3610 "Image 'main-section'.*missing.*: intel-descriptor")
3611
3612 def testPackX86RomMissingIfwi(self):
3613 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3614 self._SetupIfwi('fitimage.bin')
3615 pathname = os.path.join(self._indir, 'fitimage.bin')
3616 os.remove(pathname)
3617 with test_util.capture_sys_output() as (stdout, stderr):
3618 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3619 err = stderr.getvalue()
3620 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3621
Simon Glassd70829a2020-07-09 18:39:42 -06003622 def testPackOverlap(self):
3623 """Test that zero-size overlapping regions are ignored"""
3624 self._DoTestFile('160_pack_overlap_zero.dts')
3625
Simon Glass45d556d2020-07-09 18:39:45 -06003626 def testSimpleFit(self):
3627 """Test an image with a FIT inside"""
3628 data = self._DoReadFile('161_fit.dts')
3629 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3630 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3631 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3632
3633 # The data should be inside the FIT
3634 dtb = fdt.Fdt.FromData(fit_data)
3635 dtb.Scan()
3636 fnode = dtb.GetNode('/images/kernel')
3637 self.assertIn('data', fnode.props)
3638
3639 fname = os.path.join(self._indir, 'fit_data.fit')
3640 tools.WriteFile(fname, fit_data)
3641 out = tools.Run('dumpimage', '-l', fname)
3642
3643 # Check a few features to make sure the plumbing works. We don't need
3644 # to test the operation of mkimage or dumpimage here. First convert the
3645 # output into a dict where the keys are the fields printed by dumpimage
3646 # and the values are a list of values for each field
3647 lines = out.splitlines()
3648
3649 # Converts "Compression: gzip compressed" into two groups:
3650 # 'Compression' and 'gzip compressed'
3651 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3652 vals = collections.defaultdict(list)
3653 for line in lines:
3654 mat = re_line.match(line)
3655 vals[mat.group(1)].append(mat.group(2))
3656
3657 self.assertEquals('FIT description: test-desc', lines[0])
3658 self.assertIn('Created:', lines[1])
3659 self.assertIn('Image 0 (kernel)', vals)
3660 self.assertIn('Hash value', vals)
3661 data_sizes = vals.get('Data Size')
3662 self.assertIsNotNone(data_sizes)
3663 self.assertEqual(2, len(data_sizes))
3664 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3665 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3666 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3667
3668 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003669 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003670 data = self._DoReadFile('162_fit_external.dts')
3671 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3672
3673 # The data should be outside the FIT
3674 dtb = fdt.Fdt.FromData(fit_data)
3675 dtb.Scan()
3676 fnode = dtb.GetNode('/images/kernel')
3677 self.assertNotIn('data', fnode.props)
Simon Glassfb30e292019-07-20 12:23:51 -06003678
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003679 def testSectionIgnoreHashSignature(self):
3680 """Test that sections ignore hash, signature nodes for its data"""
3681 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3682 expected = (U_BOOT_DATA + U_BOOT_DATA)
3683 self.assertEqual(expected, data)
3684
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003685 def testPadInSections(self):
3686 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003687 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3688 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003689 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3690 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3691 U_BOOT_DATA)
3692 self.assertEqual(expected, data)
3693
Simon Glassd12599d2020-10-26 17:40:09 -06003694 dtb = fdt.Fdt(out_dtb_fname)
3695 dtb.Scan()
3696 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3697 expected = {
3698 'image-pos': 0,
3699 'offset': 0,
3700 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3701
3702 'section:image-pos': 0,
3703 'section:offset': 0,
3704 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3705
3706 'section/before:image-pos': 0,
3707 'section/before:offset': 0,
3708 'section/before:size': len(U_BOOT_DATA),
3709
3710 'section/u-boot:image-pos': 4,
3711 'section/u-boot:offset': 4,
3712 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3713
3714 'section/after:image-pos': 26,
3715 'section/after:offset': 26,
3716 'section/after:size': len(U_BOOT_DATA),
3717 }
3718 self.assertEqual(expected, props)
3719
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003720 def testFitImageSubentryAlignment(self):
3721 """Test relative alignability of FIT image subentries"""
3722 entry_args = {
3723 'test-id': TEXT_DATA,
3724 }
3725 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3726 entry_args=entry_args)
3727 dtb = fdt.Fdt.FromData(data)
3728 dtb.Scan()
3729
3730 node = dtb.GetNode('/images/kernel')
3731 data = dtb.GetProps(node)["data"].bytes
3732 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3733 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3734 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3735 self.assertEqual(expected, data)
3736
3737 node = dtb.GetNode('/images/fdt-1')
3738 data = dtb.GetProps(node)["data"].bytes
3739 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3740 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3741 U_BOOT_DTB_DATA)
3742 self.assertEqual(expected, data)
3743
3744 def testFitExtblobMissingOk(self):
3745 """Test a FIT with a missing external blob that is allowed"""
3746 with test_util.capture_sys_output() as (stdout, stderr):
3747 self._DoTestFile('168_fit_missing_blob.dts',
3748 allow_missing=True)
3749 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003750 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003751
Simon Glass21db0ff2020-09-01 05:13:54 -06003752 def testBlobNamedByArgMissing(self):
3753 """Test handling of a missing entry arg"""
3754 with self.assertRaises(ValueError) as e:
3755 self._DoReadFile('068_blob_named_by_arg.dts')
3756 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3757 str(e.exception))
3758
Simon Glass559c4de2020-09-01 05:13:58 -06003759 def testPackBl31(self):
3760 """Test that an image with an ATF BL31 binary can be created"""
3761 data = self._DoReadFile('169_atf_bl31.dts')
3762 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3763
Samuel Holland9d8cc632020-10-21 21:12:15 -05003764 def testPackScp(self):
3765 """Test that an image with an SCP binary can be created"""
3766 data = self._DoReadFile('172_scp.dts')
3767 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3768
Simon Glassa435cd12020-09-01 05:13:59 -06003769 def testFitFdt(self):
3770 """Test an image with an FIT with multiple FDT images"""
3771 def _CheckFdt(seq, expected_data):
3772 """Check the FDT nodes
3773
3774 Args:
3775 seq: Sequence number to check (0 or 1)
3776 expected_data: Expected contents of 'data' property
3777 """
3778 name = 'fdt-%d' % seq
3779 fnode = dtb.GetNode('/images/%s' % name)
3780 self.assertIsNotNone(fnode)
3781 self.assertEqual({'description','type', 'compression', 'data'},
3782 set(fnode.props.keys()))
3783 self.assertEqual(expected_data, fnode.props['data'].bytes)
3784 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3785 fnode.props['description'].value)
3786
3787 def _CheckConfig(seq, expected_data):
3788 """Check the configuration nodes
3789
3790 Args:
3791 seq: Sequence number to check (0 or 1)
3792 expected_data: Expected contents of 'data' property
3793 """
3794 cnode = dtb.GetNode('/configurations')
3795 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003796 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003797
3798 name = 'config-%d' % seq
3799 fnode = dtb.GetNode('/configurations/%s' % name)
3800 self.assertIsNotNone(fnode)
3801 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3802 set(fnode.props.keys()))
3803 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3804 fnode.props['description'].value)
3805 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3806
3807 entry_args = {
3808 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003809 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003810 }
3811 data = self._DoReadFileDtb(
Simon Glass1032acc2020-09-06 10:39:08 -06003812 '172_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003813 entry_args=entry_args,
3814 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3815 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3816 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3817
3818 dtb = fdt.Fdt.FromData(fit_data)
3819 dtb.Scan()
3820 fnode = dtb.GetNode('/images/kernel')
3821 self.assertIn('data', fnode.props)
3822
3823 # Check all the properties in fdt-1 and fdt-2
3824 _CheckFdt(1, TEST_FDT1_DATA)
3825 _CheckFdt(2, TEST_FDT2_DATA)
3826
3827 # Check configurations
3828 _CheckConfig(1, TEST_FDT1_DATA)
3829 _CheckConfig(2, TEST_FDT2_DATA)
3830
3831 def testFitFdtMissingList(self):
3832 """Test handling of a missing 'of-list' entry arg"""
3833 with self.assertRaises(ValueError) as e:
Simon Glass1032acc2020-09-06 10:39:08 -06003834 self._DoReadFile('172_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003835 self.assertIn("Generator node requires 'of-list' entry argument",
3836 str(e.exception))
3837
3838 def testFitFdtEmptyList(self):
3839 """Test handling of an empty 'of-list' entry arg"""
3840 entry_args = {
3841 'of-list': '',
3842 }
3843 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3844
3845 def testFitFdtMissingProp(self):
3846 """Test handling of a missing 'fit,fdt-list' property"""
3847 with self.assertRaises(ValueError) as e:
3848 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3849 self.assertIn("Generator node requires 'fit,fdt-list' property",
3850 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003851
Simon Glass1032acc2020-09-06 10:39:08 -06003852 def testFitFdtEmptyList(self):
3853 """Test handling of an empty 'of-list' entry arg"""
3854 entry_args = {
3855 'of-list': '',
3856 }
3857 data = self._DoReadFileDtb('172_fit_fdt.dts', entry_args=entry_args)[0]
3858
3859 def testFitFdtMissing(self):
3860 """Test handling of a missing 'default-dt' entry arg"""
3861 entry_args = {
3862 'of-list': 'test-fdt1 test-fdt2',
3863 }
3864 with self.assertRaises(ValueError) as e:
3865 self._DoReadFileDtb(
3866 '172_fit_fdt.dts',
3867 entry_args=entry_args,
3868 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3869 self.assertIn("Generated 'default' node requires default-dt entry argument",
3870 str(e.exception))
3871
3872 def testFitFdtNotInList(self):
3873 """Test handling of a default-dt that is not in the of-list"""
3874 entry_args = {
3875 'of-list': 'test-fdt1 test-fdt2',
3876 'default-dt': 'test-fdt3',
3877 }
3878 with self.assertRaises(ValueError) as e:
3879 self._DoReadFileDtb(
3880 '172_fit_fdt.dts',
3881 entry_args=entry_args,
3882 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3883 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3884 str(e.exception))
3885
Simon Glassa820af72020-09-06 10:39:09 -06003886 def testFitExtblobMissingHelp(self):
3887 """Test display of help messages when an external blob is missing"""
3888 control.missing_blob_help = control._ReadMissingBlobHelp()
3889 control.missing_blob_help['wibble'] = 'Wibble test'
3890 control.missing_blob_help['another'] = 'Another test'
3891 with test_util.capture_sys_output() as (stdout, stderr):
3892 self._DoTestFile('168_fit_missing_blob.dts',
3893 allow_missing=True)
3894 err = stderr.getvalue()
3895
3896 # We can get the tag from the name, the type or the missing-msg
3897 # property. Check all three.
3898 self.assertIn('You may need to build ARM Trusted', err)
3899 self.assertIn('Wibble test', err)
3900 self.assertIn('Another test', err)
3901
Simon Glass6f1f4d42020-09-06 10:35:32 -06003902 def testMissingBlob(self):
3903 """Test handling of a blob containing a missing file"""
3904 with self.assertRaises(ValueError) as e:
3905 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3906 self.assertIn("Filename 'missing' not found in input path",
3907 str(e.exception))
3908
Simon Glassa0729502020-09-06 10:35:33 -06003909 def testEnvironment(self):
3910 """Test adding a U-Boot environment"""
3911 data = self._DoReadFile('174_env.dts')
3912 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3913 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3914 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3915 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3916 env)
3917
3918 def testEnvironmentNoSize(self):
3919 """Test that a missing 'size' property is detected"""
3920 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003921 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003922 self.assertIn("'u-boot-env' entry must have a size property",
3923 str(e.exception))
3924
3925 def testEnvironmentTooSmall(self):
3926 """Test handling of an environment that does not fit"""
3927 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003928 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003929
3930 # checksum, start byte, environment with \0 terminator, final \0
3931 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3932 short = need - 0x8
3933 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3934 str(e.exception))
3935
Simon Glassd1fdf752020-10-26 17:40:01 -06003936 def testSkipAtStart(self):
3937 """Test handling of skip-at-start section"""
3938 data = self._DoReadFile('177_skip_at_start.dts')
3939 self.assertEqual(U_BOOT_DATA, data)
3940
3941 image = control.images['image']
3942 entries = image.GetEntries()
3943 section = entries['section']
3944 self.assertEqual(0, section.offset)
3945 self.assertEqual(len(U_BOOT_DATA), section.size)
3946 self.assertEqual(U_BOOT_DATA, section.GetData())
3947
3948 entry = section.GetEntries()['u-boot']
3949 self.assertEqual(16, entry.offset)
3950 self.assertEqual(len(U_BOOT_DATA), entry.size)
3951 self.assertEqual(U_BOOT_DATA, entry.data)
3952
3953 def testSkipAtStartPad(self):
3954 """Test handling of skip-at-start section with padded entry"""
3955 data = self._DoReadFile('178_skip_at_start_pad.dts')
3956 before = tools.GetBytes(0, 8)
3957 after = tools.GetBytes(0, 4)
3958 all = before + U_BOOT_DATA + after
3959 self.assertEqual(all, data)
3960
3961 image = control.images['image']
3962 entries = image.GetEntries()
3963 section = entries['section']
3964 self.assertEqual(0, section.offset)
3965 self.assertEqual(len(all), section.size)
3966 self.assertEqual(all, section.GetData())
3967
3968 entry = section.GetEntries()['u-boot']
3969 self.assertEqual(16, entry.offset)
3970 self.assertEqual(len(all), entry.size)
3971 self.assertEqual(U_BOOT_DATA, entry.data)
3972
3973 def testSkipAtStartSectionPad(self):
3974 """Test handling of skip-at-start section with padding"""
3975 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
3976 before = tools.GetBytes(0, 8)
3977 after = tools.GetBytes(0, 4)
3978 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06003979 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06003980
3981 image = control.images['image']
3982 entries = image.GetEntries()
3983 section = entries['section']
3984 self.assertEqual(0, section.offset)
3985 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06003986 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06003987 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06003988
3989 entry = section.GetEntries()['u-boot']
3990 self.assertEqual(16, entry.offset)
3991 self.assertEqual(len(U_BOOT_DATA), entry.size)
3992 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06003993
Simon Glassbb395742020-10-26 17:40:14 -06003994 def testSectionPad(self):
3995 """Testing padding with sections"""
3996 data = self._DoReadFile('180_section_pad.dts')
3997 expected = (tools.GetBytes(ord('&'), 3) +
3998 tools.GetBytes(ord('!'), 5) +
3999 U_BOOT_DATA +
4000 tools.GetBytes(ord('!'), 1) +
4001 tools.GetBytes(ord('&'), 2))
4002 self.assertEqual(expected, data)
4003
4004 def testSectionAlign(self):
4005 """Testing alignment with sections"""
4006 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4007 expected = (b'\0' + # fill section
4008 tools.GetBytes(ord('&'), 1) + # padding to section align
4009 b'\0' + # fill section
4010 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4011 U_BOOT_DATA +
4012 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4013 tools.GetBytes(ord('!'), 4)) # padding to section size
4014 self.assertEqual(expected, data)
4015
Simon Glassd92c8362020-10-26 17:40:25 -06004016 def testCompressImage(self):
4017 """Test compression of the entire image"""
4018 self._CheckLz4()
4019 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4020 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4021 dtb = fdt.Fdt(out_dtb_fname)
4022 dtb.Scan()
4023 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4024 'uncomp-size'])
4025 orig = self._decompress(data)
4026 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4027
4028 # Do a sanity check on various fields
4029 image = control.images['image']
4030 entries = image.GetEntries()
4031 self.assertEqual(2, len(entries))
4032
4033 entry = entries['blob']
4034 self.assertEqual(COMPRESS_DATA, entry.data)
4035 self.assertEqual(len(COMPRESS_DATA), entry.size)
4036
4037 entry = entries['u-boot']
4038 self.assertEqual(U_BOOT_DATA, entry.data)
4039 self.assertEqual(len(U_BOOT_DATA), entry.size)
4040
4041 self.assertEqual(len(data), image.size)
4042 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4043 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4044 orig = self._decompress(image.data)
4045 self.assertEqual(orig, image.uncomp_data)
4046
4047 expected = {
4048 'blob:offset': 0,
4049 'blob:size': len(COMPRESS_DATA),
4050 'u-boot:offset': len(COMPRESS_DATA),
4051 'u-boot:size': len(U_BOOT_DATA),
4052 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4053 'offset': 0,
4054 'image-pos': 0,
4055 'size': len(data),
4056 }
4057 self.assertEqual(expected, props)
4058
4059 def testCompressImageLess(self):
4060 """Test compression where compression reduces the image size"""
4061 self._CheckLz4()
4062 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4063 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4064 dtb = fdt.Fdt(out_dtb_fname)
4065 dtb.Scan()
4066 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4067 'uncomp-size'])
4068 orig = self._decompress(data)
4069
4070 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4071
4072 # Do a sanity check on various fields
4073 image = control.images['image']
4074 entries = image.GetEntries()
4075 self.assertEqual(2, len(entries))
4076
4077 entry = entries['blob']
4078 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4079 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4080
4081 entry = entries['u-boot']
4082 self.assertEqual(U_BOOT_DATA, entry.data)
4083 self.assertEqual(len(U_BOOT_DATA), entry.size)
4084
4085 self.assertEqual(len(data), image.size)
4086 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4087 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4088 image.uncomp_size)
4089 orig = self._decompress(image.data)
4090 self.assertEqual(orig, image.uncomp_data)
4091
4092 expected = {
4093 'blob:offset': 0,
4094 'blob:size': len(COMPRESS_DATA_BIG),
4095 'u-boot:offset': len(COMPRESS_DATA_BIG),
4096 'u-boot:size': len(U_BOOT_DATA),
4097 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4098 'offset': 0,
4099 'image-pos': 0,
4100 'size': len(data),
4101 }
4102 self.assertEqual(expected, props)
4103
4104 def testCompressSectionSize(self):
4105 """Test compression of a section with a fixed size"""
4106 self._CheckLz4()
4107 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4108 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4109 dtb = fdt.Fdt(out_dtb_fname)
4110 dtb.Scan()
4111 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4112 'uncomp-size'])
4113 orig = self._decompress(data)
4114 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4115 expected = {
4116 'section/blob:offset': 0,
4117 'section/blob:size': len(COMPRESS_DATA),
4118 'section/u-boot:offset': len(COMPRESS_DATA),
4119 'section/u-boot:size': len(U_BOOT_DATA),
4120 'section:offset': 0,
4121 'section:image-pos': 0,
4122 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4123 'section:size': 0x30,
4124 'offset': 0,
4125 'image-pos': 0,
4126 'size': 0x30,
4127 }
4128 self.assertEqual(expected, props)
4129
4130 def testCompressSection(self):
4131 """Test compression of a section with no fixed size"""
4132 self._CheckLz4()
4133 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4134 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4135 dtb = fdt.Fdt(out_dtb_fname)
4136 dtb.Scan()
4137 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4138 'uncomp-size'])
4139 orig = self._decompress(data)
4140 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4141 expected = {
4142 'section/blob:offset': 0,
4143 'section/blob:size': len(COMPRESS_DATA),
4144 'section/u-boot:offset': len(COMPRESS_DATA),
4145 'section/u-boot:size': len(U_BOOT_DATA),
4146 'section:offset': 0,
4147 'section:image-pos': 0,
4148 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4149 'section:size': len(data),
4150 'offset': 0,
4151 'image-pos': 0,
4152 'size': len(data),
4153 }
4154 self.assertEqual(expected, props)
4155
4156 def testCompressExtra(self):
4157 """Test compression of a section with no fixed size"""
4158 self._CheckLz4()
4159 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4160 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4161 dtb = fdt.Fdt(out_dtb_fname)
4162 dtb.Scan()
4163 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4164 'uncomp-size'])
4165
4166 base = data[len(U_BOOT_DATA):]
4167 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4168 rest = base[len(U_BOOT_DATA):]
4169
4170 # Check compressed data
4171 section1 = self._decompress(rest)
4172 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4173 self.assertEquals(expect1, rest[:len(expect1)])
4174 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4175 rest1 = rest[len(expect1):]
4176
4177 section2 = self._decompress(rest1)
4178 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4179 self.assertEquals(expect2, rest1[:len(expect2)])
4180 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4181 rest2 = rest1[len(expect2):]
4182
4183 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4184 len(expect2) + len(U_BOOT_DATA))
4185 #self.assertEquals(expect_size, len(data))
4186
4187 #self.assertEquals(U_BOOT_DATA, rest2)
4188
4189 self.maxDiff = None
4190 expected = {
4191 'u-boot:offset': 0,
4192 'u-boot:image-pos': 0,
4193 'u-boot:size': len(U_BOOT_DATA),
4194
4195 'base:offset': len(U_BOOT_DATA),
4196 'base:image-pos': len(U_BOOT_DATA),
4197 'base:size': len(data) - len(U_BOOT_DATA),
4198 'base/u-boot:offset': 0,
4199 'base/u-boot:image-pos': len(U_BOOT_DATA),
4200 'base/u-boot:size': len(U_BOOT_DATA),
4201 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4202 len(expect2),
4203 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4204 len(expect2),
4205 'base/u-boot2:size': len(U_BOOT_DATA),
4206
4207 'base/section:offset': len(U_BOOT_DATA),
4208 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4209 'base/section:size': len(expect1),
4210 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4211 'base/section/blob:offset': 0,
4212 'base/section/blob:size': len(COMPRESS_DATA),
4213 'base/section/u-boot:offset': len(COMPRESS_DATA),
4214 'base/section/u-boot:size': len(U_BOOT_DATA),
4215
4216 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4217 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4218 'base/section2:size': len(expect2),
4219 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4220 'base/section2/blob:offset': 0,
4221 'base/section2/blob:size': len(COMPRESS_DATA),
4222 'base/section2/blob2:offset': len(COMPRESS_DATA),
4223 'base/section2/blob2:size': len(COMPRESS_DATA),
4224
4225 'offset': 0,
4226 'image-pos': 0,
4227 'size': len(data),
4228 }
4229 self.assertEqual(expected, props)
4230
Simon Glassecbe4732021-01-06 21:35:15 -07004231 def testSymbolsSubsection(self):
4232 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004233 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004234
Simon Glass3fb25402021-01-06 21:35:16 -07004235 def testReadImageEntryArg(self):
4236 """Test reading an image that would need an entry arg to generate"""
4237 entry_args = {
4238 'cros-ec-rw-path': 'ecrw.bin',
4239 }
4240 data = self.data = self._DoReadFileDtb(
4241 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4242 entry_args=entry_args)
4243
4244 image_fname = tools.GetOutputFilename('image.bin')
4245 orig_image = control.images['image']
4246
4247 # This should not generate an error about the missing 'cros-ec-rw-path'
4248 # since we are reading the image from a file. Compare with
4249 # testEntryArgsRequired()
4250 image = Image.FromFile(image_fname)
4251 self.assertEqual(orig_image.GetEntries().keys(),
4252 image.GetEntries().keys())
4253
Simon Glassa2af7302021-01-06 21:35:18 -07004254 def testFilesAlign(self):
4255 """Test alignment with files"""
4256 data = self._DoReadFile('190_files_align.dts')
4257
4258 # The first string is 15 bytes so will align to 16
4259 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4260 self.assertEqual(expect, data)
4261
Simon Glassdb84b562021-01-06 21:35:19 -07004262 def testReadImageSkip(self):
4263 """Test reading an image and accessing its FDT map"""
4264 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4265 image_fname = tools.GetOutputFilename('image.bin')
4266 orig_image = control.images['image']
4267 image = Image.FromFile(image_fname)
4268 self.assertEqual(orig_image.GetEntries().keys(),
4269 image.GetEntries().keys())
4270
4271 orig_entry = orig_image.GetEntries()['fdtmap']
4272 entry = image.GetEntries()['fdtmap']
4273 self.assertEqual(orig_entry.offset, entry.offset)
4274 self.assertEqual(orig_entry.size, entry.size)
4275 self.assertEqual(16, entry.image_pos)
4276
4277 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4278
4279 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4280
Simon Glassc98de972021-03-18 20:24:57 +13004281 def testTplNoDtb(self):
4282 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004283 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004284 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4285 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4286 data[:len(U_BOOT_TPL_NODTB_DATA)])
4287
Simon Glass63f41d42021-03-18 20:24:58 +13004288 def testTplBssPad(self):
4289 """Test that we can pad TPL's BSS with zeros"""
4290 # ELF file with a '__bss_size' symbol
4291 self._SetupTplElf()
4292 data = self._DoReadFile('193_tpl_bss_pad.dts')
4293 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4294 data)
4295
4296 def testTplBssPadMissing(self):
4297 """Test that a missing symbol is detected"""
4298 self._SetupTplElf('u_boot_ucode_ptr')
4299 with self.assertRaises(ValueError) as e:
4300 self._DoReadFile('193_tpl_bss_pad.dts')
4301 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4302 str(e.exception))
4303
Simon Glass718b5292021-03-18 20:25:07 +13004304 def checkDtbSizes(self, data, pad_len, start):
4305 """Check the size arguments in a dtb embedded in an image
4306
4307 Args:
4308 data: The image data
4309 pad_len: Length of the pad section in the image, in bytes
4310 start: Start offset of the devicetree to examine, within the image
4311
4312 Returns:
4313 Size of the devicetree in bytes
4314 """
4315 dtb_data = data[start:]
4316 dtb = fdt.Fdt.FromData(dtb_data)
4317 fdt_size = dtb.GetFdtObj().totalsize()
4318 dtb.Scan()
4319 props = self._GetPropTree(dtb, 'size')
4320 self.assertEqual({
4321 'size': len(data),
4322 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4323 'u-boot-spl/u-boot-spl-dtb:size': 801,
4324 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4325 'u-boot-spl:size': 860,
4326 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4327 'u-boot/u-boot-dtb:size': 781,
4328 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4329 'u-boot:size': 827,
4330 }, props)
4331 return fdt_size
4332
4333 def testExpanded(self):
4334 """Test that an expanded entry type is selected when needed"""
4335 self._SetupSplElf()
4336 self._SetupTplElf()
4337
4338 # SPL has a devicetree, TPL does not
4339 entry_args = {
4340 'spl-dtb': '1',
4341 'spl-bss-pad': 'y',
4342 'tpl-dtb': '',
4343 }
4344 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4345 entry_args=entry_args)
4346 image = control.images['image']
4347 entries = image.GetEntries()
4348 self.assertEqual(3, len(entries))
4349
4350 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4351 self.assertIn('u-boot', entries)
4352 entry = entries['u-boot']
4353 self.assertEqual('u-boot-expanded', entry.etype)
4354 subent = entry.GetEntries()
4355 self.assertEqual(2, len(subent))
4356 self.assertIn('u-boot-nodtb', subent)
4357 self.assertIn('u-boot-dtb', subent)
4358
4359 # Second, u-boot-spl, which should be expanded into three parts
4360 self.assertIn('u-boot-spl', entries)
4361 entry = entries['u-boot-spl']
4362 self.assertEqual('u-boot-spl-expanded', entry.etype)
4363 subent = entry.GetEntries()
4364 self.assertEqual(3, len(subent))
4365 self.assertIn('u-boot-spl-nodtb', subent)
4366 self.assertIn('u-boot-spl-bss-pad', subent)
4367 self.assertIn('u-boot-spl-dtb', subent)
4368
4369 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4370 # devicetree
4371 self.assertIn('u-boot-tpl', entries)
4372 entry = entries['u-boot-tpl']
4373 self.assertEqual('u-boot-tpl', entry.etype)
4374 self.assertEqual(None, entry.GetEntries())
4375
4376 def testExpandedTpl(self):
4377 """Test that an expanded entry type is selected for TPL when needed"""
4378 self._SetupTplElf()
4379
4380 entry_args = {
4381 'tpl-bss-pad': 'y',
4382 'tpl-dtb': 'y',
4383 }
4384 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4385 entry_args=entry_args)
4386 image = control.images['image']
4387 entries = image.GetEntries()
4388 self.assertEqual(1, len(entries))
4389
4390 # We only have u-boot-tpl, which be expanded
4391 self.assertIn('u-boot-tpl', entries)
4392 entry = entries['u-boot-tpl']
4393 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4394 subent = entry.GetEntries()
4395 self.assertEqual(3, len(subent))
4396 self.assertIn('u-boot-tpl-nodtb', subent)
4397 self.assertIn('u-boot-tpl-bss-pad', subent)
4398 self.assertIn('u-boot-tpl-dtb', subent)
4399
4400 def testExpandedNoPad(self):
4401 """Test an expanded entry without BSS pad enabled"""
4402 self._SetupSplElf()
4403 self._SetupTplElf()
4404
4405 # SPL has a devicetree, TPL does not
4406 entry_args = {
4407 'spl-dtb': 'something',
4408 'spl-bss-pad': 'n',
4409 'tpl-dtb': '',
4410 }
4411 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4412 entry_args=entry_args)
4413 image = control.images['image']
4414 entries = image.GetEntries()
4415
4416 # Just check u-boot-spl, which should be expanded into two parts
4417 self.assertIn('u-boot-spl', entries)
4418 entry = entries['u-boot-spl']
4419 self.assertEqual('u-boot-spl-expanded', entry.etype)
4420 subent = entry.GetEntries()
4421 self.assertEqual(2, len(subent))
4422 self.assertIn('u-boot-spl-nodtb', subent)
4423 self.assertIn('u-boot-spl-dtb', subent)
4424
4425 def testExpandedTplNoPad(self):
4426 """Test that an expanded entry type with padding disabled in TPL"""
4427 self._SetupTplElf()
4428
4429 entry_args = {
4430 'tpl-bss-pad': '',
4431 'tpl-dtb': 'y',
4432 }
4433 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4434 entry_args=entry_args)
4435 image = control.images['image']
4436 entries = image.GetEntries()
4437 self.assertEqual(1, len(entries))
4438
4439 # We only have u-boot-tpl, which be expanded
4440 self.assertIn('u-boot-tpl', entries)
4441 entry = entries['u-boot-tpl']
4442 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4443 subent = entry.GetEntries()
4444 self.assertEqual(2, len(subent))
4445 self.assertIn('u-boot-tpl-nodtb', subent)
4446 self.assertIn('u-boot-tpl-dtb', subent)
4447
4448 def testFdtInclude(self):
4449 """Test that an Fdt is update within all binaries"""
4450 self._SetupSplElf()
4451 self._SetupTplElf()
4452
4453 # SPL has a devicetree, TPL does not
4454 self.maxDiff = None
4455 entry_args = {
4456 'spl-dtb': '1',
4457 'spl-bss-pad': 'y',
4458 'tpl-dtb': '',
4459 }
4460 # Build the image. It includes two separate devicetree binaries, each
4461 # with their own contents, but all contain the binman definition.
4462 data = self._DoReadFileDtb(
4463 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4464 update_dtb=True, entry_args=entry_args)[0]
4465 pad_len = 10
4466
4467 # Check the U-Boot dtb
4468 start = len(U_BOOT_NODTB_DATA)
4469 fdt_size = self.checkDtbSizes(data, pad_len, start)
4470
4471 # Now check SPL
4472 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4473 fdt_size = self.checkDtbSizes(data, pad_len, start)
4474
4475 # TPL has no devicetree
4476 start += fdt_size + len(U_BOOT_TPL_DATA)
4477 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004478
Simon Glass7098b7f2021-03-21 18:24:30 +13004479 def testSymbolsExpanded(self):
4480 """Test binman can assign symbols in expanded entries"""
4481 entry_args = {
4482 'spl-dtb': '1',
4483 }
4484 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4485 U_BOOT_SPL_DTB_DATA, 0x38,
4486 entry_args=entry_args, use_expanded=True)
4487
Simon Glasse1915782021-03-21 18:24:31 +13004488 def testCollection(self):
4489 """Test a collection"""
4490 data = self._DoReadFile('198_collection.dts')
4491 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4492 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4493 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4494 data)
4495
Simon Glass27a7f772021-03-21 18:24:32 +13004496 def testCollectionSection(self):
4497 """Test a collection where a section must be built first"""
4498 # Sections never have their contents when GetData() is called, but when
4499 # _BuildSectionData() is called with required=True, a section will force
4500 # building the contents, producing an error is anything is still
4501 # missing.
4502 data = self._DoReadFile('199_collection_section.dts')
4503 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4504 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4505 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4506 data)
4507
Simon Glassf427c5f2021-03-21 18:24:33 +13004508 def testAlignDefault(self):
4509 """Test that default alignment works on sections"""
4510 data = self._DoReadFile('200_align_default.dts')
4511 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4512 U_BOOT_DATA)
4513 # Special alignment for section
4514 expected += tools.GetBytes(0, 32 - len(expected))
4515 # No alignment within the nested section
4516 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4517 # Now the final piece, which should be default-aligned
4518 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4519 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004520
Simon Glassac599912017-11-12 21:52:22 -07004521if __name__ == "__main__":
4522 unittest.main()