blob: 2f3ec69709b038bee6b002d2f215f739c357f6c0 [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
Simon Glass3efb2972021-11-23 21:08:59 -070026from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060027from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060028from binman import state
29from dtoc import fdt
30from dtoc import fdt_util
31from binman.etype import fdtmap
32from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060033from binman.image import Image
Simon Glassa997ea52020-04-17 18:09:04 -060034from patman import command
35from patman import test_util
36from patman import tools
37from patman import tout
Simon Glass57454f42016-11-25 20:15:52 -070038
39# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060040U_BOOT_DATA = b'1234'
41U_BOOT_IMG_DATA = b'img'
Simon Glass4e353e22019-08-24 07:23:04 -060042U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
43U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glass303f62f2019-05-17 22:00:46 -060044BLOB_DATA = b'89'
45ME_DATA = b'0abcd'
46VGA_DATA = b'vga'
47U_BOOT_DTB_DATA = b'udtb'
48U_BOOT_SPL_DTB_DATA = b'spldtb'
49U_BOOT_TPL_DTB_DATA = b'tpldtb'
50X86_START16_DATA = b'start16'
51X86_START16_SPL_DATA = b'start16spl'
52X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060053X86_RESET16_DATA = b'reset16'
54X86_RESET16_SPL_DATA = b'reset16spl'
55X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060056PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
57U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
58U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
59U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
60FSP_DATA = b'fsp'
61CMC_DATA = b'cmc'
62VBT_DATA = b'vbt'
63MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060064TEXT_DATA = 'text'
65TEXT_DATA2 = 'text2'
66TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060067CROS_EC_RW_DATA = b'ecrw'
68GBB_DATA = b'gbbd'
69BMPBLK_DATA = b'bmp'
70VBLOCK_DATA = b'vblk'
71FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
72 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060073COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060074COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060075REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060076FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060077FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060078FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060079ATF_BL31_DATA = b'bl31'
Simon Glass3efb2972021-11-23 21:08:59 -070080ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080081OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050082SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060083TEST_FDT1_DATA = b'fdt1'
84TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060085ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060086
87# Subdirectory of the input dir to use to put test FDTs
88TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060089
Simon Glass2c6adba2019-07-20 12:23:47 -060090# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060091EXTRACT_DTB_SIZE = 0x3c9
92
Simon Glass2c6adba2019-07-20 12:23:47 -060093# Properties expected to be in the device tree when update_dtb is used
94BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
95
Simon Glassfb30e292019-07-20 12:23:51 -060096# Extra properties expected to be in the device tree when allow-repack is used
97REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
98
Simon Glass57454f42016-11-25 20:15:52 -070099
100class TestFunctional(unittest.TestCase):
101 """Functional tests for binman
102
103 Most of these use a sample .dts file to build an image and then check
104 that it looks correct. The sample files are in the test/ subdirectory
105 and are numbered.
106
107 For each entry type a very small test file is created using fixed
108 string contents. This makes it easy to test that things look right, and
109 debug problems.
110
111 In some cases a 'real' file must be used - these are also supplied in
112 the test/ diurectory.
113 """
114 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600115 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700116 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600117 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700118
Simon Glass57454f42016-11-25 20:15:52 -0700119 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600120 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
121 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700122
123 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600124 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700125
126 # Create some test files
127 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
128 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
129 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600130 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700131 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700132 TestFunctional._MakeInputFile('me.bin', ME_DATA)
133 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600134 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600135
Jagdish Gediya311d4842018-09-03 21:35:08 +0530136 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600137
Simon Glassabab18c2019-08-24 07:22:49 -0600138 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
139 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700140 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600141 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600142 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600143
144 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
145 X86_RESET16_DATA)
146 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
147 X86_RESET16_SPL_DATA)
148 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
149 X86_RESET16_TPL_DATA)
150
Simon Glass57454f42016-11-25 20:15:52 -0700151 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700152 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
153 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600154 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
155 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700156 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
157 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700158 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700159 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600160 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600161 TestFunctional._MakeInputDir('devkeys')
162 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600163 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600164 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600165 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600166 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167
Simon Glassf6290892019-08-24 07:22:53 -0600168 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
169 elf_test.BuildElfTestFiles(cls._elf_testdir)
170
Simon Glass72232452016-11-25 20:15:53 -0700171 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600172 TestFunctional._MakeInputFile('u-boot',
173 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700174
175 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600176 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700177
Simon Glass862f8e22019-08-24 07:22:43 -0600178 shutil.copytree(cls.TestFile('files'),
179 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600180
Simon Glass7ba33592018-09-14 04:57:26 -0600181 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600182 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600183 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700184 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800185 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500186 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600187
Simon Glassa435cd12020-09-01 05:13:59 -0600188 # Add a few .dtb files for testing
189 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
190 TEST_FDT1_DATA)
191 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
192 TEST_FDT2_DATA)
193
Simon Glassa0729502020-09-06 10:35:33 -0600194 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
195
Simon Glass1de34482019-07-08 13:18:53 -0600196 # Travis-CI may have an old lz4
Simon Glass862f8e22019-08-24 07:22:43 -0600197 cls.have_lz4 = True
Simon Glass1de34482019-07-08 13:18:53 -0600198 try:
199 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glasscc311ac2019-10-31 07:42:50 -0600200 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glass1de34482019-07-08 13:18:53 -0600201 except:
Simon Glass862f8e22019-08-24 07:22:43 -0600202 cls.have_lz4 = False
Simon Glass1de34482019-07-08 13:18:53 -0600203
Simon Glass57454f42016-11-25 20:15:52 -0700204 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600205 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700206 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600207 if cls.preserve_indir:
208 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600209 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600210 if cls._indir:
211 shutil.rmtree(cls._indir)
212 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700213
Simon Glass1c420c92019-07-08 13:18:49 -0600214 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600215 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600216 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600217 """Accept arguments controlling test execution
218
219 Args:
220 preserve_indir: Preserve the shared input directory used by all
221 tests in this class.
222 preserve_outdir: Preserve the output directories used by tests. Each
223 test has its own, so this is normally only useful when running a
224 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600225 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600226 """
227 cls.preserve_indir = preserve_indir
228 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600229 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600230 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600231
Simon Glass1de34482019-07-08 13:18:53 -0600232 def _CheckLz4(self):
233 if not self.have_lz4:
234 self.skipTest('lz4 --no-frame-crc not available')
235
Simon Glassee9d10d2019-07-20 12:24:09 -0600236 def _CleanupOutputDir(self):
237 """Remove the temporary output directory"""
238 if self.preserve_outdirs:
239 print('Preserving output dir: %s' % tools.outdir)
240 else:
241 tools._FinaliseForTest()
242
Simon Glass57454f42016-11-25 20:15:52 -0700243 def setUp(self):
244 # Enable this to turn on debugging output
245 # tout.Init(tout.DEBUG)
246 command.test_result = None
247
248 def tearDown(self):
249 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600250 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700251
Simon Glassb3d6fc72019-07-20 12:24:10 -0600252 def _SetupImageInTmpdir(self):
253 """Set up the output image in a new temporary directory
254
255 This is used when an image has been generated in the output directory,
256 but we want to run binman again. This will create a new output
257 directory and fail to delete the original one.
258
259 This creates a new temporary directory, copies the image to it (with a
260 new name) and removes the old output directory.
261
262 Returns:
263 Tuple:
264 Temporary directory to use
265 New image filename
266 """
267 image_fname = tools.GetOutputFilename('image.bin')
268 tmpdir = tempfile.mkdtemp(prefix='binman.')
269 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
270 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
271 self._CleanupOutputDir()
272 return tmpdir, updated_fname
273
Simon Glass8425a1f2018-07-17 13:25:48 -0600274 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600275 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600276 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
277 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
278 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
279
Simon Glass57454f42016-11-25 20:15:52 -0700280 def _RunBinman(self, *args, **kwargs):
281 """Run binman using the command line
282
283 Args:
284 Arguments to pass, as a list of strings
285 kwargs: Arguments to pass to Command.RunPipe()
286 """
287 result = command.RunPipe([[self._binman_pathname] + list(args)],
288 capture=True, capture_stderr=True, raise_on_error=False)
289 if result.return_code and kwargs.get('raise_on_error', True):
290 raise Exception("Error running '%s': %s" % (' '.join(args),
291 result.stdout + result.stderr))
292 return result
293
Simon Glassf46732a2019-07-08 14:25:29 -0600294 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700295 """Run binman using directly (in the same process)
296
297 Args:
298 Arguments to pass, as a list of strings
299 Returns:
300 Return value (0 for success)
301 """
Simon Glassf46732a2019-07-08 14:25:29 -0600302 argv = list(argv)
303 args = cmdline.ParseArgs(argv)
304 args.pager = 'binman-invalid-pager'
305 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700306
307 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600308 # args.verbosity = tout.DEBUG
309 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700310
Simon Glass91710b32018-07-17 13:25:32 -0600311 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600312 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300313 use_expanded=False, verbosity=None, allow_missing=False,
Simon Glass76f496d2021-07-06 10:36:37 -0600314 extra_indirs=None, threads=None,
Simon Glassadfb8492021-11-03 21:09:18 -0600315 test_section_timeout=False, update_fdt_in_elf=None):
Simon Glass57454f42016-11-25 20:15:52 -0700316 """Run binman with a given test file
317
318 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600319 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600320 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600321 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600322 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600323 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600324 entry_args: Dict of entry args to supply to binman
325 key: arg name
326 value: value of that arg
327 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600328 use_real_dtb: True to use the test file as the contents of
329 the u-boot-dtb entry. Normally this is not needed and the
330 test contents (the U_BOOT_DTB_DATA string) can be used.
331 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300332 use_expanded: True to use expanded entries where available, e.g.
333 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600334 verbosity: Verbosity level to use (0-3, None=don't set it)
335 allow_missing: Set the '--allow-missing' flag so that missing
336 external binaries just produce a warning instead of an error
Simon Glassa435cd12020-09-01 05:13:59 -0600337 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600338 threads: Number of threads to use (None for default, 0 for
339 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600340 test_section_timeout: True to force the first time to timeout, as
341 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600342 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass9a798402021-11-03 21:09:17 -0600343
344 Returns:
345 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700346 """
Simon Glassf46732a2019-07-08 14:25:29 -0600347 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700348 if debug:
349 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600350 if verbosity is not None:
351 args.append('-v%d' % verbosity)
352 elif self.verbosity:
353 args.append('-v%d' % self.verbosity)
354 if self.toolpath:
355 for path in self.toolpath:
356 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600357 if threads is not None:
358 args.append('-T%d' % threads)
359 if test_section_timeout:
360 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600361 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600362 if map:
363 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600364 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600365 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600366 if not use_real_dtb:
367 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300368 if not use_expanded:
369 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600370 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600371 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600372 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600373 if allow_missing:
374 args.append('-M')
Simon Glassadfb8492021-11-03 21:09:18 -0600375 if update_fdt_in_elf:
376 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600377 if images:
378 for image in images:
379 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600380 if extra_indirs:
381 for indir in extra_indirs:
382 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700383 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700384
385 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700386 """Set up a new test device-tree file
387
388 The given file is compiled and set up as the device tree to be used
389 for ths test.
390
391 Args:
392 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600393 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700394
395 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600396 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700397 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600398 tmpdir = tempfile.mkdtemp(prefix='binmant.')
399 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600400 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700401 data = fd.read()
402 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600403 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600404 return data
Simon Glass57454f42016-11-25 20:15:52 -0700405
Simon Glasse219aa42018-09-14 04:57:24 -0600406 def _GetDtbContentsForSplTpl(self, dtb_data, name):
407 """Create a version of the main DTB for SPL or SPL
408
409 For testing we don't actually have different versions of the DTB. With
410 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
411 we don't normally have any unwanted nodes.
412
413 We still want the DTBs for SPL and TPL to be different though, since
414 otherwise it is confusing to know which one we are looking at. So add
415 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600416
417 Args:
418 dtb_data: dtb data to modify (this should be a value devicetree)
419 name: Name of a new property to add
420
421 Returns:
422 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600423 """
424 dtb = fdt.Fdt.FromData(dtb_data)
425 dtb.Scan()
426 dtb.GetNode('/binman').AddZeroProp(name)
427 dtb.Sync(auto_resize=True)
428 dtb.Pack()
429 return dtb.GetContents()
430
Simon Glassed930672021-03-18 20:25:05 +1300431 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
432 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600433 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700434 """Run binman and return the resulting image
435
436 This runs binman with a given test file and then reads the resulting
437 output file. It is a shortcut function since most tests need to do
438 these steps.
439
440 Raises an assertion failure if binman returns a non-zero exit code.
441
442 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600443 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700444 use_real_dtb: True to use the test file as the contents of
445 the u-boot-dtb entry. Normally this is not needed and the
446 test contents (the U_BOOT_DTB_DATA string) can be used.
447 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300448 use_expanded: True to use expanded entries where available, e.g.
449 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600450 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600451 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600452 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600453 entry_args: Dict of entry args to supply to binman
454 key: arg name
455 value: value of that arg
456 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
457 function. If reset_dtbs is True, then the original test dtb
458 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600459 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600460 threads: Number of threads to use (None for default, 0 for
461 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700462
463 Returns:
464 Tuple:
465 Resulting image contents
466 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600467 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600468 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700469 """
Simon Glass72232452016-11-25 20:15:53 -0700470 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700471 # Use the compiled test file as the u-boot-dtb input
472 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700473 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600474
475 # For testing purposes, make a copy of the DT for SPL and TPL. Add
476 # a node indicating which it is, so aid verification.
477 for name in ['spl', 'tpl']:
478 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
479 outfile = os.path.join(self._indir, dtb_fname)
480 TestFunctional._MakeInputFile(dtb_fname,
481 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700482
483 try:
Simon Glass91710b32018-07-17 13:25:32 -0600484 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600485 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600486 use_expanded=use_expanded, extra_indirs=extra_indirs,
487 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700488 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600489 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700490
491 # Find the (only) image, read it and return its contents
492 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600493 image_fname = tools.GetOutputFilename('image.bin')
494 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600495 if map:
496 map_fname = tools.GetOutputFilename('image.map')
497 with open(map_fname) as fd:
498 map_data = fd.read()
499 else:
500 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600501 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600502 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700503 finally:
504 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600505 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600506 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700507
Simon Glass5b4bce32019-07-08 14:25:26 -0600508 def _DoReadFileRealDtb(self, fname):
509 """Run binman with a real .dtb file and return the resulting data
510
511 Args:
512 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
513
514 Returns:
515 Resulting image contents
516 """
517 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
518
Simon Glass72232452016-11-25 20:15:53 -0700519 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600520 """Helper function which discards the device-tree binary
521
522 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600523 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600524 use_real_dtb: True to use the test file as the contents of
525 the u-boot-dtb entry. Normally this is not needed and the
526 test contents (the U_BOOT_DTB_DATA string) can be used.
527 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600528
529 Returns:
530 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600531 """
Simon Glass72232452016-11-25 20:15:53 -0700532 return self._DoReadFileDtb(fname, use_real_dtb)[0]
533
Simon Glass57454f42016-11-25 20:15:52 -0700534 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600535 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700536 """Create a new test input file, creating directories as needed
537
538 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600539 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700540 contents: File contents to write in to the file
541 Returns:
542 Full pathname of file created
543 """
Simon Glass862f8e22019-08-24 07:22:43 -0600544 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700545 dirname = os.path.dirname(pathname)
546 if dirname and not os.path.exists(dirname):
547 os.makedirs(dirname)
548 with open(pathname, 'wb') as fd:
549 fd.write(contents)
550 return pathname
551
552 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600553 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600554 """Create a new test input directory, creating directories as needed
555
556 Args:
557 dirname: Directory name to create
558
559 Returns:
560 Full pathname of directory created
561 """
Simon Glass862f8e22019-08-24 07:22:43 -0600562 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600563 if not os.path.exists(pathname):
564 os.makedirs(pathname)
565 return pathname
566
567 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600568 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600569 """Set up an ELF file with a '_dt_ucode_base_size' symbol
570
571 Args:
572 Filename of ELF file to use as SPL
573 """
Simon Glass93a806f2019-08-24 07:22:59 -0600574 TestFunctional._MakeInputFile('spl/u-boot-spl',
575 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600576
577 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600578 def _SetupTplElf(cls, src_fname='bss_data'):
579 """Set up an ELF file with a '_dt_ucode_base_size' symbol
580
581 Args:
582 Filename of ELF file to use as TPL
583 """
584 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
585 tools.ReadFile(cls.ElfTestFile(src_fname)))
586
587 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600588 def _SetupDescriptor(cls):
589 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
590 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
591
592 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600593 def TestFile(cls, fname):
594 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700595
Simon Glassf6290892019-08-24 07:22:53 -0600596 @classmethod
597 def ElfTestFile(cls, fname):
598 return os.path.join(cls._elf_testdir, fname)
599
Simon Glass57454f42016-11-25 20:15:52 -0700600 def AssertInList(self, grep_list, target):
601 """Assert that at least one of a list of things is in a target
602
603 Args:
604 grep_list: List of strings to check
605 target: Target string
606 """
607 for grep in grep_list:
608 if grep in target:
609 return
Simon Glass848cdb52019-05-17 22:00:50 -0600610 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700611
612 def CheckNoGaps(self, entries):
613 """Check that all entries fit together without gaps
614
615 Args:
616 entries: List of entries to check
617 """
Simon Glasse8561af2018-08-01 15:22:37 -0600618 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700619 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600620 self.assertEqual(offset, entry.offset)
621 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700622
Simon Glass72232452016-11-25 20:15:53 -0700623 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600624 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700625
626 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600627 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700628
629 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600630 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700631 """
632 return struct.unpack('>L', dtb[4:8])[0]
633
Simon Glass0f621332019-07-08 14:25:27 -0600634 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600635 def AddNode(node, path):
636 if node.name != '/':
637 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600638 for prop in node.props.values():
639 if prop.name in prop_names:
640 prop_path = path + ':' + prop.name
641 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
642 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600643 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600644 AddNode(subnode, path)
645
646 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600647 AddNode(dtb.GetRoot(), '')
648 return tree
649
Simon Glass57454f42016-11-25 20:15:52 -0700650 def testRun(self):
651 """Test a basic run with valid args"""
652 result = self._RunBinman('-h')
653
654 def testFullHelp(self):
655 """Test that the full help is displayed with -H"""
656 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300657 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500658 # Remove possible extraneous strings
659 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
660 gothelp = result.stdout.replace(extra, '')
661 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700662 self.assertEqual(0, len(result.stderr))
663 self.assertEqual(0, result.return_code)
664
665 def testFullHelpInternal(self):
666 """Test that the full help is displayed with -H"""
667 try:
668 command.test_result = command.CommandResult()
669 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300670 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700671 finally:
672 command.test_result = None
673
674 def testHelp(self):
675 """Test that the basic help is displayed with -h"""
676 result = self._RunBinman('-h')
677 self.assertTrue(len(result.stdout) > 200)
678 self.assertEqual(0, len(result.stderr))
679 self.assertEqual(0, result.return_code)
680
Simon Glass57454f42016-11-25 20:15:52 -0700681 def testBoard(self):
682 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600683 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700684 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300685 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700686 self.assertEqual(0, result)
687
688 def testNeedBoard(self):
689 """Test that we get an error when no board ius supplied"""
690 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600691 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700692 self.assertIn("Must provide a board to process (use -b <board>)",
693 str(e.exception))
694
695 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600696 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700697 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600698 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700699 # We get one error from libfdt, and a different one from fdtget.
700 self.AssertInList(["Couldn't open blob from 'missing_file'",
701 'No such file or directory'], str(e.exception))
702
703 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600704 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700705
706 Since this is a source file it should be compiled and the error
707 will come from the device-tree compiler (dtc).
708 """
709 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600710 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700711 self.assertIn("FATAL ERROR: Unable to parse input tree",
712 str(e.exception))
713
714 def testMissingNode(self):
715 """Test that a device tree without a 'binman' node generates an error"""
716 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600717 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700718 self.assertIn("does not have a 'binman' node", str(e.exception))
719
720 def testEmpty(self):
721 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600722 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700723 self.assertEqual(0, len(result.stderr))
724 self.assertEqual(0, result.return_code)
725
726 def testInvalidEntry(self):
727 """Test that an invalid entry is flagged"""
728 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600729 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600730 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700731 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
732 "'/binman/not-a-valid-type'", str(e.exception))
733
734 def testSimple(self):
735 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600736 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700737 self.assertEqual(U_BOOT_DATA, data)
738
Simon Glass075a45c2017-11-13 18:55:00 -0700739 def testSimpleDebug(self):
740 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600741 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700742
Simon Glass57454f42016-11-25 20:15:52 -0700743 def testDual(self):
744 """Test that we can handle creating two images
745
746 This also tests image padding.
747 """
Simon Glass511f6582018-10-01 12:22:30 -0600748 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700749 self.assertEqual(0, retcode)
750
751 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600752 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700753 fname = tools.GetOutputFilename('image1.bin')
754 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600755 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700756 data = fd.read()
757 self.assertEqual(U_BOOT_DATA, data)
758
759 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600760 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700761 fname = tools.GetOutputFilename('image2.bin')
762 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600763 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700764 data = fd.read()
765 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600766 self.assertEqual(tools.GetBytes(0, 3), data[:3])
767 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700768
769 def testBadAlign(self):
770 """Test that an invalid alignment value is detected"""
771 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600772 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700773 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
774 "of two", str(e.exception))
775
776 def testPackSimple(self):
777 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600778 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700779 self.assertEqual(0, retcode)
780 self.assertIn('image', control.images)
781 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600782 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700783 self.assertEqual(5, len(entries))
784
785 # First u-boot
786 self.assertIn('u-boot', entries)
787 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600788 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700789 self.assertEqual(len(U_BOOT_DATA), entry.size)
790
791 # Second u-boot, aligned to 16-byte boundary
792 self.assertIn('u-boot-align', entries)
793 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600794 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700795 self.assertEqual(len(U_BOOT_DATA), entry.size)
796
797 # Third u-boot, size 23 bytes
798 self.assertIn('u-boot-size', entries)
799 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600800 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
802 self.assertEqual(23, entry.size)
803
804 # Fourth u-boot, placed immediate after the above
805 self.assertIn('u-boot-next', entries)
806 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600807 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700808 self.assertEqual(len(U_BOOT_DATA), entry.size)
809
Simon Glasse8561af2018-08-01 15:22:37 -0600810 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700811 self.assertIn('u-boot-fixed', entries)
812 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600813 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700814 self.assertEqual(len(U_BOOT_DATA), entry.size)
815
Simon Glass39dd2152019-07-08 14:25:47 -0600816 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700817
818 def testPackExtra(self):
819 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600820 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
821 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700822
Simon Glass57454f42016-11-25 20:15:52 -0700823 self.assertIn('image', control.images)
824 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600825 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700826 self.assertEqual(5, len(entries))
827
828 # First u-boot with padding before and after
829 self.assertIn('u-boot', entries)
830 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600831 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertEqual(3, entry.pad_before)
833 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600834 self.assertEqual(U_BOOT_DATA, entry.data)
835 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
836 tools.GetBytes(0, 5), data[:entry.size])
837 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700838
839 # Second u-boot has an aligned size, but it has no effect
840 self.assertIn('u-boot-align-size-nop', entries)
841 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600842 self.assertEqual(pos, entry.offset)
843 self.assertEqual(len(U_BOOT_DATA), entry.size)
844 self.assertEqual(U_BOOT_DATA, entry.data)
845 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
846 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700847
848 # Third u-boot has an aligned size too
849 self.assertIn('u-boot-align-size', entries)
850 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600851 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700852 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600853 self.assertEqual(U_BOOT_DATA, entry.data)
854 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
855 data[pos:pos + entry.size])
856 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700857
858 # Fourth u-boot has an aligned end
859 self.assertIn('u-boot-align-end', entries)
860 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600861 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700862 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600863 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
864 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
865 data[pos:pos + entry.size])
866 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700867
868 # Fifth u-boot immediately afterwards
869 self.assertIn('u-boot-align-both', entries)
870 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600871 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700872 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600873 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
874 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
875 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700876
877 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600878 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700879
Simon Glassafb9caa2020-10-26 17:40:10 -0600880 dtb = fdt.Fdt(out_dtb_fname)
881 dtb.Scan()
882 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
883 expected = {
884 'image-pos': 0,
885 'offset': 0,
886 'size': 128,
887
888 'u-boot:image-pos': 0,
889 'u-boot:offset': 0,
890 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
891
892 'u-boot-align-size-nop:image-pos': 12,
893 'u-boot-align-size-nop:offset': 12,
894 'u-boot-align-size-nop:size': 4,
895
896 'u-boot-align-size:image-pos': 16,
897 'u-boot-align-size:offset': 16,
898 'u-boot-align-size:size': 32,
899
900 'u-boot-align-end:image-pos': 48,
901 'u-boot-align-end:offset': 48,
902 'u-boot-align-end:size': 16,
903
904 'u-boot-align-both:image-pos': 64,
905 'u-boot-align-both:offset': 64,
906 'u-boot-align-both:size': 64,
907 }
908 self.assertEqual(expected, props)
909
Simon Glass57454f42016-11-25 20:15:52 -0700910 def testPackAlignPowerOf2(self):
911 """Test that invalid entry alignment is detected"""
912 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600913 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700914 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
915 "of two", str(e.exception))
916
917 def testPackAlignSizePowerOf2(self):
918 """Test that invalid entry size alignment is detected"""
919 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600920 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700921 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
922 "power of two", str(e.exception))
923
924 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600925 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700926 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600927 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600928 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700929 "align 0x4 (4)", str(e.exception))
930
931 def testPackInvalidSizeAlign(self):
932 """Test that invalid entry size alignment is detected"""
933 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600934 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700935 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
936 "align-size 0x4 (4)", str(e.exception))
937
938 def testPackOverlap(self):
939 """Test that overlapping regions are detected"""
940 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600941 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600942 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700943 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
944 str(e.exception))
945
946 def testPackEntryOverflow(self):
947 """Test that entries that overflow their size are detected"""
948 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600949 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700950 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
951 "but entry size is 0x3 (3)", str(e.exception))
952
953 def testPackImageOverflow(self):
954 """Test that entries which overflow the image size are detected"""
955 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600956 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600957 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700958 "size 0x3 (3)", str(e.exception))
959
960 def testPackImageSize(self):
961 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600962 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700963 self.assertEqual(0, retcode)
964 self.assertIn('image', control.images)
965 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600966 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700967
968 def testPackImageSizeAlign(self):
969 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600970 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700971 self.assertEqual(0, retcode)
972 self.assertIn('image', control.images)
973 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600974 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700975
976 def testPackInvalidImageAlign(self):
977 """Test that invalid image alignment is detected"""
978 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600979 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600980 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700981 "align-size 0x8 (8)", str(e.exception))
982
983 def testPackAlignPowerOf2(self):
984 """Test that invalid image alignment is detected"""
985 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600986 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600987 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700988 "two", str(e.exception))
989
990 def testImagePadByte(self):
991 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600992 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600993 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -0600994 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
995 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -0700996
997 def testImageName(self):
998 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -0600999 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001000 self.assertEqual(0, retcode)
1001 image = control.images['image1']
1002 fname = tools.GetOutputFilename('test-name')
1003 self.assertTrue(os.path.exists(fname))
1004
1005 image = control.images['image2']
1006 fname = tools.GetOutputFilename('test-name.xx')
1007 self.assertTrue(os.path.exists(fname))
1008
1009 def testBlobFilename(self):
1010 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001011 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001012 self.assertEqual(BLOB_DATA, data)
1013
1014 def testPackSorted(self):
1015 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001016 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001017 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001018 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1019 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001020
Simon Glasse8561af2018-08-01 15:22:37 -06001021 def testPackZeroOffset(self):
1022 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001023 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001024 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001025 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001026 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1027 str(e.exception))
1028
1029 def testPackUbootDtb(self):
1030 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001031 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001032 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001033
1034 def testPackX86RomNoSize(self):
1035 """Test that the end-at-4gb property requires a size property"""
1036 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001037 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001038 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001039 "using end-at-4gb", str(e.exception))
1040
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301041 def test4gbAndSkipAtStartTogether(self):
1042 """Test that the end-at-4gb and skip-at-size property can't be used
1043 together"""
1044 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001045 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001046 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301047 "'skip-at-start'", str(e.exception))
1048
Simon Glass72232452016-11-25 20:15:53 -07001049 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001050 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001051 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001052 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001053 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1054 "is outside the section '/binman' starting at "
1055 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001056 str(e.exception))
1057
1058 def testPackX86Rom(self):
1059 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001060 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001061 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -06001062 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -06001063 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001064
1065 def testPackX86RomMeNoDesc(self):
1066 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001067 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001068 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001069 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001070 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001071 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1072 str(e.exception))
1073 finally:
1074 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001075
1076 def testPackX86RomBadDesc(self):
1077 """Test that the Intel requires a descriptor entry"""
1078 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001079 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001080 self.assertIn("Node '/binman/intel-me': No offset set with "
1081 "offset-unset: should another entry provide this correct "
1082 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001083
1084 def testPackX86RomMe(self):
1085 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001086 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -06001087 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1088 if data[:0x1000] != expected_desc:
1089 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001090 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1091
1092 def testPackVga(self):
1093 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001094 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001095 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1096
1097 def testPackStart16(self):
1098 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001099 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001100 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1101
Jagdish Gediya311d4842018-09-03 21:35:08 +05301102 def testPackPowerpcMpc85xxBootpgResetvec(self):
1103 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1104 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001105 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301106 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1107
Simon Glass6ba679c2018-07-06 10:27:17 -06001108 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001109 """Handle running a test for insertion of microcode
1110
1111 Args:
1112 dts_fname: Name of test .dts file
1113 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001114 ucode_second: True if the microsecond entry is second instead of
1115 third
Simon Glass820af1d2018-07-06 10:27:16 -06001116
1117 Returns:
1118 Tuple:
1119 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001120 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001121 in the above (two 4-byte words)
1122 """
Simon Glass3d274232017-11-12 21:52:27 -07001123 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001124
1125 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001126 if ucode_second:
1127 ucode_content = data[len(nodtb_data):]
1128 ucode_pos = len(nodtb_data)
1129 dtb_with_ucode = ucode_content[16:]
1130 fdt_len = self.GetFdtLen(dtb_with_ucode)
1131 else:
1132 dtb_with_ucode = data[len(nodtb_data):]
1133 fdt_len = self.GetFdtLen(dtb_with_ucode)
1134 ucode_content = dtb_with_ucode[fdt_len:]
1135 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001136 fname = tools.GetOutputFilename('test.dtb')
1137 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001138 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001139 dtb = fdt.FdtScan(fname)
1140 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001141 self.assertTrue(ucode)
1142 for node in ucode.subnodes:
1143 self.assertFalse(node.props.get('data'))
1144
Simon Glass72232452016-11-25 20:15:53 -07001145 # Check that the microcode appears immediately after the Fdt
1146 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001147 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001148 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1149 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001150 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001151
1152 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001153 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001154 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1155 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001156 u_boot = data[:len(nodtb_data)]
1157 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001158
1159 def testPackUbootMicrocode(self):
1160 """Test that x86 microcode can be handled correctly
1161
1162 We expect to see the following in the image, in order:
1163 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1164 place
1165 u-boot.dtb with the microcode removed
1166 the microcode
1167 """
Simon Glass511f6582018-10-01 12:22:30 -06001168 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001169 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001170 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1171 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001172
Simon Glassbac25c82017-05-27 07:38:26 -06001173 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001174 """Test that x86 microcode can be handled correctly
1175
1176 We expect to see the following in the image, in order:
1177 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1178 place
1179 u-boot.dtb with the microcode
1180 an empty microcode region
1181 """
1182 # We need the libfdt library to run this test since only that allows
1183 # finding the offset of a property. This is required by
1184 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001185 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001186
1187 second = data[len(U_BOOT_NODTB_DATA):]
1188
1189 fdt_len = self.GetFdtLen(second)
1190 third = second[fdt_len:]
1191 second = second[:fdt_len]
1192
Simon Glassbac25c82017-05-27 07:38:26 -06001193 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1194 self.assertIn(ucode_data, second)
1195 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001196
Simon Glassbac25c82017-05-27 07:38:26 -06001197 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001198 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001199 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1200 len(ucode_data))
1201 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001202 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1203 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001204
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001205 def testPackUbootSingleMicrocode(self):
1206 """Test that x86 microcode can be handled correctly with fdt_normal.
1207 """
Simon Glassbac25c82017-05-27 07:38:26 -06001208 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001209
Simon Glass996021e2016-11-25 20:15:54 -07001210 def testUBootImg(self):
1211 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001212 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001213 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001214
1215 def testNoMicrocode(self):
1216 """Test that a missing microcode region is detected"""
1217 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001218 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001219 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1220 "node found in ", str(e.exception))
1221
1222 def testMicrocodeWithoutNode(self):
1223 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1224 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001225 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001226 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1227 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1228
1229 def testMicrocodeWithoutNode2(self):
1230 """Test that a missing u-boot-ucode node is detected"""
1231 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001232 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001233 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1234 "microcode region u-boot-ucode", str(e.exception))
1235
1236 def testMicrocodeWithoutPtrInElf(self):
1237 """Test that a U-Boot binary without the microcode symbol is detected"""
1238 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001239 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001240 TestFunctional._MakeInputFile('u-boot',
1241 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001242
1243 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001244 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001245 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1246 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1247
1248 finally:
1249 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001250 TestFunctional._MakeInputFile('u-boot',
1251 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001252
1253 def testMicrocodeNotInImage(self):
1254 """Test that microcode must be placed within the image"""
1255 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001256 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001257 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1258 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001259 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001260
1261 def testWithoutMicrocode(self):
1262 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001263 TestFunctional._MakeInputFile('u-boot',
1264 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001265 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001266
1267 # Now check the device tree has no microcode
1268 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1269 second = data[len(U_BOOT_NODTB_DATA):]
1270
1271 fdt_len = self.GetFdtLen(second)
1272 self.assertEqual(dtb, second[:fdt_len])
1273
1274 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1275 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001276 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001277
1278 def testUnknownPosSize(self):
1279 """Test that microcode must be placed within the image"""
1280 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001281 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001282 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001283 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001284
1285 def testPackFsp(self):
1286 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001287 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001288 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1289
1290 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001291 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001292 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001293 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001294
1295 def testPackVbt(self):
1296 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001297 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001298 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001299
Simon Glass7f94e832017-11-12 21:52:25 -07001300 def testSplBssPad(self):
1301 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001302 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001303 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001304 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001305 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1306 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001307
Simon Glass04cda032018-10-01 21:12:42 -06001308 def testSplBssPadMissing(self):
1309 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001310 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001311 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001312 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001313 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1314 str(e.exception))
1315
Simon Glasse83679d2017-11-12 21:52:26 -07001316 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001317 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001318 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001319 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1320
Simon Glass6ba679c2018-07-06 10:27:17 -06001321 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1322 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001323
1324 We expect to see the following in the image, in order:
1325 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1326 correct place
1327 u-boot.dtb with the microcode removed
1328 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001329
1330 Args:
1331 dts: Device tree file to use for test
1332 ucode_second: True if the microsecond entry is second instead of
1333 third
Simon Glass3d274232017-11-12 21:52:27 -07001334 """
Simon Glass7057d022018-10-01 21:12:47 -06001335 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001336 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1337 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001338 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1339 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001340
Simon Glass6ba679c2018-07-06 10:27:17 -06001341 def testPackUbootSplMicrocode(self):
1342 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001343 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001344
1345 def testPackUbootSplMicrocodeReorder(self):
1346 """Test that order doesn't matter for microcode entries
1347
1348 This is the same as testPackUbootSplMicrocode but when we process the
1349 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1350 entry, so we reply on binman to try later.
1351 """
Simon Glass511f6582018-10-01 12:22:30 -06001352 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001353 ucode_second=True)
1354
Simon Glassa409c932017-11-12 21:52:28 -07001355 def testPackMrc(self):
1356 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001357 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001358 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1359
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001360 def testSplDtb(self):
1361 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001362 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001363 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1364
Simon Glass0a6da312017-11-13 18:54:56 -07001365 def testSplNoDtb(self):
1366 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001367 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001368 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001369 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1370
Simon Glass7098b7f2021-03-21 18:24:30 +13001371 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1372 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001373 """Check the image contains the expected symbol values
1374
1375 Args:
1376 dts: Device tree file to use for test
1377 base_data: Data before and after 'u-boot' section
1378 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001379 entry_args: Dict of entry args to supply to binman
1380 key: arg name
1381 value: value of that arg
1382 use_expanded: True to use expanded entries where available, e.g.
1383 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001384 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001385 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001386 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1387 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001388 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1389 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001390
Simon Glass7057d022018-10-01 21:12:47 -06001391 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001392 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1393 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001394 # The image should contain the symbols from u_boot_binman_syms.c
1395 # Note that image_pos is adjusted by the base address of the image,
1396 # which is 0x10 in our test image
1397 sym_values = struct.pack('<LQLL', 0x00,
1398 u_boot_offset + len(U_BOOT_DATA),
1399 0x10 + u_boot_offset, 0x04)
1400 expected = (sym_values + base_data[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001401 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001402 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001403 self.assertEqual(expected, data)
1404
Simon Glass31e04cb2021-03-18 20:24:56 +13001405 def testSymbols(self):
1406 """Test binman can assign symbols embedded in U-Boot"""
1407 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1408
1409 def testSymbolsNoDtb(self):
1410 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001411 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001412 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1413 0x38)
1414
Simon Glasse76a3e62018-06-01 09:38:11 -06001415 def testPackUnitAddress(self):
1416 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001417 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001418 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1419
Simon Glassa91e1152018-06-01 09:38:16 -06001420 def testSections(self):
1421 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001422 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001423 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1424 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1425 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001426 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001427
Simon Glass30732662018-06-01 09:38:20 -06001428 def testMap(self):
1429 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001430 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001431 self.assertEqual('''ImagePos Offset Size Name
143200000000 00000000 00000028 main-section
143300000000 00000000 00000010 section@0
143400000000 00000000 00000004 u-boot
143500000010 00000010 00000010 section@1
143600000010 00000000 00000004 u-boot
143700000020 00000020 00000004 section@2
143800000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001439''', map_data)
1440
Simon Glass3b78d532018-06-01 09:38:21 -06001441 def testNamePrefix(self):
1442 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001443 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001444 self.assertEqual('''ImagePos Offset Size Name
144500000000 00000000 00000028 main-section
144600000000 00000000 00000010 section@0
144700000000 00000000 00000004 ro-u-boot
144800000010 00000010 00000010 section@1
144900000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001450''', map_data)
1451
Simon Glass6ba679c2018-07-06 10:27:17 -06001452 def testUnknownContents(self):
1453 """Test that obtaining the contents works as expected"""
1454 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001455 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001456 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001457 "processing of contents: remaining ["
1458 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001459
Simon Glass2e1169f2018-07-06 10:27:19 -06001460 def testBadChangeSize(self):
1461 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001462 try:
1463 state.SetAllowEntryExpansion(False)
1464 with self.assertRaises(ValueError) as e:
1465 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001466 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001467 str(e.exception))
1468 finally:
1469 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001470
Simon Glassa87014e2018-07-06 10:27:42 -06001471 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001472 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001473 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001474 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001475 dtb = fdt.Fdt(out_dtb_fname)
1476 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001477 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001478 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001479 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001480 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001481 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001482 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001483 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001484 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001485 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001486 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001487 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001488 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001489 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001490
Simon Glasse8561af2018-08-01 15:22:37 -06001491 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001492 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001493 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001494 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001495 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001496 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001497 'size': 40
1498 }, props)
1499
1500 def testUpdateFdtBad(self):
1501 """Test that we detect when ProcessFdt never completes"""
1502 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001503 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001504 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001505 '[<binman.etype._testing.Entry__testing',
1506 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001507
Simon Glass91710b32018-07-17 13:25:32 -06001508 def testEntryArgs(self):
1509 """Test passing arguments to entries from the command line"""
1510 entry_args = {
1511 'test-str-arg': 'test1',
1512 'test-int-arg': '456',
1513 }
Simon Glass511f6582018-10-01 12:22:30 -06001514 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001515 self.assertIn('image', control.images)
1516 entry = control.images['image'].GetEntries()['_testing']
1517 self.assertEqual('test0', entry.test_str_fdt)
1518 self.assertEqual('test1', entry.test_str_arg)
1519 self.assertEqual(123, entry.test_int_fdt)
1520 self.assertEqual(456, entry.test_int_arg)
1521
1522 def testEntryArgsMissing(self):
1523 """Test missing arguments and properties"""
1524 entry_args = {
1525 'test-int-arg': '456',
1526 }
Simon Glass511f6582018-10-01 12:22:30 -06001527 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001528 entry = control.images['image'].GetEntries()['_testing']
1529 self.assertEqual('test0', entry.test_str_fdt)
1530 self.assertEqual(None, entry.test_str_arg)
1531 self.assertEqual(None, entry.test_int_fdt)
1532 self.assertEqual(456, entry.test_int_arg)
1533
1534 def testEntryArgsRequired(self):
1535 """Test missing arguments and properties"""
1536 entry_args = {
1537 'test-int-arg': '456',
1538 }
1539 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001540 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001541 self.assertIn("Node '/binman/_testing': "
1542 'Missing required properties/entry args: test-str-arg, '
1543 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001544 str(e.exception))
1545
1546 def testEntryArgsInvalidFormat(self):
1547 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001548 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1549 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001550 with self.assertRaises(ValueError) as e:
1551 self._DoBinman(*args)
1552 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1553
1554 def testEntryArgsInvalidInteger(self):
1555 """Test that an invalid entry-argument integer is detected"""
1556 entry_args = {
1557 'test-int-arg': 'abc',
1558 }
1559 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001560 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001561 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1562 "'test-int-arg' (value 'abc') to integer",
1563 str(e.exception))
1564
1565 def testEntryArgsInvalidDatatype(self):
1566 """Test that an invalid entry-argument datatype is detected
1567
1568 This test could be written in entry_test.py except that it needs
1569 access to control.entry_args, which seems more than that module should
1570 be able to see.
1571 """
1572 entry_args = {
1573 'test-bad-datatype-arg': '12',
1574 }
1575 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001576 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001577 entry_args=entry_args)
1578 self.assertIn('GetArg() internal error: Unknown data type ',
1579 str(e.exception))
1580
Simon Glass2ca52032018-07-17 13:25:33 -06001581 def testText(self):
1582 """Test for a text entry type"""
1583 entry_args = {
1584 'test-id': TEXT_DATA,
1585 'test-id2': TEXT_DATA2,
1586 'test-id3': TEXT_DATA3,
1587 }
Simon Glass511f6582018-10-01 12:22:30 -06001588 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001589 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001590 expected = (tools.ToBytes(TEXT_DATA) +
1591 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1592 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001593 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001594 self.assertEqual(expected, data)
1595
Simon Glass969616c2018-07-17 13:25:36 -06001596 def testEntryDocs(self):
1597 """Test for creation of entry documentation"""
1598 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001599 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001600 self.assertTrue(len(stdout.getvalue()) > 0)
1601
1602 def testEntryDocsMissing(self):
1603 """Test handling of missing entry documentation"""
1604 with self.assertRaises(ValueError) as e:
1605 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001606 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001607 self.assertIn('Documentation is missing for modules: u_boot',
1608 str(e.exception))
1609
Simon Glass704784b2018-07-17 13:25:38 -06001610 def testFmap(self):
1611 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001612 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001613 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001614 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1615 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001616 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001617 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001618 self.assertEqual(1, fhdr.ver_major)
1619 self.assertEqual(0, fhdr.ver_minor)
1620 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001621 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001622 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001623 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001624 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001625 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001626
Simon Glass82059c22021-04-03 11:05:09 +13001627 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001628 self.assertEqual(b'SECTION0', fentry.name)
1629 self.assertEqual(0, fentry.offset)
1630 self.assertEqual(16, fentry.size)
1631 self.assertEqual(0, fentry.flags)
1632
1633 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001634 self.assertEqual(b'RO_U_BOOT', fentry.name)
1635 self.assertEqual(0, fentry.offset)
1636 self.assertEqual(4, fentry.size)
1637 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001638
Simon Glass82059c22021-04-03 11:05:09 +13001639 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001640 self.assertEqual(b'SECTION1', fentry.name)
1641 self.assertEqual(16, fentry.offset)
1642 self.assertEqual(16, fentry.size)
1643 self.assertEqual(0, fentry.flags)
1644
1645 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001646 self.assertEqual(b'RW_U_BOOT', fentry.name)
1647 self.assertEqual(16, fentry.offset)
1648 self.assertEqual(4, fentry.size)
1649 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001650
Simon Glass82059c22021-04-03 11:05:09 +13001651 fentry = next(fiter)
1652 self.assertEqual(b'FMAP', fentry.name)
1653 self.assertEqual(32, fentry.offset)
1654 self.assertEqual(expect_size, fentry.size)
1655 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001656
Simon Glassdb168d42018-07-17 13:25:39 -06001657 def testBlobNamedByArg(self):
1658 """Test we can add a blob with the filename coming from an entry arg"""
1659 entry_args = {
1660 'cros-ec-rw-path': 'ecrw.bin',
1661 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001662 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001663
Simon Glass53f53992018-07-17 13:25:40 -06001664 def testFill(self):
1665 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001666 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001667 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001668 self.assertEqual(expected, data)
1669
1670 def testFillNoSize(self):
1671 """Test for an fill entry type with no size"""
1672 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001673 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001674 self.assertIn("'fill' entry must have a size property",
1675 str(e.exception))
1676
Simon Glassc1ae83c2018-07-17 13:25:44 -06001677 def _HandleGbbCommand(self, pipe_list):
1678 """Fake calls to the futility utility"""
1679 if pipe_list[0][0] == 'futility':
1680 fname = pipe_list[0][-1]
1681 # Append our GBB data to the file, which will happen every time the
1682 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001683 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001684 fd.write(GBB_DATA)
1685 return command.CommandResult()
1686
1687 def testGbb(self):
1688 """Test for the Chromium OS Google Binary Block"""
1689 command.test_result = self._HandleGbbCommand
1690 entry_args = {
1691 'keydir': 'devkeys',
1692 'bmpblk': 'bmpblk.bin',
1693 }
Simon Glass511f6582018-10-01 12:22:30 -06001694 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001695
1696 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001697 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1698 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001699 self.assertEqual(expected, data)
1700
1701 def testGbbTooSmall(self):
1702 """Test for the Chromium OS Google Binary Block being large enough"""
1703 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001704 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001705 self.assertIn("Node '/binman/gbb': GBB is too small",
1706 str(e.exception))
1707
1708 def testGbbNoSize(self):
1709 """Test for the Chromium OS Google Binary Block having a size"""
1710 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001711 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001712 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1713 str(e.exception))
1714
Simon Glass5c350162018-07-17 13:25:47 -06001715 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001716 """Fake calls to the futility utility
1717
1718 The expected pipe is:
1719
1720 [('futility', 'vbutil_firmware', '--vblock',
1721 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1722 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1723 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1724 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1725
1726 This writes to the output file (here, 'vblock.vblock'). If
1727 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1728 of the input data (here, 'input.vblock').
1729 """
Simon Glass5c350162018-07-17 13:25:47 -06001730 if pipe_list[0][0] == 'futility':
1731 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001732 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001733 if self._hash_data:
1734 infile = pipe_list[0][11]
1735 m = hashlib.sha256()
1736 data = tools.ReadFile(infile)
1737 m.update(data)
1738 fd.write(m.digest())
1739 else:
1740 fd.write(VBLOCK_DATA)
1741
Simon Glass5c350162018-07-17 13:25:47 -06001742 return command.CommandResult()
1743
1744 def testVblock(self):
1745 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001746 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001747 command.test_result = self._HandleVblockCommand
1748 entry_args = {
1749 'keydir': 'devkeys',
1750 }
Simon Glass511f6582018-10-01 12:22:30 -06001751 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001752 entry_args=entry_args)
1753 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1754 self.assertEqual(expected, data)
1755
1756 def testVblockNoContent(self):
1757 """Test we detect a vblock which has no content to sign"""
1758 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001759 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001760 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001761 'property', str(e.exception))
1762
1763 def testVblockBadPhandle(self):
1764 """Test that we detect a vblock with an invalid phandle in contents"""
1765 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001766 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001767 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1768 '1000', str(e.exception))
1769
1770 def testVblockBadEntry(self):
1771 """Test that we detect an entry that points to a non-entry"""
1772 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001773 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001774 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1775 "'other'", str(e.exception))
1776
Simon Glass220c6222021-01-06 21:35:17 -07001777 def testVblockContent(self):
1778 """Test that the vblock signs the right data"""
1779 self._hash_data = True
1780 command.test_result = self._HandleVblockCommand
1781 entry_args = {
1782 'keydir': 'devkeys',
1783 }
1784 data = self._DoReadFileDtb(
1785 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1786 entry_args=entry_args)[0]
1787 hashlen = 32 # SHA256 hash is 32 bytes
1788 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1789 hashval = data[-hashlen:]
1790 dtb = data[len(U_BOOT_DATA):-hashlen]
1791
1792 expected_data = U_BOOT_DATA + dtb
1793
1794 # The hashval should be a hash of the dtb
1795 m = hashlib.sha256()
1796 m.update(expected_data)
1797 expected_hashval = m.digest()
1798 self.assertEqual(expected_hashval, hashval)
1799
Simon Glass8425a1f2018-07-17 13:25:48 -06001800 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001801 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001802 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001803 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001804 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001805 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1806
Simon Glass24b97442018-07-17 13:25:51 -06001807 def testUsesPos(self):
1808 """Test that the 'pos' property cannot be used anymore"""
1809 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001810 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001811 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1812 "'pos'", str(e.exception))
1813
Simon Glass274bf092018-09-14 04:57:08 -06001814 def testFillZero(self):
1815 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001816 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001817 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001818
Simon Glass267de432018-09-14 04:57:09 -06001819 def testTextMissing(self):
1820 """Test for a text entry type where there is no text"""
1821 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001822 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001823 self.assertIn("Node '/binman/text': No value provided for text label "
1824 "'test-id'", str(e.exception))
1825
Simon Glassed40e962018-09-14 04:57:10 -06001826 def testPackStart16Tpl(self):
1827 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001828 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001829 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1830
Simon Glass3b376c32018-09-14 04:57:12 -06001831 def testSelectImage(self):
1832 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001833 expected = 'Skipping images: image1'
1834
1835 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001836 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001837 with test_util.capture_sys_output() as (stdout, stderr):
1838 retcode = self._DoTestFile('006_dual_image.dts',
1839 verbosity=verbosity,
1840 images=['image2'])
1841 self.assertEqual(0, retcode)
1842 if verbosity:
1843 self.assertIn(expected, stdout.getvalue())
1844 else:
1845 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001846
Simon Glassb4595d82019-04-25 21:58:34 -06001847 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1848 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001849 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001850
Simon Glasse219aa42018-09-14 04:57:24 -06001851 def testUpdateFdtAll(self):
1852 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001853 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001854
1855 base_expected = {
1856 'section:image-pos': 0,
1857 'u-boot-tpl-dtb:size': 513,
1858 'u-boot-spl-dtb:size': 513,
1859 'u-boot-spl-dtb:offset': 493,
1860 'image-pos': 0,
1861 'section/u-boot-dtb:image-pos': 0,
1862 'u-boot-spl-dtb:image-pos': 493,
1863 'section/u-boot-dtb:size': 493,
1864 'u-boot-tpl-dtb:image-pos': 1006,
1865 'section/u-boot-dtb:offset': 0,
1866 'section:size': 493,
1867 'offset': 0,
1868 'section:offset': 0,
1869 'u-boot-tpl-dtb:offset': 1006,
1870 'size': 1519
1871 }
1872
1873 # We expect three device-tree files in the output, one after the other.
1874 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1875 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1876 # main U-Boot tree. All three should have the same postions and offset.
1877 start = 0
1878 for item in ['', 'spl', 'tpl']:
1879 dtb = fdt.Fdt.FromData(data[start:])
1880 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001881 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1882 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001883 expected = dict(base_expected)
1884 if item:
1885 expected[item] = 0
1886 self.assertEqual(expected, props)
1887 start += dtb._fdt_obj.totalsize()
1888
1889 def testUpdateFdtOutput(self):
1890 """Test that output DTB files are updated"""
1891 try:
Simon Glass511f6582018-10-01 12:22:30 -06001892 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001893 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1894
1895 # Unfortunately, compiling a source file always results in a file
1896 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001897 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001898 # binman as a file called u-boot.dtb. To fix this, copy the file
1899 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001900 start = 0
1901 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1902 'tpl/u-boot-tpl.dtb.out']:
1903 dtb = fdt.Fdt.FromData(data[start:])
1904 size = dtb._fdt_obj.totalsize()
1905 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1906 outdata = tools.ReadFile(pathname)
1907 name = os.path.split(fname)[0]
1908
1909 if name:
1910 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1911 else:
1912 orig_indata = dtb_data
1913 self.assertNotEqual(outdata, orig_indata,
1914 "Expected output file '%s' be updated" % pathname)
1915 self.assertEqual(outdata, data[start:start + size],
1916 "Expected output file '%s' to match output image" %
1917 pathname)
1918 start += size
1919 finally:
1920 self._ResetDtbs()
1921
Simon Glass7ba33592018-09-14 04:57:26 -06001922 def _decompress(self, data):
Simon Glassccec0262019-07-08 13:18:42 -06001923 return tools.Decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001924
1925 def testCompress(self):
1926 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001927 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001928 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001929 use_real_dtb=True, update_dtb=True)
1930 dtb = fdt.Fdt(out_dtb_fname)
1931 dtb.Scan()
1932 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1933 orig = self._decompress(data)
1934 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001935
1936 # Do a sanity check on various fields
1937 image = control.images['image']
1938 entries = image.GetEntries()
1939 self.assertEqual(1, len(entries))
1940
1941 entry = entries['blob']
1942 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1943 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1944 orig = self._decompress(entry.data)
1945 self.assertEqual(orig, entry.uncomp_data)
1946
Simon Glass72eeff12020-10-26 17:40:16 -06001947 self.assertEqual(image.data, entry.data)
1948
Simon Glass7ba33592018-09-14 04:57:26 -06001949 expected = {
1950 'blob:uncomp-size': len(COMPRESS_DATA),
1951 'blob:size': len(data),
1952 'size': len(data),
1953 }
1954 self.assertEqual(expected, props)
1955
Simon Glassac6328c2018-09-14 04:57:28 -06001956 def testFiles(self):
1957 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001958 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001959 self.assertEqual(FILES_DATA, data)
1960
1961 def testFilesCompress(self):
1962 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001963 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001964 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001965
1966 image = control.images['image']
1967 entries = image.GetEntries()
1968 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001969 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001970
Simon Glass303f62f2019-05-17 22:00:46 -06001971 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001972 for i in range(1, 3):
1973 key = '%d.dat' % i
1974 start = entries[key].image_pos
1975 len = entries[key].size
1976 chunk = data[start:start + len]
1977 orig += self._decompress(chunk)
1978
1979 self.assertEqual(FILES_DATA, orig)
1980
1981 def testFilesMissing(self):
1982 """Test missing files"""
1983 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001984 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001985 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1986 'no files', str(e.exception))
1987
1988 def testFilesNoPattern(self):
1989 """Test missing files"""
1990 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001991 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001992 self.assertIn("Node '/binman/files': Missing 'pattern' property",
1993 str(e.exception))
1994
Simon Glassfa79a812018-09-14 04:57:29 -06001995 def testExpandSize(self):
1996 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06001997 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06001998 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06001999 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2000 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2001 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2002 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002003 self.assertEqual(expect, data)
2004 self.assertEqual('''ImagePos Offset Size Name
200500000000 00000000 00000028 main-section
200600000000 00000000 00000008 fill
200700000008 00000008 00000004 u-boot
20080000000c 0000000c 00000004 section
20090000000c 00000000 00000003 intel-mrc
201000000010 00000010 00000004 u-boot2
201100000014 00000014 0000000c section2
201200000014 00000000 00000008 fill
20130000001c 00000008 00000004 u-boot
201400000020 00000020 00000008 fill2
2015''', map_data)
2016
2017 def testExpandSizeBad(self):
2018 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002019 with test_util.capture_sys_output() as (stdout, stderr):
2020 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002021 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002022 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2023 'expanding entry', str(e.exception))
2024
Simon Glassae7cf032018-09-14 04:57:31 -06002025 def testHash(self):
2026 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002027 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002028 use_real_dtb=True, update_dtb=True)
2029 dtb = fdt.Fdt(out_dtb_fname)
2030 dtb.Scan()
2031 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2032 m = hashlib.sha256()
2033 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002034 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002035
2036 def testHashNoAlgo(self):
2037 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002038 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002039 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2040 'hash node', str(e.exception))
2041
2042 def testHashBadAlgo(self):
2043 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002044 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002045 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2046 str(e.exception))
2047
2048 def testHashSection(self):
2049 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002050 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002051 use_real_dtb=True, update_dtb=True)
2052 dtb = fdt.Fdt(out_dtb_fname)
2053 dtb.Scan()
2054 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2055 m = hashlib.sha256()
2056 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002057 m.update(tools.GetBytes(ord('a'), 16))
2058 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002059
Simon Glass3fb4f422018-09-14 04:57:32 -06002060 def testPackUBootTplMicrocode(self):
2061 """Test that x86 microcode can be handled correctly in TPL
2062
2063 We expect to see the following in the image, in order:
2064 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2065 place
2066 u-boot-tpl.dtb with the microcode removed
2067 the microcode
2068 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002069 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002070 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002071 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002072 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2073 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002074
Simon Glassc64aea52018-09-14 04:57:34 -06002075 def testFmapX86(self):
2076 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002077 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002078 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06002079 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002080 self.assertEqual(expected, data[:32])
2081 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2082
2083 self.assertEqual(0x100, fhdr.image_size)
2084
2085 self.assertEqual(0, fentries[0].offset)
2086 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002087 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002088
2089 self.assertEqual(4, fentries[1].offset)
2090 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002091 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002092
2093 self.assertEqual(32, fentries[2].offset)
2094 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2095 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002096 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002097
2098 def testFmapX86Section(self):
2099 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002100 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06002101 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002102 self.assertEqual(expected, data[:32])
2103 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2104
Simon Glassb1d414c2021-04-03 11:05:10 +13002105 self.assertEqual(0x180, fhdr.image_size)
2106 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002107 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002108
Simon Glass82059c22021-04-03 11:05:09 +13002109 fentry = next(fiter)
2110 self.assertEqual(b'U_BOOT', fentry.name)
2111 self.assertEqual(0, fentry.offset)
2112 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002113
Simon Glass82059c22021-04-03 11:05:09 +13002114 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002115 self.assertEqual(b'SECTION', fentry.name)
2116 self.assertEqual(4, fentry.offset)
2117 self.assertEqual(0x20 + expect_size, fentry.size)
2118
2119 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002120 self.assertEqual(b'INTEL_MRC', fentry.name)
2121 self.assertEqual(4, fentry.offset)
2122 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002123
Simon Glass82059c22021-04-03 11:05:09 +13002124 fentry = next(fiter)
2125 self.assertEqual(b'FMAP', fentry.name)
2126 self.assertEqual(36, fentry.offset)
2127 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002128
Simon Glassb1714232018-09-14 04:57:35 -06002129 def testElf(self):
2130 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002131 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002132 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002133 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002134 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002135 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002136
Simon Glass0d673792019-07-08 13:18:25 -06002137 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002138 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002139 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002140 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002141 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002142 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002143
Simon Glasscd817d52018-09-14 04:57:36 -06002144 def testPackOverlapMap(self):
2145 """Test that overlapping regions are detected"""
2146 with test_util.capture_sys_output() as (stdout, stderr):
2147 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002148 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06002149 map_fname = tools.GetOutputFilename('image.map')
2150 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2151 stdout.getvalue())
2152
2153 # We should not get an inmage, but there should be a map file
2154 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2155 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06002156 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002157 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002158<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002159<none> 00000000 00000004 u-boot
2160<none> 00000003 00000004 u-boot-align
2161''', map_data)
2162
Simon Glass0d673792019-07-08 13:18:25 -06002163 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002164 """Test that an image with an Intel Reference code binary works"""
2165 data = self._DoReadFile('100_intel_refcode.dts')
2166 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2167
Simon Glasseb023b32019-04-25 21:58:39 -06002168 def testSectionOffset(self):
2169 """Tests use of a section with an offset"""
2170 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2171 map=True)
2172 self.assertEqual('''ImagePos Offset Size Name
217300000000 00000000 00000038 main-section
217400000004 00000004 00000010 section@0
217500000004 00000000 00000004 u-boot
217600000018 00000018 00000010 section@1
217700000018 00000000 00000004 u-boot
21780000002c 0000002c 00000004 section@2
21790000002c 00000000 00000004 u-boot
2180''', map_data)
2181 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06002182 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2183 tools.GetBytes(0x21, 12) +
2184 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2185 tools.GetBytes(0x61, 12) +
2186 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2187 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002188
Simon Glass1de34482019-07-08 13:18:53 -06002189 def testCbfsRaw(self):
2190 """Test base handling of a Coreboot Filesystem (CBFS)
2191
2192 The exact contents of the CBFS is verified by similar tests in
2193 cbfs_util_test.py. The tests here merely check that the files added to
2194 the CBFS can be found in the final image.
2195 """
2196 data = self._DoReadFile('102_cbfs_raw.dts')
2197 size = 0xb0
2198
2199 cbfs = cbfs_util.CbfsReader(data)
2200 self.assertEqual(size, cbfs.rom_size)
2201
2202 self.assertIn('u-boot-dtb', cbfs.files)
2203 cfile = cbfs.files['u-boot-dtb']
2204 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2205
2206 def testCbfsArch(self):
2207 """Test on non-x86 architecture"""
2208 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2209 size = 0x100
2210
2211 cbfs = cbfs_util.CbfsReader(data)
2212 self.assertEqual(size, cbfs.rom_size)
2213
2214 self.assertIn('u-boot-dtb', cbfs.files)
2215 cfile = cbfs.files['u-boot-dtb']
2216 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2217
2218 def testCbfsStage(self):
2219 """Tests handling of a Coreboot Filesystem (CBFS)"""
2220 if not elf.ELF_TOOLS:
2221 self.skipTest('Python elftools not available')
2222 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2223 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2224 size = 0xb0
2225
2226 data = self._DoReadFile('104_cbfs_stage.dts')
2227 cbfs = cbfs_util.CbfsReader(data)
2228 self.assertEqual(size, cbfs.rom_size)
2229
2230 self.assertIn('u-boot', cbfs.files)
2231 cfile = cbfs.files['u-boot']
2232 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2233
2234 def testCbfsRawCompress(self):
2235 """Test handling of compressing raw files"""
2236 self._CheckLz4()
2237 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2238 size = 0x140
2239
2240 cbfs = cbfs_util.CbfsReader(data)
2241 self.assertIn('u-boot', cbfs.files)
2242 cfile = cbfs.files['u-boot']
2243 self.assertEqual(COMPRESS_DATA, cfile.data)
2244
2245 def testCbfsBadArch(self):
2246 """Test handling of a bad architecture"""
2247 with self.assertRaises(ValueError) as e:
2248 self._DoReadFile('106_cbfs_bad_arch.dts')
2249 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2250
2251 def testCbfsNoSize(self):
2252 """Test handling of a missing size property"""
2253 with self.assertRaises(ValueError) as e:
2254 self._DoReadFile('107_cbfs_no_size.dts')
2255 self.assertIn('entry must have a size property', str(e.exception))
2256
Simon Glass3e28f4f2021-11-23 11:03:54 -07002257 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002258 """Test handling of a CBFS entry which does not provide contentsy"""
2259 with self.assertRaises(ValueError) as e:
2260 self._DoReadFile('108_cbfs_no_contents.dts')
2261 self.assertIn('Could not complete processing of contents',
2262 str(e.exception))
2263
2264 def testCbfsBadCompress(self):
2265 """Test handling of a bad architecture"""
2266 with self.assertRaises(ValueError) as e:
2267 self._DoReadFile('109_cbfs_bad_compress.dts')
2268 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2269 str(e.exception))
2270
2271 def testCbfsNamedEntries(self):
2272 """Test handling of named entries"""
2273 data = self._DoReadFile('110_cbfs_name.dts')
2274
2275 cbfs = cbfs_util.CbfsReader(data)
2276 self.assertIn('FRED', cbfs.files)
2277 cfile1 = cbfs.files['FRED']
2278 self.assertEqual(U_BOOT_DATA, cfile1.data)
2279
2280 self.assertIn('hello', cbfs.files)
2281 cfile2 = cbfs.files['hello']
2282 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2283
Simon Glass759af872019-07-08 13:18:54 -06002284 def _SetupIfwi(self, fname):
2285 """Set up to run an IFWI test
2286
2287 Args:
2288 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2289 """
2290 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002291 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002292
2293 # Intel Integrated Firmware Image (IFWI) file
2294 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2295 data = fd.read()
2296 TestFunctional._MakeInputFile(fname,data)
2297
2298 def _CheckIfwi(self, data):
2299 """Check that an image with an IFWI contains the correct output
2300
2301 Args:
2302 data: Conents of output file
2303 """
2304 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2305 if data[:0x1000] != expected_desc:
2306 self.fail('Expected descriptor binary at start of image')
2307
2308 # We expect to find the TPL wil in subpart IBBP entry IBBL
2309 image_fname = tools.GetOutputFilename('image.bin')
2310 tpl_fname = tools.GetOutputFilename('tpl.out')
2311 tools.RunIfwiTool(image_fname, tools.CMD_EXTRACT, fname=tpl_fname,
2312 subpart='IBBP', entry_name='IBBL')
2313
2314 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002315 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002316
2317 def testPackX86RomIfwi(self):
2318 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2319 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002320 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002321 self._CheckIfwi(data)
2322
2323 def testPackX86RomIfwiNoDesc(self):
2324 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2325 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002326 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002327 self._CheckIfwi(data)
2328
2329 def testPackX86RomIfwiNoData(self):
2330 """Test that an x86 ROM with IFWI handles missing data"""
2331 self._SetupIfwi('ifwi.bin')
2332 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002333 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002334 self.assertIn('Could not complete processing of contents',
2335 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002336
Simon Glassc2f1aed2019-07-08 13:18:56 -06002337 def testCbfsOffset(self):
2338 """Test a CBFS with files at particular offsets
2339
2340 Like all CFBS tests, this is just checking the logic that calls
2341 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2342 """
2343 data = self._DoReadFile('114_cbfs_offset.dts')
2344 size = 0x200
2345
2346 cbfs = cbfs_util.CbfsReader(data)
2347 self.assertEqual(size, cbfs.rom_size)
2348
2349 self.assertIn('u-boot', cbfs.files)
2350 cfile = cbfs.files['u-boot']
2351 self.assertEqual(U_BOOT_DATA, cfile.data)
2352 self.assertEqual(0x40, cfile.cbfs_offset)
2353
2354 self.assertIn('u-boot-dtb', cbfs.files)
2355 cfile2 = cbfs.files['u-boot-dtb']
2356 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2357 self.assertEqual(0x140, cfile2.cbfs_offset)
2358
Simon Glass0f621332019-07-08 14:25:27 -06002359 def testFdtmap(self):
2360 """Test an FDT map can be inserted in the image"""
2361 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2362 fdtmap_data = data[len(U_BOOT_DATA):]
2363 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002364 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002365 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2366
2367 fdt_data = fdtmap_data[16:]
2368 dtb = fdt.Fdt.FromData(fdt_data)
2369 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002370 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002371 self.assertEqual({
2372 'image-pos': 0,
2373 'offset': 0,
2374 'u-boot:offset': 0,
2375 'u-boot:size': len(U_BOOT_DATA),
2376 'u-boot:image-pos': 0,
2377 'fdtmap:image-pos': 4,
2378 'fdtmap:offset': 4,
2379 'fdtmap:size': len(fdtmap_data),
2380 'size': len(data),
2381 }, props)
2382
2383 def testFdtmapNoMatch(self):
2384 """Check handling of an FDT map when the section cannot be found"""
2385 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2386
2387 # Mangle the section name, which should cause a mismatch between the
2388 # correct FDT path and the one expected by the section
2389 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002390 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002391 entries = image.GetEntries()
2392 fdtmap = entries['fdtmap']
2393 with self.assertRaises(ValueError) as e:
2394 fdtmap._GetFdtmap()
2395 self.assertIn("Cannot locate node for path '/binman-suffix'",
2396 str(e.exception))
2397
Simon Glasscec34ba2019-07-08 14:25:28 -06002398 def testFdtmapHeader(self):
2399 """Test an FDT map and image header can be inserted in the image"""
2400 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2401 fdtmap_pos = len(U_BOOT_DATA)
2402 fdtmap_data = data[fdtmap_pos:]
2403 fdt_data = fdtmap_data[16:]
2404 dtb = fdt.Fdt.FromData(fdt_data)
2405 fdt_size = dtb.GetFdtObj().totalsize()
2406 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002407 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002408 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2409 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2410
2411 def testFdtmapHeaderStart(self):
2412 """Test an image header can be inserted at the image start"""
2413 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2414 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2415 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002416 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002417 offset = struct.unpack('<I', hdr_data[4:])[0]
2418 self.assertEqual(fdtmap_pos, offset)
2419
2420 def testFdtmapHeaderPos(self):
2421 """Test an image header can be inserted at a chosen position"""
2422 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2423 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2424 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002425 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002426 offset = struct.unpack('<I', hdr_data[4:])[0]
2427 self.assertEqual(fdtmap_pos, offset)
2428
2429 def testHeaderMissingFdtmap(self):
2430 """Test an image header requires an fdtmap"""
2431 with self.assertRaises(ValueError) as e:
2432 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2433 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2434 str(e.exception))
2435
2436 def testHeaderNoLocation(self):
2437 """Test an image header with a no specified location is detected"""
2438 with self.assertRaises(ValueError) as e:
2439 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2440 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2441 str(e.exception))
2442
Simon Glasse61b6f62019-07-08 14:25:37 -06002443 def testEntryExpand(self):
2444 """Test expanding an entry after it is packed"""
2445 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002446 self.assertEqual(b'aaa', data[:3])
2447 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2448 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002449
2450 def testEntryExpandBad(self):
2451 """Test expanding an entry after it is packed, twice"""
2452 with self.assertRaises(ValueError) as e:
2453 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002454 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002455 str(e.exception))
2456
2457 def testEntryExpandSection(self):
2458 """Test expanding an entry within a section after it is packed"""
2459 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002460 self.assertEqual(b'aaa', data[:3])
2461 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2462 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002463
Simon Glass90d29682019-07-08 14:25:38 -06002464 def testCompressDtb(self):
2465 """Test that compress of device-tree files is supported"""
2466 self._CheckLz4()
2467 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2468 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2469 comp_data = data[len(U_BOOT_DATA):]
2470 orig = self._decompress(comp_data)
2471 dtb = fdt.Fdt.FromData(orig)
2472 dtb.Scan()
2473 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2474 expected = {
2475 'u-boot:size': len(U_BOOT_DATA),
2476 'u-boot-dtb:uncomp-size': len(orig),
2477 'u-boot-dtb:size': len(comp_data),
2478 'size': len(data),
2479 }
2480 self.assertEqual(expected, props)
2481
Simon Glass151bbbf2019-07-08 14:25:41 -06002482 def testCbfsUpdateFdt(self):
2483 """Test that we can update the device tree with CBFS offset/size info"""
2484 self._CheckLz4()
2485 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2486 update_dtb=True)
2487 dtb = fdt.Fdt(out_dtb_fname)
2488 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002489 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002490 del props['cbfs/u-boot:size']
2491 self.assertEqual({
2492 'offset': 0,
2493 'size': len(data),
2494 'image-pos': 0,
2495 'cbfs:offset': 0,
2496 'cbfs:size': len(data),
2497 'cbfs:image-pos': 0,
2498 'cbfs/u-boot:offset': 0x38,
2499 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2500 'cbfs/u-boot:image-pos': 0x38,
2501 'cbfs/u-boot-dtb:offset': 0xb8,
2502 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2503 'cbfs/u-boot-dtb:image-pos': 0xb8,
2504 }, props)
2505
Simon Glass3c9b4f22019-07-08 14:25:42 -06002506 def testCbfsBadType(self):
2507 """Test an image header with a no specified location is detected"""
2508 with self.assertRaises(ValueError) as e:
2509 self._DoReadFile('126_cbfs_bad_type.dts')
2510 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2511
Simon Glass6b156f82019-07-08 14:25:43 -06002512 def testList(self):
2513 """Test listing the files in an image"""
2514 self._CheckLz4()
2515 data = self._DoReadFile('127_list.dts')
2516 image = control.images['image']
2517 entries = image.BuildEntryList()
2518 self.assertEqual(7, len(entries))
2519
2520 ent = entries[0]
2521 self.assertEqual(0, ent.indent)
2522 self.assertEqual('main-section', ent.name)
2523 self.assertEqual('section', ent.etype)
2524 self.assertEqual(len(data), ent.size)
2525 self.assertEqual(0, ent.image_pos)
2526 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002527 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002528
2529 ent = entries[1]
2530 self.assertEqual(1, ent.indent)
2531 self.assertEqual('u-boot', ent.name)
2532 self.assertEqual('u-boot', ent.etype)
2533 self.assertEqual(len(U_BOOT_DATA), ent.size)
2534 self.assertEqual(0, ent.image_pos)
2535 self.assertEqual(None, ent.uncomp_size)
2536 self.assertEqual(0, ent.offset)
2537
2538 ent = entries[2]
2539 self.assertEqual(1, ent.indent)
2540 self.assertEqual('section', ent.name)
2541 self.assertEqual('section', ent.etype)
2542 section_size = ent.size
2543 self.assertEqual(0x100, ent.image_pos)
2544 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002545 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002546
2547 ent = entries[3]
2548 self.assertEqual(2, ent.indent)
2549 self.assertEqual('cbfs', ent.name)
2550 self.assertEqual('cbfs', ent.etype)
2551 self.assertEqual(0x400, ent.size)
2552 self.assertEqual(0x100, ent.image_pos)
2553 self.assertEqual(None, ent.uncomp_size)
2554 self.assertEqual(0, ent.offset)
2555
2556 ent = entries[4]
2557 self.assertEqual(3, ent.indent)
2558 self.assertEqual('u-boot', ent.name)
2559 self.assertEqual('u-boot', ent.etype)
2560 self.assertEqual(len(U_BOOT_DATA), ent.size)
2561 self.assertEqual(0x138, ent.image_pos)
2562 self.assertEqual(None, ent.uncomp_size)
2563 self.assertEqual(0x38, ent.offset)
2564
2565 ent = entries[5]
2566 self.assertEqual(3, ent.indent)
2567 self.assertEqual('u-boot-dtb', ent.name)
2568 self.assertEqual('text', ent.etype)
2569 self.assertGreater(len(COMPRESS_DATA), ent.size)
2570 self.assertEqual(0x178, ent.image_pos)
2571 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2572 self.assertEqual(0x78, ent.offset)
2573
2574 ent = entries[6]
2575 self.assertEqual(2, ent.indent)
2576 self.assertEqual('u-boot-dtb', ent.name)
2577 self.assertEqual('u-boot-dtb', ent.etype)
2578 self.assertEqual(0x500, ent.image_pos)
2579 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2580 dtb_size = ent.size
2581 # Compressing this data expands it since headers are added
2582 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2583 self.assertEqual(0x400, ent.offset)
2584
2585 self.assertEqual(len(data), 0x100 + section_size)
2586 self.assertEqual(section_size, 0x400 + dtb_size)
2587
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002588 def testFindFdtmap(self):
2589 """Test locating an FDT map in an image"""
2590 self._CheckLz4()
2591 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2592 image = control.images['image']
2593 entries = image.GetEntries()
2594 entry = entries['fdtmap']
2595 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2596
2597 def testFindFdtmapMissing(self):
2598 """Test failing to locate an FDP map"""
2599 data = self._DoReadFile('005_simple.dts')
2600 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2601
Simon Glassed39a3c2019-07-08 14:25:45 -06002602 def testFindImageHeader(self):
2603 """Test locating a image header"""
2604 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002605 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002606 image = control.images['image']
2607 entries = image.GetEntries()
2608 entry = entries['fdtmap']
2609 # The header should point to the FDT map
2610 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2611
2612 def testFindImageHeaderStart(self):
2613 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002614 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002615 image = control.images['image']
2616 entries = image.GetEntries()
2617 entry = entries['fdtmap']
2618 # The header should point to the FDT map
2619 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2620
2621 def testFindImageHeaderMissing(self):
2622 """Test failing to locate an image header"""
2623 data = self._DoReadFile('005_simple.dts')
2624 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2625
Simon Glassb8424fa2019-07-08 14:25:46 -06002626 def testReadImage(self):
2627 """Test reading an image and accessing its FDT map"""
2628 self._CheckLz4()
2629 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2630 image_fname = tools.GetOutputFilename('image.bin')
2631 orig_image = control.images['image']
2632 image = Image.FromFile(image_fname)
2633 self.assertEqual(orig_image.GetEntries().keys(),
2634 image.GetEntries().keys())
2635
2636 orig_entry = orig_image.GetEntries()['fdtmap']
2637 entry = image.GetEntries()['fdtmap']
2638 self.assertEquals(orig_entry.offset, entry.offset)
2639 self.assertEquals(orig_entry.size, entry.size)
2640 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2641
2642 def testReadImageNoHeader(self):
2643 """Test accessing an image's FDT map without an image header"""
2644 self._CheckLz4()
2645 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2646 image_fname = tools.GetOutputFilename('image.bin')
2647 image = Image.FromFile(image_fname)
2648 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002649 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002650
2651 def testReadImageFail(self):
2652 """Test failing to read an image image's FDT map"""
2653 self._DoReadFile('005_simple.dts')
2654 image_fname = tools.GetOutputFilename('image.bin')
2655 with self.assertRaises(ValueError) as e:
2656 image = Image.FromFile(image_fname)
2657 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002658
Simon Glassb2fd11d2019-07-08 14:25:48 -06002659 def testListCmd(self):
2660 """Test listing the files in an image using an Fdtmap"""
2661 self._CheckLz4()
2662 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2663
2664 # lz4 compression size differs depending on the version
2665 image = control.images['image']
2666 entries = image.GetEntries()
2667 section_size = entries['section'].size
2668 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2669 fdtmap_offset = entries['fdtmap'].offset
2670
Simon Glassb3d6fc72019-07-20 12:24:10 -06002671 try:
2672 tmpdir, updated_fname = self._SetupImageInTmpdir()
2673 with test_util.capture_sys_output() as (stdout, stderr):
2674 self._DoBinman('ls', '-i', updated_fname)
2675 finally:
2676 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002677 lines = stdout.getvalue().splitlines()
2678 expected = [
2679'Name Image-pos Size Entry-type Offset Uncomp-size',
2680'----------------------------------------------------------------------',
2681'main-section 0 c00 section 0',
2682' u-boot 0 4 u-boot 0',
2683' section 100 %x section 100' % section_size,
2684' cbfs 100 400 cbfs 0',
2685' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002686' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002687' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002688' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002689 (fdtmap_offset, fdtmap_offset),
2690' image-header bf8 8 image-header bf8',
2691 ]
2692 self.assertEqual(expected, lines)
2693
2694 def testListCmdFail(self):
2695 """Test failing to list an image"""
2696 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002697 try:
2698 tmpdir, updated_fname = self._SetupImageInTmpdir()
2699 with self.assertRaises(ValueError) as e:
2700 self._DoBinman('ls', '-i', updated_fname)
2701 finally:
2702 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002703 self.assertIn("Cannot find FDT map in image", str(e.exception))
2704
2705 def _RunListCmd(self, paths, expected):
2706 """List out entries and check the result
2707
2708 Args:
2709 paths: List of paths to pass to the list command
2710 expected: Expected list of filenames to be returned, in order
2711 """
2712 self._CheckLz4()
2713 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2714 image_fname = tools.GetOutputFilename('image.bin')
2715 image = Image.FromFile(image_fname)
2716 lines = image.GetListEntries(paths)[1]
2717 files = [line[0].strip() for line in lines[1:]]
2718 self.assertEqual(expected, files)
2719
2720 def testListCmdSection(self):
2721 """Test listing the files in a section"""
2722 self._RunListCmd(['section'],
2723 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2724
2725 def testListCmdFile(self):
2726 """Test listing a particular file"""
2727 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2728
2729 def testListCmdWildcard(self):
2730 """Test listing a wildcarded file"""
2731 self._RunListCmd(['*boot*'],
2732 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2733
2734 def testListCmdWildcardMulti(self):
2735 """Test listing a wildcarded file"""
2736 self._RunListCmd(['*cb*', '*head*'],
2737 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2738
2739 def testListCmdEmpty(self):
2740 """Test listing a wildcarded file"""
2741 self._RunListCmd(['nothing'], [])
2742
2743 def testListCmdPath(self):
2744 """Test listing the files in a sub-entry of a section"""
2745 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2746
Simon Glass4c613bf2019-07-08 14:25:50 -06002747 def _RunExtractCmd(self, entry_name, decomp=True):
2748 """Extract an entry from an image
2749
2750 Args:
2751 entry_name: Entry name to extract
2752 decomp: True to decompress the data if compressed, False to leave
2753 it in its raw uncompressed format
2754
2755 Returns:
2756 data from entry
2757 """
2758 self._CheckLz4()
2759 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2760 image_fname = tools.GetOutputFilename('image.bin')
2761 return control.ReadEntry(image_fname, entry_name, decomp)
2762
2763 def testExtractSimple(self):
2764 """Test extracting a single file"""
2765 data = self._RunExtractCmd('u-boot')
2766 self.assertEqual(U_BOOT_DATA, data)
2767
Simon Glass980a2842019-07-08 14:25:52 -06002768 def testExtractSection(self):
2769 """Test extracting the files in a section"""
2770 data = self._RunExtractCmd('section')
2771 cbfs_data = data[:0x400]
2772 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002773 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002774 dtb_data = data[0x400:]
2775 dtb = self._decompress(dtb_data)
2776 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2777
2778 def testExtractCompressed(self):
2779 """Test extracting compressed data"""
2780 data = self._RunExtractCmd('section/u-boot-dtb')
2781 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2782
2783 def testExtractRaw(self):
2784 """Test extracting compressed data without decompressing it"""
2785 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2786 dtb = self._decompress(data)
2787 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2788
2789 def testExtractCbfs(self):
2790 """Test extracting CBFS data"""
2791 data = self._RunExtractCmd('section/cbfs/u-boot')
2792 self.assertEqual(U_BOOT_DATA, data)
2793
2794 def testExtractCbfsCompressed(self):
2795 """Test extracting CBFS compressed data"""
2796 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2797 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2798
2799 def testExtractCbfsRaw(self):
2800 """Test extracting CBFS compressed data without decompressing it"""
2801 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glass37fdd142019-07-20 12:24:06 -06002802 dtb = tools.Decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002803 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2804
Simon Glass4c613bf2019-07-08 14:25:50 -06002805 def testExtractBadEntry(self):
2806 """Test extracting a bad section path"""
2807 with self.assertRaises(ValueError) as e:
2808 self._RunExtractCmd('section/does-not-exist')
2809 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2810 str(e.exception))
2811
2812 def testExtractMissingFile(self):
2813 """Test extracting file that does not exist"""
2814 with self.assertRaises(IOError) as e:
2815 control.ReadEntry('missing-file', 'name')
2816
2817 def testExtractBadFile(self):
2818 """Test extracting an invalid file"""
2819 fname = os.path.join(self._indir, 'badfile')
2820 tools.WriteFile(fname, b'')
2821 with self.assertRaises(ValueError) as e:
2822 control.ReadEntry(fname, 'name')
2823
Simon Glass980a2842019-07-08 14:25:52 -06002824 def testExtractCmd(self):
2825 """Test extracting a file fron an image on the command line"""
2826 self._CheckLz4()
2827 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002828 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002829 try:
2830 tmpdir, updated_fname = self._SetupImageInTmpdir()
2831 with test_util.capture_sys_output() as (stdout, stderr):
2832 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2833 '-f', fname)
2834 finally:
2835 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002836 data = tools.ReadFile(fname)
2837 self.assertEqual(U_BOOT_DATA, data)
2838
2839 def testExtractOneEntry(self):
2840 """Test extracting a single entry fron an image """
2841 self._CheckLz4()
2842 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2843 image_fname = tools.GetOutputFilename('image.bin')
2844 fname = os.path.join(self._indir, 'output.extact')
2845 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2846 data = tools.ReadFile(fname)
2847 self.assertEqual(U_BOOT_DATA, data)
2848
2849 def _CheckExtractOutput(self, decomp):
2850 """Helper to test file output with and without decompression
2851
2852 Args:
2853 decomp: True to decompress entry data, False to output it raw
2854 """
2855 def _CheckPresent(entry_path, expect_data, expect_size=None):
2856 """Check and remove expected file
2857
2858 This checks the data/size of a file and removes the file both from
2859 the outfiles set and from the output directory. Once all files are
2860 processed, both the set and directory should be empty.
2861
2862 Args:
2863 entry_path: Entry path
2864 expect_data: Data to expect in file, or None to skip check
2865 expect_size: Size of data to expect in file, or None to skip
2866 """
2867 path = os.path.join(outdir, entry_path)
2868 data = tools.ReadFile(path)
2869 os.remove(path)
2870 if expect_data:
2871 self.assertEqual(expect_data, data)
2872 elif expect_size:
2873 self.assertEqual(expect_size, len(data))
2874 outfiles.remove(path)
2875
2876 def _CheckDirPresent(name):
2877 """Remove expected directory
2878
2879 This gives an error if the directory does not exist as expected
2880
2881 Args:
2882 name: Name of directory to remove
2883 """
2884 path = os.path.join(outdir, name)
2885 os.rmdir(path)
2886
2887 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2888 image_fname = tools.GetOutputFilename('image.bin')
2889 outdir = os.path.join(self._indir, 'extract')
2890 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2891
2892 # Create a set of all file that were output (should be 9)
2893 outfiles = set()
2894 for root, dirs, files in os.walk(outdir):
2895 outfiles |= set([os.path.join(root, fname) for fname in files])
2896 self.assertEqual(9, len(outfiles))
2897 self.assertEqual(9, len(einfos))
2898
2899 image = control.images['image']
2900 entries = image.GetEntries()
2901
2902 # Check the 9 files in various ways
2903 section = entries['section']
2904 section_entries = section.GetEntries()
2905 cbfs_entries = section_entries['cbfs'].GetEntries()
2906 _CheckPresent('u-boot', U_BOOT_DATA)
2907 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2908 dtb_len = EXTRACT_DTB_SIZE
2909 if not decomp:
2910 dtb_len = cbfs_entries['u-boot-dtb'].size
2911 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2912 if not decomp:
2913 dtb_len = section_entries['u-boot-dtb'].size
2914 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2915
2916 fdtmap = entries['fdtmap']
2917 _CheckPresent('fdtmap', fdtmap.data)
2918 hdr = entries['image-header']
2919 _CheckPresent('image-header', hdr.data)
2920
2921 _CheckPresent('section/root', section.data)
2922 cbfs = section_entries['cbfs']
2923 _CheckPresent('section/cbfs/root', cbfs.data)
2924 data = tools.ReadFile(image_fname)
2925 _CheckPresent('root', data)
2926
2927 # There should be no files left. Remove all the directories to check.
2928 # If there are any files/dirs remaining, one of these checks will fail.
2929 self.assertEqual(0, len(outfiles))
2930 _CheckDirPresent('section/cbfs')
2931 _CheckDirPresent('section')
2932 _CheckDirPresent('')
2933 self.assertFalse(os.path.exists(outdir))
2934
2935 def testExtractAllEntries(self):
2936 """Test extracting all entries"""
2937 self._CheckLz4()
2938 self._CheckExtractOutput(decomp=True)
2939
2940 def testExtractAllEntriesRaw(self):
2941 """Test extracting all entries without decompressing them"""
2942 self._CheckLz4()
2943 self._CheckExtractOutput(decomp=False)
2944
2945 def testExtractSelectedEntries(self):
2946 """Test extracting some entries"""
2947 self._CheckLz4()
2948 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2949 image_fname = tools.GetOutputFilename('image.bin')
2950 outdir = os.path.join(self._indir, 'extract')
2951 einfos = control.ExtractEntries(image_fname, None, outdir,
2952 ['*cb*', '*head*'])
2953
2954 # File output is tested by testExtractAllEntries(), so just check that
2955 # the expected entries are selected
2956 names = [einfo.name for einfo in einfos]
2957 self.assertEqual(names,
2958 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2959
2960 def testExtractNoEntryPaths(self):
2961 """Test extracting some entries"""
2962 self._CheckLz4()
2963 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2964 image_fname = tools.GetOutputFilename('image.bin')
2965 with self.assertRaises(ValueError) as e:
2966 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002967 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002968 str(e.exception))
2969
2970 def testExtractTooManyEntryPaths(self):
2971 """Test extracting some entries"""
2972 self._CheckLz4()
2973 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2974 image_fname = tools.GetOutputFilename('image.bin')
2975 with self.assertRaises(ValueError) as e:
2976 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002977 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002978 str(e.exception))
2979
Simon Glass52d06212019-07-08 14:25:53 -06002980 def testPackAlignSection(self):
2981 """Test that sections can have alignment"""
2982 self._DoReadFile('131_pack_align_section.dts')
2983
2984 self.assertIn('image', control.images)
2985 image = control.images['image']
2986 entries = image.GetEntries()
2987 self.assertEqual(3, len(entries))
2988
2989 # First u-boot
2990 self.assertIn('u-boot', entries)
2991 entry = entries['u-boot']
2992 self.assertEqual(0, entry.offset)
2993 self.assertEqual(0, entry.image_pos)
2994 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
2995 self.assertEqual(len(U_BOOT_DATA), entry.size)
2996
2997 # Section0
2998 self.assertIn('section0', entries)
2999 section0 = entries['section0']
3000 self.assertEqual(0x10, section0.offset)
3001 self.assertEqual(0x10, section0.image_pos)
3002 self.assertEqual(len(U_BOOT_DATA), section0.size)
3003
3004 # Second u-boot
3005 section_entries = section0.GetEntries()
3006 self.assertIn('u-boot', section_entries)
3007 entry = section_entries['u-boot']
3008 self.assertEqual(0, entry.offset)
3009 self.assertEqual(0x10, entry.image_pos)
3010 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3011 self.assertEqual(len(U_BOOT_DATA), entry.size)
3012
3013 # Section1
3014 self.assertIn('section1', entries)
3015 section1 = entries['section1']
3016 self.assertEqual(0x14, section1.offset)
3017 self.assertEqual(0x14, section1.image_pos)
3018 self.assertEqual(0x20, section1.size)
3019
3020 # Second u-boot
3021 section_entries = section1.GetEntries()
3022 self.assertIn('u-boot', section_entries)
3023 entry = section_entries['u-boot']
3024 self.assertEqual(0, entry.offset)
3025 self.assertEqual(0x14, entry.image_pos)
3026 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3027 self.assertEqual(len(U_BOOT_DATA), entry.size)
3028
3029 # Section2
3030 self.assertIn('section2', section_entries)
3031 section2 = section_entries['section2']
3032 self.assertEqual(0x4, section2.offset)
3033 self.assertEqual(0x18, section2.image_pos)
3034 self.assertEqual(4, section2.size)
3035
3036 # Third u-boot
3037 section_entries = section2.GetEntries()
3038 self.assertIn('u-boot', section_entries)
3039 entry = section_entries['u-boot']
3040 self.assertEqual(0, entry.offset)
3041 self.assertEqual(0x18, entry.image_pos)
3042 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3043 self.assertEqual(len(U_BOOT_DATA), entry.size)
3044
Simon Glassf8a54bc2019-07-20 12:23:56 -06003045 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3046 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003047 """Replace an entry in an image
3048
3049 This writes the entry data to update it, then opens the updated file and
3050 returns the value that it now finds there.
3051
3052 Args:
3053 entry_name: Entry name to replace
3054 data: Data to replace it with
3055 decomp: True to compress the data if needed, False if data is
3056 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003057 allow_resize: True to allow entries to change size, False to raise
3058 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003059
3060 Returns:
3061 Tuple:
3062 data from entry
3063 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003064 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003065 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003066 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003067 update_dtb=True)[1]
3068
3069 self.assertIn('image', control.images)
3070 image = control.images['image']
3071 entries = image.GetEntries()
3072 orig_dtb_data = entries['u-boot-dtb'].data
3073 orig_fdtmap_data = entries['fdtmap'].data
3074
3075 image_fname = tools.GetOutputFilename('image.bin')
3076 updated_fname = tools.GetOutputFilename('image-updated.bin')
3077 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003078 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3079 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003080 data = control.ReadEntry(updated_fname, entry_name, decomp)
3081
Simon Glassf8a54bc2019-07-20 12:23:56 -06003082 # The DT data should not change unless resized:
3083 if not allow_resize:
3084 new_dtb_data = entries['u-boot-dtb'].data
3085 self.assertEqual(new_dtb_data, orig_dtb_data)
3086 new_fdtmap_data = entries['fdtmap'].data
3087 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003088
Simon Glassf8a54bc2019-07-20 12:23:56 -06003089 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003090
3091 def testReplaceSimple(self):
3092 """Test replacing a single file"""
3093 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003094 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3095 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003096 self.assertEqual(expected, data)
3097
3098 # Test that the state looks right. There should be an FDT for the fdtmap
3099 # that we jsut read back in, and it should match what we find in the
3100 # 'control' tables. Checking for an FDT that does not exist should
3101 # return None.
3102 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003103 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003104 self.assertEqual(expected_fdtmap, fdtmap)
3105
3106 dtb = state.GetFdtForEtype('fdtmap')
3107 self.assertEqual(dtb.GetContents(), fdtmap)
3108
3109 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3110 self.assertIsNone(missing_path)
3111 self.assertIsNone(missing_fdtmap)
3112
3113 missing_dtb = state.GetFdtForEtype('missing')
3114 self.assertIsNone(missing_dtb)
3115
3116 self.assertEqual('/binman', state.fdt_path_prefix)
3117
3118 def testReplaceResizeFail(self):
3119 """Test replacing a file by something larger"""
3120 expected = U_BOOT_DATA + b'x'
3121 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003122 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3123 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003124 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3125 str(e.exception))
3126
3127 def testReplaceMulti(self):
3128 """Test replacing entry data where multiple images are generated"""
3129 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3130 update_dtb=True)[0]
3131 expected = b'x' * len(U_BOOT_DATA)
3132 updated_fname = tools.GetOutputFilename('image-updated.bin')
3133 tools.WriteFile(updated_fname, data)
3134 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003135 control.WriteEntry(updated_fname, entry_name, expected,
3136 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003137 data = control.ReadEntry(updated_fname, entry_name)
3138 self.assertEqual(expected, data)
3139
3140 # Check the state looks right.
3141 self.assertEqual('/binman/image', state.fdt_path_prefix)
3142
3143 # Now check we can write the first image
3144 image_fname = tools.GetOutputFilename('first-image.bin')
3145 updated_fname = tools.GetOutputFilename('first-updated.bin')
3146 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3147 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003148 control.WriteEntry(updated_fname, entry_name, expected,
3149 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003150 data = control.ReadEntry(updated_fname, entry_name)
3151 self.assertEqual(expected, data)
3152
3153 # Check the state looks right.
3154 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003155
Simon Glassfb30e292019-07-20 12:23:51 -06003156 def testUpdateFdtAllRepack(self):
3157 """Test that all device trees are updated with offset/size info"""
3158 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3159 SECTION_SIZE = 0x300
3160 DTB_SIZE = 602
3161 FDTMAP_SIZE = 608
3162 base_expected = {
3163 'offset': 0,
3164 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3165 'image-pos': 0,
3166 'section:offset': 0,
3167 'section:size': SECTION_SIZE,
3168 'section:image-pos': 0,
3169 'section/u-boot-dtb:offset': 4,
3170 'section/u-boot-dtb:size': 636,
3171 'section/u-boot-dtb:image-pos': 4,
3172 'u-boot-spl-dtb:offset': SECTION_SIZE,
3173 'u-boot-spl-dtb:size': DTB_SIZE,
3174 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3175 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3176 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3177 'u-boot-tpl-dtb:size': DTB_SIZE,
3178 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3179 'fdtmap:size': FDTMAP_SIZE,
3180 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3181 }
3182 main_expected = {
3183 'section:orig-size': SECTION_SIZE,
3184 'section/u-boot-dtb:orig-offset': 4,
3185 }
3186
3187 # We expect three device-tree files in the output, with the first one
3188 # within a fixed-size section.
3189 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3190 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3191 # main U-Boot tree. All three should have the same positions and offset
3192 # except that the main tree should include the main_expected properties
3193 start = 4
3194 for item in ['', 'spl', 'tpl', None]:
3195 if item is None:
3196 start += 16 # Move past fdtmap header
3197 dtb = fdt.Fdt.FromData(data[start:])
3198 dtb.Scan()
3199 props = self._GetPropTree(dtb,
3200 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3201 prefix='/' if item is None else '/binman/')
3202 expected = dict(base_expected)
3203 if item:
3204 expected[item] = 0
3205 else:
3206 # Main DTB and fdtdec should include the 'orig-' properties
3207 expected.update(main_expected)
3208 # Helpful for debugging:
3209 #for prop in sorted(props):
3210 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3211 self.assertEqual(expected, props)
3212 if item == '':
3213 start = SECTION_SIZE
3214 else:
3215 start += dtb._fdt_obj.totalsize()
3216
Simon Glass11453762019-07-20 12:23:55 -06003217 def testFdtmapHeaderMiddle(self):
3218 """Test an FDT map in the middle of an image when it should be at end"""
3219 with self.assertRaises(ValueError) as e:
3220 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3221 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3222 str(e.exception))
3223
3224 def testFdtmapHeaderStartBad(self):
3225 """Test an FDT map in middle of an image when it should be at start"""
3226 with self.assertRaises(ValueError) as e:
3227 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3228 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3229 str(e.exception))
3230
3231 def testFdtmapHeaderEndBad(self):
3232 """Test an FDT map at the start of an image when it should be at end"""
3233 with self.assertRaises(ValueError) as e:
3234 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3235 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3236 str(e.exception))
3237
3238 def testFdtmapHeaderNoSize(self):
3239 """Test an image header at the end of an image with undefined size"""
3240 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3241
Simon Glassf8a54bc2019-07-20 12:23:56 -06003242 def testReplaceResize(self):
3243 """Test replacing a single file in an entry with a larger file"""
3244 expected = U_BOOT_DATA + b'x'
3245 data, _, image = self._RunReplaceCmd('u-boot', expected,
3246 dts='139_replace_repack.dts')
3247 self.assertEqual(expected, data)
3248
3249 entries = image.GetEntries()
3250 dtb_data = entries['u-boot-dtb'].data
3251 dtb = fdt.Fdt.FromData(dtb_data)
3252 dtb.Scan()
3253
3254 # The u-boot section should now be larger in the dtb
3255 node = dtb.GetNode('/binman/u-boot')
3256 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3257
3258 # Same for the fdtmap
3259 fdata = entries['fdtmap'].data
3260 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3261 fdtb.Scan()
3262 fnode = fdtb.GetNode('/u-boot')
3263 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3264
3265 def testReplaceResizeNoRepack(self):
3266 """Test replacing an entry with a larger file when not allowed"""
3267 expected = U_BOOT_DATA + b'x'
3268 with self.assertRaises(ValueError) as e:
3269 self._RunReplaceCmd('u-boot', expected)
3270 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3271 str(e.exception))
3272
Simon Glass9d8ee322019-07-20 12:23:58 -06003273 def testEntryShrink(self):
3274 """Test contracting an entry after it is packed"""
3275 try:
3276 state.SetAllowEntryContraction(True)
3277 data = self._DoReadFileDtb('140_entry_shrink.dts',
3278 update_dtb=True)[0]
3279 finally:
3280 state.SetAllowEntryContraction(False)
3281 self.assertEqual(b'a', data[:1])
3282 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3283 self.assertEqual(b'a', data[-1:])
3284
3285 def testEntryShrinkFail(self):
3286 """Test not being allowed to contract an entry after it is packed"""
3287 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3288
3289 # In this case there is a spare byte at the end of the data. The size of
3290 # the contents is only 1 byte but we still have the size before it
3291 # shrunk.
3292 self.assertEqual(b'a\0', data[:2])
3293 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3294 self.assertEqual(b'a\0', data[-2:])
3295
Simon Glass70e32982019-07-20 12:24:01 -06003296 def testDescriptorOffset(self):
3297 """Test that the Intel descriptor is always placed at at the start"""
3298 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3299 image = control.images['image']
3300 entries = image.GetEntries()
3301 desc = entries['intel-descriptor']
3302 self.assertEqual(0xff800000, desc.offset);
3303 self.assertEqual(0xff800000, desc.image_pos);
3304
Simon Glass37fdd142019-07-20 12:24:06 -06003305 def testReplaceCbfs(self):
3306 """Test replacing a single file in CBFS without changing the size"""
3307 self._CheckLz4()
3308 expected = b'x' * len(U_BOOT_DATA)
3309 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3310 updated_fname = tools.GetOutputFilename('image-updated.bin')
3311 tools.WriteFile(updated_fname, data)
3312 entry_name = 'section/cbfs/u-boot'
3313 control.WriteEntry(updated_fname, entry_name, expected,
3314 allow_resize=True)
3315 data = control.ReadEntry(updated_fname, entry_name)
3316 self.assertEqual(expected, data)
3317
3318 def testReplaceResizeCbfs(self):
3319 """Test replacing a single file in CBFS with one of a different size"""
3320 self._CheckLz4()
3321 expected = U_BOOT_DATA + b'x'
3322 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3323 updated_fname = tools.GetOutputFilename('image-updated.bin')
3324 tools.WriteFile(updated_fname, data)
3325 entry_name = 'section/cbfs/u-boot'
3326 control.WriteEntry(updated_fname, entry_name, expected,
3327 allow_resize=True)
3328 data = control.ReadEntry(updated_fname, entry_name)
3329 self.assertEqual(expected, data)
3330
Simon Glass30033c22019-07-20 12:24:15 -06003331 def _SetupForReplace(self):
3332 """Set up some files to use to replace entries
3333
3334 This generates an image, copies it to a new file, extracts all the files
3335 in it and updates some of them
3336
3337 Returns:
3338 List
3339 Image filename
3340 Output directory
3341 Expected values for updated entries, each a string
3342 """
3343 data = self._DoReadFileRealDtb('143_replace_all.dts')
3344
3345 updated_fname = tools.GetOutputFilename('image-updated.bin')
3346 tools.WriteFile(updated_fname, data)
3347
3348 outdir = os.path.join(self._indir, 'extract')
3349 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3350
3351 expected1 = b'x' + U_BOOT_DATA + b'y'
3352 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3353 tools.WriteFile(u_boot_fname1, expected1)
3354
3355 expected2 = b'a' + U_BOOT_DATA + b'b'
3356 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3357 tools.WriteFile(u_boot_fname2, expected2)
3358
3359 expected_text = b'not the same text'
3360 text_fname = os.path.join(outdir, 'text')
3361 tools.WriteFile(text_fname, expected_text)
3362
3363 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3364 dtb = fdt.FdtScan(dtb_fname)
3365 node = dtb.GetNode('/binman/text')
3366 node.AddString('my-property', 'the value')
3367 dtb.Sync(auto_resize=True)
3368 dtb.Flush()
3369
3370 return updated_fname, outdir, expected1, expected2, expected_text
3371
3372 def _CheckReplaceMultiple(self, entry_paths):
3373 """Handle replacing the contents of multiple entries
3374
3375 Args:
3376 entry_paths: List of entry paths to replace
3377
3378 Returns:
3379 List
3380 Dict of entries in the image:
3381 key: Entry name
3382 Value: Entry object
3383 Expected values for updated entries, each a string
3384 """
3385 updated_fname, outdir, expected1, expected2, expected_text = (
3386 self._SetupForReplace())
3387 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3388
3389 image = Image.FromFile(updated_fname)
3390 image.LoadData()
3391 return image.GetEntries(), expected1, expected2, expected_text
3392
3393 def testReplaceAll(self):
3394 """Test replacing the contents of all entries"""
3395 entries, expected1, expected2, expected_text = (
3396 self._CheckReplaceMultiple([]))
3397 data = entries['u-boot'].data
3398 self.assertEqual(expected1, data)
3399
3400 data = entries['u-boot2'].data
3401 self.assertEqual(expected2, data)
3402
3403 data = entries['text'].data
3404 self.assertEqual(expected_text, data)
3405
3406 # Check that the device tree is updated
3407 data = entries['u-boot-dtb'].data
3408 dtb = fdt.Fdt.FromData(data)
3409 dtb.Scan()
3410 node = dtb.GetNode('/binman/text')
3411 self.assertEqual('the value', node.props['my-property'].value)
3412
3413 def testReplaceSome(self):
3414 """Test replacing the contents of a few entries"""
3415 entries, expected1, expected2, expected_text = (
3416 self._CheckReplaceMultiple(['u-boot2', 'text']))
3417
3418 # This one should not change
3419 data = entries['u-boot'].data
3420 self.assertEqual(U_BOOT_DATA, data)
3421
3422 data = entries['u-boot2'].data
3423 self.assertEqual(expected2, data)
3424
3425 data = entries['text'].data
3426 self.assertEqual(expected_text, data)
3427
3428 def testReplaceCmd(self):
3429 """Test replacing a file fron an image on the command line"""
3430 self._DoReadFileRealDtb('143_replace_all.dts')
3431
3432 try:
3433 tmpdir, updated_fname = self._SetupImageInTmpdir()
3434
3435 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3436 expected = b'x' * len(U_BOOT_DATA)
3437 tools.WriteFile(fname, expected)
3438
3439 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3440 data = tools.ReadFile(updated_fname)
3441 self.assertEqual(expected, data[:len(expected)])
3442 map_fname = os.path.join(tmpdir, 'image-updated.map')
3443 self.assertFalse(os.path.exists(map_fname))
3444 finally:
3445 shutil.rmtree(tmpdir)
3446
3447 def testReplaceCmdSome(self):
3448 """Test replacing some files fron an image on the command line"""
3449 updated_fname, outdir, expected1, expected2, expected_text = (
3450 self._SetupForReplace())
3451
3452 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3453 'u-boot2', 'text')
3454
3455 tools.PrepareOutputDir(None)
3456 image = Image.FromFile(updated_fname)
3457 image.LoadData()
3458 entries = image.GetEntries()
3459
3460 # This one should not change
3461 data = entries['u-boot'].data
3462 self.assertEqual(U_BOOT_DATA, data)
3463
3464 data = entries['u-boot2'].data
3465 self.assertEqual(expected2, data)
3466
3467 data = entries['text'].data
3468 self.assertEqual(expected_text, data)
3469
3470 def testReplaceMissing(self):
3471 """Test replacing entries where the file is missing"""
3472 updated_fname, outdir, expected1, expected2, expected_text = (
3473 self._SetupForReplace())
3474
3475 # Remove one of the files, to generate a warning
3476 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3477 os.remove(u_boot_fname1)
3478
3479 with test_util.capture_sys_output() as (stdout, stderr):
3480 control.ReplaceEntries(updated_fname, None, outdir, [])
3481 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003482 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003483
3484 def testReplaceCmdMap(self):
3485 """Test replacing a file fron an image on the command line"""
3486 self._DoReadFileRealDtb('143_replace_all.dts')
3487
3488 try:
3489 tmpdir, updated_fname = self._SetupImageInTmpdir()
3490
3491 fname = os.path.join(self._indir, 'update-u-boot.bin')
3492 expected = b'x' * len(U_BOOT_DATA)
3493 tools.WriteFile(fname, expected)
3494
3495 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3496 '-f', fname, '-m')
3497 map_fname = os.path.join(tmpdir, 'image-updated.map')
3498 self.assertTrue(os.path.exists(map_fname))
3499 finally:
3500 shutil.rmtree(tmpdir)
3501
3502 def testReplaceNoEntryPaths(self):
3503 """Test replacing an entry without an entry path"""
3504 self._DoReadFileRealDtb('143_replace_all.dts')
3505 image_fname = tools.GetOutputFilename('image.bin')
3506 with self.assertRaises(ValueError) as e:
3507 control.ReplaceEntries(image_fname, 'fname', None, [])
3508 self.assertIn('Must specify an entry path to read with -f',
3509 str(e.exception))
3510
3511 def testReplaceTooManyEntryPaths(self):
3512 """Test extracting some entries"""
3513 self._DoReadFileRealDtb('143_replace_all.dts')
3514 image_fname = tools.GetOutputFilename('image.bin')
3515 with self.assertRaises(ValueError) as e:
3516 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3517 self.assertIn('Must specify exactly one entry path to write with -f',
3518 str(e.exception))
3519
Simon Glass0b074d62019-08-24 07:22:48 -06003520 def testPackReset16(self):
3521 """Test that an image with an x86 reset16 region can be created"""
3522 data = self._DoReadFile('144_x86_reset16.dts')
3523 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3524
3525 def testPackReset16Spl(self):
3526 """Test that an image with an x86 reset16-spl region can be created"""
3527 data = self._DoReadFile('145_x86_reset16_spl.dts')
3528 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3529
3530 def testPackReset16Tpl(self):
3531 """Test that an image with an x86 reset16-tpl region can be created"""
3532 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3533 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3534
Simon Glass232f90c2019-08-24 07:22:50 -06003535 def testPackIntelFit(self):
3536 """Test that an image with an Intel FIT and pointer can be created"""
3537 data = self._DoReadFile('147_intel_fit.dts')
3538 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3539 fit = data[16:32];
3540 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3541 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3542
3543 image = control.images['image']
3544 entries = image.GetEntries()
3545 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3546 self.assertEqual(expected_ptr, ptr)
3547
3548 def testPackIntelFitMissing(self):
3549 """Test detection of a FIT pointer with not FIT region"""
3550 with self.assertRaises(ValueError) as e:
3551 self._DoReadFile('148_intel_fit_missing.dts')
3552 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3553 str(e.exception))
3554
Simon Glass72555fa2019-11-06 17:22:44 -07003555 def _CheckSymbolsTplSection(self, dts, expected_vals):
3556 data = self._DoReadFile(dts)
3557 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003558 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003559 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003560 self.assertEqual(expected1, data[:upto1])
3561
3562 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003563 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003564 self.assertEqual(expected2, data[upto1:upto2])
3565
Simon Glass4e353e22019-08-24 07:23:04 -06003566 upto3 = 0x34 + len(U_BOOT_DATA)
3567 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003568 self.assertEqual(expected3, data[upto2:upto3])
3569
Simon Glass3f8ff012019-08-24 07:23:05 -06003570 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003571 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3572
3573 def testSymbolsTplSection(self):
3574 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3575 self._SetupSplElf('u_boot_binman_syms')
3576 self._SetupTplElf('u_boot_binman_syms')
3577 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3578 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3579
3580 def testSymbolsTplSectionX86(self):
3581 """Test binman can assign symbols in a section with end-at-4gb"""
3582 self._SetupSplElf('u_boot_binman_syms_x86')
3583 self._SetupTplElf('u_boot_binman_syms_x86')
3584 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3585 [0xffffff04, 0xffffff1c, 0xffffff34,
3586 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003587
Simon Glass98c59572019-08-24 07:23:03 -06003588 def testPackX86RomIfwiSectiom(self):
3589 """Test that a section can be placed in an IFWI region"""
3590 self._SetupIfwi('fitimage.bin')
3591 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3592 self._CheckIfwi(data)
3593
Simon Glassba7985d2019-08-24 07:23:07 -06003594 def testPackFspM(self):
3595 """Test that an image with a FSP memory-init binary can be created"""
3596 data = self._DoReadFile('152_intel_fsp_m.dts')
3597 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3598
Simon Glass4d9086d2019-10-20 21:31:35 -06003599 def testPackFspS(self):
3600 """Test that an image with a FSP silicon-init binary can be created"""
3601 data = self._DoReadFile('153_intel_fsp_s.dts')
3602 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003603
Simon Glass9ea87b22019-10-20 21:31:36 -06003604 def testPackFspT(self):
3605 """Test that an image with a FSP temp-ram-init binary can be created"""
3606 data = self._DoReadFile('154_intel_fsp_t.dts')
3607 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3608
Simon Glass48f3aad2020-07-09 18:39:31 -06003609 def testMkimage(self):
3610 """Test using mkimage to build an image"""
3611 data = self._DoReadFile('156_mkimage.dts')
3612
3613 # Just check that the data appears in the file somewhere
3614 self.assertIn(U_BOOT_SPL_DATA, data)
3615
Simon Glass5e560182020-07-09 18:39:36 -06003616 def testExtblob(self):
3617 """Test an image with an external blob"""
3618 data = self._DoReadFile('157_blob_ext.dts')
3619 self.assertEqual(REFCODE_DATA, data)
3620
3621 def testExtblobMissing(self):
3622 """Test an image with a missing external blob"""
3623 with self.assertRaises(ValueError) as e:
3624 self._DoReadFile('158_blob_ext_missing.dts')
3625 self.assertIn("Filename 'missing-file' not found in input path",
3626 str(e.exception))
3627
Simon Glass5d94cc62020-07-09 18:39:38 -06003628 def testExtblobMissingOk(self):
3629 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003630 with test_util.capture_sys_output() as (stdout, stderr):
3631 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3632 err = stderr.getvalue()
3633 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3634
3635 def testExtblobMissingOkSect(self):
3636 """Test an image with an missing external blob that is allowed"""
3637 with test_util.capture_sys_output() as (stdout, stderr):
3638 self._DoTestFile('159_blob_ext_missing_sect.dts',
3639 allow_missing=True)
3640 err = stderr.getvalue()
3641 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3642 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003643
Simon Glasse88cef92020-07-09 18:39:41 -06003644 def testPackX86RomMeMissingDesc(self):
3645 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003646 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003647 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003648 err = stderr.getvalue()
3649 self.assertRegex(err,
3650 "Image 'main-section'.*missing.*: intel-descriptor")
3651
3652 def testPackX86RomMissingIfwi(self):
3653 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3654 self._SetupIfwi('fitimage.bin')
3655 pathname = os.path.join(self._indir, 'fitimage.bin')
3656 os.remove(pathname)
3657 with test_util.capture_sys_output() as (stdout, stderr):
3658 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3659 err = stderr.getvalue()
3660 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3661
Simon Glassd70829a2020-07-09 18:39:42 -06003662 def testPackOverlap(self):
3663 """Test that zero-size overlapping regions are ignored"""
3664 self._DoTestFile('160_pack_overlap_zero.dts')
3665
Simon Glass45d556d2020-07-09 18:39:45 -06003666 def testSimpleFit(self):
3667 """Test an image with a FIT inside"""
3668 data = self._DoReadFile('161_fit.dts')
3669 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3670 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3671 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3672
3673 # The data should be inside the FIT
3674 dtb = fdt.Fdt.FromData(fit_data)
3675 dtb.Scan()
3676 fnode = dtb.GetNode('/images/kernel')
3677 self.assertIn('data', fnode.props)
3678
3679 fname = os.path.join(self._indir, 'fit_data.fit')
3680 tools.WriteFile(fname, fit_data)
3681 out = tools.Run('dumpimage', '-l', fname)
3682
3683 # Check a few features to make sure the plumbing works. We don't need
3684 # to test the operation of mkimage or dumpimage here. First convert the
3685 # output into a dict where the keys are the fields printed by dumpimage
3686 # and the values are a list of values for each field
3687 lines = out.splitlines()
3688
3689 # Converts "Compression: gzip compressed" into two groups:
3690 # 'Compression' and 'gzip compressed'
3691 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3692 vals = collections.defaultdict(list)
3693 for line in lines:
3694 mat = re_line.match(line)
3695 vals[mat.group(1)].append(mat.group(2))
3696
3697 self.assertEquals('FIT description: test-desc', lines[0])
3698 self.assertIn('Created:', lines[1])
3699 self.assertIn('Image 0 (kernel)', vals)
3700 self.assertIn('Hash value', vals)
3701 data_sizes = vals.get('Data Size')
3702 self.assertIsNotNone(data_sizes)
3703 self.assertEqual(2, len(data_sizes))
3704 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3705 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3706 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3707
3708 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003709 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003710 data = self._DoReadFile('162_fit_external.dts')
3711 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3712
3713 # The data should be outside the FIT
3714 dtb = fdt.Fdt.FromData(fit_data)
3715 dtb.Scan()
3716 fnode = dtb.GetNode('/images/kernel')
3717 self.assertNotIn('data', fnode.props)
Simon Glassfb30e292019-07-20 12:23:51 -06003718
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003719 def testSectionIgnoreHashSignature(self):
3720 """Test that sections ignore hash, signature nodes for its data"""
3721 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3722 expected = (U_BOOT_DATA + U_BOOT_DATA)
3723 self.assertEqual(expected, data)
3724
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003725 def testPadInSections(self):
3726 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003727 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3728 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003729 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3730 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3731 U_BOOT_DATA)
3732 self.assertEqual(expected, data)
3733
Simon Glassd12599d2020-10-26 17:40:09 -06003734 dtb = fdt.Fdt(out_dtb_fname)
3735 dtb.Scan()
3736 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3737 expected = {
3738 'image-pos': 0,
3739 'offset': 0,
3740 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3741
3742 'section:image-pos': 0,
3743 'section:offset': 0,
3744 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3745
3746 'section/before:image-pos': 0,
3747 'section/before:offset': 0,
3748 'section/before:size': len(U_BOOT_DATA),
3749
3750 'section/u-boot:image-pos': 4,
3751 'section/u-boot:offset': 4,
3752 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3753
3754 'section/after:image-pos': 26,
3755 'section/after:offset': 26,
3756 'section/after:size': len(U_BOOT_DATA),
3757 }
3758 self.assertEqual(expected, props)
3759
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003760 def testFitImageSubentryAlignment(self):
3761 """Test relative alignability of FIT image subentries"""
3762 entry_args = {
3763 'test-id': TEXT_DATA,
3764 }
3765 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3766 entry_args=entry_args)
3767 dtb = fdt.Fdt.FromData(data)
3768 dtb.Scan()
3769
3770 node = dtb.GetNode('/images/kernel')
3771 data = dtb.GetProps(node)["data"].bytes
3772 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3773 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3774 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3775 self.assertEqual(expected, data)
3776
3777 node = dtb.GetNode('/images/fdt-1')
3778 data = dtb.GetProps(node)["data"].bytes
3779 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3780 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3781 U_BOOT_DTB_DATA)
3782 self.assertEqual(expected, data)
3783
3784 def testFitExtblobMissingOk(self):
3785 """Test a FIT with a missing external blob that is allowed"""
3786 with test_util.capture_sys_output() as (stdout, stderr):
3787 self._DoTestFile('168_fit_missing_blob.dts',
3788 allow_missing=True)
3789 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003790 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003791
Simon Glass21db0ff2020-09-01 05:13:54 -06003792 def testBlobNamedByArgMissing(self):
3793 """Test handling of a missing entry arg"""
3794 with self.assertRaises(ValueError) as e:
3795 self._DoReadFile('068_blob_named_by_arg.dts')
3796 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3797 str(e.exception))
3798
Simon Glass559c4de2020-09-01 05:13:58 -06003799 def testPackBl31(self):
3800 """Test that an image with an ATF BL31 binary can be created"""
3801 data = self._DoReadFile('169_atf_bl31.dts')
3802 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3803
Samuel Holland9d8cc632020-10-21 21:12:15 -05003804 def testPackScp(self):
3805 """Test that an image with an SCP binary can be created"""
3806 data = self._DoReadFile('172_scp.dts')
3807 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3808
Simon Glassa435cd12020-09-01 05:13:59 -06003809 def testFitFdt(self):
3810 """Test an image with an FIT with multiple FDT images"""
3811 def _CheckFdt(seq, expected_data):
3812 """Check the FDT nodes
3813
3814 Args:
3815 seq: Sequence number to check (0 or 1)
3816 expected_data: Expected contents of 'data' property
3817 """
3818 name = 'fdt-%d' % seq
3819 fnode = dtb.GetNode('/images/%s' % name)
3820 self.assertIsNotNone(fnode)
3821 self.assertEqual({'description','type', 'compression', 'data'},
3822 set(fnode.props.keys()))
3823 self.assertEqual(expected_data, fnode.props['data'].bytes)
3824 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3825 fnode.props['description'].value)
3826
3827 def _CheckConfig(seq, expected_data):
3828 """Check the configuration nodes
3829
3830 Args:
3831 seq: Sequence number to check (0 or 1)
3832 expected_data: Expected contents of 'data' property
3833 """
3834 cnode = dtb.GetNode('/configurations')
3835 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003836 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003837
3838 name = 'config-%d' % seq
3839 fnode = dtb.GetNode('/configurations/%s' % name)
3840 self.assertIsNotNone(fnode)
3841 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3842 set(fnode.props.keys()))
3843 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3844 fnode.props['description'].value)
3845 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3846
3847 entry_args = {
3848 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003849 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003850 }
3851 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003852 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003853 entry_args=entry_args,
3854 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3855 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3856 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3857
3858 dtb = fdt.Fdt.FromData(fit_data)
3859 dtb.Scan()
3860 fnode = dtb.GetNode('/images/kernel')
3861 self.assertIn('data', fnode.props)
3862
3863 # Check all the properties in fdt-1 and fdt-2
3864 _CheckFdt(1, TEST_FDT1_DATA)
3865 _CheckFdt(2, TEST_FDT2_DATA)
3866
3867 # Check configurations
3868 _CheckConfig(1, TEST_FDT1_DATA)
3869 _CheckConfig(2, TEST_FDT2_DATA)
3870
3871 def testFitFdtMissingList(self):
3872 """Test handling of a missing 'of-list' entry arg"""
3873 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08003874 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003875 self.assertIn("Generator node requires 'of-list' entry argument",
3876 str(e.exception))
3877
3878 def testFitFdtEmptyList(self):
3879 """Test handling of an empty 'of-list' entry arg"""
3880 entry_args = {
3881 'of-list': '',
3882 }
3883 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3884
3885 def testFitFdtMissingProp(self):
3886 """Test handling of a missing 'fit,fdt-list' property"""
3887 with self.assertRaises(ValueError) as e:
3888 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3889 self.assertIn("Generator node requires 'fit,fdt-list' property",
3890 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003891
Simon Glass1032acc2020-09-06 10:39:08 -06003892 def testFitFdtEmptyList(self):
3893 """Test handling of an empty 'of-list' entry arg"""
3894 entry_args = {
3895 'of-list': '',
3896 }
Bin Meng16cf5662021-05-10 20:23:32 +08003897 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glass1032acc2020-09-06 10:39:08 -06003898
3899 def testFitFdtMissing(self):
3900 """Test handling of a missing 'default-dt' entry arg"""
3901 entry_args = {
3902 'of-list': 'test-fdt1 test-fdt2',
3903 }
3904 with self.assertRaises(ValueError) as e:
3905 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003906 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003907 entry_args=entry_args,
3908 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3909 self.assertIn("Generated 'default' node requires default-dt entry argument",
3910 str(e.exception))
3911
3912 def testFitFdtNotInList(self):
3913 """Test handling of a default-dt that is not in the of-list"""
3914 entry_args = {
3915 'of-list': 'test-fdt1 test-fdt2',
3916 'default-dt': 'test-fdt3',
3917 }
3918 with self.assertRaises(ValueError) as e:
3919 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003920 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003921 entry_args=entry_args,
3922 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3923 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3924 str(e.exception))
3925
Simon Glassa820af72020-09-06 10:39:09 -06003926 def testFitExtblobMissingHelp(self):
3927 """Test display of help messages when an external blob is missing"""
3928 control.missing_blob_help = control._ReadMissingBlobHelp()
3929 control.missing_blob_help['wibble'] = 'Wibble test'
3930 control.missing_blob_help['another'] = 'Another test'
3931 with test_util.capture_sys_output() as (stdout, stderr):
3932 self._DoTestFile('168_fit_missing_blob.dts',
3933 allow_missing=True)
3934 err = stderr.getvalue()
3935
3936 # We can get the tag from the name, the type or the missing-msg
3937 # property. Check all three.
3938 self.assertIn('You may need to build ARM Trusted', err)
3939 self.assertIn('Wibble test', err)
3940 self.assertIn('Another test', err)
3941
Simon Glass6f1f4d42020-09-06 10:35:32 -06003942 def testMissingBlob(self):
3943 """Test handling of a blob containing a missing file"""
3944 with self.assertRaises(ValueError) as e:
3945 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3946 self.assertIn("Filename 'missing' not found in input path",
3947 str(e.exception))
3948
Simon Glassa0729502020-09-06 10:35:33 -06003949 def testEnvironment(self):
3950 """Test adding a U-Boot environment"""
3951 data = self._DoReadFile('174_env.dts')
3952 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3953 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3954 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3955 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3956 env)
3957
3958 def testEnvironmentNoSize(self):
3959 """Test that a missing 'size' property is detected"""
3960 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003961 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003962 self.assertIn("'u-boot-env' entry must have a size property",
3963 str(e.exception))
3964
3965 def testEnvironmentTooSmall(self):
3966 """Test handling of an environment that does not fit"""
3967 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003968 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003969
3970 # checksum, start byte, environment with \0 terminator, final \0
3971 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3972 short = need - 0x8
3973 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3974 str(e.exception))
3975
Simon Glassd1fdf752020-10-26 17:40:01 -06003976 def testSkipAtStart(self):
3977 """Test handling of skip-at-start section"""
3978 data = self._DoReadFile('177_skip_at_start.dts')
3979 self.assertEqual(U_BOOT_DATA, data)
3980
3981 image = control.images['image']
3982 entries = image.GetEntries()
3983 section = entries['section']
3984 self.assertEqual(0, section.offset)
3985 self.assertEqual(len(U_BOOT_DATA), section.size)
3986 self.assertEqual(U_BOOT_DATA, section.GetData())
3987
3988 entry = section.GetEntries()['u-boot']
3989 self.assertEqual(16, entry.offset)
3990 self.assertEqual(len(U_BOOT_DATA), entry.size)
3991 self.assertEqual(U_BOOT_DATA, entry.data)
3992
3993 def testSkipAtStartPad(self):
3994 """Test handling of skip-at-start section with padded entry"""
3995 data = self._DoReadFile('178_skip_at_start_pad.dts')
3996 before = tools.GetBytes(0, 8)
3997 after = tools.GetBytes(0, 4)
3998 all = before + U_BOOT_DATA + after
3999 self.assertEqual(all, data)
4000
4001 image = control.images['image']
4002 entries = image.GetEntries()
4003 section = entries['section']
4004 self.assertEqual(0, section.offset)
4005 self.assertEqual(len(all), section.size)
4006 self.assertEqual(all, section.GetData())
4007
4008 entry = section.GetEntries()['u-boot']
4009 self.assertEqual(16, entry.offset)
4010 self.assertEqual(len(all), entry.size)
4011 self.assertEqual(U_BOOT_DATA, entry.data)
4012
4013 def testSkipAtStartSectionPad(self):
4014 """Test handling of skip-at-start section with padding"""
4015 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4016 before = tools.GetBytes(0, 8)
4017 after = tools.GetBytes(0, 4)
4018 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004019 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004020
4021 image = control.images['image']
4022 entries = image.GetEntries()
4023 section = entries['section']
4024 self.assertEqual(0, section.offset)
4025 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004026 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004027 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004028
4029 entry = section.GetEntries()['u-boot']
4030 self.assertEqual(16, entry.offset)
4031 self.assertEqual(len(U_BOOT_DATA), entry.size)
4032 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004033
Simon Glassbb395742020-10-26 17:40:14 -06004034 def testSectionPad(self):
4035 """Testing padding with sections"""
4036 data = self._DoReadFile('180_section_pad.dts')
4037 expected = (tools.GetBytes(ord('&'), 3) +
4038 tools.GetBytes(ord('!'), 5) +
4039 U_BOOT_DATA +
4040 tools.GetBytes(ord('!'), 1) +
4041 tools.GetBytes(ord('&'), 2))
4042 self.assertEqual(expected, data)
4043
4044 def testSectionAlign(self):
4045 """Testing alignment with sections"""
4046 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4047 expected = (b'\0' + # fill section
4048 tools.GetBytes(ord('&'), 1) + # padding to section align
4049 b'\0' + # fill section
4050 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4051 U_BOOT_DATA +
4052 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4053 tools.GetBytes(ord('!'), 4)) # padding to section size
4054 self.assertEqual(expected, data)
4055
Simon Glassd92c8362020-10-26 17:40:25 -06004056 def testCompressImage(self):
4057 """Test compression of the entire image"""
4058 self._CheckLz4()
4059 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4060 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4061 dtb = fdt.Fdt(out_dtb_fname)
4062 dtb.Scan()
4063 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4064 'uncomp-size'])
4065 orig = self._decompress(data)
4066 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4067
4068 # Do a sanity check on various fields
4069 image = control.images['image']
4070 entries = image.GetEntries()
4071 self.assertEqual(2, len(entries))
4072
4073 entry = entries['blob']
4074 self.assertEqual(COMPRESS_DATA, entry.data)
4075 self.assertEqual(len(COMPRESS_DATA), entry.size)
4076
4077 entry = entries['u-boot']
4078 self.assertEqual(U_BOOT_DATA, entry.data)
4079 self.assertEqual(len(U_BOOT_DATA), entry.size)
4080
4081 self.assertEqual(len(data), image.size)
4082 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4083 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4084 orig = self._decompress(image.data)
4085 self.assertEqual(orig, image.uncomp_data)
4086
4087 expected = {
4088 'blob:offset': 0,
4089 'blob:size': len(COMPRESS_DATA),
4090 'u-boot:offset': len(COMPRESS_DATA),
4091 'u-boot:size': len(U_BOOT_DATA),
4092 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4093 'offset': 0,
4094 'image-pos': 0,
4095 'size': len(data),
4096 }
4097 self.assertEqual(expected, props)
4098
4099 def testCompressImageLess(self):
4100 """Test compression where compression reduces the image size"""
4101 self._CheckLz4()
4102 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4103 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4104 dtb = fdt.Fdt(out_dtb_fname)
4105 dtb.Scan()
4106 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4107 'uncomp-size'])
4108 orig = self._decompress(data)
4109
4110 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4111
4112 # Do a sanity check on various fields
4113 image = control.images['image']
4114 entries = image.GetEntries()
4115 self.assertEqual(2, len(entries))
4116
4117 entry = entries['blob']
4118 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4119 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4120
4121 entry = entries['u-boot']
4122 self.assertEqual(U_BOOT_DATA, entry.data)
4123 self.assertEqual(len(U_BOOT_DATA), entry.size)
4124
4125 self.assertEqual(len(data), image.size)
4126 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4127 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4128 image.uncomp_size)
4129 orig = self._decompress(image.data)
4130 self.assertEqual(orig, image.uncomp_data)
4131
4132 expected = {
4133 'blob:offset': 0,
4134 'blob:size': len(COMPRESS_DATA_BIG),
4135 'u-boot:offset': len(COMPRESS_DATA_BIG),
4136 'u-boot:size': len(U_BOOT_DATA),
4137 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4138 'offset': 0,
4139 'image-pos': 0,
4140 'size': len(data),
4141 }
4142 self.assertEqual(expected, props)
4143
4144 def testCompressSectionSize(self):
4145 """Test compression of a section with a fixed size"""
4146 self._CheckLz4()
4147 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4148 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4149 dtb = fdt.Fdt(out_dtb_fname)
4150 dtb.Scan()
4151 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4152 'uncomp-size'])
4153 orig = self._decompress(data)
4154 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4155 expected = {
4156 'section/blob:offset': 0,
4157 'section/blob:size': len(COMPRESS_DATA),
4158 'section/u-boot:offset': len(COMPRESS_DATA),
4159 'section/u-boot:size': len(U_BOOT_DATA),
4160 'section:offset': 0,
4161 'section:image-pos': 0,
4162 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4163 'section:size': 0x30,
4164 'offset': 0,
4165 'image-pos': 0,
4166 'size': 0x30,
4167 }
4168 self.assertEqual(expected, props)
4169
4170 def testCompressSection(self):
4171 """Test compression of a section with no fixed size"""
4172 self._CheckLz4()
4173 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4174 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4175 dtb = fdt.Fdt(out_dtb_fname)
4176 dtb.Scan()
4177 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4178 'uncomp-size'])
4179 orig = self._decompress(data)
4180 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4181 expected = {
4182 'section/blob:offset': 0,
4183 'section/blob:size': len(COMPRESS_DATA),
4184 'section/u-boot:offset': len(COMPRESS_DATA),
4185 'section/u-boot:size': len(U_BOOT_DATA),
4186 'section:offset': 0,
4187 'section:image-pos': 0,
4188 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4189 'section:size': len(data),
4190 'offset': 0,
4191 'image-pos': 0,
4192 'size': len(data),
4193 }
4194 self.assertEqual(expected, props)
4195
4196 def testCompressExtra(self):
4197 """Test compression of a section with no fixed size"""
4198 self._CheckLz4()
4199 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4200 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4201 dtb = fdt.Fdt(out_dtb_fname)
4202 dtb.Scan()
4203 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4204 'uncomp-size'])
4205
4206 base = data[len(U_BOOT_DATA):]
4207 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4208 rest = base[len(U_BOOT_DATA):]
4209
4210 # Check compressed data
4211 section1 = self._decompress(rest)
4212 expect1 = tools.Compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
4213 self.assertEquals(expect1, rest[:len(expect1)])
4214 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4215 rest1 = rest[len(expect1):]
4216
4217 section2 = self._decompress(rest1)
4218 expect2 = tools.Compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
4219 self.assertEquals(expect2, rest1[:len(expect2)])
4220 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4221 rest2 = rest1[len(expect2):]
4222
4223 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4224 len(expect2) + len(U_BOOT_DATA))
4225 #self.assertEquals(expect_size, len(data))
4226
4227 #self.assertEquals(U_BOOT_DATA, rest2)
4228
4229 self.maxDiff = None
4230 expected = {
4231 'u-boot:offset': 0,
4232 'u-boot:image-pos': 0,
4233 'u-boot:size': len(U_BOOT_DATA),
4234
4235 'base:offset': len(U_BOOT_DATA),
4236 'base:image-pos': len(U_BOOT_DATA),
4237 'base:size': len(data) - len(U_BOOT_DATA),
4238 'base/u-boot:offset': 0,
4239 'base/u-boot:image-pos': len(U_BOOT_DATA),
4240 'base/u-boot:size': len(U_BOOT_DATA),
4241 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4242 len(expect2),
4243 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4244 len(expect2),
4245 'base/u-boot2:size': len(U_BOOT_DATA),
4246
4247 'base/section:offset': len(U_BOOT_DATA),
4248 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4249 'base/section:size': len(expect1),
4250 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4251 'base/section/blob:offset': 0,
4252 'base/section/blob:size': len(COMPRESS_DATA),
4253 'base/section/u-boot:offset': len(COMPRESS_DATA),
4254 'base/section/u-boot:size': len(U_BOOT_DATA),
4255
4256 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4257 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4258 'base/section2:size': len(expect2),
4259 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4260 'base/section2/blob:offset': 0,
4261 'base/section2/blob:size': len(COMPRESS_DATA),
4262 'base/section2/blob2:offset': len(COMPRESS_DATA),
4263 'base/section2/blob2:size': len(COMPRESS_DATA),
4264
4265 'offset': 0,
4266 'image-pos': 0,
4267 'size': len(data),
4268 }
4269 self.assertEqual(expected, props)
4270
Simon Glassecbe4732021-01-06 21:35:15 -07004271 def testSymbolsSubsection(self):
4272 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004273 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004274
Simon Glass3fb25402021-01-06 21:35:16 -07004275 def testReadImageEntryArg(self):
4276 """Test reading an image that would need an entry arg to generate"""
4277 entry_args = {
4278 'cros-ec-rw-path': 'ecrw.bin',
4279 }
4280 data = self.data = self._DoReadFileDtb(
4281 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4282 entry_args=entry_args)
4283
4284 image_fname = tools.GetOutputFilename('image.bin')
4285 orig_image = control.images['image']
4286
4287 # This should not generate an error about the missing 'cros-ec-rw-path'
4288 # since we are reading the image from a file. Compare with
4289 # testEntryArgsRequired()
4290 image = Image.FromFile(image_fname)
4291 self.assertEqual(orig_image.GetEntries().keys(),
4292 image.GetEntries().keys())
4293
Simon Glassa2af7302021-01-06 21:35:18 -07004294 def testFilesAlign(self):
4295 """Test alignment with files"""
4296 data = self._DoReadFile('190_files_align.dts')
4297
4298 # The first string is 15 bytes so will align to 16
4299 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4300 self.assertEqual(expect, data)
4301
Simon Glassdb84b562021-01-06 21:35:19 -07004302 def testReadImageSkip(self):
4303 """Test reading an image and accessing its FDT map"""
4304 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4305 image_fname = tools.GetOutputFilename('image.bin')
4306 orig_image = control.images['image']
4307 image = Image.FromFile(image_fname)
4308 self.assertEqual(orig_image.GetEntries().keys(),
4309 image.GetEntries().keys())
4310
4311 orig_entry = orig_image.GetEntries()['fdtmap']
4312 entry = image.GetEntries()['fdtmap']
4313 self.assertEqual(orig_entry.offset, entry.offset)
4314 self.assertEqual(orig_entry.size, entry.size)
4315 self.assertEqual(16, entry.image_pos)
4316
4317 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4318
4319 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4320
Simon Glassc98de972021-03-18 20:24:57 +13004321 def testTplNoDtb(self):
4322 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004323 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004324 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4325 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4326 data[:len(U_BOOT_TPL_NODTB_DATA)])
4327
Simon Glass63f41d42021-03-18 20:24:58 +13004328 def testTplBssPad(self):
4329 """Test that we can pad TPL's BSS with zeros"""
4330 # ELF file with a '__bss_size' symbol
4331 self._SetupTplElf()
4332 data = self._DoReadFile('193_tpl_bss_pad.dts')
4333 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4334 data)
4335
4336 def testTplBssPadMissing(self):
4337 """Test that a missing symbol is detected"""
4338 self._SetupTplElf('u_boot_ucode_ptr')
4339 with self.assertRaises(ValueError) as e:
4340 self._DoReadFile('193_tpl_bss_pad.dts')
4341 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4342 str(e.exception))
4343
Simon Glass718b5292021-03-18 20:25:07 +13004344 def checkDtbSizes(self, data, pad_len, start):
4345 """Check the size arguments in a dtb embedded in an image
4346
4347 Args:
4348 data: The image data
4349 pad_len: Length of the pad section in the image, in bytes
4350 start: Start offset of the devicetree to examine, within the image
4351
4352 Returns:
4353 Size of the devicetree in bytes
4354 """
4355 dtb_data = data[start:]
4356 dtb = fdt.Fdt.FromData(dtb_data)
4357 fdt_size = dtb.GetFdtObj().totalsize()
4358 dtb.Scan()
4359 props = self._GetPropTree(dtb, 'size')
4360 self.assertEqual({
4361 'size': len(data),
4362 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4363 'u-boot-spl/u-boot-spl-dtb:size': 801,
4364 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4365 'u-boot-spl:size': 860,
4366 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4367 'u-boot/u-boot-dtb:size': 781,
4368 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4369 'u-boot:size': 827,
4370 }, props)
4371 return fdt_size
4372
4373 def testExpanded(self):
4374 """Test that an expanded entry type is selected when needed"""
4375 self._SetupSplElf()
4376 self._SetupTplElf()
4377
4378 # SPL has a devicetree, TPL does not
4379 entry_args = {
4380 'spl-dtb': '1',
4381 'spl-bss-pad': 'y',
4382 'tpl-dtb': '',
4383 }
4384 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4385 entry_args=entry_args)
4386 image = control.images['image']
4387 entries = image.GetEntries()
4388 self.assertEqual(3, len(entries))
4389
4390 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4391 self.assertIn('u-boot', entries)
4392 entry = entries['u-boot']
4393 self.assertEqual('u-boot-expanded', entry.etype)
4394 subent = entry.GetEntries()
4395 self.assertEqual(2, len(subent))
4396 self.assertIn('u-boot-nodtb', subent)
4397 self.assertIn('u-boot-dtb', subent)
4398
4399 # Second, u-boot-spl, which should be expanded into three parts
4400 self.assertIn('u-boot-spl', entries)
4401 entry = entries['u-boot-spl']
4402 self.assertEqual('u-boot-spl-expanded', entry.etype)
4403 subent = entry.GetEntries()
4404 self.assertEqual(3, len(subent))
4405 self.assertIn('u-boot-spl-nodtb', subent)
4406 self.assertIn('u-boot-spl-bss-pad', subent)
4407 self.assertIn('u-boot-spl-dtb', subent)
4408
4409 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4410 # devicetree
4411 self.assertIn('u-boot-tpl', entries)
4412 entry = entries['u-boot-tpl']
4413 self.assertEqual('u-boot-tpl', entry.etype)
4414 self.assertEqual(None, entry.GetEntries())
4415
4416 def testExpandedTpl(self):
4417 """Test that an expanded entry type is selected for TPL when needed"""
4418 self._SetupTplElf()
4419
4420 entry_args = {
4421 'tpl-bss-pad': 'y',
4422 'tpl-dtb': 'y',
4423 }
4424 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4425 entry_args=entry_args)
4426 image = control.images['image']
4427 entries = image.GetEntries()
4428 self.assertEqual(1, len(entries))
4429
4430 # We only have u-boot-tpl, which be expanded
4431 self.assertIn('u-boot-tpl', entries)
4432 entry = entries['u-boot-tpl']
4433 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4434 subent = entry.GetEntries()
4435 self.assertEqual(3, len(subent))
4436 self.assertIn('u-boot-tpl-nodtb', subent)
4437 self.assertIn('u-boot-tpl-bss-pad', subent)
4438 self.assertIn('u-boot-tpl-dtb', subent)
4439
4440 def testExpandedNoPad(self):
4441 """Test an expanded entry without BSS pad enabled"""
4442 self._SetupSplElf()
4443 self._SetupTplElf()
4444
4445 # SPL has a devicetree, TPL does not
4446 entry_args = {
4447 'spl-dtb': 'something',
4448 'spl-bss-pad': 'n',
4449 'tpl-dtb': '',
4450 }
4451 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4452 entry_args=entry_args)
4453 image = control.images['image']
4454 entries = image.GetEntries()
4455
4456 # Just check u-boot-spl, which should be expanded into two parts
4457 self.assertIn('u-boot-spl', entries)
4458 entry = entries['u-boot-spl']
4459 self.assertEqual('u-boot-spl-expanded', entry.etype)
4460 subent = entry.GetEntries()
4461 self.assertEqual(2, len(subent))
4462 self.assertIn('u-boot-spl-nodtb', subent)
4463 self.assertIn('u-boot-spl-dtb', subent)
4464
4465 def testExpandedTplNoPad(self):
4466 """Test that an expanded entry type with padding disabled in TPL"""
4467 self._SetupTplElf()
4468
4469 entry_args = {
4470 'tpl-bss-pad': '',
4471 'tpl-dtb': 'y',
4472 }
4473 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4474 entry_args=entry_args)
4475 image = control.images['image']
4476 entries = image.GetEntries()
4477 self.assertEqual(1, len(entries))
4478
4479 # We only have u-boot-tpl, which be expanded
4480 self.assertIn('u-boot-tpl', entries)
4481 entry = entries['u-boot-tpl']
4482 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4483 subent = entry.GetEntries()
4484 self.assertEqual(2, len(subent))
4485 self.assertIn('u-boot-tpl-nodtb', subent)
4486 self.assertIn('u-boot-tpl-dtb', subent)
4487
4488 def testFdtInclude(self):
4489 """Test that an Fdt is update within all binaries"""
4490 self._SetupSplElf()
4491 self._SetupTplElf()
4492
4493 # SPL has a devicetree, TPL does not
4494 self.maxDiff = None
4495 entry_args = {
4496 'spl-dtb': '1',
4497 'spl-bss-pad': 'y',
4498 'tpl-dtb': '',
4499 }
4500 # Build the image. It includes two separate devicetree binaries, each
4501 # with their own contents, but all contain the binman definition.
4502 data = self._DoReadFileDtb(
4503 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4504 update_dtb=True, entry_args=entry_args)[0]
4505 pad_len = 10
4506
4507 # Check the U-Boot dtb
4508 start = len(U_BOOT_NODTB_DATA)
4509 fdt_size = self.checkDtbSizes(data, pad_len, start)
4510
4511 # Now check SPL
4512 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4513 fdt_size = self.checkDtbSizes(data, pad_len, start)
4514
4515 # TPL has no devicetree
4516 start += fdt_size + len(U_BOOT_TPL_DATA)
4517 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004518
Simon Glass7098b7f2021-03-21 18:24:30 +13004519 def testSymbolsExpanded(self):
4520 """Test binman can assign symbols in expanded entries"""
4521 entry_args = {
4522 'spl-dtb': '1',
4523 }
4524 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4525 U_BOOT_SPL_DTB_DATA, 0x38,
4526 entry_args=entry_args, use_expanded=True)
4527
Simon Glasse1915782021-03-21 18:24:31 +13004528 def testCollection(self):
4529 """Test a collection"""
4530 data = self._DoReadFile('198_collection.dts')
4531 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4532 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4533 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4534 data)
4535
Simon Glass27a7f772021-03-21 18:24:32 +13004536 def testCollectionSection(self):
4537 """Test a collection where a section must be built first"""
4538 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004539 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004540 # building the contents, producing an error is anything is still
4541 # missing.
4542 data = self._DoReadFile('199_collection_section.dts')
4543 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4544 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4545 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4546 data)
4547
Simon Glassf427c5f2021-03-21 18:24:33 +13004548 def testAlignDefault(self):
4549 """Test that default alignment works on sections"""
4550 data = self._DoReadFile('200_align_default.dts')
4551 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4552 U_BOOT_DATA)
4553 # Special alignment for section
4554 expected += tools.GetBytes(0, 32 - len(expected))
4555 # No alignment within the nested section
4556 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4557 # Now the final piece, which should be default-aligned
4558 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4559 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004560
Bin Mengc0b15742021-05-10 20:23:33 +08004561 def testPackOpenSBI(self):
4562 """Test that an image with an OpenSBI binary can be created"""
4563 data = self._DoReadFile('201_opensbi.dts')
4564 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4565
Simon Glass76f496d2021-07-06 10:36:37 -06004566 def testSectionsSingleThread(self):
4567 """Test sections without multithreading"""
4568 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4569 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4570 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4571 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4572 self.assertEqual(expected, data)
4573
4574 def testThreadTimeout(self):
4575 """Test handling a thread that takes too long"""
4576 with self.assertRaises(ValueError) as e:
4577 self._DoTestFile('202_section_timeout.dts',
4578 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004579 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004580
Simon Glass748a1d42021-07-06 10:36:41 -06004581 def testTiming(self):
4582 """Test output of timing information"""
4583 data = self._DoReadFile('055_sections.dts')
4584 with test_util.capture_sys_output() as (stdout, stderr):
4585 state.TimingShow()
4586 self.assertIn('read:', stdout.getvalue())
4587 self.assertIn('compress:', stdout.getvalue())
4588
Simon Glassadfb8492021-11-03 21:09:18 -06004589 def testUpdateFdtInElf(self):
4590 """Test that we can update the devicetree in an ELF file"""
4591 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4592 outfile = os.path.join(self._indir, 'u-boot.out')
4593 begin_sym = 'dtb_embed_begin'
4594 end_sym = 'dtb_embed_end'
4595 retcode = self._DoTestFile(
4596 '060_fdt_update.dts', update_dtb=True,
4597 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4598 self.assertEqual(0, retcode)
4599
4600 # Check that the output file does in fact contact a dtb with the binman
4601 # definition in the correct place
4602 syms = elf.GetSymbolFileOffset(infile,
4603 ['dtb_embed_begin', 'dtb_embed_end'])
4604 data = tools.ReadFile(outfile)
4605 dtb_data = data[syms['dtb_embed_begin'].offset:
4606 syms['dtb_embed_end'].offset]
4607
4608 dtb = fdt.Fdt.FromData(dtb_data)
4609 dtb.Scan()
4610 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4611 self.assertEqual({
4612 'image-pos': 0,
4613 'offset': 0,
4614 '_testing:offset': 32,
4615 '_testing:size': 2,
4616 '_testing:image-pos': 32,
4617 'section@0/u-boot:offset': 0,
4618 'section@0/u-boot:size': len(U_BOOT_DATA),
4619 'section@0/u-boot:image-pos': 0,
4620 'section@0:offset': 0,
4621 'section@0:size': 16,
4622 'section@0:image-pos': 0,
4623
4624 'section@1/u-boot:offset': 0,
4625 'section@1/u-boot:size': len(U_BOOT_DATA),
4626 'section@1/u-boot:image-pos': 16,
4627 'section@1:offset': 16,
4628 'section@1:size': 16,
4629 'section@1:image-pos': 16,
4630 'size': 40
4631 }, props)
4632
4633 def testUpdateFdtInElfInvalid(self):
4634 """Test that invalid args are detected with --update-fdt-in-elf"""
4635 with self.assertRaises(ValueError) as e:
4636 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4637 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4638 str(e.exception))
4639
4640 def testUpdateFdtInElfNoSyms(self):
4641 """Test that missing symbols are detected with --update-fdt-in-elf"""
4642 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4643 outfile = ''
4644 begin_sym = 'wrong_begin'
4645 end_sym = 'wrong_end'
4646 with self.assertRaises(ValueError) as e:
4647 self._DoTestFile(
4648 '060_fdt_update.dts',
4649 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4650 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4651 str(e.exception))
4652
4653 def testUpdateFdtInElfTooSmall(self):
4654 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4655 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4656 outfile = os.path.join(self._indir, 'u-boot.out')
4657 begin_sym = 'dtb_embed_begin'
4658 end_sym = 'dtb_embed_end'
4659 with self.assertRaises(ValueError) as e:
4660 self._DoTestFile(
4661 '060_fdt_update.dts', update_dtb=True,
4662 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4663 self.assertRegex(
4664 str(e.exception),
4665 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4666
Simon Glass88e04da2021-11-23 11:03:42 -07004667 def testVersion(self):
4668 """Test we can get the binman version"""
4669 version = '(unreleased)'
4670 self.assertEqual(version, state.GetVersion(self._indir))
4671
4672 with self.assertRaises(SystemExit):
4673 with test_util.capture_sys_output() as (_, stderr):
4674 self._DoBinman('-V')
4675 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4676
4677 # Try running the tool too, just to be safe
4678 result = self._RunBinman('-V')
4679 self.assertEqual('Binman %s\n' % version, result.stderr)
4680
4681 # Set up a version file to make sure that works
4682 version = 'v2025.01-rc2'
4683 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4684 binary=False)
4685 self.assertEqual(version, state.GetVersion(self._indir))
4686
Simon Glass637958f2021-11-23 21:09:50 -07004687 def testAltFormat(self):
4688 """Test that alternative formats can be used to extract"""
4689 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4690
4691 try:
4692 tmpdir, updated_fname = self._SetupImageInTmpdir()
4693 with test_util.capture_sys_output() as (stdout, _):
4694 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4695 self.assertEqual(
4696 '''Flag (-F) Entry type Description
4697fdt fdtmap Extract the devicetree blob from the fdtmap
4698''',
4699 stdout.getvalue())
4700
4701 dtb = os.path.join(tmpdir, 'fdt.dtb')
4702 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4703 dtb, 'fdtmap')
4704
4705 # Check that we can read it and it can be scanning, meaning it does
4706 # not have a 16-byte fdtmap header
4707 data = tools.ReadFile(dtb)
4708 dtb = fdt.Fdt.FromData(data)
4709 dtb.Scan()
4710
4711 # Now check u-boot which has no alt_format
4712 fname = os.path.join(tmpdir, 'fdt.dtb')
4713 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4714 '-f', fname, 'u-boot')
4715 data = tools.ReadFile(fname)
4716 self.assertEqual(U_BOOT_DATA, data)
4717
4718 finally:
4719 shutil.rmtree(tmpdir)
4720
Simon Glass0b00ae62021-11-23 21:09:52 -07004721 def testExtblobList(self):
4722 """Test an image with an external blob list"""
4723 data = self._DoReadFile('215_blob_ext_list.dts')
4724 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4725
4726 def testExtblobListMissing(self):
4727 """Test an image with a missing external blob"""
4728 with self.assertRaises(ValueError) as e:
4729 self._DoReadFile('216_blob_ext_list_missing.dts')
4730 self.assertIn("Filename 'missing-file' not found in input path",
4731 str(e.exception))
4732
4733 def testExtblobListMissingOk(self):
4734 """Test an image with an missing external blob that is allowed"""
4735 with test_util.capture_sys_output() as (stdout, stderr):
4736 self._DoTestFile('216_blob_ext_list_missing.dts',
4737 allow_missing=True)
4738 err = stderr.getvalue()
4739 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4740
Simon Glass3efb2972021-11-23 21:08:59 -07004741 def testFip(self):
4742 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4743 data = self._DoReadFile('203_fip.dts')
4744 hdr, fents = fip_util.decode_fip(data)
4745 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4746 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4747 self.assertEqual(0x123, hdr.flags)
4748
4749 self.assertEqual(2, len(fents))
4750
4751 fent = fents[0]
4752 self.assertEqual(
4753 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4754 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4755 self.assertEqual('soc-fw', fent.fip_type)
4756 self.assertEqual(0x88, fent.offset)
4757 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4758 self.assertEqual(0x123456789abcdef, fent.flags)
4759 self.assertEqual(ATF_BL31_DATA, fent.data)
4760 self.assertEqual(True, fent.valid)
4761
4762 fent = fents[1]
4763 self.assertEqual(
4764 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4765 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4766 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4767 self.assertEqual(0x8c, fent.offset)
4768 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4769 self.assertEqual(0, fent.flags)
4770 self.assertEqual(ATF_BL2U_DATA, fent.data)
4771 self.assertEqual(True, fent.valid)
4772
4773 def testFipOther(self):
4774 """Basic FIP with something that isn't a external blob"""
4775 data = self._DoReadFile('204_fip_other.dts')
4776 hdr, fents = fip_util.decode_fip(data)
4777
4778 self.assertEqual(2, len(fents))
4779 fent = fents[1]
4780 self.assertEqual('rot-cert', fent.fip_type)
4781 self.assertEqual(b'aa', fent.data)
4782
4783 def testFipOther(self):
4784 """Basic FIP with something that isn't a external blob"""
4785 data = self._DoReadFile('204_fip_other.dts')
4786 hdr, fents = fip_util.decode_fip(data)
4787
4788 self.assertEqual(2, len(fents))
4789 fent = fents[1]
4790 self.assertEqual('rot-cert', fent.fip_type)
4791 self.assertEqual(b'aa', fent.data)
4792
4793 def testFipNoType(self):
4794 """FIP with an entry of an unknown type"""
4795 with self.assertRaises(ValueError) as e:
4796 self._DoReadFile('205_fip_no_type.dts')
4797 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4798 str(e.exception))
4799
4800 def testFipUuid(self):
4801 """Basic FIP with a manual uuid"""
4802 data = self._DoReadFile('206_fip_uuid.dts')
4803 hdr, fents = fip_util.decode_fip(data)
4804
4805 self.assertEqual(2, len(fents))
4806 fent = fents[1]
4807 self.assertEqual(None, fent.fip_type)
4808 self.assertEqual(
4809 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4810 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4811 fent.uuid)
4812 self.assertEqual(U_BOOT_DATA, fent.data)
4813
4814 def testFipLs(self):
4815 """Test listing a FIP"""
4816 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4817 hdr, fents = fip_util.decode_fip(data)
4818
4819 try:
4820 tmpdir, updated_fname = self._SetupImageInTmpdir()
4821 with test_util.capture_sys_output() as (stdout, stderr):
4822 self._DoBinman('ls', '-i', updated_fname)
4823 finally:
4824 shutil.rmtree(tmpdir)
4825 lines = stdout.getvalue().splitlines()
4826 expected = [
4827'Name Image-pos Size Entry-type Offset Uncomp-size',
4828'----------------------------------------------------------------',
4829'main-section 0 2d3 section 0',
4830' atf-fip 0 90 atf-fip 0',
4831' soc-fw 88 4 blob-ext 88',
4832' u-boot 8c 4 u-boot 8c',
4833' fdtmap 90 243 fdtmap 90',
4834]
4835 self.assertEqual(expected, lines)
4836
4837 image = control.images['image']
4838 entries = image.GetEntries()
4839 fdtmap = entries['fdtmap']
4840
4841 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4842 magic = fdtmap_data[:8]
4843 self.assertEqual(b'_FDTMAP_', magic)
4844 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
4845
4846 fdt_data = fdtmap_data[16:]
4847 dtb = fdt.Fdt.FromData(fdt_data)
4848 dtb.Scan()
4849 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4850 self.assertEqual({
4851 'atf-fip/soc-fw:image-pos': 136,
4852 'atf-fip/soc-fw:offset': 136,
4853 'atf-fip/soc-fw:size': 4,
4854 'atf-fip/u-boot:image-pos': 140,
4855 'atf-fip/u-boot:offset': 140,
4856 'atf-fip/u-boot:size': 4,
4857 'atf-fip:image-pos': 0,
4858 'atf-fip:offset': 0,
4859 'atf-fip:size': 144,
4860 'image-pos': 0,
4861 'offset': 0,
4862 'fdtmap:image-pos': fdtmap.image_pos,
4863 'fdtmap:offset': fdtmap.offset,
4864 'fdtmap:size': len(fdtmap_data),
4865 'size': len(data),
4866 }, props)
4867
4868 def testFipExtractOneEntry(self):
4869 """Test extracting a single entry fron an FIP"""
4870 self._DoReadFileRealDtb('207_fip_ls.dts')
4871 image_fname = tools.GetOutputFilename('image.bin')
4872 fname = os.path.join(self._indir, 'output.extact')
4873 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4874 data = tools.ReadFile(fname)
4875 self.assertEqual(U_BOOT_DATA, data)
4876
4877 def testFipReplace(self):
4878 """Test replacing a single file in a FIP"""
4879 expected = U_BOOT_DATA + tools.GetBytes(0x78, 50)
4880 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4881 updated_fname = tools.GetOutputFilename('image-updated.bin')
4882 tools.WriteFile(updated_fname, data)
4883 entry_name = 'atf-fip/u-boot'
4884 control.WriteEntry(updated_fname, entry_name, expected,
4885 allow_resize=True)
4886 actual = control.ReadEntry(updated_fname, entry_name)
4887 self.assertEqual(expected, actual)
4888
4889 new_data = tools.ReadFile(updated_fname)
4890 hdr, fents = fip_util.decode_fip(new_data)
4891
4892 self.assertEqual(2, len(fents))
4893
4894 # Check that the FIP entry is updated
4895 fent = fents[1]
4896 self.assertEqual(0x8c, fent.offset)
4897 self.assertEqual(len(expected), fent.size)
4898 self.assertEqual(0, fent.flags)
4899 self.assertEqual(expected, fent.data)
4900 self.assertEqual(True, fent.valid)
4901
4902 def testFipMissing(self):
4903 with test_util.capture_sys_output() as (stdout, stderr):
4904 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4905 err = stderr.getvalue()
4906 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4907
4908 def testFipSize(self):
4909 """Test a FIP with a size property"""
4910 data = self._DoReadFile('210_fip_size.dts')
4911 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4912 hdr, fents = fip_util.decode_fip(data)
4913 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4914 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4915
4916 self.assertEqual(1, len(fents))
4917
4918 fent = fents[0]
4919 self.assertEqual('soc-fw', fent.fip_type)
4920 self.assertEqual(0x60, fent.offset)
4921 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4922 self.assertEqual(ATF_BL31_DATA, fent.data)
4923 self.assertEqual(True, fent.valid)
4924
4925 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
4926 self.assertEqual(tools.GetBytes(0xff, len(rest)), rest)
4927
4928 def testFipBadAlign(self):
4929 """Test that an invalid alignment value in a FIP is detected"""
4930 with self.assertRaises(ValueError) as e:
4931 self._DoTestFile('211_fip_bad_align.dts')
4932 self.assertIn(
4933 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
4934 str(e.exception))
4935
4936 def testFipCollection(self):
4937 """Test using a FIP in a collection"""
4938 data = self._DoReadFile('212_fip_collection.dts')
4939 entry1 = control.images['image'].GetEntries()['collection']
4940 data1 = data[:entry1.size]
4941 hdr1, fents2 = fip_util.decode_fip(data1)
4942
4943 entry2 = control.images['image'].GetEntries()['atf-fip']
4944 data2 = data[entry2.offset:entry2.offset + entry2.size]
4945 hdr1, fents2 = fip_util.decode_fip(data2)
4946
4947 # The 'collection' entry should have U-Boot included at the end
4948 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
4949 self.assertEqual(data1, data2 + U_BOOT_DATA)
4950 self.assertEqual(U_BOOT_DATA, data1[-4:])
4951
4952 # There should be a U-Boot after the final FIP
4953 self.assertEqual(U_BOOT_DATA, data[-4:])
4954
Simon Glass76f496d2021-07-06 10:36:37 -06004955
Simon Glassac599912017-11-12 21:52:22 -07004956if __name__ == "__main__":
4957 unittest.main()