blob: 779b8997ab0d4c90faa9c7906ca959ae7d8d10d6 [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
Simon Glass162017b2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070022
Simon Glass4eae9252022-01-09 20:13:50 -070023from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
Simon Glass3ac7d832022-01-09 20:14:03 -070026from binman import comp_util
Simon Glassc585dd42020-04-17 18:09:03 -060027from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glassa997ea52020-04-17 18:09:04 -060038from patman import command
39from patman import test_util
40from patman import tools
41from patman import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Simon Glass4e353e22019-08-24 07:23:04 -060046U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glass303f62f2019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
51U_BOOT_DTB_DATA = b'udtb'
52U_BOOT_SPL_DTB_DATA = b'spldtb'
53U_BOOT_TPL_DTB_DATA = b'tpldtb'
54X86_START16_DATA = b'start16'
55X86_START16_SPL_DATA = b'start16spl'
56X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060057X86_RESET16_DATA = b'reset16'
58X86_RESET16_SPL_DATA = b'reset16spl'
59X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060060PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
61U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
62U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
63U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
64FSP_DATA = b'fsp'
65CMC_DATA = b'cmc'
66VBT_DATA = b'vbt'
67MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060068TEXT_DATA = 'text'
69TEXT_DATA2 = 'text2'
70TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060071CROS_EC_RW_DATA = b'ecrw'
72GBB_DATA = b'gbbd'
73BMPBLK_DATA = b'bmp'
74VBLOCK_DATA = b'vblk'
75FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
76 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060077COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060078COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060079REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060080FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060081FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060082FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060083ATF_BL31_DATA = b'bl31'
Simon Glass3efb2972021-11-23 21:08:59 -070084ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080085OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050086SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060087TEST_FDT1_DATA = b'fdt1'
88TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060089ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060090
91# Subdirectory of the input dir to use to put test FDTs
92TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060093
Simon Glass2c6adba2019-07-20 12:23:47 -060094# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060095EXTRACT_DTB_SIZE = 0x3c9
96
Simon Glass2c6adba2019-07-20 12:23:47 -060097# Properties expected to be in the device tree when update_dtb is used
98BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
99
Simon Glassfb30e292019-07-20 12:23:51 -0600100# Extra properties expected to be in the device tree when allow-repack is used
101REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
102
Simon Glass57454f42016-11-25 20:15:52 -0700103
104class TestFunctional(unittest.TestCase):
105 """Functional tests for binman
106
107 Most of these use a sample .dts file to build an image and then check
108 that it looks correct. The sample files are in the test/ subdirectory
109 and are numbered.
110
111 For each entry type a very small test file is created using fixed
112 string contents. This makes it easy to test that things look right, and
113 debug problems.
114
115 In some cases a 'real' file must be used - these are also supplied in
116 the test/ diurectory.
117 """
118 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600119 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700120 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600121 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700122
Simon Glass57454f42016-11-25 20:15:52 -0700123 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600124 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
125 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700126
127 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600128 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700129
130 # Create some test files
131 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
132 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
133 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600134 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700135 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700136 TestFunctional._MakeInputFile('me.bin', ME_DATA)
137 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600138 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600139
Jagdish Gediya311d4842018-09-03 21:35:08 +0530140 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600141
Simon Glassabab18c2019-08-24 07:22:49 -0600142 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
143 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700144 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600145 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600146 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600147
148 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
149 X86_RESET16_DATA)
150 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
151 X86_RESET16_SPL_DATA)
152 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
153 X86_RESET16_TPL_DATA)
154
Simon Glass57454f42016-11-25 20:15:52 -0700155 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700156 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
157 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600158 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
159 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700160 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
161 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700162 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700163 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600164 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600165 TestFunctional._MakeInputDir('devkeys')
166 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600167 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600168 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600169 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600170 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700171
Simon Glassf6290892019-08-24 07:22:53 -0600172 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
173 elf_test.BuildElfTestFiles(cls._elf_testdir)
174
Simon Glass72232452016-11-25 20:15:53 -0700175 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600176 TestFunctional._MakeInputFile('u-boot',
177 tools.ReadFile(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700178
179 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600180 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700181
Simon Glass862f8e22019-08-24 07:22:43 -0600182 shutil.copytree(cls.TestFile('files'),
183 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600184
Simon Glass7ba33592018-09-14 04:57:26 -0600185 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600186 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600187 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700188 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800189 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500190 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600191
Simon Glassa435cd12020-09-01 05:13:59 -0600192 # Add a few .dtb files for testing
193 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
194 TEST_FDT1_DATA)
195 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
196 TEST_FDT2_DATA)
197
Simon Glassa0729502020-09-06 10:35:33 -0600198 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
199
Simon Glass1de34482019-07-08 13:18:53 -0600200 # Travis-CI may have an old lz4
Simon Glass862f8e22019-08-24 07:22:43 -0600201 cls.have_lz4 = True
Simon Glass1de34482019-07-08 13:18:53 -0600202 try:
203 tools.Run('lz4', '--no-frame-crc', '-c',
Simon Glasscc311ac2019-10-31 07:42:50 -0600204 os.path.join(cls._indir, 'u-boot.bin'), binary=True)
Simon Glass1de34482019-07-08 13:18:53 -0600205 except:
Simon Glass862f8e22019-08-24 07:22:43 -0600206 cls.have_lz4 = False
Simon Glass1de34482019-07-08 13:18:53 -0600207
Simon Glass57454f42016-11-25 20:15:52 -0700208 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600209 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700210 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600211 if cls.preserve_indir:
212 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600213 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600214 if cls._indir:
215 shutil.rmtree(cls._indir)
216 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700217
Simon Glass1c420c92019-07-08 13:18:49 -0600218 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600219 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600220 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600221 """Accept arguments controlling test execution
222
223 Args:
224 preserve_indir: Preserve the shared input directory used by all
225 tests in this class.
226 preserve_outdir: Preserve the output directories used by tests. Each
227 test has its own, so this is normally only useful when running a
228 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600229 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600230 """
231 cls.preserve_indir = preserve_indir
232 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600233 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600234 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600235
Simon Glass1de34482019-07-08 13:18:53 -0600236 def _CheckLz4(self):
237 if not self.have_lz4:
238 self.skipTest('lz4 --no-frame-crc not available')
239
Simon Glassee9d10d2019-07-20 12:24:09 -0600240 def _CleanupOutputDir(self):
241 """Remove the temporary output directory"""
242 if self.preserve_outdirs:
243 print('Preserving output dir: %s' % tools.outdir)
244 else:
245 tools._FinaliseForTest()
246
Simon Glass57454f42016-11-25 20:15:52 -0700247 def setUp(self):
248 # Enable this to turn on debugging output
249 # tout.Init(tout.DEBUG)
250 command.test_result = None
251
252 def tearDown(self):
253 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600254 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700255
Simon Glassb3d6fc72019-07-20 12:24:10 -0600256 def _SetupImageInTmpdir(self):
257 """Set up the output image in a new temporary directory
258
259 This is used when an image has been generated in the output directory,
260 but we want to run binman again. This will create a new output
261 directory and fail to delete the original one.
262
263 This creates a new temporary directory, copies the image to it (with a
264 new name) and removes the old output directory.
265
266 Returns:
267 Tuple:
268 Temporary directory to use
269 New image filename
270 """
271 image_fname = tools.GetOutputFilename('image.bin')
272 tmpdir = tempfile.mkdtemp(prefix='binman.')
273 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
274 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
275 self._CleanupOutputDir()
276 return tmpdir, updated_fname
277
Simon Glass8425a1f2018-07-17 13:25:48 -0600278 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600279 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600280 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
281 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
282 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
283
Simon Glass57454f42016-11-25 20:15:52 -0700284 def _RunBinman(self, *args, **kwargs):
285 """Run binman using the command line
286
287 Args:
288 Arguments to pass, as a list of strings
289 kwargs: Arguments to pass to Command.RunPipe()
290 """
291 result = command.RunPipe([[self._binman_pathname] + list(args)],
292 capture=True, capture_stderr=True, raise_on_error=False)
293 if result.return_code and kwargs.get('raise_on_error', True):
294 raise Exception("Error running '%s': %s" % (' '.join(args),
295 result.stdout + result.stderr))
296 return result
297
Simon Glassf46732a2019-07-08 14:25:29 -0600298 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700299 """Run binman using directly (in the same process)
300
301 Args:
302 Arguments to pass, as a list of strings
303 Returns:
304 Return value (0 for success)
305 """
Simon Glassf46732a2019-07-08 14:25:29 -0600306 argv = list(argv)
307 args = cmdline.ParseArgs(argv)
308 args.pager = 'binman-invalid-pager'
309 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700310
311 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600312 # args.verbosity = tout.DEBUG
313 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700314
Simon Glass91710b32018-07-17 13:25:32 -0600315 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600316 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300317 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100318 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glassadfb8492021-11-03 21:09:18 -0600319 test_section_timeout=False, update_fdt_in_elf=None):
Simon Glass57454f42016-11-25 20:15:52 -0700320 """Run binman with a given test file
321
322 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600323 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600324 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600325 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600326 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600327 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600328 entry_args: Dict of entry args to supply to binman
329 key: arg name
330 value: value of that arg
331 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600332 use_real_dtb: True to use the test file as the contents of
333 the u-boot-dtb entry. Normally this is not needed and the
334 test contents (the U_BOOT_DTB_DATA string) can be used.
335 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300336 use_expanded: True to use expanded entries where available, e.g.
337 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600338 verbosity: Verbosity level to use (0-3, None=don't set it)
339 allow_missing: Set the '--allow-missing' flag so that missing
340 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100341 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600342 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600343 threads: Number of threads to use (None for default, 0 for
344 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600345 test_section_timeout: True to force the first time to timeout, as
346 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600347 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass9a798402021-11-03 21:09:17 -0600348
349 Returns:
350 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700351 """
Simon Glassf46732a2019-07-08 14:25:29 -0600352 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700353 if debug:
354 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600355 if verbosity is not None:
356 args.append('-v%d' % verbosity)
357 elif self.verbosity:
358 args.append('-v%d' % self.verbosity)
359 if self.toolpath:
360 for path in self.toolpath:
361 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600362 if threads is not None:
363 args.append('-T%d' % threads)
364 if test_section_timeout:
365 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600366 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600367 if map:
368 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600369 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600370 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600371 if not use_real_dtb:
372 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300373 if not use_expanded:
374 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600375 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600376 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600377 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600378 if allow_missing:
379 args.append('-M')
Heiko Thiery6d451362022-01-06 11:49:41 +0100380 if allow_fake_blobs:
381 args.append('--fake-ext-blobs')
Simon Glassadfb8492021-11-03 21:09:18 -0600382 if update_fdt_in_elf:
383 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600384 if images:
385 for image in images:
386 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600387 if extra_indirs:
388 for indir in extra_indirs:
389 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700390 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700391
392 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700393 """Set up a new test device-tree file
394
395 The given file is compiled and set up as the device tree to be used
396 for ths test.
397
398 Args:
399 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600400 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700401
402 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600403 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700404 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600405 tmpdir = tempfile.mkdtemp(prefix='binmant.')
406 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600407 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700408 data = fd.read()
409 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600410 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600411 return data
Simon Glass57454f42016-11-25 20:15:52 -0700412
Simon Glasse219aa42018-09-14 04:57:24 -0600413 def _GetDtbContentsForSplTpl(self, dtb_data, name):
414 """Create a version of the main DTB for SPL or SPL
415
416 For testing we don't actually have different versions of the DTB. With
417 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
418 we don't normally have any unwanted nodes.
419
420 We still want the DTBs for SPL and TPL to be different though, since
421 otherwise it is confusing to know which one we are looking at. So add
422 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600423
424 Args:
425 dtb_data: dtb data to modify (this should be a value devicetree)
426 name: Name of a new property to add
427
428 Returns:
429 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600430 """
431 dtb = fdt.Fdt.FromData(dtb_data)
432 dtb.Scan()
433 dtb.GetNode('/binman').AddZeroProp(name)
434 dtb.Sync(auto_resize=True)
435 dtb.Pack()
436 return dtb.GetContents()
437
Simon Glassed930672021-03-18 20:25:05 +1300438 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
439 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600440 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700441 """Run binman and return the resulting image
442
443 This runs binman with a given test file and then reads the resulting
444 output file. It is a shortcut function since most tests need to do
445 these steps.
446
447 Raises an assertion failure if binman returns a non-zero exit code.
448
449 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600450 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700451 use_real_dtb: True to use the test file as the contents of
452 the u-boot-dtb entry. Normally this is not needed and the
453 test contents (the U_BOOT_DTB_DATA string) can be used.
454 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300455 use_expanded: True to use expanded entries where available, e.g.
456 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600457 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600458 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600459 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600460 entry_args: Dict of entry args to supply to binman
461 key: arg name
462 value: value of that arg
463 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
464 function. If reset_dtbs is True, then the original test dtb
465 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600466 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600467 threads: Number of threads to use (None for default, 0 for
468 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700469
470 Returns:
471 Tuple:
472 Resulting image contents
473 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600474 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600475 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700476 """
Simon Glass72232452016-11-25 20:15:53 -0700477 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700478 # Use the compiled test file as the u-boot-dtb input
479 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700480 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600481
482 # For testing purposes, make a copy of the DT for SPL and TPL. Add
483 # a node indicating which it is, so aid verification.
484 for name in ['spl', 'tpl']:
485 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
486 outfile = os.path.join(self._indir, dtb_fname)
487 TestFunctional._MakeInputFile(dtb_fname,
488 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700489
490 try:
Simon Glass91710b32018-07-17 13:25:32 -0600491 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600492 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600493 use_expanded=use_expanded, extra_indirs=extra_indirs,
494 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700495 self.assertEqual(0, retcode)
Simon Glasse219aa42018-09-14 04:57:24 -0600496 out_dtb_fname = tools.GetOutputFilename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700497
498 # Find the (only) image, read it and return its contents
499 image = control.images['image']
Simon Glassa87014e2018-07-06 10:27:42 -0600500 image_fname = tools.GetOutputFilename('image.bin')
501 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600502 if map:
503 map_fname = tools.GetOutputFilename('image.map')
504 with open(map_fname) as fd:
505 map_data = fd.read()
506 else:
507 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600508 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600509 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700510 finally:
511 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600512 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600513 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700514
Simon Glass5b4bce32019-07-08 14:25:26 -0600515 def _DoReadFileRealDtb(self, fname):
516 """Run binman with a real .dtb file and return the resulting data
517
518 Args:
519 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
520
521 Returns:
522 Resulting image contents
523 """
524 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
525
Simon Glass72232452016-11-25 20:15:53 -0700526 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600527 """Helper function which discards the device-tree binary
528
529 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600530 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600531 use_real_dtb: True to use the test file as the contents of
532 the u-boot-dtb entry. Normally this is not needed and the
533 test contents (the U_BOOT_DTB_DATA string) can be used.
534 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600535
536 Returns:
537 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600538 """
Simon Glass72232452016-11-25 20:15:53 -0700539 return self._DoReadFileDtb(fname, use_real_dtb)[0]
540
Simon Glass57454f42016-11-25 20:15:52 -0700541 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600542 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700543 """Create a new test input file, creating directories as needed
544
545 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600546 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700547 contents: File contents to write in to the file
548 Returns:
549 Full pathname of file created
550 """
Simon Glass862f8e22019-08-24 07:22:43 -0600551 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700552 dirname = os.path.dirname(pathname)
553 if dirname and not os.path.exists(dirname):
554 os.makedirs(dirname)
555 with open(pathname, 'wb') as fd:
556 fd.write(contents)
557 return pathname
558
559 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600560 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600561 """Create a new test input directory, creating directories as needed
562
563 Args:
564 dirname: Directory name to create
565
566 Returns:
567 Full pathname of directory created
568 """
Simon Glass862f8e22019-08-24 07:22:43 -0600569 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600570 if not os.path.exists(pathname):
571 os.makedirs(pathname)
572 return pathname
573
574 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600575 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600576 """Set up an ELF file with a '_dt_ucode_base_size' symbol
577
578 Args:
579 Filename of ELF file to use as SPL
580 """
Simon Glass93a806f2019-08-24 07:22:59 -0600581 TestFunctional._MakeInputFile('spl/u-boot-spl',
582 tools.ReadFile(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600583
584 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600585 def _SetupTplElf(cls, src_fname='bss_data'):
586 """Set up an ELF file with a '_dt_ucode_base_size' symbol
587
588 Args:
589 Filename of ELF file to use as TPL
590 """
591 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
592 tools.ReadFile(cls.ElfTestFile(src_fname)))
593
594 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600595 def _SetupDescriptor(cls):
596 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
597 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
598
599 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600600 def TestFile(cls, fname):
601 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700602
Simon Glassf6290892019-08-24 07:22:53 -0600603 @classmethod
604 def ElfTestFile(cls, fname):
605 return os.path.join(cls._elf_testdir, fname)
606
Simon Glass57454f42016-11-25 20:15:52 -0700607 def AssertInList(self, grep_list, target):
608 """Assert that at least one of a list of things is in a target
609
610 Args:
611 grep_list: List of strings to check
612 target: Target string
613 """
614 for grep in grep_list:
615 if grep in target:
616 return
Simon Glass848cdb52019-05-17 22:00:50 -0600617 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700618
619 def CheckNoGaps(self, entries):
620 """Check that all entries fit together without gaps
621
622 Args:
623 entries: List of entries to check
624 """
Simon Glasse8561af2018-08-01 15:22:37 -0600625 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700626 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600627 self.assertEqual(offset, entry.offset)
628 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700629
Simon Glass72232452016-11-25 20:15:53 -0700630 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600631 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700632
633 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600634 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700635
636 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600637 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700638 """
639 return struct.unpack('>L', dtb[4:8])[0]
640
Simon Glass0f621332019-07-08 14:25:27 -0600641 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600642 def AddNode(node, path):
643 if node.name != '/':
644 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600645 for prop in node.props.values():
646 if prop.name in prop_names:
647 prop_path = path + ':' + prop.name
648 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
649 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600650 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600651 AddNode(subnode, path)
652
653 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600654 AddNode(dtb.GetRoot(), '')
655 return tree
656
Simon Glass57454f42016-11-25 20:15:52 -0700657 def testRun(self):
658 """Test a basic run with valid args"""
659 result = self._RunBinman('-h')
660
661 def testFullHelp(self):
662 """Test that the full help is displayed with -H"""
663 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300664 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500665 # Remove possible extraneous strings
666 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
667 gothelp = result.stdout.replace(extra, '')
668 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700669 self.assertEqual(0, len(result.stderr))
670 self.assertEqual(0, result.return_code)
671
672 def testFullHelpInternal(self):
673 """Test that the full help is displayed with -H"""
674 try:
675 command.test_result = command.CommandResult()
676 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300677 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700678 finally:
679 command.test_result = None
680
681 def testHelp(self):
682 """Test that the basic help is displayed with -h"""
683 result = self._RunBinman('-h')
684 self.assertTrue(len(result.stdout) > 200)
685 self.assertEqual(0, len(result.stderr))
686 self.assertEqual(0, result.return_code)
687
Simon Glass57454f42016-11-25 20:15:52 -0700688 def testBoard(self):
689 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600690 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700691 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300692 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700693 self.assertEqual(0, result)
694
695 def testNeedBoard(self):
696 """Test that we get an error when no board ius supplied"""
697 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600698 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700699 self.assertIn("Must provide a board to process (use -b <board>)",
700 str(e.exception))
701
702 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600703 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700704 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600705 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700706 # We get one error from libfdt, and a different one from fdtget.
707 self.AssertInList(["Couldn't open blob from 'missing_file'",
708 'No such file or directory'], str(e.exception))
709
710 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600711 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700712
713 Since this is a source file it should be compiled and the error
714 will come from the device-tree compiler (dtc).
715 """
716 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600717 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700718 self.assertIn("FATAL ERROR: Unable to parse input tree",
719 str(e.exception))
720
721 def testMissingNode(self):
722 """Test that a device tree without a 'binman' node generates an error"""
723 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600724 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700725 self.assertIn("does not have a 'binman' node", str(e.exception))
726
727 def testEmpty(self):
728 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600729 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700730 self.assertEqual(0, len(result.stderr))
731 self.assertEqual(0, result.return_code)
732
733 def testInvalidEntry(self):
734 """Test that an invalid entry is flagged"""
735 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600736 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600737 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700738 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
739 "'/binman/not-a-valid-type'", str(e.exception))
740
741 def testSimple(self):
742 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600743 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700744 self.assertEqual(U_BOOT_DATA, data)
745
Simon Glass075a45c2017-11-13 18:55:00 -0700746 def testSimpleDebug(self):
747 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600748 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700749
Simon Glass57454f42016-11-25 20:15:52 -0700750 def testDual(self):
751 """Test that we can handle creating two images
752
753 This also tests image padding.
754 """
Simon Glass511f6582018-10-01 12:22:30 -0600755 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700756 self.assertEqual(0, retcode)
757
758 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600759 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700760 fname = tools.GetOutputFilename('image1.bin')
761 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600762 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700763 data = fd.read()
764 self.assertEqual(U_BOOT_DATA, data)
765
766 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600767 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700768 fname = tools.GetOutputFilename('image2.bin')
769 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600770 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700771 data = fd.read()
772 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassac0d4952019-05-14 15:53:47 -0600773 self.assertEqual(tools.GetBytes(0, 3), data[:3])
774 self.assertEqual(tools.GetBytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700775
776 def testBadAlign(self):
777 """Test that an invalid alignment value is detected"""
778 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600779 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700780 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
781 "of two", str(e.exception))
782
783 def testPackSimple(self):
784 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600785 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700786 self.assertEqual(0, retcode)
787 self.assertIn('image', control.images)
788 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600789 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700790 self.assertEqual(5, len(entries))
791
792 # First u-boot
793 self.assertIn('u-boot', entries)
794 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600795 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700796 self.assertEqual(len(U_BOOT_DATA), entry.size)
797
798 # Second u-boot, aligned to 16-byte boundary
799 self.assertIn('u-boot-align', entries)
800 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600801 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700802 self.assertEqual(len(U_BOOT_DATA), entry.size)
803
804 # Third u-boot, size 23 bytes
805 self.assertIn('u-boot-size', entries)
806 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600807 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700808 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
809 self.assertEqual(23, entry.size)
810
811 # Fourth u-boot, placed immediate after the above
812 self.assertIn('u-boot-next', entries)
813 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600814 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700815 self.assertEqual(len(U_BOOT_DATA), entry.size)
816
Simon Glasse8561af2018-08-01 15:22:37 -0600817 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700818 self.assertIn('u-boot-fixed', entries)
819 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600820 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700821 self.assertEqual(len(U_BOOT_DATA), entry.size)
822
Simon Glass39dd2152019-07-08 14:25:47 -0600823 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700824
825 def testPackExtra(self):
826 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600827 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
828 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700829
Simon Glass57454f42016-11-25 20:15:52 -0700830 self.assertIn('image', control.images)
831 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600832 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700833 self.assertEqual(5, len(entries))
834
835 # First u-boot with padding before and after
836 self.assertIn('u-boot', entries)
837 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600838 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700839 self.assertEqual(3, entry.pad_before)
840 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600841 self.assertEqual(U_BOOT_DATA, entry.data)
842 self.assertEqual(tools.GetBytes(0, 3) + U_BOOT_DATA +
843 tools.GetBytes(0, 5), data[:entry.size])
844 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700845
846 # Second u-boot has an aligned size, but it has no effect
847 self.assertIn('u-boot-align-size-nop', entries)
848 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600849 self.assertEqual(pos, entry.offset)
850 self.assertEqual(len(U_BOOT_DATA), entry.size)
851 self.assertEqual(U_BOOT_DATA, entry.data)
852 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
853 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700854
855 # Third u-boot has an aligned size too
856 self.assertIn('u-boot-align-size', entries)
857 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600858 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700859 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600860 self.assertEqual(U_BOOT_DATA, entry.data)
861 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 32 - len(U_BOOT_DATA)),
862 data[pos:pos + entry.size])
863 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700864
865 # Fourth u-boot has an aligned end
866 self.assertIn('u-boot-align-end', entries)
867 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600868 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700869 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600870 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
871 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 16 - len(U_BOOT_DATA)),
872 data[pos:pos + entry.size])
873 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700874
875 # Fifth u-boot immediately afterwards
876 self.assertIn('u-boot-align-both', entries)
877 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600878 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700879 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600880 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
881 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 64 - len(U_BOOT_DATA)),
882 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700883
884 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600885 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700886
Simon Glassafb9caa2020-10-26 17:40:10 -0600887 dtb = fdt.Fdt(out_dtb_fname)
888 dtb.Scan()
889 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
890 expected = {
891 'image-pos': 0,
892 'offset': 0,
893 'size': 128,
894
895 'u-boot:image-pos': 0,
896 'u-boot:offset': 0,
897 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
898
899 'u-boot-align-size-nop:image-pos': 12,
900 'u-boot-align-size-nop:offset': 12,
901 'u-boot-align-size-nop:size': 4,
902
903 'u-boot-align-size:image-pos': 16,
904 'u-boot-align-size:offset': 16,
905 'u-boot-align-size:size': 32,
906
907 'u-boot-align-end:image-pos': 48,
908 'u-boot-align-end:offset': 48,
909 'u-boot-align-end:size': 16,
910
911 'u-boot-align-both:image-pos': 64,
912 'u-boot-align-both:offset': 64,
913 'u-boot-align-both:size': 64,
914 }
915 self.assertEqual(expected, props)
916
Simon Glass57454f42016-11-25 20:15:52 -0700917 def testPackAlignPowerOf2(self):
918 """Test that invalid entry alignment is detected"""
919 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600920 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700921 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
922 "of two", str(e.exception))
923
924 def testPackAlignSizePowerOf2(self):
925 """Test that invalid entry size alignment is detected"""
926 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600927 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700928 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
929 "power of two", str(e.exception))
930
931 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600932 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700933 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600934 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600935 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700936 "align 0x4 (4)", str(e.exception))
937
938 def testPackInvalidSizeAlign(self):
939 """Test that invalid entry size alignment is detected"""
940 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600941 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700942 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
943 "align-size 0x4 (4)", str(e.exception))
944
945 def testPackOverlap(self):
946 """Test that overlapping regions are detected"""
947 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600948 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600949 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700950 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
951 str(e.exception))
952
953 def testPackEntryOverflow(self):
954 """Test that entries that overflow their size are detected"""
955 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600956 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700957 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
958 "but entry size is 0x3 (3)", str(e.exception))
959
960 def testPackImageOverflow(self):
961 """Test that entries which overflow the image size are detected"""
962 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600963 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600964 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700965 "size 0x3 (3)", str(e.exception))
966
967 def testPackImageSize(self):
968 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600969 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700970 self.assertEqual(0, retcode)
971 self.assertIn('image', control.images)
972 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600973 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700974
975 def testPackImageSizeAlign(self):
976 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600977 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700978 self.assertEqual(0, retcode)
979 self.assertIn('image', control.images)
980 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600981 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700982
983 def testPackInvalidImageAlign(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('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600987 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700988 "align-size 0x8 (8)", str(e.exception))
989
990 def testPackAlignPowerOf2(self):
991 """Test that invalid image alignment is detected"""
992 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600993 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600994 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700995 "two", str(e.exception))
996
997 def testImagePadByte(self):
998 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600999 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001000 data = self._DoReadFile('021_image_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001001 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0xff, 1) +
1002 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001003
1004 def testImageName(self):
1005 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001006 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001007 self.assertEqual(0, retcode)
1008 image = control.images['image1']
1009 fname = tools.GetOutputFilename('test-name')
1010 self.assertTrue(os.path.exists(fname))
1011
1012 image = control.images['image2']
1013 fname = tools.GetOutputFilename('test-name.xx')
1014 self.assertTrue(os.path.exists(fname))
1015
1016 def testBlobFilename(self):
1017 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001018 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001019 self.assertEqual(BLOB_DATA, data)
1020
1021 def testPackSorted(self):
1022 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001023 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001024 data = self._DoReadFile('024_sorted.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001025 self.assertEqual(tools.GetBytes(0, 1) + U_BOOT_SPL_DATA +
1026 tools.GetBytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001027
Simon Glasse8561af2018-08-01 15:22:37 -06001028 def testPackZeroOffset(self):
1029 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001030 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001031 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001032 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001033 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1034 str(e.exception))
1035
1036 def testPackUbootDtb(self):
1037 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001038 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001039 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001040
1041 def testPackX86RomNoSize(self):
1042 """Test that the end-at-4gb property requires a size property"""
1043 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001044 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001045 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001046 "using end-at-4gb", str(e.exception))
1047
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301048 def test4gbAndSkipAtStartTogether(self):
1049 """Test that the end-at-4gb and skip-at-size property can't be used
1050 together"""
1051 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001052 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001053 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301054 "'skip-at-start'", str(e.exception))
1055
Simon Glass72232452016-11-25 20:15:53 -07001056 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001057 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001058 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001059 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001060 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1061 "is outside the section '/binman' starting at "
1062 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001063 str(e.exception))
1064
1065 def testPackX86Rom(self):
1066 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001067 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001068 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass4e353e22019-08-24 07:23:04 -06001069 self.assertEqual(U_BOOT_DATA + tools.GetBytes(0, 3) + U_BOOT_SPL_DATA +
Simon Glassac0d4952019-05-14 15:53:47 -06001070 tools.GetBytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001071
1072 def testPackX86RomMeNoDesc(self):
1073 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001074 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001075 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001076 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001077 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001078 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1079 str(e.exception))
1080 finally:
1081 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001082
1083 def testPackX86RomBadDesc(self):
1084 """Test that the Intel requires a descriptor entry"""
1085 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001086 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001087 self.assertIn("Node '/binman/intel-me': No offset set with "
1088 "offset-unset: should another entry provide this correct "
1089 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001090
1091 def testPackX86RomMe(self):
1092 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001093 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass759af872019-07-08 13:18:54 -06001094 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
1095 if data[:0x1000] != expected_desc:
1096 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001097 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1098
1099 def testPackVga(self):
1100 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001101 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001102 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1103
1104 def testPackStart16(self):
1105 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001106 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001107 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1108
Jagdish Gediya311d4842018-09-03 21:35:08 +05301109 def testPackPowerpcMpc85xxBootpgResetvec(self):
1110 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1111 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001112 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301113 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1114
Simon Glass6ba679c2018-07-06 10:27:17 -06001115 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001116 """Handle running a test for insertion of microcode
1117
1118 Args:
1119 dts_fname: Name of test .dts file
1120 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001121 ucode_second: True if the microsecond entry is second instead of
1122 third
Simon Glass820af1d2018-07-06 10:27:16 -06001123
1124 Returns:
1125 Tuple:
1126 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001127 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001128 in the above (two 4-byte words)
1129 """
Simon Glass3d274232017-11-12 21:52:27 -07001130 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001131
1132 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001133 if ucode_second:
1134 ucode_content = data[len(nodtb_data):]
1135 ucode_pos = len(nodtb_data)
1136 dtb_with_ucode = ucode_content[16:]
1137 fdt_len = self.GetFdtLen(dtb_with_ucode)
1138 else:
1139 dtb_with_ucode = data[len(nodtb_data):]
1140 fdt_len = self.GetFdtLen(dtb_with_ucode)
1141 ucode_content = dtb_with_ucode[fdt_len:]
1142 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass72232452016-11-25 20:15:53 -07001143 fname = tools.GetOutputFilename('test.dtb')
1144 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001145 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001146 dtb = fdt.FdtScan(fname)
1147 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001148 self.assertTrue(ucode)
1149 for node in ucode.subnodes:
1150 self.assertFalse(node.props.get('data'))
1151
Simon Glass72232452016-11-25 20:15:53 -07001152 # Check that the microcode appears immediately after the Fdt
1153 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001154 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001155 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1156 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001157 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001158
1159 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001160 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001161 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1162 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001163 u_boot = data[:len(nodtb_data)]
1164 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001165
1166 def testPackUbootMicrocode(self):
1167 """Test that x86 microcode can be handled correctly
1168
1169 We expect to see the following in the image, in order:
1170 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1171 place
1172 u-boot.dtb with the microcode removed
1173 the microcode
1174 """
Simon Glass511f6582018-10-01 12:22:30 -06001175 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001176 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001177 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1178 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001179
Simon Glassbac25c82017-05-27 07:38:26 -06001180 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001181 """Test that x86 microcode can be handled correctly
1182
1183 We expect to see the following in the image, in order:
1184 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1185 place
1186 u-boot.dtb with the microcode
1187 an empty microcode region
1188 """
1189 # We need the libfdt library to run this test since only that allows
1190 # finding the offset of a property. This is required by
1191 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001192 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001193
1194 second = data[len(U_BOOT_NODTB_DATA):]
1195
1196 fdt_len = self.GetFdtLen(second)
1197 third = second[fdt_len:]
1198 second = second[:fdt_len]
1199
Simon Glassbac25c82017-05-27 07:38:26 -06001200 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1201 self.assertIn(ucode_data, second)
1202 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001203
Simon Glassbac25c82017-05-27 07:38:26 -06001204 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001205 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001206 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1207 len(ucode_data))
1208 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001209 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1210 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001211
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001212 def testPackUbootSingleMicrocode(self):
1213 """Test that x86 microcode can be handled correctly with fdt_normal.
1214 """
Simon Glassbac25c82017-05-27 07:38:26 -06001215 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001216
Simon Glass996021e2016-11-25 20:15:54 -07001217 def testUBootImg(self):
1218 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001219 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001220 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001221
1222 def testNoMicrocode(self):
1223 """Test that a missing microcode region is detected"""
1224 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001225 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001226 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1227 "node found in ", str(e.exception))
1228
1229 def testMicrocodeWithoutNode(self):
1230 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1231 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001232 self._DoReadFile('038_x86_ucode_missing_node.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-dtb-with-ucode", str(e.exception))
1235
1236 def testMicrocodeWithoutNode2(self):
1237 """Test that a missing u-boot-ucode node is detected"""
1238 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001239 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001240 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1241 "microcode region u-boot-ucode", str(e.exception))
1242
1243 def testMicrocodeWithoutPtrInElf(self):
1244 """Test that a U-Boot binary without the microcode symbol is detected"""
1245 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001246 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001247 TestFunctional._MakeInputFile('u-boot',
1248 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001249
1250 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001251 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001252 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1253 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1254
1255 finally:
1256 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001257 TestFunctional._MakeInputFile('u-boot',
1258 tools.ReadFile(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001259
1260 def testMicrocodeNotInImage(self):
1261 """Test that microcode must be placed within the image"""
1262 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001263 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001264 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1265 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001266 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001267
1268 def testWithoutMicrocode(self):
1269 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001270 TestFunctional._MakeInputFile('u-boot',
1271 tools.ReadFile(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001272 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001273
1274 # Now check the device tree has no microcode
1275 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1276 second = data[len(U_BOOT_NODTB_DATA):]
1277
1278 fdt_len = self.GetFdtLen(second)
1279 self.assertEqual(dtb, second[:fdt_len])
1280
1281 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1282 third = data[used_len:]
Simon Glassac0d4952019-05-14 15:53:47 -06001283 self.assertEqual(tools.GetBytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001284
1285 def testUnknownPosSize(self):
1286 """Test that microcode must be placed within the image"""
1287 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001288 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001289 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001290 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001291
1292 def testPackFsp(self):
1293 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001294 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001295 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1296
1297 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001298 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001299 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001300 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001301
1302 def testPackVbt(self):
1303 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001304 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001305 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001306
Simon Glass7f94e832017-11-12 21:52:25 -07001307 def testSplBssPad(self):
1308 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001309 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001310 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001311 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001312 self.assertEqual(U_BOOT_SPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
1313 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001314
Simon Glass04cda032018-10-01 21:12:42 -06001315 def testSplBssPadMissing(self):
1316 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001317 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001318 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001319 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001320 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1321 str(e.exception))
1322
Simon Glasse83679d2017-11-12 21:52:26 -07001323 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001324 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001325 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001326 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1327
Simon Glass6ba679c2018-07-06 10:27:17 -06001328 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1329 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001330
1331 We expect to see the following in the image, in order:
1332 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1333 correct place
1334 u-boot.dtb with the microcode removed
1335 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001336
1337 Args:
1338 dts: Device tree file to use for test
1339 ucode_second: True if the microsecond entry is second instead of
1340 third
Simon Glass3d274232017-11-12 21:52:27 -07001341 """
Simon Glass7057d022018-10-01 21:12:47 -06001342 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001343 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1344 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001345 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1346 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001347
Simon Glass6ba679c2018-07-06 10:27:17 -06001348 def testPackUbootSplMicrocode(self):
1349 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001350 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001351
1352 def testPackUbootSplMicrocodeReorder(self):
1353 """Test that order doesn't matter for microcode entries
1354
1355 This is the same as testPackUbootSplMicrocode but when we process the
1356 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1357 entry, so we reply on binman to try later.
1358 """
Simon Glass511f6582018-10-01 12:22:30 -06001359 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001360 ucode_second=True)
1361
Simon Glassa409c932017-11-12 21:52:28 -07001362 def testPackMrc(self):
1363 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001364 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001365 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1366
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001367 def testSplDtb(self):
1368 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001369 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001370 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1371
Simon Glass0a6da312017-11-13 18:54:56 -07001372 def testSplNoDtb(self):
1373 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001374 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001375 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001376 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1377
Simon Glass7098b7f2021-03-21 18:24:30 +13001378 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1379 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001380 """Check the image contains the expected symbol values
1381
1382 Args:
1383 dts: Device tree file to use for test
1384 base_data: Data before and after 'u-boot' section
1385 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001386 entry_args: Dict of entry args to supply to binman
1387 key: arg name
1388 value: value of that arg
1389 use_expanded: True to use expanded entries where available, e.g.
1390 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001391 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001392 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001393 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1394 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001395 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1396 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001397
Simon Glass7057d022018-10-01 21:12:47 -06001398 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001399 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1400 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001401 # The image should contain the symbols from u_boot_binman_syms.c
1402 # Note that image_pos is adjusted by the base address of the image,
1403 # which is 0x10 in our test image
1404 sym_values = struct.pack('<LQLL', 0x00,
1405 u_boot_offset + len(U_BOOT_DATA),
1406 0x10 + u_boot_offset, 0x04)
1407 expected = (sym_values + base_data[20:] +
Simon Glassac0d4952019-05-14 15:53:47 -06001408 tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001409 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001410 self.assertEqual(expected, data)
1411
Simon Glass31e04cb2021-03-18 20:24:56 +13001412 def testSymbols(self):
1413 """Test binman can assign symbols embedded in U-Boot"""
1414 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1415
1416 def testSymbolsNoDtb(self):
1417 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001418 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001419 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1420 0x38)
1421
Simon Glasse76a3e62018-06-01 09:38:11 -06001422 def testPackUnitAddress(self):
1423 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001424 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001425 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1426
Simon Glassa91e1152018-06-01 09:38:16 -06001427 def testSections(self):
1428 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001429 data = self._DoReadFile('055_sections.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06001430 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1431 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
1432 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001433 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001434
Simon Glass30732662018-06-01 09:38:20 -06001435 def testMap(self):
1436 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001437 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001438 self.assertEqual('''ImagePos Offset Size Name
143900000000 00000000 00000028 main-section
144000000000 00000000 00000010 section@0
144100000000 00000000 00000004 u-boot
144200000010 00000010 00000010 section@1
144300000010 00000000 00000004 u-boot
144400000020 00000020 00000004 section@2
144500000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001446''', map_data)
1447
Simon Glass3b78d532018-06-01 09:38:21 -06001448 def testNamePrefix(self):
1449 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001450 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001451 self.assertEqual('''ImagePos Offset Size Name
145200000000 00000000 00000028 main-section
145300000000 00000000 00000010 section@0
145400000000 00000000 00000004 ro-u-boot
145500000010 00000010 00000010 section@1
145600000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001457''', map_data)
1458
Simon Glass6ba679c2018-07-06 10:27:17 -06001459 def testUnknownContents(self):
1460 """Test that obtaining the contents works as expected"""
1461 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001462 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001463 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001464 "processing of contents: remaining ["
1465 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001466
Simon Glass2e1169f2018-07-06 10:27:19 -06001467 def testBadChangeSize(self):
1468 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001469 try:
1470 state.SetAllowEntryExpansion(False)
1471 with self.assertRaises(ValueError) as e:
1472 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001473 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001474 str(e.exception))
1475 finally:
1476 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001477
Simon Glassa87014e2018-07-06 10:27:42 -06001478 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001479 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001480 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001481 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001482 dtb = fdt.Fdt(out_dtb_fname)
1483 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001484 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001485 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001486 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001487 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001488 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001489 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001490 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001491 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001492 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001493 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001494 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001495 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001496 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001497
Simon Glasse8561af2018-08-01 15:22:37 -06001498 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001499 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001500 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001501 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001502 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001503 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001504 'size': 40
1505 }, props)
1506
1507 def testUpdateFdtBad(self):
1508 """Test that we detect when ProcessFdt never completes"""
1509 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001510 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001511 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001512 '[<binman.etype._testing.Entry__testing',
1513 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001514
Simon Glass91710b32018-07-17 13:25:32 -06001515 def testEntryArgs(self):
1516 """Test passing arguments to entries from the command line"""
1517 entry_args = {
1518 'test-str-arg': 'test1',
1519 'test-int-arg': '456',
1520 }
Simon Glass511f6582018-10-01 12:22:30 -06001521 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001522 self.assertIn('image', control.images)
1523 entry = control.images['image'].GetEntries()['_testing']
1524 self.assertEqual('test0', entry.test_str_fdt)
1525 self.assertEqual('test1', entry.test_str_arg)
1526 self.assertEqual(123, entry.test_int_fdt)
1527 self.assertEqual(456, entry.test_int_arg)
1528
1529 def testEntryArgsMissing(self):
1530 """Test missing arguments and properties"""
1531 entry_args = {
1532 'test-int-arg': '456',
1533 }
Simon Glass511f6582018-10-01 12:22:30 -06001534 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001535 entry = control.images['image'].GetEntries()['_testing']
1536 self.assertEqual('test0', entry.test_str_fdt)
1537 self.assertEqual(None, entry.test_str_arg)
1538 self.assertEqual(None, entry.test_int_fdt)
1539 self.assertEqual(456, entry.test_int_arg)
1540
1541 def testEntryArgsRequired(self):
1542 """Test missing arguments and properties"""
1543 entry_args = {
1544 'test-int-arg': '456',
1545 }
1546 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001547 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001548 self.assertIn("Node '/binman/_testing': "
1549 'Missing required properties/entry args: test-str-arg, '
1550 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001551 str(e.exception))
1552
1553 def testEntryArgsInvalidFormat(self):
1554 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001555 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1556 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001557 with self.assertRaises(ValueError) as e:
1558 self._DoBinman(*args)
1559 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1560
1561 def testEntryArgsInvalidInteger(self):
1562 """Test that an invalid entry-argument integer is detected"""
1563 entry_args = {
1564 'test-int-arg': 'abc',
1565 }
1566 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001567 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001568 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1569 "'test-int-arg' (value 'abc') to integer",
1570 str(e.exception))
1571
1572 def testEntryArgsInvalidDatatype(self):
1573 """Test that an invalid entry-argument datatype is detected
1574
1575 This test could be written in entry_test.py except that it needs
1576 access to control.entry_args, which seems more than that module should
1577 be able to see.
1578 """
1579 entry_args = {
1580 'test-bad-datatype-arg': '12',
1581 }
1582 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001583 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001584 entry_args=entry_args)
1585 self.assertIn('GetArg() internal error: Unknown data type ',
1586 str(e.exception))
1587
Simon Glass2ca52032018-07-17 13:25:33 -06001588 def testText(self):
1589 """Test for a text entry type"""
1590 entry_args = {
1591 'test-id': TEXT_DATA,
1592 'test-id2': TEXT_DATA2,
1593 'test-id3': TEXT_DATA3,
1594 }
Simon Glass511f6582018-10-01 12:22:30 -06001595 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001596 entry_args=entry_args)
Simon Glass303f62f2019-05-17 22:00:46 -06001597 expected = (tools.ToBytes(TEXT_DATA) +
1598 tools.GetBytes(0, 8 - len(TEXT_DATA)) +
1599 tools.ToBytes(TEXT_DATA2) + tools.ToBytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001600 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001601 self.assertEqual(expected, data)
1602
Simon Glass969616c2018-07-17 13:25:36 -06001603 def testEntryDocs(self):
1604 """Test for creation of entry documentation"""
1605 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001606 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001607 self.assertTrue(len(stdout.getvalue()) > 0)
1608
1609 def testEntryDocsMissing(self):
1610 """Test handling of missing entry documentation"""
1611 with self.assertRaises(ValueError) as e:
1612 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001613 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001614 self.assertIn('Documentation is missing for modules: u_boot',
1615 str(e.exception))
1616
Simon Glass704784b2018-07-17 13:25:38 -06001617 def testFmap(self):
1618 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001619 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001620 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06001621 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
1622 U_BOOT_DATA + tools.GetBytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001623 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001624 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001625 self.assertEqual(1, fhdr.ver_major)
1626 self.assertEqual(0, fhdr.ver_minor)
1627 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001628 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001629 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001630 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001631 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001632 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001633
Simon Glass82059c22021-04-03 11:05:09 +13001634 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001635 self.assertEqual(b'SECTION0', fentry.name)
1636 self.assertEqual(0, fentry.offset)
1637 self.assertEqual(16, fentry.size)
1638 self.assertEqual(0, fentry.flags)
1639
1640 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001641 self.assertEqual(b'RO_U_BOOT', fentry.name)
1642 self.assertEqual(0, fentry.offset)
1643 self.assertEqual(4, fentry.size)
1644 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001645
Simon Glass82059c22021-04-03 11:05:09 +13001646 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001647 self.assertEqual(b'SECTION1', fentry.name)
1648 self.assertEqual(16, fentry.offset)
1649 self.assertEqual(16, fentry.size)
1650 self.assertEqual(0, fentry.flags)
1651
1652 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001653 self.assertEqual(b'RW_U_BOOT', fentry.name)
1654 self.assertEqual(16, fentry.offset)
1655 self.assertEqual(4, fentry.size)
1656 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001657
Simon Glass82059c22021-04-03 11:05:09 +13001658 fentry = next(fiter)
1659 self.assertEqual(b'FMAP', fentry.name)
1660 self.assertEqual(32, fentry.offset)
1661 self.assertEqual(expect_size, fentry.size)
1662 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001663
Simon Glassdb168d42018-07-17 13:25:39 -06001664 def testBlobNamedByArg(self):
1665 """Test we can add a blob with the filename coming from an entry arg"""
1666 entry_args = {
1667 'cros-ec-rw-path': 'ecrw.bin',
1668 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001669 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001670
Simon Glass53f53992018-07-17 13:25:40 -06001671 def testFill(self):
1672 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001673 data = self._DoReadFile('069_fill.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001674 expected = tools.GetBytes(0xff, 8) + tools.GetBytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001675 self.assertEqual(expected, data)
1676
1677 def testFillNoSize(self):
1678 """Test for an fill entry type with no size"""
1679 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001680 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001681 self.assertIn("'fill' entry must have a size property",
1682 str(e.exception))
1683
Simon Glassc1ae83c2018-07-17 13:25:44 -06001684 def _HandleGbbCommand(self, pipe_list):
1685 """Fake calls to the futility utility"""
1686 if pipe_list[0][0] == 'futility':
1687 fname = pipe_list[0][-1]
1688 # Append our GBB data to the file, which will happen every time the
1689 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001690 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001691 fd.write(GBB_DATA)
1692 return command.CommandResult()
1693
1694 def testGbb(self):
1695 """Test for the Chromium OS Google Binary Block"""
1696 command.test_result = self._HandleGbbCommand
1697 entry_args = {
1698 'keydir': 'devkeys',
1699 'bmpblk': 'bmpblk.bin',
1700 }
Simon Glass511f6582018-10-01 12:22:30 -06001701 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001702
1703 # Since futility
Simon Glassac0d4952019-05-14 15:53:47 -06001704 expected = (GBB_DATA + GBB_DATA + tools.GetBytes(0, 8) +
1705 tools.GetBytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001706 self.assertEqual(expected, data)
1707
1708 def testGbbTooSmall(self):
1709 """Test for the Chromium OS Google Binary Block being large enough"""
1710 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001711 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001712 self.assertIn("Node '/binman/gbb': GBB is too small",
1713 str(e.exception))
1714
1715 def testGbbNoSize(self):
1716 """Test for the Chromium OS Google Binary Block having a size"""
1717 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001718 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001719 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1720 str(e.exception))
1721
Simon Glass5c350162018-07-17 13:25:47 -06001722 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001723 """Fake calls to the futility utility
1724
1725 The expected pipe is:
1726
1727 [('futility', 'vbutil_firmware', '--vblock',
1728 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1729 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1730 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1731 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1732
1733 This writes to the output file (here, 'vblock.vblock'). If
1734 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1735 of the input data (here, 'input.vblock').
1736 """
Simon Glass5c350162018-07-17 13:25:47 -06001737 if pipe_list[0][0] == 'futility':
1738 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001739 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001740 if self._hash_data:
1741 infile = pipe_list[0][11]
1742 m = hashlib.sha256()
1743 data = tools.ReadFile(infile)
1744 m.update(data)
1745 fd.write(m.digest())
1746 else:
1747 fd.write(VBLOCK_DATA)
1748
Simon Glass5c350162018-07-17 13:25:47 -06001749 return command.CommandResult()
1750
1751 def testVblock(self):
1752 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001753 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001754 command.test_result = self._HandleVblockCommand
1755 entry_args = {
1756 'keydir': 'devkeys',
1757 }
Simon Glass511f6582018-10-01 12:22:30 -06001758 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001759 entry_args=entry_args)
1760 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1761 self.assertEqual(expected, data)
1762
1763 def testVblockNoContent(self):
1764 """Test we detect a vblock which has no content to sign"""
1765 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001766 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001767 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001768 'property', str(e.exception))
1769
1770 def testVblockBadPhandle(self):
1771 """Test that we detect a vblock with an invalid phandle in contents"""
1772 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001773 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001774 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1775 '1000', str(e.exception))
1776
1777 def testVblockBadEntry(self):
1778 """Test that we detect an entry that points to a non-entry"""
1779 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001780 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001781 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1782 "'other'", str(e.exception))
1783
Simon Glass220c6222021-01-06 21:35:17 -07001784 def testVblockContent(self):
1785 """Test that the vblock signs the right data"""
1786 self._hash_data = True
1787 command.test_result = self._HandleVblockCommand
1788 entry_args = {
1789 'keydir': 'devkeys',
1790 }
1791 data = self._DoReadFileDtb(
1792 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1793 entry_args=entry_args)[0]
1794 hashlen = 32 # SHA256 hash is 32 bytes
1795 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1796 hashval = data[-hashlen:]
1797 dtb = data[len(U_BOOT_DATA):-hashlen]
1798
1799 expected_data = U_BOOT_DATA + dtb
1800
1801 # The hashval should be a hash of the dtb
1802 m = hashlib.sha256()
1803 m.update(expected_data)
1804 expected_hashval = m.digest()
1805 self.assertEqual(expected_hashval, hashval)
1806
Simon Glass8425a1f2018-07-17 13:25:48 -06001807 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001808 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001809 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001810 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001811 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001812 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1813
Simon Glass24b97442018-07-17 13:25:51 -06001814 def testUsesPos(self):
1815 """Test that the 'pos' property cannot be used anymore"""
1816 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001817 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001818 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1819 "'pos'", str(e.exception))
1820
Simon Glass274bf092018-09-14 04:57:08 -06001821 def testFillZero(self):
1822 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001823 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassac0d4952019-05-14 15:53:47 -06001824 self.assertEqual(tools.GetBytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001825
Simon Glass267de432018-09-14 04:57:09 -06001826 def testTextMissing(self):
1827 """Test for a text entry type where there is no text"""
1828 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001829 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001830 self.assertIn("Node '/binman/text': No value provided for text label "
1831 "'test-id'", str(e.exception))
1832
Simon Glassed40e962018-09-14 04:57:10 -06001833 def testPackStart16Tpl(self):
1834 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001835 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001836 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1837
Simon Glass3b376c32018-09-14 04:57:12 -06001838 def testSelectImage(self):
1839 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001840 expected = 'Skipping images: image1'
1841
1842 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001843 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001844 with test_util.capture_sys_output() as (stdout, stderr):
1845 retcode = self._DoTestFile('006_dual_image.dts',
1846 verbosity=verbosity,
1847 images=['image2'])
1848 self.assertEqual(0, retcode)
1849 if verbosity:
1850 self.assertIn(expected, stdout.getvalue())
1851 else:
1852 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001853
Simon Glassb4595d82019-04-25 21:58:34 -06001854 self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin')))
1855 self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001856 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001857
Simon Glasse219aa42018-09-14 04:57:24 -06001858 def testUpdateFdtAll(self):
1859 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001860 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001861
1862 base_expected = {
1863 'section:image-pos': 0,
1864 'u-boot-tpl-dtb:size': 513,
1865 'u-boot-spl-dtb:size': 513,
1866 'u-boot-spl-dtb:offset': 493,
1867 'image-pos': 0,
1868 'section/u-boot-dtb:image-pos': 0,
1869 'u-boot-spl-dtb:image-pos': 493,
1870 'section/u-boot-dtb:size': 493,
1871 'u-boot-tpl-dtb:image-pos': 1006,
1872 'section/u-boot-dtb:offset': 0,
1873 'section:size': 493,
1874 'offset': 0,
1875 'section:offset': 0,
1876 'u-boot-tpl-dtb:offset': 1006,
1877 'size': 1519
1878 }
1879
1880 # We expect three device-tree files in the output, one after the other.
1881 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1882 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1883 # main U-Boot tree. All three should have the same postions and offset.
1884 start = 0
1885 for item in ['', 'spl', 'tpl']:
1886 dtb = fdt.Fdt.FromData(data[start:])
1887 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001888 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1889 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001890 expected = dict(base_expected)
1891 if item:
1892 expected[item] = 0
1893 self.assertEqual(expected, props)
1894 start += dtb._fdt_obj.totalsize()
1895
1896 def testUpdateFdtOutput(self):
1897 """Test that output DTB files are updated"""
1898 try:
Simon Glass511f6582018-10-01 12:22:30 -06001899 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001900 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1901
1902 # Unfortunately, compiling a source file always results in a file
1903 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001904 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001905 # binman as a file called u-boot.dtb. To fix this, copy the file
1906 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001907 start = 0
1908 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1909 'tpl/u-boot-tpl.dtb.out']:
1910 dtb = fdt.Fdt.FromData(data[start:])
1911 size = dtb._fdt_obj.totalsize()
1912 pathname = tools.GetOutputFilename(os.path.split(fname)[1])
1913 outdata = tools.ReadFile(pathname)
1914 name = os.path.split(fname)[0]
1915
1916 if name:
1917 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1918 else:
1919 orig_indata = dtb_data
1920 self.assertNotEqual(outdata, orig_indata,
1921 "Expected output file '%s' be updated" % pathname)
1922 self.assertEqual(outdata, data[start:start + size],
1923 "Expected output file '%s' to match output image" %
1924 pathname)
1925 start += size
1926 finally:
1927 self._ResetDtbs()
1928
Simon Glass7ba33592018-09-14 04:57:26 -06001929 def _decompress(self, data):
Simon Glassdd5c14ec2022-01-09 20:14:04 -07001930 return comp_util.decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001931
1932 def testCompress(self):
1933 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001934 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001935 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001936 use_real_dtb=True, update_dtb=True)
1937 dtb = fdt.Fdt(out_dtb_fname)
1938 dtb.Scan()
1939 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1940 orig = self._decompress(data)
1941 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001942
1943 # Do a sanity check on various fields
1944 image = control.images['image']
1945 entries = image.GetEntries()
1946 self.assertEqual(1, len(entries))
1947
1948 entry = entries['blob']
1949 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1950 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1951 orig = self._decompress(entry.data)
1952 self.assertEqual(orig, entry.uncomp_data)
1953
Simon Glass72eeff12020-10-26 17:40:16 -06001954 self.assertEqual(image.data, entry.data)
1955
Simon Glass7ba33592018-09-14 04:57:26 -06001956 expected = {
1957 'blob:uncomp-size': len(COMPRESS_DATA),
1958 'blob:size': len(data),
1959 'size': len(data),
1960 }
1961 self.assertEqual(expected, props)
1962
Simon Glassac6328c2018-09-14 04:57:28 -06001963 def testFiles(self):
1964 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001965 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001966 self.assertEqual(FILES_DATA, data)
1967
1968 def testFilesCompress(self):
1969 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001970 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001971 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001972
1973 image = control.images['image']
1974 entries = image.GetEntries()
1975 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06001976 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06001977
Simon Glass303f62f2019-05-17 22:00:46 -06001978 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06001979 for i in range(1, 3):
1980 key = '%d.dat' % i
1981 start = entries[key].image_pos
1982 len = entries[key].size
1983 chunk = data[start:start + len]
1984 orig += self._decompress(chunk)
1985
1986 self.assertEqual(FILES_DATA, orig)
1987
1988 def testFilesMissing(self):
1989 """Test missing files"""
1990 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001991 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001992 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
1993 'no files', str(e.exception))
1994
1995 def testFilesNoPattern(self):
1996 """Test missing files"""
1997 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001998 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001999 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2000 str(e.exception))
2001
Simon Glassfa79a812018-09-14 04:57:29 -06002002 def testExpandSize(self):
2003 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002004 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002005 map=True)
Simon Glass303f62f2019-05-17 22:00:46 -06002006 expect = (tools.GetBytes(ord('a'), 8) + U_BOOT_DATA +
2007 MRC_DATA + tools.GetBytes(ord('b'), 1) + U_BOOT_DATA +
2008 tools.GetBytes(ord('c'), 8) + U_BOOT_DATA +
2009 tools.GetBytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002010 self.assertEqual(expect, data)
2011 self.assertEqual('''ImagePos Offset Size Name
201200000000 00000000 00000028 main-section
201300000000 00000000 00000008 fill
201400000008 00000008 00000004 u-boot
20150000000c 0000000c 00000004 section
20160000000c 00000000 00000003 intel-mrc
201700000010 00000010 00000004 u-boot2
201800000014 00000014 0000000c section2
201900000014 00000000 00000008 fill
20200000001c 00000008 00000004 u-boot
202100000020 00000020 00000008 fill2
2022''', map_data)
2023
2024 def testExpandSizeBad(self):
2025 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002026 with test_util.capture_sys_output() as (stdout, stderr):
2027 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002028 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002029 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2030 'expanding entry', str(e.exception))
2031
Simon Glassae7cf032018-09-14 04:57:31 -06002032 def testHash(self):
2033 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002034 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002035 use_real_dtb=True, update_dtb=True)
2036 dtb = fdt.Fdt(out_dtb_fname)
2037 dtb.Scan()
2038 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2039 m = hashlib.sha256()
2040 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002041 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002042
2043 def testHashNoAlgo(self):
2044 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002045 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002046 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2047 'hash node', str(e.exception))
2048
2049 def testHashBadAlgo(self):
2050 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002051 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002052 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2053 str(e.exception))
2054
2055 def testHashSection(self):
2056 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002057 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002058 use_real_dtb=True, update_dtb=True)
2059 dtb = fdt.Fdt(out_dtb_fname)
2060 dtb.Scan()
2061 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2062 m = hashlib.sha256()
2063 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002064 m.update(tools.GetBytes(ord('a'), 16))
2065 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002066
Simon Glass3fb4f422018-09-14 04:57:32 -06002067 def testPackUBootTplMicrocode(self):
2068 """Test that x86 microcode can be handled correctly in TPL
2069
2070 We expect to see the following in the image, in order:
2071 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2072 place
2073 u-boot-tpl.dtb with the microcode removed
2074 the microcode
2075 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002076 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002077 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002078 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002079 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2080 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002081
Simon Glassc64aea52018-09-14 04:57:34 -06002082 def testFmapX86(self):
2083 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002084 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002085 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass303f62f2019-05-17 22:00:46 -06002086 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002087 self.assertEqual(expected, data[:32])
2088 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2089
2090 self.assertEqual(0x100, fhdr.image_size)
2091
2092 self.assertEqual(0, fentries[0].offset)
2093 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002094 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002095
2096 self.assertEqual(4, fentries[1].offset)
2097 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002098 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002099
2100 self.assertEqual(32, fentries[2].offset)
2101 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2102 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002103 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002104
2105 def testFmapX86Section(self):
2106 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002107 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass303f62f2019-05-17 22:00:46 -06002108 expected = U_BOOT_DATA + MRC_DATA + tools.GetBytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002109 self.assertEqual(expected, data[:32])
2110 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2111
Simon Glassb1d414c2021-04-03 11:05:10 +13002112 self.assertEqual(0x180, fhdr.image_size)
2113 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002114 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002115
Simon Glass82059c22021-04-03 11:05:09 +13002116 fentry = next(fiter)
2117 self.assertEqual(b'U_BOOT', fentry.name)
2118 self.assertEqual(0, fentry.offset)
2119 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002120
Simon Glass82059c22021-04-03 11:05:09 +13002121 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002122 self.assertEqual(b'SECTION', fentry.name)
2123 self.assertEqual(4, fentry.offset)
2124 self.assertEqual(0x20 + expect_size, fentry.size)
2125
2126 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002127 self.assertEqual(b'INTEL_MRC', fentry.name)
2128 self.assertEqual(4, fentry.offset)
2129 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002130
Simon Glass82059c22021-04-03 11:05:09 +13002131 fentry = next(fiter)
2132 self.assertEqual(b'FMAP', fentry.name)
2133 self.assertEqual(36, fentry.offset)
2134 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002135
Simon Glassb1714232018-09-14 04:57:35 -06002136 def testElf(self):
2137 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002138 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002139 self._SetupTplElf()
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('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002143
Simon Glass0d673792019-07-08 13:18:25 -06002144 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002145 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002146 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002147 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002148 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002149 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002150
Simon Glasscd817d52018-09-14 04:57:36 -06002151 def testPackOverlapMap(self):
2152 """Test that overlapping regions are detected"""
2153 with test_util.capture_sys_output() as (stdout, stderr):
2154 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002155 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glasscd817d52018-09-14 04:57:36 -06002156 map_fname = tools.GetOutputFilename('image.map')
2157 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2158 stdout.getvalue())
2159
2160 # We should not get an inmage, but there should be a map file
2161 self.assertFalse(os.path.exists(tools.GetOutputFilename('image.bin')))
2162 self.assertTrue(os.path.exists(map_fname))
Simon Glassb3774752019-05-17 22:00:51 -06002163 map_data = tools.ReadFile(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002164 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002165<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002166<none> 00000000 00000004 u-boot
2167<none> 00000003 00000004 u-boot-align
2168''', map_data)
2169
Simon Glass0d673792019-07-08 13:18:25 -06002170 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002171 """Test that an image with an Intel Reference code binary works"""
2172 data = self._DoReadFile('100_intel_refcode.dts')
2173 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2174
Simon Glasseb023b32019-04-25 21:58:39 -06002175 def testSectionOffset(self):
2176 """Tests use of a section with an offset"""
2177 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2178 map=True)
2179 self.assertEqual('''ImagePos Offset Size Name
218000000000 00000000 00000038 main-section
218100000004 00000004 00000010 section@0
218200000004 00000000 00000004 u-boot
218300000018 00000018 00000010 section@1
218400000018 00000000 00000004 u-boot
21850000002c 0000002c 00000004 section@2
21860000002c 00000000 00000004 u-boot
2187''', map_data)
2188 self.assertEqual(data,
Simon Glassac0d4952019-05-14 15:53:47 -06002189 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2190 tools.GetBytes(0x21, 12) +
2191 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2192 tools.GetBytes(0x61, 12) +
2193 tools.GetBytes(0x26, 4) + U_BOOT_DATA +
2194 tools.GetBytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002195
Simon Glass1de34482019-07-08 13:18:53 -06002196 def testCbfsRaw(self):
2197 """Test base handling of a Coreboot Filesystem (CBFS)
2198
2199 The exact contents of the CBFS is verified by similar tests in
2200 cbfs_util_test.py. The tests here merely check that the files added to
2201 the CBFS can be found in the final image.
2202 """
2203 data = self._DoReadFile('102_cbfs_raw.dts')
2204 size = 0xb0
2205
2206 cbfs = cbfs_util.CbfsReader(data)
2207 self.assertEqual(size, cbfs.rom_size)
2208
2209 self.assertIn('u-boot-dtb', cbfs.files)
2210 cfile = cbfs.files['u-boot-dtb']
2211 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2212
2213 def testCbfsArch(self):
2214 """Test on non-x86 architecture"""
2215 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2216 size = 0x100
2217
2218 cbfs = cbfs_util.CbfsReader(data)
2219 self.assertEqual(size, cbfs.rom_size)
2220
2221 self.assertIn('u-boot-dtb', cbfs.files)
2222 cfile = cbfs.files['u-boot-dtb']
2223 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2224
2225 def testCbfsStage(self):
2226 """Tests handling of a Coreboot Filesystem (CBFS)"""
2227 if not elf.ELF_TOOLS:
2228 self.skipTest('Python elftools not available')
2229 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2230 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2231 size = 0xb0
2232
2233 data = self._DoReadFile('104_cbfs_stage.dts')
2234 cbfs = cbfs_util.CbfsReader(data)
2235 self.assertEqual(size, cbfs.rom_size)
2236
2237 self.assertIn('u-boot', cbfs.files)
2238 cfile = cbfs.files['u-boot']
2239 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2240
2241 def testCbfsRawCompress(self):
2242 """Test handling of compressing raw files"""
2243 self._CheckLz4()
2244 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2245 size = 0x140
2246
2247 cbfs = cbfs_util.CbfsReader(data)
2248 self.assertIn('u-boot', cbfs.files)
2249 cfile = cbfs.files['u-boot']
2250 self.assertEqual(COMPRESS_DATA, cfile.data)
2251
2252 def testCbfsBadArch(self):
2253 """Test handling of a bad architecture"""
2254 with self.assertRaises(ValueError) as e:
2255 self._DoReadFile('106_cbfs_bad_arch.dts')
2256 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2257
2258 def testCbfsNoSize(self):
2259 """Test handling of a missing size property"""
2260 with self.assertRaises(ValueError) as e:
2261 self._DoReadFile('107_cbfs_no_size.dts')
2262 self.assertIn('entry must have a size property', str(e.exception))
2263
Simon Glass3e28f4f2021-11-23 11:03:54 -07002264 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002265 """Test handling of a CBFS entry which does not provide contentsy"""
2266 with self.assertRaises(ValueError) as e:
2267 self._DoReadFile('108_cbfs_no_contents.dts')
2268 self.assertIn('Could not complete processing of contents',
2269 str(e.exception))
2270
2271 def testCbfsBadCompress(self):
2272 """Test handling of a bad architecture"""
2273 with self.assertRaises(ValueError) as e:
2274 self._DoReadFile('109_cbfs_bad_compress.dts')
2275 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2276 str(e.exception))
2277
2278 def testCbfsNamedEntries(self):
2279 """Test handling of named entries"""
2280 data = self._DoReadFile('110_cbfs_name.dts')
2281
2282 cbfs = cbfs_util.CbfsReader(data)
2283 self.assertIn('FRED', cbfs.files)
2284 cfile1 = cbfs.files['FRED']
2285 self.assertEqual(U_BOOT_DATA, cfile1.data)
2286
2287 self.assertIn('hello', cbfs.files)
2288 cfile2 = cbfs.files['hello']
2289 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2290
Simon Glass759af872019-07-08 13:18:54 -06002291 def _SetupIfwi(self, fname):
2292 """Set up to run an IFWI test
2293
2294 Args:
2295 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2296 """
2297 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002298 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002299
2300 # Intel Integrated Firmware Image (IFWI) file
2301 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2302 data = fd.read()
2303 TestFunctional._MakeInputFile(fname,data)
2304
2305 def _CheckIfwi(self, data):
2306 """Check that an image with an IFWI contains the correct output
2307
2308 Args:
2309 data: Conents of output file
2310 """
2311 expected_desc = tools.ReadFile(self.TestFile('descriptor.bin'))
2312 if data[:0x1000] != expected_desc:
2313 self.fail('Expected descriptor binary at start of image')
2314
2315 # We expect to find the TPL wil in subpart IBBP entry IBBL
2316 image_fname = tools.GetOutputFilename('image.bin')
2317 tpl_fname = tools.GetOutputFilename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002318 ifwitool = bintool.Bintool.create('ifwitool')
2319 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002320
2321 tpl_data = tools.ReadFile(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002322 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002323
2324 def testPackX86RomIfwi(self):
2325 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2326 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002327 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002328 self._CheckIfwi(data)
2329
2330 def testPackX86RomIfwiNoDesc(self):
2331 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2332 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002333 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002334 self._CheckIfwi(data)
2335
2336 def testPackX86RomIfwiNoData(self):
2337 """Test that an x86 ROM with IFWI handles missing data"""
2338 self._SetupIfwi('ifwi.bin')
2339 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002340 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002341 self.assertIn('Could not complete processing of contents',
2342 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002343
Simon Glassc2f1aed2019-07-08 13:18:56 -06002344 def testCbfsOffset(self):
2345 """Test a CBFS with files at particular offsets
2346
2347 Like all CFBS tests, this is just checking the logic that calls
2348 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2349 """
2350 data = self._DoReadFile('114_cbfs_offset.dts')
2351 size = 0x200
2352
2353 cbfs = cbfs_util.CbfsReader(data)
2354 self.assertEqual(size, cbfs.rom_size)
2355
2356 self.assertIn('u-boot', cbfs.files)
2357 cfile = cbfs.files['u-boot']
2358 self.assertEqual(U_BOOT_DATA, cfile.data)
2359 self.assertEqual(0x40, cfile.cbfs_offset)
2360
2361 self.assertIn('u-boot-dtb', cbfs.files)
2362 cfile2 = cbfs.files['u-boot-dtb']
2363 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2364 self.assertEqual(0x140, cfile2.cbfs_offset)
2365
Simon Glass0f621332019-07-08 14:25:27 -06002366 def testFdtmap(self):
2367 """Test an FDT map can be inserted in the image"""
2368 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2369 fdtmap_data = data[len(U_BOOT_DATA):]
2370 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002371 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass0f621332019-07-08 14:25:27 -06002372 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
2373
2374 fdt_data = fdtmap_data[16:]
2375 dtb = fdt.Fdt.FromData(fdt_data)
2376 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002377 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002378 self.assertEqual({
2379 'image-pos': 0,
2380 'offset': 0,
2381 'u-boot:offset': 0,
2382 'u-boot:size': len(U_BOOT_DATA),
2383 'u-boot:image-pos': 0,
2384 'fdtmap:image-pos': 4,
2385 'fdtmap:offset': 4,
2386 'fdtmap:size': len(fdtmap_data),
2387 'size': len(data),
2388 }, props)
2389
2390 def testFdtmapNoMatch(self):
2391 """Check handling of an FDT map when the section cannot be found"""
2392 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2393
2394 # Mangle the section name, which should cause a mismatch between the
2395 # correct FDT path and the one expected by the section
2396 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002397 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002398 entries = image.GetEntries()
2399 fdtmap = entries['fdtmap']
2400 with self.assertRaises(ValueError) as e:
2401 fdtmap._GetFdtmap()
2402 self.assertIn("Cannot locate node for path '/binman-suffix'",
2403 str(e.exception))
2404
Simon Glasscec34ba2019-07-08 14:25:28 -06002405 def testFdtmapHeader(self):
2406 """Test an FDT map and image header can be inserted in the image"""
2407 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2408 fdtmap_pos = len(U_BOOT_DATA)
2409 fdtmap_data = data[fdtmap_pos:]
2410 fdt_data = fdtmap_data[16:]
2411 dtb = fdt.Fdt.FromData(fdt_data)
2412 fdt_size = dtb.GetFdtObj().totalsize()
2413 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002414 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002415 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2416 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2417
2418 def testFdtmapHeaderStart(self):
2419 """Test an image header can be inserted at the image start"""
2420 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2421 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2422 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002423 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002424 offset = struct.unpack('<I', hdr_data[4:])[0]
2425 self.assertEqual(fdtmap_pos, offset)
2426
2427 def testFdtmapHeaderPos(self):
2428 """Test an image header can be inserted at a chosen position"""
2429 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2430 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2431 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002432 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002433 offset = struct.unpack('<I', hdr_data[4:])[0]
2434 self.assertEqual(fdtmap_pos, offset)
2435
2436 def testHeaderMissingFdtmap(self):
2437 """Test an image header requires an fdtmap"""
2438 with self.assertRaises(ValueError) as e:
2439 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2440 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2441 str(e.exception))
2442
2443 def testHeaderNoLocation(self):
2444 """Test an image header with a no specified location is detected"""
2445 with self.assertRaises(ValueError) as e:
2446 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2447 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2448 str(e.exception))
2449
Simon Glasse61b6f62019-07-08 14:25:37 -06002450 def testEntryExpand(self):
2451 """Test expanding an entry after it is packed"""
2452 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002453 self.assertEqual(b'aaa', data[:3])
2454 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2455 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002456
2457 def testEntryExpandBad(self):
2458 """Test expanding an entry after it is packed, twice"""
2459 with self.assertRaises(ValueError) as e:
2460 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002461 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002462 str(e.exception))
2463
2464 def testEntryExpandSection(self):
2465 """Test expanding an entry within a section after it is packed"""
2466 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002467 self.assertEqual(b'aaa', data[:3])
2468 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2469 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002470
Simon Glass90d29682019-07-08 14:25:38 -06002471 def testCompressDtb(self):
2472 """Test that compress of device-tree files is supported"""
2473 self._CheckLz4()
2474 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2475 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2476 comp_data = data[len(U_BOOT_DATA):]
2477 orig = self._decompress(comp_data)
2478 dtb = fdt.Fdt.FromData(orig)
2479 dtb.Scan()
2480 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2481 expected = {
2482 'u-boot:size': len(U_BOOT_DATA),
2483 'u-boot-dtb:uncomp-size': len(orig),
2484 'u-boot-dtb:size': len(comp_data),
2485 'size': len(data),
2486 }
2487 self.assertEqual(expected, props)
2488
Simon Glass151bbbf2019-07-08 14:25:41 -06002489 def testCbfsUpdateFdt(self):
2490 """Test that we can update the device tree with CBFS offset/size info"""
2491 self._CheckLz4()
2492 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2493 update_dtb=True)
2494 dtb = fdt.Fdt(out_dtb_fname)
2495 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002496 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002497 del props['cbfs/u-boot:size']
2498 self.assertEqual({
2499 'offset': 0,
2500 'size': len(data),
2501 'image-pos': 0,
2502 'cbfs:offset': 0,
2503 'cbfs:size': len(data),
2504 'cbfs:image-pos': 0,
2505 'cbfs/u-boot:offset': 0x38,
2506 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2507 'cbfs/u-boot:image-pos': 0x38,
2508 'cbfs/u-boot-dtb:offset': 0xb8,
2509 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2510 'cbfs/u-boot-dtb:image-pos': 0xb8,
2511 }, props)
2512
Simon Glass3c9b4f22019-07-08 14:25:42 -06002513 def testCbfsBadType(self):
2514 """Test an image header with a no specified location is detected"""
2515 with self.assertRaises(ValueError) as e:
2516 self._DoReadFile('126_cbfs_bad_type.dts')
2517 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2518
Simon Glass6b156f82019-07-08 14:25:43 -06002519 def testList(self):
2520 """Test listing the files in an image"""
2521 self._CheckLz4()
2522 data = self._DoReadFile('127_list.dts')
2523 image = control.images['image']
2524 entries = image.BuildEntryList()
2525 self.assertEqual(7, len(entries))
2526
2527 ent = entries[0]
2528 self.assertEqual(0, ent.indent)
2529 self.assertEqual('main-section', ent.name)
2530 self.assertEqual('section', ent.etype)
2531 self.assertEqual(len(data), ent.size)
2532 self.assertEqual(0, ent.image_pos)
2533 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002534 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002535
2536 ent = entries[1]
2537 self.assertEqual(1, ent.indent)
2538 self.assertEqual('u-boot', ent.name)
2539 self.assertEqual('u-boot', ent.etype)
2540 self.assertEqual(len(U_BOOT_DATA), ent.size)
2541 self.assertEqual(0, ent.image_pos)
2542 self.assertEqual(None, ent.uncomp_size)
2543 self.assertEqual(0, ent.offset)
2544
2545 ent = entries[2]
2546 self.assertEqual(1, ent.indent)
2547 self.assertEqual('section', ent.name)
2548 self.assertEqual('section', ent.etype)
2549 section_size = ent.size
2550 self.assertEqual(0x100, ent.image_pos)
2551 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002552 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002553
2554 ent = entries[3]
2555 self.assertEqual(2, ent.indent)
2556 self.assertEqual('cbfs', ent.name)
2557 self.assertEqual('cbfs', ent.etype)
2558 self.assertEqual(0x400, ent.size)
2559 self.assertEqual(0x100, ent.image_pos)
2560 self.assertEqual(None, ent.uncomp_size)
2561 self.assertEqual(0, ent.offset)
2562
2563 ent = entries[4]
2564 self.assertEqual(3, ent.indent)
2565 self.assertEqual('u-boot', ent.name)
2566 self.assertEqual('u-boot', ent.etype)
2567 self.assertEqual(len(U_BOOT_DATA), ent.size)
2568 self.assertEqual(0x138, ent.image_pos)
2569 self.assertEqual(None, ent.uncomp_size)
2570 self.assertEqual(0x38, ent.offset)
2571
2572 ent = entries[5]
2573 self.assertEqual(3, ent.indent)
2574 self.assertEqual('u-boot-dtb', ent.name)
2575 self.assertEqual('text', ent.etype)
2576 self.assertGreater(len(COMPRESS_DATA), ent.size)
2577 self.assertEqual(0x178, ent.image_pos)
2578 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2579 self.assertEqual(0x78, ent.offset)
2580
2581 ent = entries[6]
2582 self.assertEqual(2, ent.indent)
2583 self.assertEqual('u-boot-dtb', ent.name)
2584 self.assertEqual('u-boot-dtb', ent.etype)
2585 self.assertEqual(0x500, ent.image_pos)
2586 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2587 dtb_size = ent.size
2588 # Compressing this data expands it since headers are added
2589 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2590 self.assertEqual(0x400, ent.offset)
2591
2592 self.assertEqual(len(data), 0x100 + section_size)
2593 self.assertEqual(section_size, 0x400 + dtb_size)
2594
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002595 def testFindFdtmap(self):
2596 """Test locating an FDT map in an image"""
2597 self._CheckLz4()
2598 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2599 image = control.images['image']
2600 entries = image.GetEntries()
2601 entry = entries['fdtmap']
2602 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2603
2604 def testFindFdtmapMissing(self):
2605 """Test failing to locate an FDP map"""
2606 data = self._DoReadFile('005_simple.dts')
2607 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2608
Simon Glassed39a3c2019-07-08 14:25:45 -06002609 def testFindImageHeader(self):
2610 """Test locating a image header"""
2611 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002612 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002613 image = control.images['image']
2614 entries = image.GetEntries()
2615 entry = entries['fdtmap']
2616 # The header should point to the FDT map
2617 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2618
2619 def testFindImageHeaderStart(self):
2620 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002621 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002622 image = control.images['image']
2623 entries = image.GetEntries()
2624 entry = entries['fdtmap']
2625 # The header should point to the FDT map
2626 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2627
2628 def testFindImageHeaderMissing(self):
2629 """Test failing to locate an image header"""
2630 data = self._DoReadFile('005_simple.dts')
2631 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2632
Simon Glassb8424fa2019-07-08 14:25:46 -06002633 def testReadImage(self):
2634 """Test reading an image and accessing its FDT map"""
2635 self._CheckLz4()
2636 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2637 image_fname = tools.GetOutputFilename('image.bin')
2638 orig_image = control.images['image']
2639 image = Image.FromFile(image_fname)
2640 self.assertEqual(orig_image.GetEntries().keys(),
2641 image.GetEntries().keys())
2642
2643 orig_entry = orig_image.GetEntries()['fdtmap']
2644 entry = image.GetEntries()['fdtmap']
2645 self.assertEquals(orig_entry.offset, entry.offset)
2646 self.assertEquals(orig_entry.size, entry.size)
2647 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2648
2649 def testReadImageNoHeader(self):
2650 """Test accessing an image's FDT map without an image header"""
2651 self._CheckLz4()
2652 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
2653 image_fname = tools.GetOutputFilename('image.bin')
2654 image = Image.FromFile(image_fname)
2655 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002656 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002657
2658 def testReadImageFail(self):
2659 """Test failing to read an image image's FDT map"""
2660 self._DoReadFile('005_simple.dts')
2661 image_fname = tools.GetOutputFilename('image.bin')
2662 with self.assertRaises(ValueError) as e:
2663 image = Image.FromFile(image_fname)
2664 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002665
Simon Glassb2fd11d2019-07-08 14:25:48 -06002666 def testListCmd(self):
2667 """Test listing the files in an image using an Fdtmap"""
2668 self._CheckLz4()
2669 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2670
2671 # lz4 compression size differs depending on the version
2672 image = control.images['image']
2673 entries = image.GetEntries()
2674 section_size = entries['section'].size
2675 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2676 fdtmap_offset = entries['fdtmap'].offset
2677
Simon Glassb3d6fc72019-07-20 12:24:10 -06002678 try:
2679 tmpdir, updated_fname = self._SetupImageInTmpdir()
2680 with test_util.capture_sys_output() as (stdout, stderr):
2681 self._DoBinman('ls', '-i', updated_fname)
2682 finally:
2683 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002684 lines = stdout.getvalue().splitlines()
2685 expected = [
2686'Name Image-pos Size Entry-type Offset Uncomp-size',
2687'----------------------------------------------------------------------',
2688'main-section 0 c00 section 0',
2689' u-boot 0 4 u-boot 0',
2690' section 100 %x section 100' % section_size,
2691' cbfs 100 400 cbfs 0',
2692' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002693' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002694' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002695' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002696 (fdtmap_offset, fdtmap_offset),
2697' image-header bf8 8 image-header bf8',
2698 ]
2699 self.assertEqual(expected, lines)
2700
2701 def testListCmdFail(self):
2702 """Test failing to list an image"""
2703 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002704 try:
2705 tmpdir, updated_fname = self._SetupImageInTmpdir()
2706 with self.assertRaises(ValueError) as e:
2707 self._DoBinman('ls', '-i', updated_fname)
2708 finally:
2709 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002710 self.assertIn("Cannot find FDT map in image", str(e.exception))
2711
2712 def _RunListCmd(self, paths, expected):
2713 """List out entries and check the result
2714
2715 Args:
2716 paths: List of paths to pass to the list command
2717 expected: Expected list of filenames to be returned, in order
2718 """
2719 self._CheckLz4()
2720 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2721 image_fname = tools.GetOutputFilename('image.bin')
2722 image = Image.FromFile(image_fname)
2723 lines = image.GetListEntries(paths)[1]
2724 files = [line[0].strip() for line in lines[1:]]
2725 self.assertEqual(expected, files)
2726
2727 def testListCmdSection(self):
2728 """Test listing the files in a section"""
2729 self._RunListCmd(['section'],
2730 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2731
2732 def testListCmdFile(self):
2733 """Test listing a particular file"""
2734 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2735
2736 def testListCmdWildcard(self):
2737 """Test listing a wildcarded file"""
2738 self._RunListCmd(['*boot*'],
2739 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2740
2741 def testListCmdWildcardMulti(self):
2742 """Test listing a wildcarded file"""
2743 self._RunListCmd(['*cb*', '*head*'],
2744 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2745
2746 def testListCmdEmpty(self):
2747 """Test listing a wildcarded file"""
2748 self._RunListCmd(['nothing'], [])
2749
2750 def testListCmdPath(self):
2751 """Test listing the files in a sub-entry of a section"""
2752 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2753
Simon Glass4c613bf2019-07-08 14:25:50 -06002754 def _RunExtractCmd(self, entry_name, decomp=True):
2755 """Extract an entry from an image
2756
2757 Args:
2758 entry_name: Entry name to extract
2759 decomp: True to decompress the data if compressed, False to leave
2760 it in its raw uncompressed format
2761
2762 Returns:
2763 data from entry
2764 """
2765 self._CheckLz4()
2766 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2767 image_fname = tools.GetOutputFilename('image.bin')
2768 return control.ReadEntry(image_fname, entry_name, decomp)
2769
2770 def testExtractSimple(self):
2771 """Test extracting a single file"""
2772 data = self._RunExtractCmd('u-boot')
2773 self.assertEqual(U_BOOT_DATA, data)
2774
Simon Glass980a2842019-07-08 14:25:52 -06002775 def testExtractSection(self):
2776 """Test extracting the files in a section"""
2777 data = self._RunExtractCmd('section')
2778 cbfs_data = data[:0x400]
2779 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002780 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002781 dtb_data = data[0x400:]
2782 dtb = self._decompress(dtb_data)
2783 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2784
2785 def testExtractCompressed(self):
2786 """Test extracting compressed data"""
2787 data = self._RunExtractCmd('section/u-boot-dtb')
2788 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2789
2790 def testExtractRaw(self):
2791 """Test extracting compressed data without decompressing it"""
2792 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2793 dtb = self._decompress(data)
2794 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2795
2796 def testExtractCbfs(self):
2797 """Test extracting CBFS data"""
2798 data = self._RunExtractCmd('section/cbfs/u-boot')
2799 self.assertEqual(U_BOOT_DATA, data)
2800
2801 def testExtractCbfsCompressed(self):
2802 """Test extracting CBFS compressed data"""
2803 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2804 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2805
2806 def testExtractCbfsRaw(self):
2807 """Test extracting CBFS compressed data without decompressing it"""
2808 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07002809 dtb = comp_util.decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002810 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2811
Simon Glass4c613bf2019-07-08 14:25:50 -06002812 def testExtractBadEntry(self):
2813 """Test extracting a bad section path"""
2814 with self.assertRaises(ValueError) as e:
2815 self._RunExtractCmd('section/does-not-exist')
2816 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2817 str(e.exception))
2818
2819 def testExtractMissingFile(self):
2820 """Test extracting file that does not exist"""
2821 with self.assertRaises(IOError) as e:
2822 control.ReadEntry('missing-file', 'name')
2823
2824 def testExtractBadFile(self):
2825 """Test extracting an invalid file"""
2826 fname = os.path.join(self._indir, 'badfile')
2827 tools.WriteFile(fname, b'')
2828 with self.assertRaises(ValueError) as e:
2829 control.ReadEntry(fname, 'name')
2830
Simon Glass980a2842019-07-08 14:25:52 -06002831 def testExtractCmd(self):
2832 """Test extracting a file fron an image on the command line"""
2833 self._CheckLz4()
2834 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002835 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002836 try:
2837 tmpdir, updated_fname = self._SetupImageInTmpdir()
2838 with test_util.capture_sys_output() as (stdout, stderr):
2839 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2840 '-f', fname)
2841 finally:
2842 shutil.rmtree(tmpdir)
Simon Glass980a2842019-07-08 14:25:52 -06002843 data = tools.ReadFile(fname)
2844 self.assertEqual(U_BOOT_DATA, data)
2845
2846 def testExtractOneEntry(self):
2847 """Test extracting a single entry fron an image """
2848 self._CheckLz4()
2849 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2850 image_fname = tools.GetOutputFilename('image.bin')
2851 fname = os.path.join(self._indir, 'output.extact')
2852 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
2853 data = tools.ReadFile(fname)
2854 self.assertEqual(U_BOOT_DATA, data)
2855
2856 def _CheckExtractOutput(self, decomp):
2857 """Helper to test file output with and without decompression
2858
2859 Args:
2860 decomp: True to decompress entry data, False to output it raw
2861 """
2862 def _CheckPresent(entry_path, expect_data, expect_size=None):
2863 """Check and remove expected file
2864
2865 This checks the data/size of a file and removes the file both from
2866 the outfiles set and from the output directory. Once all files are
2867 processed, both the set and directory should be empty.
2868
2869 Args:
2870 entry_path: Entry path
2871 expect_data: Data to expect in file, or None to skip check
2872 expect_size: Size of data to expect in file, or None to skip
2873 """
2874 path = os.path.join(outdir, entry_path)
2875 data = tools.ReadFile(path)
2876 os.remove(path)
2877 if expect_data:
2878 self.assertEqual(expect_data, data)
2879 elif expect_size:
2880 self.assertEqual(expect_size, len(data))
2881 outfiles.remove(path)
2882
2883 def _CheckDirPresent(name):
2884 """Remove expected directory
2885
2886 This gives an error if the directory does not exist as expected
2887
2888 Args:
2889 name: Name of directory to remove
2890 """
2891 path = os.path.join(outdir, name)
2892 os.rmdir(path)
2893
2894 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2895 image_fname = tools.GetOutputFilename('image.bin')
2896 outdir = os.path.join(self._indir, 'extract')
2897 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2898
2899 # Create a set of all file that were output (should be 9)
2900 outfiles = set()
2901 for root, dirs, files in os.walk(outdir):
2902 outfiles |= set([os.path.join(root, fname) for fname in files])
2903 self.assertEqual(9, len(outfiles))
2904 self.assertEqual(9, len(einfos))
2905
2906 image = control.images['image']
2907 entries = image.GetEntries()
2908
2909 # Check the 9 files in various ways
2910 section = entries['section']
2911 section_entries = section.GetEntries()
2912 cbfs_entries = section_entries['cbfs'].GetEntries()
2913 _CheckPresent('u-boot', U_BOOT_DATA)
2914 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2915 dtb_len = EXTRACT_DTB_SIZE
2916 if not decomp:
2917 dtb_len = cbfs_entries['u-boot-dtb'].size
2918 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2919 if not decomp:
2920 dtb_len = section_entries['u-boot-dtb'].size
2921 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2922
2923 fdtmap = entries['fdtmap']
2924 _CheckPresent('fdtmap', fdtmap.data)
2925 hdr = entries['image-header']
2926 _CheckPresent('image-header', hdr.data)
2927
2928 _CheckPresent('section/root', section.data)
2929 cbfs = section_entries['cbfs']
2930 _CheckPresent('section/cbfs/root', cbfs.data)
2931 data = tools.ReadFile(image_fname)
2932 _CheckPresent('root', data)
2933
2934 # There should be no files left. Remove all the directories to check.
2935 # If there are any files/dirs remaining, one of these checks will fail.
2936 self.assertEqual(0, len(outfiles))
2937 _CheckDirPresent('section/cbfs')
2938 _CheckDirPresent('section')
2939 _CheckDirPresent('')
2940 self.assertFalse(os.path.exists(outdir))
2941
2942 def testExtractAllEntries(self):
2943 """Test extracting all entries"""
2944 self._CheckLz4()
2945 self._CheckExtractOutput(decomp=True)
2946
2947 def testExtractAllEntriesRaw(self):
2948 """Test extracting all entries without decompressing them"""
2949 self._CheckLz4()
2950 self._CheckExtractOutput(decomp=False)
2951
2952 def testExtractSelectedEntries(self):
2953 """Test extracting some entries"""
2954 self._CheckLz4()
2955 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2956 image_fname = tools.GetOutputFilename('image.bin')
2957 outdir = os.path.join(self._indir, 'extract')
2958 einfos = control.ExtractEntries(image_fname, None, outdir,
2959 ['*cb*', '*head*'])
2960
2961 # File output is tested by testExtractAllEntries(), so just check that
2962 # the expected entries are selected
2963 names = [einfo.name for einfo in einfos]
2964 self.assertEqual(names,
2965 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2966
2967 def testExtractNoEntryPaths(self):
2968 """Test extracting some entries"""
2969 self._CheckLz4()
2970 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2971 image_fname = tools.GetOutputFilename('image.bin')
2972 with self.assertRaises(ValueError) as e:
2973 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06002974 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002975 str(e.exception))
2976
2977 def testExtractTooManyEntryPaths(self):
2978 """Test extracting some entries"""
2979 self._CheckLz4()
2980 self._DoReadFileRealDtb('130_list_fdtmap.dts')
2981 image_fname = tools.GetOutputFilename('image.bin')
2982 with self.assertRaises(ValueError) as e:
2983 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06002984 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06002985 str(e.exception))
2986
Simon Glass52d06212019-07-08 14:25:53 -06002987 def testPackAlignSection(self):
2988 """Test that sections can have alignment"""
2989 self._DoReadFile('131_pack_align_section.dts')
2990
2991 self.assertIn('image', control.images)
2992 image = control.images['image']
2993 entries = image.GetEntries()
2994 self.assertEqual(3, len(entries))
2995
2996 # First u-boot
2997 self.assertIn('u-boot', entries)
2998 entry = entries['u-boot']
2999 self.assertEqual(0, entry.offset)
3000 self.assertEqual(0, entry.image_pos)
3001 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3002 self.assertEqual(len(U_BOOT_DATA), entry.size)
3003
3004 # Section0
3005 self.assertIn('section0', entries)
3006 section0 = entries['section0']
3007 self.assertEqual(0x10, section0.offset)
3008 self.assertEqual(0x10, section0.image_pos)
3009 self.assertEqual(len(U_BOOT_DATA), section0.size)
3010
3011 # Second u-boot
3012 section_entries = section0.GetEntries()
3013 self.assertIn('u-boot', section_entries)
3014 entry = section_entries['u-boot']
3015 self.assertEqual(0, entry.offset)
3016 self.assertEqual(0x10, entry.image_pos)
3017 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3018 self.assertEqual(len(U_BOOT_DATA), entry.size)
3019
3020 # Section1
3021 self.assertIn('section1', entries)
3022 section1 = entries['section1']
3023 self.assertEqual(0x14, section1.offset)
3024 self.assertEqual(0x14, section1.image_pos)
3025 self.assertEqual(0x20, section1.size)
3026
3027 # Second u-boot
3028 section_entries = section1.GetEntries()
3029 self.assertIn('u-boot', section_entries)
3030 entry = section_entries['u-boot']
3031 self.assertEqual(0, entry.offset)
3032 self.assertEqual(0x14, entry.image_pos)
3033 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3034 self.assertEqual(len(U_BOOT_DATA), entry.size)
3035
3036 # Section2
3037 self.assertIn('section2', section_entries)
3038 section2 = section_entries['section2']
3039 self.assertEqual(0x4, section2.offset)
3040 self.assertEqual(0x18, section2.image_pos)
3041 self.assertEqual(4, section2.size)
3042
3043 # Third u-boot
3044 section_entries = section2.GetEntries()
3045 self.assertIn('u-boot', section_entries)
3046 entry = section_entries['u-boot']
3047 self.assertEqual(0, entry.offset)
3048 self.assertEqual(0x18, entry.image_pos)
3049 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3050 self.assertEqual(len(U_BOOT_DATA), entry.size)
3051
Simon Glassf8a54bc2019-07-20 12:23:56 -06003052 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3053 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003054 """Replace an entry in an image
3055
3056 This writes the entry data to update it, then opens the updated file and
3057 returns the value that it now finds there.
3058
3059 Args:
3060 entry_name: Entry name to replace
3061 data: Data to replace it with
3062 decomp: True to compress the data if needed, False if data is
3063 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003064 allow_resize: True to allow entries to change size, False to raise
3065 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003066
3067 Returns:
3068 Tuple:
3069 data from entry
3070 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003071 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003072 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003073 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003074 update_dtb=True)[1]
3075
3076 self.assertIn('image', control.images)
3077 image = control.images['image']
3078 entries = image.GetEntries()
3079 orig_dtb_data = entries['u-boot-dtb'].data
3080 orig_fdtmap_data = entries['fdtmap'].data
3081
3082 image_fname = tools.GetOutputFilename('image.bin')
3083 updated_fname = tools.GetOutputFilename('image-updated.bin')
3084 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003085 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3086 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003087 data = control.ReadEntry(updated_fname, entry_name, decomp)
3088
Simon Glassf8a54bc2019-07-20 12:23:56 -06003089 # The DT data should not change unless resized:
3090 if not allow_resize:
3091 new_dtb_data = entries['u-boot-dtb'].data
3092 self.assertEqual(new_dtb_data, orig_dtb_data)
3093 new_fdtmap_data = entries['fdtmap'].data
3094 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003095
Simon Glassf8a54bc2019-07-20 12:23:56 -06003096 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003097
3098 def testReplaceSimple(self):
3099 """Test replacing a single file"""
3100 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003101 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3102 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003103 self.assertEqual(expected, data)
3104
3105 # Test that the state looks right. There should be an FDT for the fdtmap
3106 # that we jsut read back in, and it should match what we find in the
3107 # 'control' tables. Checking for an FDT that does not exist should
3108 # return None.
3109 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003110 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003111 self.assertEqual(expected_fdtmap, fdtmap)
3112
3113 dtb = state.GetFdtForEtype('fdtmap')
3114 self.assertEqual(dtb.GetContents(), fdtmap)
3115
3116 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3117 self.assertIsNone(missing_path)
3118 self.assertIsNone(missing_fdtmap)
3119
3120 missing_dtb = state.GetFdtForEtype('missing')
3121 self.assertIsNone(missing_dtb)
3122
3123 self.assertEqual('/binman', state.fdt_path_prefix)
3124
3125 def testReplaceResizeFail(self):
3126 """Test replacing a file by something larger"""
3127 expected = U_BOOT_DATA + b'x'
3128 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003129 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3130 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003131 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3132 str(e.exception))
3133
3134 def testReplaceMulti(self):
3135 """Test replacing entry data where multiple images are generated"""
3136 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3137 update_dtb=True)[0]
3138 expected = b'x' * len(U_BOOT_DATA)
3139 updated_fname = tools.GetOutputFilename('image-updated.bin')
3140 tools.WriteFile(updated_fname, data)
3141 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003142 control.WriteEntry(updated_fname, entry_name, expected,
3143 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003144 data = control.ReadEntry(updated_fname, entry_name)
3145 self.assertEqual(expected, data)
3146
3147 # Check the state looks right.
3148 self.assertEqual('/binman/image', state.fdt_path_prefix)
3149
3150 # Now check we can write the first image
3151 image_fname = tools.GetOutputFilename('first-image.bin')
3152 updated_fname = tools.GetOutputFilename('first-updated.bin')
3153 tools.WriteFile(updated_fname, tools.ReadFile(image_fname))
3154 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003155 control.WriteEntry(updated_fname, entry_name, expected,
3156 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003157 data = control.ReadEntry(updated_fname, entry_name)
3158 self.assertEqual(expected, data)
3159
3160 # Check the state looks right.
3161 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003162
Simon Glassfb30e292019-07-20 12:23:51 -06003163 def testUpdateFdtAllRepack(self):
3164 """Test that all device trees are updated with offset/size info"""
3165 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3166 SECTION_SIZE = 0x300
3167 DTB_SIZE = 602
3168 FDTMAP_SIZE = 608
3169 base_expected = {
3170 'offset': 0,
3171 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3172 'image-pos': 0,
3173 'section:offset': 0,
3174 'section:size': SECTION_SIZE,
3175 'section:image-pos': 0,
3176 'section/u-boot-dtb:offset': 4,
3177 'section/u-boot-dtb:size': 636,
3178 'section/u-boot-dtb:image-pos': 4,
3179 'u-boot-spl-dtb:offset': SECTION_SIZE,
3180 'u-boot-spl-dtb:size': DTB_SIZE,
3181 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3182 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3183 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3184 'u-boot-tpl-dtb:size': DTB_SIZE,
3185 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3186 'fdtmap:size': FDTMAP_SIZE,
3187 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3188 }
3189 main_expected = {
3190 'section:orig-size': SECTION_SIZE,
3191 'section/u-boot-dtb:orig-offset': 4,
3192 }
3193
3194 # We expect three device-tree files in the output, with the first one
3195 # within a fixed-size section.
3196 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3197 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3198 # main U-Boot tree. All three should have the same positions and offset
3199 # except that the main tree should include the main_expected properties
3200 start = 4
3201 for item in ['', 'spl', 'tpl', None]:
3202 if item is None:
3203 start += 16 # Move past fdtmap header
3204 dtb = fdt.Fdt.FromData(data[start:])
3205 dtb.Scan()
3206 props = self._GetPropTree(dtb,
3207 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3208 prefix='/' if item is None else '/binman/')
3209 expected = dict(base_expected)
3210 if item:
3211 expected[item] = 0
3212 else:
3213 # Main DTB and fdtdec should include the 'orig-' properties
3214 expected.update(main_expected)
3215 # Helpful for debugging:
3216 #for prop in sorted(props):
3217 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3218 self.assertEqual(expected, props)
3219 if item == '':
3220 start = SECTION_SIZE
3221 else:
3222 start += dtb._fdt_obj.totalsize()
3223
Simon Glass11453762019-07-20 12:23:55 -06003224 def testFdtmapHeaderMiddle(self):
3225 """Test an FDT map in the middle of an image when it should be at end"""
3226 with self.assertRaises(ValueError) as e:
3227 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3228 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3229 str(e.exception))
3230
3231 def testFdtmapHeaderStartBad(self):
3232 """Test an FDT map in middle of an image when it should be at start"""
3233 with self.assertRaises(ValueError) as e:
3234 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3235 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3236 str(e.exception))
3237
3238 def testFdtmapHeaderEndBad(self):
3239 """Test an FDT map at the start of an image when it should be at end"""
3240 with self.assertRaises(ValueError) as e:
3241 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3242 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3243 str(e.exception))
3244
3245 def testFdtmapHeaderNoSize(self):
3246 """Test an image header at the end of an image with undefined size"""
3247 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3248
Simon Glassf8a54bc2019-07-20 12:23:56 -06003249 def testReplaceResize(self):
3250 """Test replacing a single file in an entry with a larger file"""
3251 expected = U_BOOT_DATA + b'x'
3252 data, _, image = self._RunReplaceCmd('u-boot', expected,
3253 dts='139_replace_repack.dts')
3254 self.assertEqual(expected, data)
3255
3256 entries = image.GetEntries()
3257 dtb_data = entries['u-boot-dtb'].data
3258 dtb = fdt.Fdt.FromData(dtb_data)
3259 dtb.Scan()
3260
3261 # The u-boot section should now be larger in the dtb
3262 node = dtb.GetNode('/binman/u-boot')
3263 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3264
3265 # Same for the fdtmap
3266 fdata = entries['fdtmap'].data
3267 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3268 fdtb.Scan()
3269 fnode = fdtb.GetNode('/u-boot')
3270 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3271
3272 def testReplaceResizeNoRepack(self):
3273 """Test replacing an entry with a larger file when not allowed"""
3274 expected = U_BOOT_DATA + b'x'
3275 with self.assertRaises(ValueError) as e:
3276 self._RunReplaceCmd('u-boot', expected)
3277 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3278 str(e.exception))
3279
Simon Glass9d8ee322019-07-20 12:23:58 -06003280 def testEntryShrink(self):
3281 """Test contracting an entry after it is packed"""
3282 try:
3283 state.SetAllowEntryContraction(True)
3284 data = self._DoReadFileDtb('140_entry_shrink.dts',
3285 update_dtb=True)[0]
3286 finally:
3287 state.SetAllowEntryContraction(False)
3288 self.assertEqual(b'a', data[:1])
3289 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3290 self.assertEqual(b'a', data[-1:])
3291
3292 def testEntryShrinkFail(self):
3293 """Test not being allowed to contract an entry after it is packed"""
3294 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3295
3296 # In this case there is a spare byte at the end of the data. The size of
3297 # the contents is only 1 byte but we still have the size before it
3298 # shrunk.
3299 self.assertEqual(b'a\0', data[:2])
3300 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3301 self.assertEqual(b'a\0', data[-2:])
3302
Simon Glass70e32982019-07-20 12:24:01 -06003303 def testDescriptorOffset(self):
3304 """Test that the Intel descriptor is always placed at at the start"""
3305 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3306 image = control.images['image']
3307 entries = image.GetEntries()
3308 desc = entries['intel-descriptor']
3309 self.assertEqual(0xff800000, desc.offset);
3310 self.assertEqual(0xff800000, desc.image_pos);
3311
Simon Glass37fdd142019-07-20 12:24:06 -06003312 def testReplaceCbfs(self):
3313 """Test replacing a single file in CBFS without changing the size"""
3314 self._CheckLz4()
3315 expected = b'x' * len(U_BOOT_DATA)
3316 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3317 updated_fname = tools.GetOutputFilename('image-updated.bin')
3318 tools.WriteFile(updated_fname, data)
3319 entry_name = 'section/cbfs/u-boot'
3320 control.WriteEntry(updated_fname, entry_name, expected,
3321 allow_resize=True)
3322 data = control.ReadEntry(updated_fname, entry_name)
3323 self.assertEqual(expected, data)
3324
3325 def testReplaceResizeCbfs(self):
3326 """Test replacing a single file in CBFS with one of a different size"""
3327 self._CheckLz4()
3328 expected = U_BOOT_DATA + b'x'
3329 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
3330 updated_fname = tools.GetOutputFilename('image-updated.bin')
3331 tools.WriteFile(updated_fname, data)
3332 entry_name = 'section/cbfs/u-boot'
3333 control.WriteEntry(updated_fname, entry_name, expected,
3334 allow_resize=True)
3335 data = control.ReadEntry(updated_fname, entry_name)
3336 self.assertEqual(expected, data)
3337
Simon Glass30033c22019-07-20 12:24:15 -06003338 def _SetupForReplace(self):
3339 """Set up some files to use to replace entries
3340
3341 This generates an image, copies it to a new file, extracts all the files
3342 in it and updates some of them
3343
3344 Returns:
3345 List
3346 Image filename
3347 Output directory
3348 Expected values for updated entries, each a string
3349 """
3350 data = self._DoReadFileRealDtb('143_replace_all.dts')
3351
3352 updated_fname = tools.GetOutputFilename('image-updated.bin')
3353 tools.WriteFile(updated_fname, data)
3354
3355 outdir = os.path.join(self._indir, 'extract')
3356 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3357
3358 expected1 = b'x' + U_BOOT_DATA + b'y'
3359 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3360 tools.WriteFile(u_boot_fname1, expected1)
3361
3362 expected2 = b'a' + U_BOOT_DATA + b'b'
3363 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
3364 tools.WriteFile(u_boot_fname2, expected2)
3365
3366 expected_text = b'not the same text'
3367 text_fname = os.path.join(outdir, 'text')
3368 tools.WriteFile(text_fname, expected_text)
3369
3370 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3371 dtb = fdt.FdtScan(dtb_fname)
3372 node = dtb.GetNode('/binman/text')
3373 node.AddString('my-property', 'the value')
3374 dtb.Sync(auto_resize=True)
3375 dtb.Flush()
3376
3377 return updated_fname, outdir, expected1, expected2, expected_text
3378
3379 def _CheckReplaceMultiple(self, entry_paths):
3380 """Handle replacing the contents of multiple entries
3381
3382 Args:
3383 entry_paths: List of entry paths to replace
3384
3385 Returns:
3386 List
3387 Dict of entries in the image:
3388 key: Entry name
3389 Value: Entry object
3390 Expected values for updated entries, each a string
3391 """
3392 updated_fname, outdir, expected1, expected2, expected_text = (
3393 self._SetupForReplace())
3394 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3395
3396 image = Image.FromFile(updated_fname)
3397 image.LoadData()
3398 return image.GetEntries(), expected1, expected2, expected_text
3399
3400 def testReplaceAll(self):
3401 """Test replacing the contents of all entries"""
3402 entries, expected1, expected2, expected_text = (
3403 self._CheckReplaceMultiple([]))
3404 data = entries['u-boot'].data
3405 self.assertEqual(expected1, data)
3406
3407 data = entries['u-boot2'].data
3408 self.assertEqual(expected2, data)
3409
3410 data = entries['text'].data
3411 self.assertEqual(expected_text, data)
3412
3413 # Check that the device tree is updated
3414 data = entries['u-boot-dtb'].data
3415 dtb = fdt.Fdt.FromData(data)
3416 dtb.Scan()
3417 node = dtb.GetNode('/binman/text')
3418 self.assertEqual('the value', node.props['my-property'].value)
3419
3420 def testReplaceSome(self):
3421 """Test replacing the contents of a few entries"""
3422 entries, expected1, expected2, expected_text = (
3423 self._CheckReplaceMultiple(['u-boot2', 'text']))
3424
3425 # This one should not change
3426 data = entries['u-boot'].data
3427 self.assertEqual(U_BOOT_DATA, data)
3428
3429 data = entries['u-boot2'].data
3430 self.assertEqual(expected2, data)
3431
3432 data = entries['text'].data
3433 self.assertEqual(expected_text, data)
3434
3435 def testReplaceCmd(self):
3436 """Test replacing a file fron an image on the command line"""
3437 self._DoReadFileRealDtb('143_replace_all.dts')
3438
3439 try:
3440 tmpdir, updated_fname = self._SetupImageInTmpdir()
3441
3442 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3443 expected = b'x' * len(U_BOOT_DATA)
3444 tools.WriteFile(fname, expected)
3445
3446 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
3447 data = tools.ReadFile(updated_fname)
3448 self.assertEqual(expected, data[:len(expected)])
3449 map_fname = os.path.join(tmpdir, 'image-updated.map')
3450 self.assertFalse(os.path.exists(map_fname))
3451 finally:
3452 shutil.rmtree(tmpdir)
3453
3454 def testReplaceCmdSome(self):
3455 """Test replacing some files fron an image on the command line"""
3456 updated_fname, outdir, expected1, expected2, expected_text = (
3457 self._SetupForReplace())
3458
3459 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3460 'u-boot2', 'text')
3461
3462 tools.PrepareOutputDir(None)
3463 image = Image.FromFile(updated_fname)
3464 image.LoadData()
3465 entries = image.GetEntries()
3466
3467 # This one should not change
3468 data = entries['u-boot'].data
3469 self.assertEqual(U_BOOT_DATA, data)
3470
3471 data = entries['u-boot2'].data
3472 self.assertEqual(expected2, data)
3473
3474 data = entries['text'].data
3475 self.assertEqual(expected_text, data)
3476
3477 def testReplaceMissing(self):
3478 """Test replacing entries where the file is missing"""
3479 updated_fname, outdir, expected1, expected2, expected_text = (
3480 self._SetupForReplace())
3481
3482 # Remove one of the files, to generate a warning
3483 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3484 os.remove(u_boot_fname1)
3485
3486 with test_util.capture_sys_output() as (stdout, stderr):
3487 control.ReplaceEntries(updated_fname, None, outdir, [])
3488 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003489 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003490
3491 def testReplaceCmdMap(self):
3492 """Test replacing a file fron an image on the command line"""
3493 self._DoReadFileRealDtb('143_replace_all.dts')
3494
3495 try:
3496 tmpdir, updated_fname = self._SetupImageInTmpdir()
3497
3498 fname = os.path.join(self._indir, 'update-u-boot.bin')
3499 expected = b'x' * len(U_BOOT_DATA)
3500 tools.WriteFile(fname, expected)
3501
3502 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3503 '-f', fname, '-m')
3504 map_fname = os.path.join(tmpdir, 'image-updated.map')
3505 self.assertTrue(os.path.exists(map_fname))
3506 finally:
3507 shutil.rmtree(tmpdir)
3508
3509 def testReplaceNoEntryPaths(self):
3510 """Test replacing an entry without an entry path"""
3511 self._DoReadFileRealDtb('143_replace_all.dts')
3512 image_fname = tools.GetOutputFilename('image.bin')
3513 with self.assertRaises(ValueError) as e:
3514 control.ReplaceEntries(image_fname, 'fname', None, [])
3515 self.assertIn('Must specify an entry path to read with -f',
3516 str(e.exception))
3517
3518 def testReplaceTooManyEntryPaths(self):
3519 """Test extracting some entries"""
3520 self._DoReadFileRealDtb('143_replace_all.dts')
3521 image_fname = tools.GetOutputFilename('image.bin')
3522 with self.assertRaises(ValueError) as e:
3523 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3524 self.assertIn('Must specify exactly one entry path to write with -f',
3525 str(e.exception))
3526
Simon Glass0b074d62019-08-24 07:22:48 -06003527 def testPackReset16(self):
3528 """Test that an image with an x86 reset16 region can be created"""
3529 data = self._DoReadFile('144_x86_reset16.dts')
3530 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3531
3532 def testPackReset16Spl(self):
3533 """Test that an image with an x86 reset16-spl region can be created"""
3534 data = self._DoReadFile('145_x86_reset16_spl.dts')
3535 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3536
3537 def testPackReset16Tpl(self):
3538 """Test that an image with an x86 reset16-tpl region can be created"""
3539 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3540 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3541
Simon Glass232f90c2019-08-24 07:22:50 -06003542 def testPackIntelFit(self):
3543 """Test that an image with an Intel FIT and pointer can be created"""
3544 data = self._DoReadFile('147_intel_fit.dts')
3545 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3546 fit = data[16:32];
3547 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3548 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3549
3550 image = control.images['image']
3551 entries = image.GetEntries()
3552 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3553 self.assertEqual(expected_ptr, ptr)
3554
3555 def testPackIntelFitMissing(self):
3556 """Test detection of a FIT pointer with not FIT region"""
3557 with self.assertRaises(ValueError) as e:
3558 self._DoReadFile('148_intel_fit_missing.dts')
3559 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3560 str(e.exception))
3561
Simon Glass72555fa2019-11-06 17:22:44 -07003562 def _CheckSymbolsTplSection(self, dts, expected_vals):
3563 data = self._DoReadFile(dts)
3564 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003565 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003566 expected1 = tools.GetBytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003567 self.assertEqual(expected1, data[:upto1])
3568
3569 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass3f8ff012019-08-24 07:23:05 -06003570 expected2 = tools.GetBytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003571 self.assertEqual(expected2, data[upto1:upto2])
3572
Simon Glass4e353e22019-08-24 07:23:04 -06003573 upto3 = 0x34 + len(U_BOOT_DATA)
3574 expected3 = tools.GetBytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003575 self.assertEqual(expected3, data[upto2:upto3])
3576
Simon Glass3f8ff012019-08-24 07:23:05 -06003577 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003578 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3579
3580 def testSymbolsTplSection(self):
3581 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3582 self._SetupSplElf('u_boot_binman_syms')
3583 self._SetupTplElf('u_boot_binman_syms')
3584 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3585 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3586
3587 def testSymbolsTplSectionX86(self):
3588 """Test binman can assign symbols in a section with end-at-4gb"""
3589 self._SetupSplElf('u_boot_binman_syms_x86')
3590 self._SetupTplElf('u_boot_binman_syms_x86')
3591 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3592 [0xffffff04, 0xffffff1c, 0xffffff34,
3593 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003594
Simon Glass98c59572019-08-24 07:23:03 -06003595 def testPackX86RomIfwiSectiom(self):
3596 """Test that a section can be placed in an IFWI region"""
3597 self._SetupIfwi('fitimage.bin')
3598 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3599 self._CheckIfwi(data)
3600
Simon Glassba7985d2019-08-24 07:23:07 -06003601 def testPackFspM(self):
3602 """Test that an image with a FSP memory-init binary can be created"""
3603 data = self._DoReadFile('152_intel_fsp_m.dts')
3604 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3605
Simon Glass4d9086d2019-10-20 21:31:35 -06003606 def testPackFspS(self):
3607 """Test that an image with a FSP silicon-init binary can be created"""
3608 data = self._DoReadFile('153_intel_fsp_s.dts')
3609 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003610
Simon Glass9ea87b22019-10-20 21:31:36 -06003611 def testPackFspT(self):
3612 """Test that an image with a FSP temp-ram-init binary can be created"""
3613 data = self._DoReadFile('154_intel_fsp_t.dts')
3614 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3615
Simon Glass48f3aad2020-07-09 18:39:31 -06003616 def testMkimage(self):
3617 """Test using mkimage to build an image"""
3618 data = self._DoReadFile('156_mkimage.dts')
3619
3620 # Just check that the data appears in the file somewhere
3621 self.assertIn(U_BOOT_SPL_DATA, data)
3622
Simon Glass5e560182020-07-09 18:39:36 -06003623 def testExtblob(self):
3624 """Test an image with an external blob"""
3625 data = self._DoReadFile('157_blob_ext.dts')
3626 self.assertEqual(REFCODE_DATA, data)
3627
3628 def testExtblobMissing(self):
3629 """Test an image with a missing external blob"""
3630 with self.assertRaises(ValueError) as e:
3631 self._DoReadFile('158_blob_ext_missing.dts')
3632 self.assertIn("Filename 'missing-file' not found in input path",
3633 str(e.exception))
3634
Simon Glass5d94cc62020-07-09 18:39:38 -06003635 def testExtblobMissingOk(self):
3636 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003637 with test_util.capture_sys_output() as (stdout, stderr):
3638 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3639 err = stderr.getvalue()
3640 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3641
3642 def testExtblobMissingOkSect(self):
3643 """Test an image with an missing external blob that is allowed"""
3644 with test_util.capture_sys_output() as (stdout, stderr):
3645 self._DoTestFile('159_blob_ext_missing_sect.dts',
3646 allow_missing=True)
3647 err = stderr.getvalue()
3648 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3649 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003650
Simon Glasse88cef92020-07-09 18:39:41 -06003651 def testPackX86RomMeMissingDesc(self):
3652 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003653 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003654 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003655 err = stderr.getvalue()
3656 self.assertRegex(err,
3657 "Image 'main-section'.*missing.*: intel-descriptor")
3658
3659 def testPackX86RomMissingIfwi(self):
3660 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3661 self._SetupIfwi('fitimage.bin')
3662 pathname = os.path.join(self._indir, 'fitimage.bin')
3663 os.remove(pathname)
3664 with test_util.capture_sys_output() as (stdout, stderr):
3665 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3666 err = stderr.getvalue()
3667 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3668
Simon Glassd70829a2020-07-09 18:39:42 -06003669 def testPackOverlap(self):
3670 """Test that zero-size overlapping regions are ignored"""
3671 self._DoTestFile('160_pack_overlap_zero.dts')
3672
Simon Glass45d556d2020-07-09 18:39:45 -06003673 def testSimpleFit(self):
3674 """Test an image with a FIT inside"""
3675 data = self._DoReadFile('161_fit.dts')
3676 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3677 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3678 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3679
3680 # The data should be inside the FIT
3681 dtb = fdt.Fdt.FromData(fit_data)
3682 dtb.Scan()
3683 fnode = dtb.GetNode('/images/kernel')
3684 self.assertIn('data', fnode.props)
3685
3686 fname = os.path.join(self._indir, 'fit_data.fit')
3687 tools.WriteFile(fname, fit_data)
3688 out = tools.Run('dumpimage', '-l', fname)
3689
3690 # Check a few features to make sure the plumbing works. We don't need
3691 # to test the operation of mkimage or dumpimage here. First convert the
3692 # output into a dict where the keys are the fields printed by dumpimage
3693 # and the values are a list of values for each field
3694 lines = out.splitlines()
3695
3696 # Converts "Compression: gzip compressed" into two groups:
3697 # 'Compression' and 'gzip compressed'
3698 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3699 vals = collections.defaultdict(list)
3700 for line in lines:
3701 mat = re_line.match(line)
3702 vals[mat.group(1)].append(mat.group(2))
3703
3704 self.assertEquals('FIT description: test-desc', lines[0])
3705 self.assertIn('Created:', lines[1])
3706 self.assertIn('Image 0 (kernel)', vals)
3707 self.assertIn('Hash value', vals)
3708 data_sizes = vals.get('Data Size')
3709 self.assertIsNotNone(data_sizes)
3710 self.assertEqual(2, len(data_sizes))
3711 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3712 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3713 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3714
3715 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003716 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003717 data = self._DoReadFile('162_fit_external.dts')
3718 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3719
Simon Glass7932c882022-01-09 20:13:39 -07003720 # Size of the external-data region as set up by mkimage
3721 external_data_size = len(U_BOOT_DATA) + 2
3722 expected_size = (len(U_BOOT_DATA) + 0x400 +
3723 tools.Align(external_data_size, 4) +
3724 len(U_BOOT_NODTB_DATA))
3725
Simon Glass45d556d2020-07-09 18:39:45 -06003726 # The data should be outside the FIT
3727 dtb = fdt.Fdt.FromData(fit_data)
3728 dtb.Scan()
3729 fnode = dtb.GetNode('/images/kernel')
3730 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003731 self.assertEqual(len(U_BOOT_DATA),
3732 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3733 fit_pos = 0x400;
3734 self.assertEqual(
3735 fit_pos,
3736 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3737
3738 self.assertEquals(expected_size, len(data))
3739 actual_pos = len(U_BOOT_DATA) + fit_pos
3740 self.assertEqual(U_BOOT_DATA + b'aa',
3741 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003742
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003743 def testSectionIgnoreHashSignature(self):
3744 """Test that sections ignore hash, signature nodes for its data"""
3745 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3746 expected = (U_BOOT_DATA + U_BOOT_DATA)
3747 self.assertEqual(expected, data)
3748
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003749 def testPadInSections(self):
3750 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003751 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3752 '166_pad_in_sections.dts', update_dtb=True)
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003753 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
3754 U_BOOT_DATA + tools.GetBytes(ord('!'), 6) +
3755 U_BOOT_DATA)
3756 self.assertEqual(expected, data)
3757
Simon Glassd12599d2020-10-26 17:40:09 -06003758 dtb = fdt.Fdt(out_dtb_fname)
3759 dtb.Scan()
3760 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3761 expected = {
3762 'image-pos': 0,
3763 'offset': 0,
3764 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3765
3766 'section:image-pos': 0,
3767 'section:offset': 0,
3768 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3769
3770 'section/before:image-pos': 0,
3771 'section/before:offset': 0,
3772 'section/before:size': len(U_BOOT_DATA),
3773
3774 'section/u-boot:image-pos': 4,
3775 'section/u-boot:offset': 4,
3776 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3777
3778 'section/after:image-pos': 26,
3779 'section/after:offset': 26,
3780 'section/after:size': len(U_BOOT_DATA),
3781 }
3782 self.assertEqual(expected, props)
3783
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003784 def testFitImageSubentryAlignment(self):
3785 """Test relative alignability of FIT image subentries"""
3786 entry_args = {
3787 'test-id': TEXT_DATA,
3788 }
3789 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3790 entry_args=entry_args)
3791 dtb = fdt.Fdt.FromData(data)
3792 dtb.Scan()
3793
3794 node = dtb.GetNode('/images/kernel')
3795 data = dtb.GetProps(node)["data"].bytes
3796 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
3797 expected = (tools.GetBytes(0, 0x20) + U_BOOT_SPL_DATA +
3798 tools.GetBytes(0, align_pad) + U_BOOT_DATA)
3799 self.assertEqual(expected, data)
3800
3801 node = dtb.GetNode('/images/fdt-1')
3802 data = dtb.GetProps(node)["data"].bytes
3803 expected = (U_BOOT_SPL_DTB_DATA + tools.GetBytes(0, 20) +
3804 tools.ToBytes(TEXT_DATA) + tools.GetBytes(0, 30) +
3805 U_BOOT_DTB_DATA)
3806 self.assertEqual(expected, data)
3807
3808 def testFitExtblobMissingOk(self):
3809 """Test a FIT with a missing external blob that is allowed"""
3810 with test_util.capture_sys_output() as (stdout, stderr):
3811 self._DoTestFile('168_fit_missing_blob.dts',
3812 allow_missing=True)
3813 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003814 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003815
Simon Glass21db0ff2020-09-01 05:13:54 -06003816 def testBlobNamedByArgMissing(self):
3817 """Test handling of a missing entry arg"""
3818 with self.assertRaises(ValueError) as e:
3819 self._DoReadFile('068_blob_named_by_arg.dts')
3820 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3821 str(e.exception))
3822
Simon Glass559c4de2020-09-01 05:13:58 -06003823 def testPackBl31(self):
3824 """Test that an image with an ATF BL31 binary can be created"""
3825 data = self._DoReadFile('169_atf_bl31.dts')
3826 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3827
Samuel Holland9d8cc632020-10-21 21:12:15 -05003828 def testPackScp(self):
3829 """Test that an image with an SCP binary can be created"""
3830 data = self._DoReadFile('172_scp.dts')
3831 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3832
Simon Glassa435cd12020-09-01 05:13:59 -06003833 def testFitFdt(self):
3834 """Test an image with an FIT with multiple FDT images"""
3835 def _CheckFdt(seq, expected_data):
3836 """Check the FDT nodes
3837
3838 Args:
3839 seq: Sequence number to check (0 or 1)
3840 expected_data: Expected contents of 'data' property
3841 """
3842 name = 'fdt-%d' % seq
3843 fnode = dtb.GetNode('/images/%s' % name)
3844 self.assertIsNotNone(fnode)
3845 self.assertEqual({'description','type', 'compression', 'data'},
3846 set(fnode.props.keys()))
3847 self.assertEqual(expected_data, fnode.props['data'].bytes)
3848 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3849 fnode.props['description'].value)
3850
3851 def _CheckConfig(seq, expected_data):
3852 """Check the configuration nodes
3853
3854 Args:
3855 seq: Sequence number to check (0 or 1)
3856 expected_data: Expected contents of 'data' property
3857 """
3858 cnode = dtb.GetNode('/configurations')
3859 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003860 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003861
3862 name = 'config-%d' % seq
3863 fnode = dtb.GetNode('/configurations/%s' % name)
3864 self.assertIsNotNone(fnode)
3865 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3866 set(fnode.props.keys()))
3867 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3868 fnode.props['description'].value)
3869 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3870
3871 entry_args = {
3872 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003873 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003874 }
3875 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003876 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003877 entry_args=entry_args,
3878 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3879 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3880 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3881
3882 dtb = fdt.Fdt.FromData(fit_data)
3883 dtb.Scan()
3884 fnode = dtb.GetNode('/images/kernel')
3885 self.assertIn('data', fnode.props)
3886
3887 # Check all the properties in fdt-1 and fdt-2
3888 _CheckFdt(1, TEST_FDT1_DATA)
3889 _CheckFdt(2, TEST_FDT2_DATA)
3890
3891 # Check configurations
3892 _CheckConfig(1, TEST_FDT1_DATA)
3893 _CheckConfig(2, TEST_FDT2_DATA)
3894
3895 def testFitFdtMissingList(self):
3896 """Test handling of a missing 'of-list' entry arg"""
3897 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08003898 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003899 self.assertIn("Generator node requires 'of-list' entry argument",
3900 str(e.exception))
3901
3902 def testFitFdtEmptyList(self):
3903 """Test handling of an empty 'of-list' entry arg"""
3904 entry_args = {
3905 'of-list': '',
3906 }
3907 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3908
3909 def testFitFdtMissingProp(self):
3910 """Test handling of a missing 'fit,fdt-list' property"""
3911 with self.assertRaises(ValueError) as e:
3912 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3913 self.assertIn("Generator node requires 'fit,fdt-list' property",
3914 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003915
Simon Glass1032acc2020-09-06 10:39:08 -06003916 def testFitFdtEmptyList(self):
3917 """Test handling of an empty 'of-list' entry arg"""
3918 entry_args = {
3919 'of-list': '',
3920 }
Bin Meng16cf5662021-05-10 20:23:32 +08003921 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glass1032acc2020-09-06 10:39:08 -06003922
3923 def testFitFdtMissing(self):
3924 """Test handling of a missing 'default-dt' entry arg"""
3925 entry_args = {
3926 'of-list': 'test-fdt1 test-fdt2',
3927 }
3928 with self.assertRaises(ValueError) as e:
3929 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003930 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003931 entry_args=entry_args,
3932 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3933 self.assertIn("Generated 'default' node requires default-dt entry argument",
3934 str(e.exception))
3935
3936 def testFitFdtNotInList(self):
3937 """Test handling of a default-dt that is not in the of-list"""
3938 entry_args = {
3939 'of-list': 'test-fdt1 test-fdt2',
3940 'default-dt': 'test-fdt3',
3941 }
3942 with self.assertRaises(ValueError) as e:
3943 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003944 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003945 entry_args=entry_args,
3946 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3947 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
3948 str(e.exception))
3949
Simon Glassa820af72020-09-06 10:39:09 -06003950 def testFitExtblobMissingHelp(self):
3951 """Test display of help messages when an external blob is missing"""
3952 control.missing_blob_help = control._ReadMissingBlobHelp()
3953 control.missing_blob_help['wibble'] = 'Wibble test'
3954 control.missing_blob_help['another'] = 'Another test'
3955 with test_util.capture_sys_output() as (stdout, stderr):
3956 self._DoTestFile('168_fit_missing_blob.dts',
3957 allow_missing=True)
3958 err = stderr.getvalue()
3959
3960 # We can get the tag from the name, the type or the missing-msg
3961 # property. Check all three.
3962 self.assertIn('You may need to build ARM Trusted', err)
3963 self.assertIn('Wibble test', err)
3964 self.assertIn('Another test', err)
3965
Simon Glass6f1f4d42020-09-06 10:35:32 -06003966 def testMissingBlob(self):
3967 """Test handling of a blob containing a missing file"""
3968 with self.assertRaises(ValueError) as e:
3969 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
3970 self.assertIn("Filename 'missing' not found in input path",
3971 str(e.exception))
3972
Simon Glassa0729502020-09-06 10:35:33 -06003973 def testEnvironment(self):
3974 """Test adding a U-Boot environment"""
3975 data = self._DoReadFile('174_env.dts')
3976 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3977 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3978 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3979 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
3980 env)
3981
3982 def testEnvironmentNoSize(self):
3983 """Test that a missing 'size' property is detected"""
3984 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003985 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003986 self.assertIn("'u-boot-env' entry must have a size property",
3987 str(e.exception))
3988
3989 def testEnvironmentTooSmall(self):
3990 """Test handling of an environment that does not fit"""
3991 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06003992 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06003993
3994 # checksum, start byte, environment with \0 terminator, final \0
3995 need = 4 + 1 + len(ENV_DATA) + 1 + 1
3996 short = need - 0x8
3997 self.assertIn("too small to hold data (need %#x more bytes)" % short,
3998 str(e.exception))
3999
Simon Glassd1fdf752020-10-26 17:40:01 -06004000 def testSkipAtStart(self):
4001 """Test handling of skip-at-start section"""
4002 data = self._DoReadFile('177_skip_at_start.dts')
4003 self.assertEqual(U_BOOT_DATA, data)
4004
4005 image = control.images['image']
4006 entries = image.GetEntries()
4007 section = entries['section']
4008 self.assertEqual(0, section.offset)
4009 self.assertEqual(len(U_BOOT_DATA), section.size)
4010 self.assertEqual(U_BOOT_DATA, section.GetData())
4011
4012 entry = section.GetEntries()['u-boot']
4013 self.assertEqual(16, entry.offset)
4014 self.assertEqual(len(U_BOOT_DATA), entry.size)
4015 self.assertEqual(U_BOOT_DATA, entry.data)
4016
4017 def testSkipAtStartPad(self):
4018 """Test handling of skip-at-start section with padded entry"""
4019 data = self._DoReadFile('178_skip_at_start_pad.dts')
4020 before = tools.GetBytes(0, 8)
4021 after = tools.GetBytes(0, 4)
4022 all = before + U_BOOT_DATA + after
4023 self.assertEqual(all, data)
4024
4025 image = control.images['image']
4026 entries = image.GetEntries()
4027 section = entries['section']
4028 self.assertEqual(0, section.offset)
4029 self.assertEqual(len(all), section.size)
4030 self.assertEqual(all, section.GetData())
4031
4032 entry = section.GetEntries()['u-boot']
4033 self.assertEqual(16, entry.offset)
4034 self.assertEqual(len(all), entry.size)
4035 self.assertEqual(U_BOOT_DATA, entry.data)
4036
4037 def testSkipAtStartSectionPad(self):
4038 """Test handling of skip-at-start section with padding"""
4039 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
4040 before = tools.GetBytes(0, 8)
4041 after = tools.GetBytes(0, 4)
4042 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004043 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004044
4045 image = control.images['image']
4046 entries = image.GetEntries()
4047 section = entries['section']
4048 self.assertEqual(0, section.offset)
4049 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004050 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004051 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004052
4053 entry = section.GetEntries()['u-boot']
4054 self.assertEqual(16, entry.offset)
4055 self.assertEqual(len(U_BOOT_DATA), entry.size)
4056 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004057
Simon Glassbb395742020-10-26 17:40:14 -06004058 def testSectionPad(self):
4059 """Testing padding with sections"""
4060 data = self._DoReadFile('180_section_pad.dts')
4061 expected = (tools.GetBytes(ord('&'), 3) +
4062 tools.GetBytes(ord('!'), 5) +
4063 U_BOOT_DATA +
4064 tools.GetBytes(ord('!'), 1) +
4065 tools.GetBytes(ord('&'), 2))
4066 self.assertEqual(expected, data)
4067
4068 def testSectionAlign(self):
4069 """Testing alignment with sections"""
4070 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4071 expected = (b'\0' + # fill section
4072 tools.GetBytes(ord('&'), 1) + # padding to section align
4073 b'\0' + # fill section
4074 tools.GetBytes(ord('!'), 3) + # padding to u-boot align
4075 U_BOOT_DATA +
4076 tools.GetBytes(ord('!'), 4) + # padding to u-boot size
4077 tools.GetBytes(ord('!'), 4)) # padding to section size
4078 self.assertEqual(expected, data)
4079
Simon Glassd92c8362020-10-26 17:40:25 -06004080 def testCompressImage(self):
4081 """Test compression of the entire image"""
4082 self._CheckLz4()
4083 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4084 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4085 dtb = fdt.Fdt(out_dtb_fname)
4086 dtb.Scan()
4087 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4088 'uncomp-size'])
4089 orig = self._decompress(data)
4090 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4091
4092 # Do a sanity check on various fields
4093 image = control.images['image']
4094 entries = image.GetEntries()
4095 self.assertEqual(2, len(entries))
4096
4097 entry = entries['blob']
4098 self.assertEqual(COMPRESS_DATA, entry.data)
4099 self.assertEqual(len(COMPRESS_DATA), entry.size)
4100
4101 entry = entries['u-boot']
4102 self.assertEqual(U_BOOT_DATA, entry.data)
4103 self.assertEqual(len(U_BOOT_DATA), entry.size)
4104
4105 self.assertEqual(len(data), image.size)
4106 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4107 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4108 orig = self._decompress(image.data)
4109 self.assertEqual(orig, image.uncomp_data)
4110
4111 expected = {
4112 'blob:offset': 0,
4113 'blob:size': len(COMPRESS_DATA),
4114 'u-boot:offset': len(COMPRESS_DATA),
4115 'u-boot:size': len(U_BOOT_DATA),
4116 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4117 'offset': 0,
4118 'image-pos': 0,
4119 'size': len(data),
4120 }
4121 self.assertEqual(expected, props)
4122
4123 def testCompressImageLess(self):
4124 """Test compression where compression reduces the image size"""
4125 self._CheckLz4()
4126 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4127 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4128 dtb = fdt.Fdt(out_dtb_fname)
4129 dtb.Scan()
4130 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4131 'uncomp-size'])
4132 orig = self._decompress(data)
4133
4134 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4135
4136 # Do a sanity check on various fields
4137 image = control.images['image']
4138 entries = image.GetEntries()
4139 self.assertEqual(2, len(entries))
4140
4141 entry = entries['blob']
4142 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4143 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4144
4145 entry = entries['u-boot']
4146 self.assertEqual(U_BOOT_DATA, entry.data)
4147 self.assertEqual(len(U_BOOT_DATA), entry.size)
4148
4149 self.assertEqual(len(data), image.size)
4150 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4151 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4152 image.uncomp_size)
4153 orig = self._decompress(image.data)
4154 self.assertEqual(orig, image.uncomp_data)
4155
4156 expected = {
4157 'blob:offset': 0,
4158 'blob:size': len(COMPRESS_DATA_BIG),
4159 'u-boot:offset': len(COMPRESS_DATA_BIG),
4160 'u-boot:size': len(U_BOOT_DATA),
4161 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4162 'offset': 0,
4163 'image-pos': 0,
4164 'size': len(data),
4165 }
4166 self.assertEqual(expected, props)
4167
4168 def testCompressSectionSize(self):
4169 """Test compression of a section with a fixed size"""
4170 self._CheckLz4()
4171 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4172 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4173 dtb = fdt.Fdt(out_dtb_fname)
4174 dtb.Scan()
4175 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4176 'uncomp-size'])
4177 orig = self._decompress(data)
4178 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4179 expected = {
4180 'section/blob:offset': 0,
4181 'section/blob:size': len(COMPRESS_DATA),
4182 'section/u-boot:offset': len(COMPRESS_DATA),
4183 'section/u-boot:size': len(U_BOOT_DATA),
4184 'section:offset': 0,
4185 'section:image-pos': 0,
4186 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4187 'section:size': 0x30,
4188 'offset': 0,
4189 'image-pos': 0,
4190 'size': 0x30,
4191 }
4192 self.assertEqual(expected, props)
4193
4194 def testCompressSection(self):
4195 """Test compression of a section with no fixed size"""
4196 self._CheckLz4()
4197 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4198 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4199 dtb = fdt.Fdt(out_dtb_fname)
4200 dtb.Scan()
4201 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4202 'uncomp-size'])
4203 orig = self._decompress(data)
4204 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4205 expected = {
4206 'section/blob:offset': 0,
4207 'section/blob:size': len(COMPRESS_DATA),
4208 'section/u-boot:offset': len(COMPRESS_DATA),
4209 'section/u-boot:size': len(U_BOOT_DATA),
4210 'section:offset': 0,
4211 'section:image-pos': 0,
4212 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4213 'section:size': len(data),
4214 'offset': 0,
4215 'image-pos': 0,
4216 'size': len(data),
4217 }
4218 self.assertEqual(expected, props)
4219
4220 def testCompressExtra(self):
4221 """Test compression of a section with no fixed size"""
4222 self._CheckLz4()
4223 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4224 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4225 dtb = fdt.Fdt(out_dtb_fname)
4226 dtb.Scan()
4227 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4228 'uncomp-size'])
4229
4230 base = data[len(U_BOOT_DATA):]
4231 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4232 rest = base[len(U_BOOT_DATA):]
4233
4234 # Check compressed data
4235 section1 = self._decompress(rest)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004236 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004237 self.assertEquals(expect1, rest[:len(expect1)])
4238 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4239 rest1 = rest[len(expect1):]
4240
4241 section2 = self._decompress(rest1)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004242 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004243 self.assertEquals(expect2, rest1[:len(expect2)])
4244 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4245 rest2 = rest1[len(expect2):]
4246
4247 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4248 len(expect2) + len(U_BOOT_DATA))
4249 #self.assertEquals(expect_size, len(data))
4250
4251 #self.assertEquals(U_BOOT_DATA, rest2)
4252
4253 self.maxDiff = None
4254 expected = {
4255 'u-boot:offset': 0,
4256 'u-boot:image-pos': 0,
4257 'u-boot:size': len(U_BOOT_DATA),
4258
4259 'base:offset': len(U_BOOT_DATA),
4260 'base:image-pos': len(U_BOOT_DATA),
4261 'base:size': len(data) - len(U_BOOT_DATA),
4262 'base/u-boot:offset': 0,
4263 'base/u-boot:image-pos': len(U_BOOT_DATA),
4264 'base/u-boot:size': len(U_BOOT_DATA),
4265 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4266 len(expect2),
4267 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4268 len(expect2),
4269 'base/u-boot2:size': len(U_BOOT_DATA),
4270
4271 'base/section:offset': len(U_BOOT_DATA),
4272 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4273 'base/section:size': len(expect1),
4274 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4275 'base/section/blob:offset': 0,
4276 'base/section/blob:size': len(COMPRESS_DATA),
4277 'base/section/u-boot:offset': len(COMPRESS_DATA),
4278 'base/section/u-boot:size': len(U_BOOT_DATA),
4279
4280 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4281 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4282 'base/section2:size': len(expect2),
4283 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4284 'base/section2/blob:offset': 0,
4285 'base/section2/blob:size': len(COMPRESS_DATA),
4286 'base/section2/blob2:offset': len(COMPRESS_DATA),
4287 'base/section2/blob2:size': len(COMPRESS_DATA),
4288
4289 'offset': 0,
4290 'image-pos': 0,
4291 'size': len(data),
4292 }
4293 self.assertEqual(expected, props)
4294
Simon Glassecbe4732021-01-06 21:35:15 -07004295 def testSymbolsSubsection(self):
4296 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004297 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004298
Simon Glass3fb25402021-01-06 21:35:16 -07004299 def testReadImageEntryArg(self):
4300 """Test reading an image that would need an entry arg to generate"""
4301 entry_args = {
4302 'cros-ec-rw-path': 'ecrw.bin',
4303 }
4304 data = self.data = self._DoReadFileDtb(
4305 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4306 entry_args=entry_args)
4307
4308 image_fname = tools.GetOutputFilename('image.bin')
4309 orig_image = control.images['image']
4310
4311 # This should not generate an error about the missing 'cros-ec-rw-path'
4312 # since we are reading the image from a file. Compare with
4313 # testEntryArgsRequired()
4314 image = Image.FromFile(image_fname)
4315 self.assertEqual(orig_image.GetEntries().keys(),
4316 image.GetEntries().keys())
4317
Simon Glassa2af7302021-01-06 21:35:18 -07004318 def testFilesAlign(self):
4319 """Test alignment with files"""
4320 data = self._DoReadFile('190_files_align.dts')
4321
4322 # The first string is 15 bytes so will align to 16
4323 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4324 self.assertEqual(expect, data)
4325
Simon Glassdb84b562021-01-06 21:35:19 -07004326 def testReadImageSkip(self):
4327 """Test reading an image and accessing its FDT map"""
4328 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
4329 image_fname = tools.GetOutputFilename('image.bin')
4330 orig_image = control.images['image']
4331 image = Image.FromFile(image_fname)
4332 self.assertEqual(orig_image.GetEntries().keys(),
4333 image.GetEntries().keys())
4334
4335 orig_entry = orig_image.GetEntries()['fdtmap']
4336 entry = image.GetEntries()['fdtmap']
4337 self.assertEqual(orig_entry.offset, entry.offset)
4338 self.assertEqual(orig_entry.size, entry.size)
4339 self.assertEqual(16, entry.image_pos)
4340
4341 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4342
4343 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4344
Simon Glassc98de972021-03-18 20:24:57 +13004345 def testTplNoDtb(self):
4346 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004347 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004348 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4349 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4350 data[:len(U_BOOT_TPL_NODTB_DATA)])
4351
Simon Glass63f41d42021-03-18 20:24:58 +13004352 def testTplBssPad(self):
4353 """Test that we can pad TPL's BSS with zeros"""
4354 # ELF file with a '__bss_size' symbol
4355 self._SetupTplElf()
4356 data = self._DoReadFile('193_tpl_bss_pad.dts')
4357 self.assertEqual(U_BOOT_TPL_DATA + tools.GetBytes(0, 10) + U_BOOT_DATA,
4358 data)
4359
4360 def testTplBssPadMissing(self):
4361 """Test that a missing symbol is detected"""
4362 self._SetupTplElf('u_boot_ucode_ptr')
4363 with self.assertRaises(ValueError) as e:
4364 self._DoReadFile('193_tpl_bss_pad.dts')
4365 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4366 str(e.exception))
4367
Simon Glass718b5292021-03-18 20:25:07 +13004368 def checkDtbSizes(self, data, pad_len, start):
4369 """Check the size arguments in a dtb embedded in an image
4370
4371 Args:
4372 data: The image data
4373 pad_len: Length of the pad section in the image, in bytes
4374 start: Start offset of the devicetree to examine, within the image
4375
4376 Returns:
4377 Size of the devicetree in bytes
4378 """
4379 dtb_data = data[start:]
4380 dtb = fdt.Fdt.FromData(dtb_data)
4381 fdt_size = dtb.GetFdtObj().totalsize()
4382 dtb.Scan()
4383 props = self._GetPropTree(dtb, 'size')
4384 self.assertEqual({
4385 'size': len(data),
4386 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4387 'u-boot-spl/u-boot-spl-dtb:size': 801,
4388 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4389 'u-boot-spl:size': 860,
4390 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4391 'u-boot/u-boot-dtb:size': 781,
4392 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4393 'u-boot:size': 827,
4394 }, props)
4395 return fdt_size
4396
4397 def testExpanded(self):
4398 """Test that an expanded entry type is selected when needed"""
4399 self._SetupSplElf()
4400 self._SetupTplElf()
4401
4402 # SPL has a devicetree, TPL does not
4403 entry_args = {
4404 'spl-dtb': '1',
4405 'spl-bss-pad': 'y',
4406 'tpl-dtb': '',
4407 }
4408 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4409 entry_args=entry_args)
4410 image = control.images['image']
4411 entries = image.GetEntries()
4412 self.assertEqual(3, len(entries))
4413
4414 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4415 self.assertIn('u-boot', entries)
4416 entry = entries['u-boot']
4417 self.assertEqual('u-boot-expanded', entry.etype)
4418 subent = entry.GetEntries()
4419 self.assertEqual(2, len(subent))
4420 self.assertIn('u-boot-nodtb', subent)
4421 self.assertIn('u-boot-dtb', subent)
4422
4423 # Second, u-boot-spl, which should be expanded into three parts
4424 self.assertIn('u-boot-spl', entries)
4425 entry = entries['u-boot-spl']
4426 self.assertEqual('u-boot-spl-expanded', entry.etype)
4427 subent = entry.GetEntries()
4428 self.assertEqual(3, len(subent))
4429 self.assertIn('u-boot-spl-nodtb', subent)
4430 self.assertIn('u-boot-spl-bss-pad', subent)
4431 self.assertIn('u-boot-spl-dtb', subent)
4432
4433 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4434 # devicetree
4435 self.assertIn('u-boot-tpl', entries)
4436 entry = entries['u-boot-tpl']
4437 self.assertEqual('u-boot-tpl', entry.etype)
4438 self.assertEqual(None, entry.GetEntries())
4439
4440 def testExpandedTpl(self):
4441 """Test that an expanded entry type is selected for TPL when needed"""
4442 self._SetupTplElf()
4443
4444 entry_args = {
4445 'tpl-bss-pad': 'y',
4446 'tpl-dtb': 'y',
4447 }
4448 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4449 entry_args=entry_args)
4450 image = control.images['image']
4451 entries = image.GetEntries()
4452 self.assertEqual(1, len(entries))
4453
4454 # We only have u-boot-tpl, which be expanded
4455 self.assertIn('u-boot-tpl', entries)
4456 entry = entries['u-boot-tpl']
4457 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4458 subent = entry.GetEntries()
4459 self.assertEqual(3, len(subent))
4460 self.assertIn('u-boot-tpl-nodtb', subent)
4461 self.assertIn('u-boot-tpl-bss-pad', subent)
4462 self.assertIn('u-boot-tpl-dtb', subent)
4463
4464 def testExpandedNoPad(self):
4465 """Test an expanded entry without BSS pad enabled"""
4466 self._SetupSplElf()
4467 self._SetupTplElf()
4468
4469 # SPL has a devicetree, TPL does not
4470 entry_args = {
4471 'spl-dtb': 'something',
4472 'spl-bss-pad': 'n',
4473 'tpl-dtb': '',
4474 }
4475 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4476 entry_args=entry_args)
4477 image = control.images['image']
4478 entries = image.GetEntries()
4479
4480 # Just check u-boot-spl, which should be expanded into two parts
4481 self.assertIn('u-boot-spl', entries)
4482 entry = entries['u-boot-spl']
4483 self.assertEqual('u-boot-spl-expanded', entry.etype)
4484 subent = entry.GetEntries()
4485 self.assertEqual(2, len(subent))
4486 self.assertIn('u-boot-spl-nodtb', subent)
4487 self.assertIn('u-boot-spl-dtb', subent)
4488
4489 def testExpandedTplNoPad(self):
4490 """Test that an expanded entry type with padding disabled in TPL"""
4491 self._SetupTplElf()
4492
4493 entry_args = {
4494 'tpl-bss-pad': '',
4495 'tpl-dtb': 'y',
4496 }
4497 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4498 entry_args=entry_args)
4499 image = control.images['image']
4500 entries = image.GetEntries()
4501 self.assertEqual(1, len(entries))
4502
4503 # We only have u-boot-tpl, which be expanded
4504 self.assertIn('u-boot-tpl', entries)
4505 entry = entries['u-boot-tpl']
4506 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4507 subent = entry.GetEntries()
4508 self.assertEqual(2, len(subent))
4509 self.assertIn('u-boot-tpl-nodtb', subent)
4510 self.assertIn('u-boot-tpl-dtb', subent)
4511
4512 def testFdtInclude(self):
4513 """Test that an Fdt is update within all binaries"""
4514 self._SetupSplElf()
4515 self._SetupTplElf()
4516
4517 # SPL has a devicetree, TPL does not
4518 self.maxDiff = None
4519 entry_args = {
4520 'spl-dtb': '1',
4521 'spl-bss-pad': 'y',
4522 'tpl-dtb': '',
4523 }
4524 # Build the image. It includes two separate devicetree binaries, each
4525 # with their own contents, but all contain the binman definition.
4526 data = self._DoReadFileDtb(
4527 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4528 update_dtb=True, entry_args=entry_args)[0]
4529 pad_len = 10
4530
4531 # Check the U-Boot dtb
4532 start = len(U_BOOT_NODTB_DATA)
4533 fdt_size = self.checkDtbSizes(data, pad_len, start)
4534
4535 # Now check SPL
4536 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4537 fdt_size = self.checkDtbSizes(data, pad_len, start)
4538
4539 # TPL has no devicetree
4540 start += fdt_size + len(U_BOOT_TPL_DATA)
4541 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004542
Simon Glass7098b7f2021-03-21 18:24:30 +13004543 def testSymbolsExpanded(self):
4544 """Test binman can assign symbols in expanded entries"""
4545 entry_args = {
4546 'spl-dtb': '1',
4547 }
4548 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4549 U_BOOT_SPL_DTB_DATA, 0x38,
4550 entry_args=entry_args, use_expanded=True)
4551
Simon Glasse1915782021-03-21 18:24:31 +13004552 def testCollection(self):
4553 """Test a collection"""
4554 data = self._DoReadFile('198_collection.dts')
4555 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
4556 tools.GetBytes(0xff, 2) + U_BOOT_NODTB_DATA +
4557 tools.GetBytes(0xfe, 3) + U_BOOT_DTB_DATA,
4558 data)
4559
Simon Glass27a7f772021-03-21 18:24:32 +13004560 def testCollectionSection(self):
4561 """Test a collection where a section must be built first"""
4562 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004563 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004564 # building the contents, producing an error is anything is still
4565 # missing.
4566 data = self._DoReadFile('199_collection_section.dts')
4567 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
4568 self.assertEqual(section + U_BOOT_DATA + tools.GetBytes(0xff, 2) +
4569 section + tools.GetBytes(0xfe, 3) + U_BOOT_DATA,
4570 data)
4571
Simon Glassf427c5f2021-03-21 18:24:33 +13004572 def testAlignDefault(self):
4573 """Test that default alignment works on sections"""
4574 data = self._DoReadFile('200_align_default.dts')
4575 expected = (U_BOOT_DATA + tools.GetBytes(0, 8 - len(U_BOOT_DATA)) +
4576 U_BOOT_DATA)
4577 # Special alignment for section
4578 expected += tools.GetBytes(0, 32 - len(expected))
4579 # No alignment within the nested section
4580 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4581 # Now the final piece, which should be default-aligned
4582 expected += tools.GetBytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
4583 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004584
Bin Mengc0b15742021-05-10 20:23:33 +08004585 def testPackOpenSBI(self):
4586 """Test that an image with an OpenSBI binary can be created"""
4587 data = self._DoReadFile('201_opensbi.dts')
4588 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4589
Simon Glass76f496d2021-07-06 10:36:37 -06004590 def testSectionsSingleThread(self):
4591 """Test sections without multithreading"""
4592 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
4593 expected = (U_BOOT_DATA + tools.GetBytes(ord('!'), 12) +
4594 U_BOOT_DATA + tools.GetBytes(ord('a'), 12) +
4595 U_BOOT_DATA + tools.GetBytes(ord('&'), 4))
4596 self.assertEqual(expected, data)
4597
4598 def testThreadTimeout(self):
4599 """Test handling a thread that takes too long"""
4600 with self.assertRaises(ValueError) as e:
4601 self._DoTestFile('202_section_timeout.dts',
4602 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004603 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004604
Simon Glass748a1d42021-07-06 10:36:41 -06004605 def testTiming(self):
4606 """Test output of timing information"""
4607 data = self._DoReadFile('055_sections.dts')
4608 with test_util.capture_sys_output() as (stdout, stderr):
4609 state.TimingShow()
4610 self.assertIn('read:', stdout.getvalue())
4611 self.assertIn('compress:', stdout.getvalue())
4612
Simon Glassadfb8492021-11-03 21:09:18 -06004613 def testUpdateFdtInElf(self):
4614 """Test that we can update the devicetree in an ELF file"""
4615 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4616 outfile = os.path.join(self._indir, 'u-boot.out')
4617 begin_sym = 'dtb_embed_begin'
4618 end_sym = 'dtb_embed_end'
4619 retcode = self._DoTestFile(
4620 '060_fdt_update.dts', update_dtb=True,
4621 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4622 self.assertEqual(0, retcode)
4623
4624 # Check that the output file does in fact contact a dtb with the binman
4625 # definition in the correct place
4626 syms = elf.GetSymbolFileOffset(infile,
4627 ['dtb_embed_begin', 'dtb_embed_end'])
4628 data = tools.ReadFile(outfile)
4629 dtb_data = data[syms['dtb_embed_begin'].offset:
4630 syms['dtb_embed_end'].offset]
4631
4632 dtb = fdt.Fdt.FromData(dtb_data)
4633 dtb.Scan()
4634 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4635 self.assertEqual({
4636 'image-pos': 0,
4637 'offset': 0,
4638 '_testing:offset': 32,
4639 '_testing:size': 2,
4640 '_testing:image-pos': 32,
4641 'section@0/u-boot:offset': 0,
4642 'section@0/u-boot:size': len(U_BOOT_DATA),
4643 'section@0/u-boot:image-pos': 0,
4644 'section@0:offset': 0,
4645 'section@0:size': 16,
4646 'section@0:image-pos': 0,
4647
4648 'section@1/u-boot:offset': 0,
4649 'section@1/u-boot:size': len(U_BOOT_DATA),
4650 'section@1/u-boot:image-pos': 16,
4651 'section@1:offset': 16,
4652 'section@1:size': 16,
4653 'section@1:image-pos': 16,
4654 'size': 40
4655 }, props)
4656
4657 def testUpdateFdtInElfInvalid(self):
4658 """Test that invalid args are detected with --update-fdt-in-elf"""
4659 with self.assertRaises(ValueError) as e:
4660 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4661 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4662 str(e.exception))
4663
4664 def testUpdateFdtInElfNoSyms(self):
4665 """Test that missing symbols are detected with --update-fdt-in-elf"""
4666 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4667 outfile = ''
4668 begin_sym = 'wrong_begin'
4669 end_sym = 'wrong_end'
4670 with self.assertRaises(ValueError) as e:
4671 self._DoTestFile(
4672 '060_fdt_update.dts',
4673 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4674 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4675 str(e.exception))
4676
4677 def testUpdateFdtInElfTooSmall(self):
4678 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4679 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4680 outfile = os.path.join(self._indir, 'u-boot.out')
4681 begin_sym = 'dtb_embed_begin'
4682 end_sym = 'dtb_embed_end'
4683 with self.assertRaises(ValueError) as e:
4684 self._DoTestFile(
4685 '060_fdt_update.dts', update_dtb=True,
4686 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4687 self.assertRegex(
4688 str(e.exception),
4689 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4690
Simon Glass88e04da2021-11-23 11:03:42 -07004691 def testVersion(self):
4692 """Test we can get the binman version"""
4693 version = '(unreleased)'
4694 self.assertEqual(version, state.GetVersion(self._indir))
4695
4696 with self.assertRaises(SystemExit):
4697 with test_util.capture_sys_output() as (_, stderr):
4698 self._DoBinman('-V')
4699 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4700
4701 # Try running the tool too, just to be safe
4702 result = self._RunBinman('-V')
4703 self.assertEqual('Binman %s\n' % version, result.stderr)
4704
4705 # Set up a version file to make sure that works
4706 version = 'v2025.01-rc2'
4707 tools.WriteFile(os.path.join(self._indir, 'version'), version,
4708 binary=False)
4709 self.assertEqual(version, state.GetVersion(self._indir))
4710
Simon Glass637958f2021-11-23 21:09:50 -07004711 def testAltFormat(self):
4712 """Test that alternative formats can be used to extract"""
4713 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4714
4715 try:
4716 tmpdir, updated_fname = self._SetupImageInTmpdir()
4717 with test_util.capture_sys_output() as (stdout, _):
4718 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4719 self.assertEqual(
4720 '''Flag (-F) Entry type Description
4721fdt fdtmap Extract the devicetree blob from the fdtmap
4722''',
4723 stdout.getvalue())
4724
4725 dtb = os.path.join(tmpdir, 'fdt.dtb')
4726 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4727 dtb, 'fdtmap')
4728
4729 # Check that we can read it and it can be scanning, meaning it does
4730 # not have a 16-byte fdtmap header
4731 data = tools.ReadFile(dtb)
4732 dtb = fdt.Fdt.FromData(data)
4733 dtb.Scan()
4734
4735 # Now check u-boot which has no alt_format
4736 fname = os.path.join(tmpdir, 'fdt.dtb')
4737 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4738 '-f', fname, 'u-boot')
4739 data = tools.ReadFile(fname)
4740 self.assertEqual(U_BOOT_DATA, data)
4741
4742 finally:
4743 shutil.rmtree(tmpdir)
4744
Simon Glass0b00ae62021-11-23 21:09:52 -07004745 def testExtblobList(self):
4746 """Test an image with an external blob list"""
4747 data = self._DoReadFile('215_blob_ext_list.dts')
4748 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4749
4750 def testExtblobListMissing(self):
4751 """Test an image with a missing external blob"""
4752 with self.assertRaises(ValueError) as e:
4753 self._DoReadFile('216_blob_ext_list_missing.dts')
4754 self.assertIn("Filename 'missing-file' not found in input path",
4755 str(e.exception))
4756
4757 def testExtblobListMissingOk(self):
4758 """Test an image with an missing external blob that is allowed"""
4759 with test_util.capture_sys_output() as (stdout, stderr):
4760 self._DoTestFile('216_blob_ext_list_missing.dts',
4761 allow_missing=True)
4762 err = stderr.getvalue()
4763 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4764
Simon Glass3efb2972021-11-23 21:08:59 -07004765 def testFip(self):
4766 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4767 data = self._DoReadFile('203_fip.dts')
4768 hdr, fents = fip_util.decode_fip(data)
4769 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4770 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4771 self.assertEqual(0x123, hdr.flags)
4772
4773 self.assertEqual(2, len(fents))
4774
4775 fent = fents[0]
4776 self.assertEqual(
4777 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4778 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4779 self.assertEqual('soc-fw', fent.fip_type)
4780 self.assertEqual(0x88, fent.offset)
4781 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4782 self.assertEqual(0x123456789abcdef, fent.flags)
4783 self.assertEqual(ATF_BL31_DATA, fent.data)
4784 self.assertEqual(True, fent.valid)
4785
4786 fent = fents[1]
4787 self.assertEqual(
4788 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4789 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4790 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4791 self.assertEqual(0x8c, fent.offset)
4792 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4793 self.assertEqual(0, fent.flags)
4794 self.assertEqual(ATF_BL2U_DATA, fent.data)
4795 self.assertEqual(True, fent.valid)
4796
4797 def testFipOther(self):
4798 """Basic FIP with something that isn't a external blob"""
4799 data = self._DoReadFile('204_fip_other.dts')
4800 hdr, fents = fip_util.decode_fip(data)
4801
4802 self.assertEqual(2, len(fents))
4803 fent = fents[1]
4804 self.assertEqual('rot-cert', fent.fip_type)
4805 self.assertEqual(b'aa', fent.data)
4806
4807 def testFipOther(self):
4808 """Basic FIP with something that isn't a external blob"""
4809 data = self._DoReadFile('204_fip_other.dts')
4810 hdr, fents = fip_util.decode_fip(data)
4811
4812 self.assertEqual(2, len(fents))
4813 fent = fents[1]
4814 self.assertEqual('rot-cert', fent.fip_type)
4815 self.assertEqual(b'aa', fent.data)
4816
4817 def testFipNoType(self):
4818 """FIP with an entry of an unknown type"""
4819 with self.assertRaises(ValueError) as e:
4820 self._DoReadFile('205_fip_no_type.dts')
4821 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4822 str(e.exception))
4823
4824 def testFipUuid(self):
4825 """Basic FIP with a manual uuid"""
4826 data = self._DoReadFile('206_fip_uuid.dts')
4827 hdr, fents = fip_util.decode_fip(data)
4828
4829 self.assertEqual(2, len(fents))
4830 fent = fents[1]
4831 self.assertEqual(None, fent.fip_type)
4832 self.assertEqual(
4833 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4834 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4835 fent.uuid)
4836 self.assertEqual(U_BOOT_DATA, fent.data)
4837
4838 def testFipLs(self):
4839 """Test listing a FIP"""
4840 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4841 hdr, fents = fip_util.decode_fip(data)
4842
4843 try:
4844 tmpdir, updated_fname = self._SetupImageInTmpdir()
4845 with test_util.capture_sys_output() as (stdout, stderr):
4846 self._DoBinman('ls', '-i', updated_fname)
4847 finally:
4848 shutil.rmtree(tmpdir)
4849 lines = stdout.getvalue().splitlines()
4850 expected = [
4851'Name Image-pos Size Entry-type Offset Uncomp-size',
4852'----------------------------------------------------------------',
4853'main-section 0 2d3 section 0',
4854' atf-fip 0 90 atf-fip 0',
4855' soc-fw 88 4 blob-ext 88',
4856' u-boot 8c 4 u-boot 8c',
4857' fdtmap 90 243 fdtmap 90',
4858]
4859 self.assertEqual(expected, lines)
4860
4861 image = control.images['image']
4862 entries = image.GetEntries()
4863 fdtmap = entries['fdtmap']
4864
4865 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4866 magic = fdtmap_data[:8]
4867 self.assertEqual(b'_FDTMAP_', magic)
4868 self.assertEqual(tools.GetBytes(0, 8), fdtmap_data[8:16])
4869
4870 fdt_data = fdtmap_data[16:]
4871 dtb = fdt.Fdt.FromData(fdt_data)
4872 dtb.Scan()
4873 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4874 self.assertEqual({
4875 'atf-fip/soc-fw:image-pos': 136,
4876 'atf-fip/soc-fw:offset': 136,
4877 'atf-fip/soc-fw:size': 4,
4878 'atf-fip/u-boot:image-pos': 140,
4879 'atf-fip/u-boot:offset': 140,
4880 'atf-fip/u-boot:size': 4,
4881 'atf-fip:image-pos': 0,
4882 'atf-fip:offset': 0,
4883 'atf-fip:size': 144,
4884 'image-pos': 0,
4885 'offset': 0,
4886 'fdtmap:image-pos': fdtmap.image_pos,
4887 'fdtmap:offset': fdtmap.offset,
4888 'fdtmap:size': len(fdtmap_data),
4889 'size': len(data),
4890 }, props)
4891
4892 def testFipExtractOneEntry(self):
4893 """Test extracting a single entry fron an FIP"""
4894 self._DoReadFileRealDtb('207_fip_ls.dts')
4895 image_fname = tools.GetOutputFilename('image.bin')
4896 fname = os.path.join(self._indir, 'output.extact')
4897 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
4898 data = tools.ReadFile(fname)
4899 self.assertEqual(U_BOOT_DATA, data)
4900
4901 def testFipReplace(self):
4902 """Test replacing a single file in a FIP"""
4903 expected = U_BOOT_DATA + tools.GetBytes(0x78, 50)
4904 data = self._DoReadFileRealDtb('208_fip_replace.dts')
4905 updated_fname = tools.GetOutputFilename('image-updated.bin')
4906 tools.WriteFile(updated_fname, data)
4907 entry_name = 'atf-fip/u-boot'
4908 control.WriteEntry(updated_fname, entry_name, expected,
4909 allow_resize=True)
4910 actual = control.ReadEntry(updated_fname, entry_name)
4911 self.assertEqual(expected, actual)
4912
4913 new_data = tools.ReadFile(updated_fname)
4914 hdr, fents = fip_util.decode_fip(new_data)
4915
4916 self.assertEqual(2, len(fents))
4917
4918 # Check that the FIP entry is updated
4919 fent = fents[1]
4920 self.assertEqual(0x8c, fent.offset)
4921 self.assertEqual(len(expected), fent.size)
4922 self.assertEqual(0, fent.flags)
4923 self.assertEqual(expected, fent.data)
4924 self.assertEqual(True, fent.valid)
4925
4926 def testFipMissing(self):
4927 with test_util.capture_sys_output() as (stdout, stderr):
4928 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4929 err = stderr.getvalue()
4930 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4931
4932 def testFipSize(self):
4933 """Test a FIP with a size property"""
4934 data = self._DoReadFile('210_fip_size.dts')
4935 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4936 hdr, fents = fip_util.decode_fip(data)
4937 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4938 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4939
4940 self.assertEqual(1, len(fents))
4941
4942 fent = fents[0]
4943 self.assertEqual('soc-fw', fent.fip_type)
4944 self.assertEqual(0x60, fent.offset)
4945 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4946 self.assertEqual(ATF_BL31_DATA, fent.data)
4947 self.assertEqual(True, fent.valid)
4948
4949 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
4950 self.assertEqual(tools.GetBytes(0xff, len(rest)), rest)
4951
4952 def testFipBadAlign(self):
4953 """Test that an invalid alignment value in a FIP is detected"""
4954 with self.assertRaises(ValueError) as e:
4955 self._DoTestFile('211_fip_bad_align.dts')
4956 self.assertIn(
4957 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
4958 str(e.exception))
4959
4960 def testFipCollection(self):
4961 """Test using a FIP in a collection"""
4962 data = self._DoReadFile('212_fip_collection.dts')
4963 entry1 = control.images['image'].GetEntries()['collection']
4964 data1 = data[:entry1.size]
4965 hdr1, fents2 = fip_util.decode_fip(data1)
4966
4967 entry2 = control.images['image'].GetEntries()['atf-fip']
4968 data2 = data[entry2.offset:entry2.offset + entry2.size]
4969 hdr1, fents2 = fip_util.decode_fip(data2)
4970
4971 # The 'collection' entry should have U-Boot included at the end
4972 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
4973 self.assertEqual(data1, data2 + U_BOOT_DATA)
4974 self.assertEqual(U_BOOT_DATA, data1[-4:])
4975
4976 # There should be a U-Boot after the final FIP
4977 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06004978
Simon Glassccae6862022-01-12 13:10:35 -07004979 def testFakeBlob(self):
4980 """Test handling of faking an external blob"""
4981 with test_util.capture_sys_output() as (stdout, stderr):
4982 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
4983 allow_fake_blobs=True)
4984 err = stderr.getvalue()
4985 self.assertRegex(
4986 err,
4987 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07004988
Simon Glassceb5f912022-01-09 20:13:46 -07004989 def testExtblobListFaked(self):
4990 """Test an extblob with missing external blob that are faked"""
4991 with test_util.capture_sys_output() as (stdout, stderr):
4992 self._DoTestFile('216_blob_ext_list_missing.dts',
4993 allow_fake_blobs=True)
4994 err = stderr.getvalue()
4995 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
4996
Simon Glass162017b2022-01-09 20:13:57 -07004997 def testListBintools(self):
4998 args = ['tool', '--list']
4999 with test_util.capture_sys_output() as (stdout, _):
5000 self._DoBinman(*args)
5001 out = stdout.getvalue().splitlines()
5002 self.assertTrue(len(out) >= 2)
5003
5004 def testFetchBintools(self):
5005 def fail_download(url):
5006 """Take the tools.Download() function by raising an exception"""
5007 raise urllib.error.URLError('my error')
5008
5009 args = ['tool']
5010 with self.assertRaises(ValueError) as e:
5011 self._DoBinman(*args)
5012 self.assertIn("Invalid arguments to 'tool' subcommand",
5013 str(e.exception))
5014
5015 args = ['tool', '--fetch']
5016 with self.assertRaises(ValueError) as e:
5017 self._DoBinman(*args)
5018 self.assertIn('Please specify bintools to fetch', str(e.exception))
5019
5020 args = ['tool', '--fetch', '_testing']
5021 with unittest.mock.patch.object(tools, 'Download',
5022 side_effect=fail_download):
5023 with test_util.capture_sys_output() as (stdout, _):
5024 self._DoBinman(*args)
5025 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5026
Simon Glassccae6862022-01-12 13:10:35 -07005027
Simon Glassac599912017-11-12 21:52:22 -07005028if __name__ == "__main__":
5029 unittest.main()